Beispiel #1
0
    def sessionOpened(self):
        if self.networkSession is not None:
            config = self.networkSession.configuration()

            if config.type() == QNetworkConfiguration.UserChoice:
                id = self.networkSession.sessionProperty('UserChoiceConfiguration')
            else:
                id = config.identifier()

            settings = QSettings(QSettings.UserScope, 'QtProject')
            settings.beginGroup('QtNetwork')
            settings.setValue('DefaultNetworkConfiguration', id)
            settings.endGroup();

        self.tcpServer = QTcpServer(self)
        if not self.tcpServer.listen():
            QMessageBox.critical(self, "Fortune Server",
                    "Unable to start the server: %s." % self.tcpServer.errorString())
            self.close()
            return

        for ipAddress in QNetworkInterface.allAddresses():
            if ipAddress != QHostAddress.LocalHost and ipAddress.toIPv4Address() != 0:
                break
        else:
            ipAddress = QHostAddress(QHostAddress.LocalHost)

        ipAddress = ipAddress.toString()

        self.statusLabel.setText("The server is running on\n\nIP: %s\nport %d\n\n"
                "Run the Fortune Client example now." % (ipAddress, self.tcpServer.serverPort()))
Beispiel #2
0
class CookieJar(QNetworkCookieJar):
    def __init__(self):
        super(CookieJar, self).__init__()

        cookie_location = os.path.join(QStandardPaths.writableLocation(QStandardPaths.DataLocation) ,'cookies.ini')
        self.cookie_store = QSettings(cookie_location, QSettings.IniFormat)
        self.load()

    def load(self):
        data = self.cookie_store.value('cookies', [])
        if data:
            self.setAllCookies([QNetworkCookie.parseCookies(c)[0] for c in data])

    def save(self):
        self.remove_expired_cookies()
        lines = []
        for cookie in self.allCookies():
            if not cookie.isSessionCookie():
                lines.append(cookie.toRawForm())
        self.cookie_store.setValue('cookies', QVariant(lines))

    def remove_expired_cookies(self):
        now = QDateTime.currentDateTime()
        cookies = [c for c in self.allCookies()
                   if c.isSessionCookie() or c.expirationDate() >= now]
        self.setAllCookies(cookies)
Beispiel #3
0
 def writeSettings(self):
     s = QSettings()
     s.beginGroup("pitch-menu")
     s.setValue("relative-first-pitch-absolute",
         self.actionCollection.pitch_relative_assume_first_pitch_absolute.isChecked())
     s.setValue("relative-write-startpitch",
         self.actionCollection.pitch_relative_write_startpitch.isChecked())
Beispiel #4
0
    def setCurrentFile(self, fileName):
        self.curFile = QFileInfo(fileName).canonicalFilePath()
        self.isUntitled = False
        self.setWindowModified(False)
        if self.curFile:
            self.setWindowTitle("Recent Files %s" % self.strippedName(self.curFile))
        else:
            self.setWindowTitle("Recent Files")

        settings = QSettings('Trolltech', 'Recent Files Example')
        files = settings.value('recentFileList', [])

        try:
            files.remove(fileName)
        except ValueError:
            pass

        files.insert(0, fileName)
        del files[MainWindow.MaxRecentFiles:]

        settings.setValue('recentFileList', files)

        for widget in QApplication.topLevelWidgets():
            if isinstance(widget, MainWindow):
                widget.updateRecentFileActions()
Beispiel #5
0
    def updateRecentFileActions(self, insert_file=None):
        settings = QSettings('Cemu', 'Recent Files')
        files = settings.value('recentFileList')
        if files is None:
            # if setting doesn't exist, create it
            settings.setValue('recentFileList', [])
            files = settings.value('recentFileList')

        maxRecentFiles = CEmuWindow.MaxRecentFiles

        if insert_file:
            # insert new file to list
            if insert_file not in files:
                files.insert(0, insert_file)
            # ensure list size
            if len(files) > maxRecentFiles:
                files = files[0:maxRecentFiles]
            # save the setting
            settings.setValue('recentFileList', files)

        numRecentFiles = min(len(files), maxRecentFiles)

        for i in range(numRecentFiles):
            text = "&%d %s" % (i + 1, self.strippedName(files[i]))
            self.recentFileActions[i].setText(text)
            self.recentFileActions[i].setData(files[i])
            self.recentFileActions[i].setVisible(True)

        for j in range(numRecentFiles, maxRecentFiles):
            self.recentFileActions[j].setVisible(False)
        return
 def closeEvent(self, event):
     print("Main window close event")
     # Save layout settings
     settings = QSettings("PhotoCalendar")
     settings.beginGroup("MainWindow")
     curSize = self.size()
     settings.setValue("Size", QVariant(curSize))
     curPos = self.pos()
     settings.setValue("Position", QVariant(curPos))
     #settings.setValue("MainWindow/State", QVariant(self.saveState()))
     horzSplitterState = self.horzSplitter.saveState()
     #print("HorzSplitter save", horzSplitterState)
     settings.setValue("HorzSplitter", QVariant(horzSplitterState))
     leftPaneSplitterState = self.leftPane.saveState()
     settings.setValue("LeftPaneSplitter", QVariant(leftPaneSplitterState))
     #print("LeftPaneSplitter save", leftPaneSplitterState)
     rightPaneSplitterState = self.rightPane.saveState()
     settings.setValue("RightPaneSplitter", QVariant(rightPaneSplitterState))
     #print("RightPaneSplitter save", leftPaneSplitterState)
     settings.endGroup()
     # Stop the sub-elements
     self.calendar.stop()
     self.clock.stop()
     self.photos.stop()
     # Accept the close event
     event.accept()
    def add_path(self, path):
        "Adds path to recent documents"
        recent = self.read_paths()

        # Make the path absolute, resolving any symlinks.
        path = self._resolved_if_possible(Path(path))

        # Remove the existing occurrence of path, if present.
        # A linear scan is acceptable here because the list will always
        # be very short
        try:
            recent.remove(path)
        except ValueError:
            # path is not currently in recent
            pass

        # Prepend the path
        recent.insert(0, str(path))

        # Limit to MAX_RECENT_DOCS
        recent = recent[:self.MAX_RECENT_DOCS]

        debug_print('Writing {0} recent document paths'.format(len(recent)))

        settings = QSettings()
        settings.beginWriteArray(self.KEY, len(recent))
        try:
            for index, path in enumerate(recent):
                settings.setArrayIndex(index)
                settings.setValue('path', str(path))
        finally:
            settings.endArray()
Beispiel #8
0
    def start(self):
        file = self.destination.text().strip()
        if not file:
            QMessageBox.warning(self,
                              self.tr("Create mobile collection"),
                              self.tr("Destination file not specified"))
            return

        density = self.densitySelector.currentText()
        settings = QSettings()
        settings.setValue('density', density)

        self.params['filter'] = self.filterSelector.itemData(self.filterSelector.currentIndex())
        self.params['density'] = density
        self.params['file'] = file
        if self.obverseRadio.isChecked():
            self.params['image'] = self.IMAGE_OBVERSE
        elif self.reverseRadio.isChecked():
            self.params['image'] = self.IMAGE_REVERSE
        elif self.noneRadio.isChecked():
            self.params['image'] = self.IMAGE_NONE
        else:
            self.params['image'] = self.IMAGE_BOTH

        self.accept()
Beispiel #9
0
 def _on_click_on_favorite(self, path, value):
     settings = QSettings(resources.SETTINGS_PATH, QSettings.IniFormat)
     recent_projects = settings.value("recentProjects")
     properties = recent_projects[path]
     properties["isFavorite"] = value
     recent_projects[path] = properties
     settings.setValue("recentProjects", recent_projects)
Beispiel #10
0
 def dropEvent(self, event):
     if event.mimeData().hasFormat('text/uri-list'):
         paths = [url for url in event.mimeData().urls()]
         # If we drop many files, only the first one will be take into
         # acount
         fileName = paths[0]
         index = self.indexAt(event.pos())
         row, col = index.row(), index.column()
         settings = QSettings()
         if col == UploadListView.COL_VIDEO:
             if(VideoTools.isVideofile(fileName)):
                 settings.setValue("mainwindow/workingDirectory", fileName)
                 video = VideoFile(fileName)
                 self.model().layoutAboutToBeChanged.emit()
                 self.model().addVideos(row, [video])
                 subtitle = Subtitle.AutoDetectSubtitle(video.getFilePath())
                 if subtitle:
                     sub = SubtitleFile(False, subtitle)
                     self.model().addSubs(row, [sub])
                     thread.start_new_thread(
                         self.uploadModel.ObtainUploadInfo, ())
                 self.resizeRowsToContents()
                 self.model().layoutChanged.emit()
         else:  # if it's the column in SUBTITLES
             print(fileName)
             if(Subtitle.isSubtitle(fileName)):
                 settings.setValue("mainwindow/workingDirectory", fileName)
                 sub = SubtitleFile(False, fileName)
                 self.model().layoutAboutToBeChanged.emit()
                 self.model().addSubs(row, [sub])
                 self.resizeRowsToContents()
                 self.model().layoutChanged.emit()
                 thread.start_new_thread(
                     self.uploadModel.ObtainUploadInfo, ())
Beispiel #11
0
 def saveSettings(self):
     s = QSettings()
     s.beginGroup("documentstructure")
     if self.patternList.value() != documentstructure.default_outline_patterns:
         s.setValue("outline_patterns", self.patternList.value())
     else:
         s.remove("outline_patterns")
 def SetLanguage(self):
     global actualLanguage
     settings = QSettings('Pandoc', 'PanConvert')
     settings.setValue('default_language', str(self.ui.comboBoxLanguageSelector.currentText()))
     actualLanguage = str(self.ui.comboBoxLanguageSelector.currentText())
     settings.sync()
     settings.status()
Beispiel #13
0
    def on_save_defaults(self):
        settings = QSettings()

        parameters = MaskParameters()
        self.update_parameters_from_ui(parameters)
        defaults = parameters.serialize()
        settings.setValue("mask/defaults", defaults)
Beispiel #14
0
    def _save_settings(self):
        """ Save the user specific settings. """

        settings = QSettings()

        settings.setValue('size', self.size())
        settings.setValue('pos', self.pos())
Beispiel #15
0
 def saveSettings(self):
     s = QSettings()
     s.beginGroup("typographical_quotes")
     s.setValue("language", self._langs[self.languageCombo.currentIndex()])
     s.setValue("primary_left", self.primaryLeft.text())
     s.setValue("primary_right", self.primaryRight.text())
     s.setValue("secondary_left", self.secondaryLeft.text())
     s.setValue("secondary_right", self.secondaryRight.text())
    def save_sizes(self):
        """ Save sizes of Splitters """

        qsettings = QSettings(settings.SETTINGS_PATH, QSettings.IniFormat)
        qsettings.setValue('result_splitter_query_sizes',
                           self.result_splitter.saveState())
        qsettings.setValue('editor_splitter_query_sizes',
                           self._editor_splitter.saveState())
Beispiel #17
0
 def saveSettings(self):
     s = QSettings()
     s.beginGroup("log")
     s.setValue("fontfamily", self.fontChooser.currentFont().family())
     s.setValue("fontsize", self.fontSize.value())
     s.setValue("show_on_start", self.showlog.isChecked())
     s.setValue("rawview", self.rawview.isChecked())
     s.setValue("hide_auto_engrave", self.hideauto.isChecked())
Beispiel #18
0
 def saveSettings(self):
     s = QSettings()
     s.beginGroup("hyphenation")
     paths = self.listedit.value()
     if paths:
         s.setValue("paths", paths)
     else:
         s.remove("paths")
    def done(self, r):
        settings = QSettings()
        orig_class_name = self.__class__.__name__
        settings.setValue('%s/maximized' % orig_class_name, self.isMaximized())
        if not self.isMaximized():
            settings.setValue('%s/size' % orig_class_name, self.size())

        orig_done(self, r)  # call the original done
Beispiel #20
0
 def saveSettings(self):
     s = QSettings()
     s.beginGroup("documentation")
     paths = self.paths.value()
     if paths:
         s.setValue("paths", paths)
     else:
         s.remove("paths")
Beispiel #21
0
 def writeSettings(self):
     s = QSettings()
     s.beginGroup("copy_image")
     s.setValue("dpi", self.dpiCombo.currentText())
     s.setValue("papercolor", self.colorButton.color())
     s.setValue("autocrop", self.crop.isChecked())
     s.setValue("antialias", self.antialias.isChecked())
     s.setValue("scaleup", self.scaleup.isChecked())
Beispiel #22
0
    def save_sizes(self):
        """ Save sizes of Splitters """

        qsettings = QSettings(settings.SETTINGS_PATH, QSettings.IniFormat)
        qsettings.setValue('hsplitter_query_sizes',
                           self._hsplitter.saveState())
        qsettings.setValue('vsplitter_query_sizes',
                           self._vsplitter.saveState())
Beispiel #23
0
 def closeEvent(self, event):
     device_settings = QSettings('superboucle', 'devices')
     device_settings.setValue('devices',
                              [pickle.dumps(x.mapping)
                               for x in self.devices])
     self.settings.setValue('playlist', self.playlist)
     self.settings.setValue('paths_used', self.paths_used)
     self.settings.setValue('auto_connect', self.auto_connect)
Beispiel #24
0
    def closeEvent(self, event):
        qsettings = QSettings(settings.SETTINGS_PATH, QSettings.IniFormat)
        # Save window geometry
        if self.isMaximized():
            qsettings.setValue('window_max', True)
        else:
            qsettings.setValue('window_max', False)
            qsettings.setValue('window_pos', self.pos())
            qsettings.setValue('window_size', self.size())

        central_widget = Pireal.get_service("central")
        # Save recent databases
        qsettings.setValue('recent_databases',
                           central_widget.recent_databases)
        db = central_widget.get_active_db()
        if db is not None:
            # Save splitters size
            db.save_sizes()
            # Databases unsaved
            if db.modified:
                msg = QMessageBox(self)
                msg.setIcon(QMessageBox.Question)
                msg.setWindowTitle(self.tr("Some changes where not saved"))
                msg.setText(
                    self.tr("Do you want to save changes to the database?"))
                cancel_btn = msg.addButton(self.tr("Cancel"),
                                           QMessageBox.RejectRole)
                msg.addButton(self.tr("No"),
                              QMessageBox.NoRole)
                yes_btn = msg.addButton(self.tr("Yes"),
                                        QMessageBox.YesRole)
                msg.exec_()
                r = msg.clickedButton()
                if r == yes_btn:
                    central_widget.save_database()
                if r == cancel_btn:
                    event.ignore()
            # Query files
            unsaved_editors = central_widget.get_unsaved_queries()
            if unsaved_editors:
                msg = QMessageBox(self)
                msg.setIcon(QMessageBox.Question)
                msg.setWindowTitle(self.tr("Unsaved Queries"))
                text = '\n'.join([editor.name for editor in unsaved_editors])
                msg.setText(self.tr("{files}<br><br>Do you want to "
                                    "save them?".format(files=text)))
                cancel_btn = msg.addButton(self.tr("Cancel"),
                                           QMessageBox.RejectRole)
                msg.addButton(self.tr("No"),
                              QMessageBox.NoRole)
                yes_btn = msg.addButton(self.tr("Yes"),
                                        QMessageBox.YesRole)
                msg.exec_()
                if msg.clickedButton() == yes_btn:
                    for editor in unsaved_editors:
                        central_widget.save_query(editor)
                if msg.clickedButton() == cancel_btn:
                    event.ignore()
Beispiel #25
0
def GetFirstRunTime():
    settings = QSettings()
    firstRunTime = settings.value("mainwindow/size2", "")
    if firstRunTime != "":
        return float(firstRunTime)
    else:
        now = time.time()
        settings.setValue("mainwindow/size2", now)
        return now
def test_init(init_patch, config_tmpdir):
    configfiles.init()

    # Make sure qsettings land in a subdir
    if utils.is_linux:
        settings = QSettings()
        settings.setValue("hello", "world")
        settings.sync()
        assert (config_tmpdir / 'qsettings').exists()
Beispiel #27
0
    def write_settings(self):
        """Saves known application settings to disk"""

        settings = QSettings()

        settings.setValue('myValue', 123456)

        # per PyQt docs to force write almost immediately...
        del settings
Beispiel #28
0
 def save_profile(self, profileName):
     """Save the updates from a profile."""
     projects_obj = self.ide.explorer.get_opened_projects()
     projects = [p.path for p in projects_obj]
     files = self.ide.mainContainer.get_opened_documents()
     files = files[0] + files[1]
     settings.PROFILES[profileName] = [files, projects]
     qsettings = QSettings(resources.SETTINGS_PATH, QSettings.IniFormat)
     qsettings.setValue('ide/profiles', settings.PROFILES)
Beispiel #29
0
 def save_state(self):
     assert self.ROLE
     settings = QSettings()
     settings.beginGroup(self.ROLE)
     settings.setValue('geometry', self.saveGeometry())
     if isinstance(self, QMainWindow):
         settings.setValue('state', self.saveState())
     self._save_state(settings)
     settings.endGroup()
Beispiel #30
0
 def closeEvent(self, event):
     Settings = QSettings('kicad-tools', 'Schematic Component Manager')
     Settings.setValue( 'geometry', self.saveGeometry() )
     Settings.setValue( 'cmptable',  [self.CmpTable.columnWidth(0), self.CmpTable.columnWidth(1)] )
     Settings.setValue( 'selector',  [self.Selector.columnWidth(0), self.Selector.columnWidth(1)] )
     Settings.setValue( 'inspector', [self.Inspector.columnWidth(0), self.Inspector.columnWidth(1)] )
     Settings.setValue( 'splitter', self.Splitter.saveState() )
     Settings.setValue( 'inssplitter', self.InspectorSplit.saveState() )
     QWidget.closeEvent(self, event)
Beispiel #31
0
class Geo360Dialog(QWidget, Ui_orbitalDialog):
    """Geo360 Dialog Class"""
    def __init__(self, iface, parent=None, featuresId=None, layer=None):

        QDialog.__init__(self)

        self.setupUi(self)
        self.s = QSettings()

        self.plugin_path = os.path.dirname(os.path.realpath(__file__))

        self.iface = iface
        self.canvas = self.iface.mapCanvas()
        self.parent = parent

        # Orientation from image
        self.yaw = math.pi
        self.bearing = None

        self.layer = layer
        self.featuresId = featuresId

        self.actualPointDx = None
        self.actualPointSx = None
        self.actualPointOrientation = None

        self.selected_features = qgsutils.getToFeature(self.layer,
                                                       self.featuresId)

        # Get image path
        self.current_image = self.GetImage()

        # Create Viewer
        self.CreateViewer()
        self.RestoreSize()
        # Check if image exist
        if os.path.exists(self.current_image) is False:
            qgsutils.showUserAndLogMessage(u"Information: ",
                                           u"There is no associated image.")
            self.resetQgsRubberBand()
            time.sleep(1)
            self.ChangeUrlViewer(config.DEFAULT_EMPTY)
            return

        # Copy file to local server
        self.CopyFile(self.current_image)

        # Set RubberBand
        self.resetQgsRubberBand()
        self.setOrientation()
        self.setPosition()

    def SetInitialYaw(self):
        ''' Set Initial Yaw '''
        self.bearing = self.selected_features.attribute(config.column_yaw)
        self.view.browser.GetMainFrame().ExecuteFunction(
            "InitialYaw", self.bearing)
        return

    def CreateViewer(self):
        ''' Create Viewer '''
        qgsutils.showUserAndLogMessage(u"Information: ",
                                       u"Create viewer",
                                       onlyLog=True)

        self.view = CefWidget(self)
        self.ViewerLayout.addWidget(self.view)
        self.view.embedBrowser()
        return

    def RemoveImage(self):
        ''' Remove Image '''
        try:
            os.remove(self.plugin_path + "\\viewer\\image.jpg")
        except OSError:
            pass

    def CopyFile(self, src):
        ''' Copy Image File in Local Server '''
        qgsutils.showUserAndLogMessage(u"Information: ",
                                       u"Copiar imagem",
                                       onlyLog=True)

        src_dir = src
        dst_dir = self.plugin_path + "\\viewer"

        # Copy image in local folder
        # Uncomment for large images if viewer is blank screen
        img = Image.open(src_dir)
        newwidth = 8000
        dst_dir = dst_dir + "\\image.jpg"

        try:
            os.remove(dst_dir)
        except OSError:
            pass

        width, _ = img.size

        if width > newwidth:
            wpercent = (newwidth / float(img.size[0]))
            hsize = int((float(img.size[1]) * float(wpercent)))
            img = img.resize((newwidth, hsize), Image.ANTIALIAS)
            img.save(dst_dir, optimize=True, quality=95)

        # Comment for large images if viewer is blank screen
        else:
            shutil.copy(src_dir, dst_dir)

        return

    def RestoreSize(self):
        ''' Restore Dialog Size '''
        dw = self.s.value("EquirectangularViewer/width")
        dh = self.s.value("EquirectangularViewer/height")

        if dw is None:
            return
        size = self.size()

        anim = QPropertyAnimation(self, b'size', self)
        anim.setStartValue(size)
        anim.setEndValue(QSize(int(dw), int(dh)))
        anim.setDuration(1)
        anim.start()
        return

    def SaveSize(self):
        ''' Save Dialog Size '''
        dw = self.width()
        dh = self.height()
        self.s.setValue("EquirectangularViewer/width", dw)
        self.s.setValue("EquirectangularViewer/height", dh)
        return

    def GetImage(self):
        ''' Get Selected Image '''
        try:
            path = qgsutils.getAttributeFromFeature(self.selected_features,
                                                    config.column_name)
            if not os.path.isabs(path):  # Relative Path to Project
                path_project = QgsProject.instance().readPath("./")
                path = os.path.normpath(os.path.join(path_project, path))
        except Exception:
            qgsutils.showUserAndLogMessage(u"Information: ",
                                           u"Column not found.")
            return

        qgsutils.showUserAndLogMessage(u"Information: ",
                                       str(path),
                                       onlyLog=True)
        return path

    def ChangeUrlViewer(self, new_url):
        ''' Change Url Viewer '''
        self.view.browser.GetMainFrame().ExecuteJavascript(
            "window.location='%s'" % new_url)
        return

    def ReloadView(self, newId):
        ''' Reaload Image viewer '''
        self.setWindowState(self.windowState() & ~Qt.WindowMinimized
                            | Qt.WindowActive)
        # this will activate the window
        self.activateWindow()
        self.selected_features = qgsutils.getToFeature(self.layer, newId)

        self.current_image = self.GetImage()

        # Check if image exist
        if os.path.exists(self.current_image) is False:
            qgsutils.showUserAndLogMessage(u"Information: ",
                                           u"There is no associated image.")
            self.ChangeUrlViewer(config.DEFAULT_EMPTY)
            self.resetQgsRubberBand()
            return

        # Set RubberBand
        self.resetQgsRubberBand()
        self.setOrientation()
        self.setPosition()

        # Copy file to local server
        self.CopyFile(self.current_image)

        self.ChangeUrlViewer(config.DEFAULT_URL)
        return

    def ResizeDialog(self):
        ''' Expanded/Decreased Dialog '''
        sender = QObject.sender(self)

        w = self.width()
        h = self.height()

        size = self.size()
        anim = QPropertyAnimation(self, b'size', self)
        anim.setStartValue(size)

        if sender.objectName() == "btn_ZoomOut":
            anim.setEndValue(QSize(w - 50, h - 50))
        else:
            anim.setEndValue(QSize(w + 50, h + 50))

        anim.setDuration(300)
        anim.start()
        return

    def GetBackNextImage(self):
        ''' Get to Back Image '''
        sender = QObject.sender(self)

        lys = self.canvas.layers()  # Check if mapa foto is loaded
        if len(lys) == 0:
            qgsutils.showUserAndLogMessage(
                u"Information: ", u"You need to upload the photo layer.")
            return

        for layer in lys:
            if layer.name() == config.layer_name:
                self.encontrado = True
                self.iface.setActiveLayer(layer)

                f = self.selected_features

                ac_lordem = f.attribute(config.column_order)

                if sender.objectName() == "btn_back":
                    new_lordem = int(ac_lordem) - 1
                else:
                    new_lordem = int(ac_lordem) + 1

                # Filter mapa foto layer
                ids = [
                    feat.id() for feat in layer.getFeatures(QgsFeatureRequest(
                    ).setFilterExpression(config.column_order + " ='" +
                                          str(new_lordem) + "'"))
                ]

                if len(ids) == 0:
                    qgsutils.showUserAndLogMessage(
                        u"Information: ",
                        u"There is no superiority that follows.")
                    # Filter mapa foto layer
                    ids = [
                        feat.id()
                        for feat in layer.getFeatures(QgsFeatureRequest(
                        ).setFilterExpression(config.column_order + " ='" +
                                              str(ac_lordem) + "'"))
                    ]
                    # Update selected feature
                    self.ReloadView(ids[0])
                    return

                self.ReloadView(ids[0])

        if self.encontrado is False:
            qgsutils.showUserAndLogMessage(
                u"Information: ", u"You need to upload the photo layer.")

        return

    def FullScreen(self, value):
        ''' FullScreen action button '''
        qgsutils.showUserAndLogMessage(u"Information: ",
                                       u"Fullscreen.",
                                       onlyLog=True)
        if (value):
            self.showFullScreen()
        else:
            self.showNormal()
        return

    @staticmethod
    def ActualOrientation(yaw):
        ''' Get Actual yaw '''
        geo360Plugin = qgis.utils.plugins["EquirectangularViewer"]
        if geo360Plugin is not None:
            geo360Dialog = qgis.utils.plugins["EquirectangularViewer"].dlg
            if geo360Dialog is not None:
                geo360Dialog.UpdateOrientation(yaw=float(yaw))
        return

    def UpdateOrientation(self, yaw=None):
        ''' Update Orientation '''
        self.bearing = self.selected_features.attribute(config.column_yaw)
        try:
            self.actualPointOrientation.reset()
        except Exception:
            pass

        self.actualPointOrientation = QgsRubberBand(self.iface.mapCanvas(),
                                                    QgsWkbTypes.LineGeometry)
        self.actualPointOrientation.setColor(Qt.blue)
        self.actualPointOrientation.setWidth(5)
        self.actualPointOrientation.addPoint(self.actualPointDx)

        # End Point
        CS = self.canvas.mapUnitsPerPixel() * 25
        A1x = self.actualPointDx.x() - CS * math.cos(math.pi / 2)
        A1y = self.actualPointDx.y() + CS * math.sin(math.pi / 2)

        self.actualPointOrientation.addPoint(QgsPointXY(
            float(A1x), float(A1y)))

        # Vision Angle
        if yaw is not None:
            angle = float(self.bearing + yaw) * math.pi / -180
        else:
            angle = float(self.bearing) * math.pi / -180

        tmpGeom = self.actualPointOrientation.asGeometry()

        self.actualPointOrientation.setToGeometry(
            self.rotateTool.rotate(tmpGeom, self.actualPointDx, angle),
            self.dumLayer)

    def setOrientation(self, yaw=None):
        ''' Set Orientation in the firt time '''
        self.bearing = self.selected_features.attribute(config.column_yaw)

        self.actualPointDx = self.selected_features.geometry().asPoint()

        self.actualPointOrientation = QgsRubberBand(self.iface.mapCanvas(),
                                                    QgsWkbTypes.LineGeometry)
        self.actualPointOrientation.setColor(Qt.blue)
        self.actualPointOrientation.setWidth(5)

        self.actualPointOrientation.addPoint(self.actualPointDx)

        # End Point
        CS = self.canvas.mapUnitsPerPixel() * 25
        A1x = self.actualPointDx.x() - CS * math.cos(math.pi / 2)
        A1y = self.actualPointDx.y() + CS * math.sin(math.pi / 2)

        self.actualPointOrientation.addPoint(QgsPointXY(
            float(A1x), float(A1y)))
        # Vision Angle
        if yaw is not None:
            angle = float(self.bearing + yaw) * math.pi / -180
        else:
            angle = float(self.bearing) * math.pi / -180

        tmpGeom = self.actualPointOrientation.asGeometry()

        self.rotateTool = transformGeometry()
        epsg = self.canvas.mapSettings().destinationCrs().authid()
        self.dumLayer = QgsVectorLayer("Point?crs=" + epsg, "temporary_points",
                                       "memory")
        self.actualPointOrientation.setToGeometry(
            self.rotateTool.rotate(tmpGeom, self.actualPointDx, angle),
            self.dumLayer)

    def setPosition(self):
        ''' Set RubberBand Position '''
        self.actualPointDx = self.selected_features.geometry().asPoint()

        self.positionDx = QgsRubberBand(self.iface.mapCanvas(),
                                        QgsWkbTypes.PointGeometry)
        self.positionDx.setWidth(6)
        self.positionDx.setIcon(QgsRubberBand.ICON_CIRCLE)
        self.positionDx.setIconSize(6)
        self.positionDx.setColor(Qt.black)
        self.positionSx = QgsRubberBand(self.iface.mapCanvas(),
                                        QgsWkbTypes.PointGeometry)
        self.positionSx.setWidth(5)
        self.positionSx.setIcon(QgsRubberBand.ICON_CIRCLE)
        self.positionSx.setIconSize(4)
        self.positionSx.setColor(Qt.blue)
        self.positionInt = QgsRubberBand(self.iface.mapCanvas(),
                                         QgsWkbTypes.PointGeometry)
        self.positionInt.setWidth(5)
        self.positionInt.setIcon(QgsRubberBand.ICON_CIRCLE)
        self.positionInt.setIconSize(3)
        self.positionInt.setColor(Qt.white)

        self.positionDx.addPoint(self.actualPointDx)
        self.positionSx.addPoint(self.actualPointDx)
        self.positionInt.addPoint(self.actualPointDx)

    def closeEvent(self, _):
        ''' Close dialog '''
        self.resetQgsRubberBand()
        self.canvas.refresh()
        self.iface.actionPan().trigger()
        self.SaveSize()
        self.parent.dlg = None
        self.RemoveImage()
        return

    def resetQgsRubberBand(self):
        ''' Remove RubbeBand '''
        try:
            self.positionSx.reset()
            self.positionInt.reset()
            self.positionDx.reset()
            self.actualPointOrientation.reset()
        except Exception:
            None
Beispiel #32
0
 def closeEvent(self, event):
     settings = QSettings()
     settings.setValue('splitterSize', self.split.sizes())
     settings.setValue('guiIcon', self.windowIcon())
     settings.setValue('guiGeometry', self.geometry())
Beispiel #33
0
class CreateDirs(QDialog):
    '''
    CreateDirs is a dialog that enables the user to disable the auto gen of directories
    and provides a facility to choose what months of subdirectories to be created.
    '''
    def __init__(self, testSettings=None):
        '''
        :params testSettings: Override the settings key. Intended for testing. Proividing
            a value for testSettings will prevent show from being called.
        '''
        super().__init__(parent=None)
        if testSettings:
            self.settings = testSettings
        else:
            self.settings = QSettings('zero_substance', 'structjour')

        self.ui = CreateDirsDialog()
        self.ui.setupUi(self)
        self.setWindowIcon(QIcon("structjour/images/ZSLogo.png"))

        self.ui.createDirsBtn.pressed.connect(self.createDirs)
        self.ui.enabledRb.clicked.connect(self.enableAutoGen)
        self.ui.disabledRb.clicked.connect(self.disableAutoGen)

        autog = self.settings.value('directories_autogen', defaultValue=True, type=bool)
        if autog:
            self.ui.enabledRb.setChecked(True)
            self.enableAutoGen()
        else:
            self.ui.disabledRb.setChecked(True)
            self.disableAutoGen()

        lastDir = self.settings.value('lastDirCreated')
        if lastDir:
            dd = pd.Timestamp(lastDir)
            year = dd.strftime('%Y')
            month = dd.strftime('%B')
            self.ui.createDirsYear.setCurrentText(year)
            self.ui.createDirsMonth.setCurrentText(month)

        if not testSettings:
            self.show()

    def createDirs(self):
        '''Create the sub directories in the journal directory'''
        if not self.settings.value('journal') or self.settings.value('journal') == "":
            if hasattr(self, 'debug') and self.debug:
                return ""
            msg = f'<h3>Please select a journal directory</h3>'
            msg += f'<p>Go to file->filesettings and select a location for your journal files.</p>'
            msgbx = QMessageBox()
            msgbx.setIconPixmap(QPixmap("structjour/images/ZSLogo.png"))
            msgbx.setText(msg)
            msgbx.exec()
        m = pd.Timestamp(f'{self.ui.createDirsMonth.currentText()} {self.ui.createDirsYear.currentText()}')
        try:
            theDir = createDirsStructjour(m, self.settings)
        except ValueError as m:
            if m.args[0].startswith('Directory Already'):
                msg = f'<h3>{m.args[0]}</h3>'
                msg += f'<p>{m.args[1]}</p>'
                msgbx = QMessageBox()
                msgbx.setIconPixmap(QPixmap("structjour/images/ZSLogo.png"))
                msgbx.setText(msg)
                msgbx.exec()
            else:
                raise ValueError(m)
        else:
            # self.settings.setValue('lastDir')
            self.settings.setValue('lastDirCreated', m.strftime('%Y%m01'))
            if hasattr(self, 'debug') and self.debug:
                return theDir
            msg = f'<h3>Directories created</h3>'
            msg += f'<p>under {theDir}</p>'
            msgbx = QMessageBox()
            msgbx.setIconPixmap(QPixmap("structjour/images/ZSLogo.png"))
            msgbx.setText(msg)
            msgbx.exec()
        return theDir

    def disableAutoGen(self):
        self.settings.setValue('directories_autogen', 'false')
        self.ui.createDirsBtn.setEnabled(True)

    def enableAutoGen(self):
        self.settings.setValue('directories_autogen', 'true')
        self.ui.createDirsBtn.setEnabled(False)
Beispiel #34
0
 def writeSettings(self):
     settings = QSettings('china', 'seven')
     settings.setValue('pos', self.pos())
     settings.setValue('size', self.size())
Beispiel #35
0
 def saveSettings(self):
     settings = QSettings("Cadence", "JackSettings")
     settings.setValue("Geometry", self.saveGeometry())
     settings.setValue("CurrentTab", self.ui.tabWidget.currentIndex())
Beispiel #36
0
 def close(self):
     #save window position (only; not size!)
     settings = QSettings()
     settings.setValue("AxisPosition", self.frameGeometry().topLeft())
     self.aw.closeEventSettings()
     super(WindowsDlg, self).close()
Beispiel #37
0
def write_settings(**kwargs):
    """Write application settings."""
    settings = QSettings()
    for key, value in kwargs.items():
        settings.setValue(key, value)
class MainWindow(QMainWindow):
    def __init__(self, parent=None):
        super().__init__(parent)

        self.ui = Ui_MainWindowForm()
        self.ui.setupUi(self)

        self.ui.actionOpen_DB_File.triggered.connect(self.open_db)
        self.ui.actionOpen_SPS_File.triggered.connect(self.open_sps)
        self.ui.actionProcess.triggered.connect(self.process)
        self.ui.actionAbout.triggered.connect(about)
        self.ui.actionLicense.triggered.connect(license)
        self.ui.actionHelp.triggered.connect(help)
        self.ui.actionQuit.triggered.connect(self.close_application)
        self.ui.actionCreate_DB.triggered.connect(self.create_db_file)
        self.ui.actionUpdate_DB.triggered.connect(db_update)
        # status tips copied from tool tip ?
        # self.ui.actionOpen_DB_File.setStatusTip(self.ui.actionOpen_DB_File.toolTip())

        self.ui.lblDb.setText('')
        self.ui.lblSPS.setText('')

        self.db_file = None
        self.sps_file = None
        self.log_file = None

        self.settings = QSettings(app_settings.ORG, app_settings.APP)

        self.settings_read()

    def warning_nothing_to_process(self):
        dlg = Warning()
        dlg.set_label(
            'Are you dumb ?\nWhat do you want to process ?\nSelect both DB & SPS files'
        )
        dlg.exec_()

    def open_db(self):
        """
            Opens DB file
        """
        previous_db_file = self.db_file
        self.db_file, _ = QFileDialog.getOpenFileName(
            self,
            "Open file",
            "",
            "SQLite (*.sqlite );;All files (*.*)",
            # options=QFileDialog.DontUseNativeDialog
        )

        if not self.db_file:
            self.db_file = previous_db_file

        self.ui.lblDb.setText(self.db_file)

    def open_sps(self):
        """
            Opens SPS file
        """
        previous_sps_file = self.sps_file
        self.sps_file, _ = QFileDialog.getOpenFileName(
            self,
            "Open file",
            "",
            "SPS Source (*.S *.SPS *.s *.sps);;SPS Receiver (*.R *.RPS *.r *.rps);;All files (*.*)",
            # options=QFileDialog.DontUseNativeDialog
        )

        if not self.sps_file:
            self.sps_file = previous_sps_file

        self.ui.lblSPS.setText(self.sps_file)
        self.log_file = self.sps_file + LOG_EXT

    def process(self):
        if self.db_file and self.sps_file:
            self.runner()
        else:
            self.warning_nothing_to_process()

    def runner(self):
        common.log_file_create(self.log_file)
        start_time = time.time()
        if self.db_file and self.sps_file:
            line_numbers = common.count_file_line_number(self.sps_file)
            self.ui.progressBar.setMaximum(line_numbers)
            limit_x = float(self.ui.limitX.text())
            limit_y = float(self.ui.limitY.text())
            self.log(datetime.today().strftime("%Y-%m-%d %H:%M:%S"))
            self.log('DB: %s' % self.db_file)
            self.log('DB record count: %d' % db.count_db_records(self.db_file))
            self.log('SPS: %s' % self.sps_file)
            self.log('SPS record count: %d' % line_numbers)
            self.log('Limits: E: %.2f, N: %.2f' % (limit_x, limit_y))
            result = self.check(limit_x, limit_y)
            timing = time.time() - start_time
            point_count = result['PC']
            not_in_db_count = result['NDB']
            offset_count_x = result['OCX']
            offset_count_y = result['OCY']
            poffset_count_x = offset_count_x / point_count * 100
            poffset_count_y = offset_count_y / point_count * 100

            self.log('Number of points: %d' % point_count)
            self.log('Number of points not in DB: %d' % not_in_db_count)
            self.log('Errors Easting: %d points, %.2f%s' %
                     (offset_count_x, poffset_count_x, '%'))
            self.log('Errors Nothing: %d points, %.2f%s' %
                     (offset_count_y, poffset_count_y, '%'))
            self.log('Elapsed time: %d sec' % timing)
            self.print2output(
                '-----------------------------------------------------------------'
            )

    def print2output(self, text):
        self.ui.txtOutput.append(text)

    def log(self, text):
        self.print2output(text)
        common.log_file_record_add(self.log_file, text)

    def settings_save(self):
        self.settings.setValue(app_settings.LIMIT_X, self.ui.limitX.text())
        self.settings.setValue(app_settings.LIMIT_Y, self.ui.limitY.text())
        self.settings.setValue(app_settings.DB_PATH, self.db_file)

    def settings_read(self):
        self.ui.limitX.setText(
            self.settings.value(app_settings.LIMIT_X, '0.0', type=str))
        self.ui.limitY.setText(
            self.settings.value(app_settings.LIMIT_Y, '0.0', type=str))
        db_file = self.settings.value(app_settings.DB_PATH, '', type=str)
        if 0 == len(db_file):
            db_file = None
        self.db_file = db_file
        self.ui.lblDb.setText(db_file)

    def close_application(self):
        self.settings_save()
        self.close()

    def create_db_file(self):
        db_file, _ = QFileDialog.getSaveFileName(
            self,
            "Create DB",
            "",
            "SQLite files (*.sqlite);;All Files (*)",
            # options=QFileDialog.DontUseNativeDialog
        )

        if not db_file:
            return

        if not db_file.endswith(db.DB_FILE_EXT):
            db_file += db.DB_FILE_EXT
        db.create_db(db_file)
        db_log_file = db_file + common.DB_LOG_FILE_EXT
        common.log_file_create(db_log_file)
        common.log_file_record_add(
            db_log_file,
            f"Created: {datetime.today().strftime('%Y-%m-%d %H:%M:%S')}")
        common.log_file_record_add(
            db_log_file,
            '-----------------------------------------------------------------'
        )

    def check(self, limit_x, limit_y):
        connection = db.create_connection(self.db_file)
        parser = Sps21Parser()
        check_file = self.sps_file + CHECK_EXT
        not_in_db_file = self.sps_file + NOT_IN_DB_EXT

        common.csv_file_create(check_file, CHECK_CSV_HEADER)
        common.csv_file_create(not_in_db_file, NOT_IN_DB_CSV_HEADER)

        with open(self.sps_file) as sps:
            line = sps.readline()
            sps_counter = 0
            not_in_db_counter = 0
            offset_counter_x = 0
            offset_counter_y = 0
            while line:
                stats = parser.parse_point(line)
                if stats is not None:
                    point = Point(stats)

                    stats = db.get_record_for_point(connection, point)

                    if stats is None:
                        sps_counter += 1
                        not_in_db_counter += 1
                        record = "%.2f,%.2f,%.1f,%.1f" \
                                 % (
                                     point.line, point.point, point.easting, point.northing)
                        common.csv_file_record_add(not_in_db_file, record)
                        line = sps.readline()
                        continue
                    de = point.easting - stats[0]
                    dn = point.northing - stats[1]

                    error_easting = 0
                    if abs(de) > limit_x:
                        offset_counter_x += 1
                        error_easting = 1

                    error_northing = 0
                    if abs(dn) > limit_y:
                        offset_counter_y += 1
                        error_northing = 1

                    record = "%.2f,%.2f,%.1f,%.1f,%.1f,%.1f,%d,%d" \
                             % (
                                 point.line, point.point, point.easting, point.northing, de, dn, error_easting,
                                 error_northing)
                    common.csv_file_record_add(check_file, record)

                    sps_counter += 1
                    self.ui.progressBar.setValue(sps_counter)

                line = sps.readline()

            sps.close()

            stats = {
                'PC': sps_counter,
                'NDB': not_in_db_counter,
                'OCX': offset_counter_x,
                'OCY': offset_counter_y
            }

            connection.close()

            return stats
Beispiel #39
0
 def saveSettings(self):
     s = QSettings()
     s.setValue("strip_trailing_whitespace", self.stripwsp.isChecked())
     s.setValue("backup_keep", self.backup.isChecked())
     s.setValue("metainfo", self.metainfo.isChecked())
     s.setValue("basedir", self.basedir.path())
     s.setValue("custom_default_filename", self.customFilename.isChecked())
     s.setValue("default_filename_template", self.filenameTemplate.text())
Beispiel #40
0
# user download folder path    
download_path = os.path.join(str(home_address), 'Downloads', 'Persepolis')

# Persepolis default setting
default_setting_dict = {'toolbar_icon_size': 32, 'wait-queue': [0, 0], 'awake': 'no', 'custom-font': 'no', 'column0': 'yes', 'column1': 'yes', 'column2': 'yes', 'column3': 'yes', 'column4': 'yes', 'column5': 'yes', 'column6': 'yes', 'column7': 'yes', 'column10': 'yes', 'column11': 'yes', 'column12': 'yes',
                             'subfolder': 'yes', 'startup': 'no', 'show-progress': 'yes', 'show-menubar': 'no', 'show-sidepanel': 'yes', 'rpc-port': 6801, 'notification': 'Native notification', 'after-dialog': 'yes', 'tray-icon': 'yes',
                             'max-tries': 5, 'retry-wait': 0, 'timeout': 60, 'connections': 16, 'download_path_temp': download_path_temp, 'download_path': download_path, 'sound': 'yes', 'sound-volume': 100, 'style': 'Fusion',
                             'color-scheme': 'Persepolis Light Blue', 'icons': 'Papirus-Light', 'font': 'Ubuntu', 'font-size': 9, 'aria2_path': ''}

# this loop is checking values in persepolis_setting . if value is not
# valid then value replaced by default_setting_dict value
for key in default_setting_dict.keys():

    setting_value = persepolis_setting.value(key, default_setting_dict[key])
    persepolis_setting.setValue(key, setting_value)

persepolis_setting.sync()

# this section  creates temporary download folder and download folder and
# download sub folders if they did not existed.
download_path_temp = persepolis_setting.value('download_path_temp')
download_path = persepolis_setting.value('download_path')


folder_list = [download_path_temp, download_path]

# add subfolders to folder_list if user checked subfolders check box in setting window.
if persepolis_setting.value('subfolder') == 'yes':
    for folder in ['Audios', 'Videos', 'Others', 'Documents', 'Compressed']:
        folder_list.append(os.path.join(download_path, folder))
Beispiel #41
0
class MainWindow(QMainWindow):
    def __init__(self):
        super(MainWindow, self).__init__()

        self.ui = Ui_MainWindow()
        self.ui.setupUi(self)

        self.settings = QSettings()

        self.ui.exitAction.triggered.connect(QApplication.quit)
        self.ui.zoomInAction.triggered.connect(self.ui.imageLabel.zoomIn)
        self.ui.zoomOutAction.triggered.connect(self.ui.imageLabel.zoomOut)

        self.enableImageActions(False)
        self.enableSamplesActions(False)

    @pyqtSlot()
    def on_openAction_triggered(self):
        dir = self.settings.value(Settings.LAST_DIRECTORY_KEY,
                                  Settings.DEFAULT_LAST_DIRECTORY)
        (filename,
         _) = QFileDialog.getOpenFileName(self, self.tr('Open Image'), dir,
                                          self.tr('Images (*.png *.jpg)'))
        if filename:
            self.settings.setValue(Settings.LAST_DIRECTORY_KEY,
                                   QFileInfo(filename).absolutePath())
            self.ui.imageLabel.loadImage(filename)
            self.statusBar().showMessage(QDir.toNativeSeparators(filename))
            self.enableImageActions(True)
            self.on_clearAction_triggered()

    @pyqtSlot()
    def on_saveAction_triggered(self):
        dir = self.settings.value(Settings.LAST_DIRECTORY_KEY,
                                  Settings.DEFAULT_LAST_DIRECTORY)
        (filename, _) = QFileDialog.getSaveFileName(
            self, self.tr('Open Image'), dir,
            self.tr(
                'Comma Separated Values files (*.csv)\nText files (*.txt)\n'))
        if filename:
            self.settings.setValue(Settings.LAST_DIRECTORY_KEY,
                                   QFileInfo(filename).absolutePath())
            text = self.getCoordinatesAsCsv()
            with open(filename, 'w') as file:
                file.write(text)

    @pyqtSlot()
    def on_settingsAction_triggered(self):
        settingsDialog = SettingsDialog(self)
        if settingsDialog.exec_():
            self.ui.imageLabel.reset()

    @pyqtSlot()
    def on_clearAction_triggered(self):
        self.ui.listWidget.clear()
        self.ui.imageLabel.clearSamples()
        self.enableSamplesActions(False)

    @pyqtSlot()
    def on_copyAction_triggered(self):
        text = self.getCoordinatesAsTsv()
        clipboard = QApplication.clipboard()
        clipboard.setText(text)

    @pyqtSlot()
    def on_aboutQtAction_triggered(self):
        QMessageBox.aboutQt(self)

    @pyqtSlot()
    def on_aboutAction_triggered(self):
        QMessageBox.about(
            self, self.tr('About'),
            self.tr('<h1>%s %s</h1>\n' +
                    '<p>Developed by <a href="%s">%s</a></p>') %
            (QApplication.applicationName(), QApplication.applicationVersion(),
             QApplication.organizationDomain(),
             QApplication.organizationName()))

    @pyqtSlot()
    def on_pathLengthAction_triggered(self):
        coordinates = list(self.getCoordinates())
        totalDistance = lengthOfPath(coordinates)
        QMessageBox.information(
            self, self.tr('Path Length'),
            self.tr("The path's length is %f" % totalDistance))

    @pyqtSlot()
    def on_polygonAreaAction_triggered(self):
        coordinates = list(self.getCoordinates())
        totalArea = areaOfPolygon(coordinates)
        QMessageBox.information(
            self, self.tr('Polygon Area'),
            self.tr("The polygon's area is %f" % totalArea))

    @pyqtSlot(float, float)
    def on_imageLabel_mouseMoved(self, x, y):
        self.ui.coordinatesLineEdit.setText("%f × %f" % (x, y))

    @pyqtSlot(float, float)
    def on_imageLabel_clicked(self, x, y):
        item = QListWidgetItem("%f × %f" % (x, y))
        item.setData(Qt.UserRole, x)
        item.setData(Qt.UserRole + 1, y)
        self.ui.listWidget.addItem(item)
        self.enableSamplesActions(True)

    def getCoordinates(self):
        items = self.ui.listWidget.findItems('*', Qt.MatchWildcard)
        return map(
            lambda item: (item.data(Qt.UserRole), item.data(Qt.UserRole + 1)),
            items)

    def getCoordinatesAsCsv(self):
        coordinates = self.getCoordinates()
        lines = map(lambda coordinate: "%f,%f" % coordinate, coordinates)
        return 'x,y\n' + '\n'.join(lines)

    def getCoordinatesAsTsv(self):
        coordinates = self.getCoordinates()
        lines = map(lambda coordinate: "%f\t%f" % coordinate, coordinates)
        return 'x\ty\n' + '\n'.join(lines)

    def enableSamplesActions(self, enable):
        self.ui.saveAction.setEnabled(enable)
        self.ui.clearAction.setEnabled(enable)
        self.ui.copyAction.setEnabled(enable)
        self.ui.pathLengthAction.setEnabled(enable)
        self.ui.polygonAreaAction.setEnabled(enable)

    def enableImageActions(self, enable):
        self.ui.zoomInAction.setEnabled(enable)
        self.ui.zoomOutAction.setEnabled(enable)
Beispiel #42
0
 def setStyle(self, style):
     # Save style to Qt Settings
     sttgs = QSettings(qApp.organizationName(), qApp.applicationName())
     sttgs.setValue("applicationStyle", style)
     qApp.setStyle(style)
Beispiel #43
0
class TriblerWindow(QMainWindow):

    resize_event = pyqtSignal()
    escape_pressed = pyqtSignal()
    received_search_completions = pyqtSignal(object)

    def on_exception(self, *exc_info):
        # Stop the download loop
        self.downloads_page.stop_loading_downloads()

        # Add info about whether we are stopping Tribler or not
        os.environ['TRIBLER_SHUTTING_DOWN'] = str(
            self.core_manager.shutting_down)

        if not self.core_manager.shutting_down:
            self.core_manager.stop(stop_app_on_shutdown=False)

        self.setHidden(True)

        if self.debug_window:
            self.debug_window.setHidden(True)

        exception_text = "".join(traceback.format_exception(*exc_info))
        logging.error(exception_text)

        if not self.feedback_dialog_is_open:
            dialog = FeedbackDialog(
                self, exception_text,
                self.core_manager.events_manager.tribler_version)
            self.feedback_dialog_is_open = True
            _ = dialog.exec_()

    def __init__(self):
        QMainWindow.__init__(self)

        self.navigation_stack = []
        self.feedback_dialog_is_open = False
        self.tribler_started = False
        self.tribler_settings = None
        self.debug_window = None
        self.core_manager = CoreManager()
        self.pending_requests = {}
        self.pending_uri_requests = []
        self.download_uri = None
        self.dialog = None
        self.start_download_dialog_active = False
        self.request_mgr = None
        self.search_request_mgr = None
        self.search_suggestion_mgr = None
        self.selected_torrent_files = []
        self.vlc_available = True
        self.has_search_results = False

        sys.excepthook = self.on_exception

        uic.loadUi(get_ui_file_path('mainwindow.ui'), self)
        TriblerRequestManager.window = self

        self.magnet_handler = MagnetHandler(self.window)
        QDesktopServices.setUrlHandler("magnet", self.magnet_handler,
                                       "on_open_magnet_link")

        QCoreApplication.setOrganizationDomain("nl")
        QCoreApplication.setOrganizationName("TUDelft")
        QCoreApplication.setApplicationName("Tribler")
        QCoreApplication.setAttribute(Qt.AA_UseHighDpiPixmaps)

        self.read_settings()

        # Remove the focus rect on OS X
        for widget in self.findChildren(QLineEdit) + self.findChildren(
                QListWidget) + self.findChildren(QTreeWidget):
            widget.setAttribute(Qt.WA_MacShowFocusRect, 0)

        self.menu_buttons = [
            self.left_menu_button_home, self.left_menu_button_search,
            self.left_menu_button_my_channel,
            self.left_menu_button_subscriptions,
            self.left_menu_button_video_player,
            self.left_menu_button_downloads, self.left_menu_button_discovered
        ]

        self.video_player_page.initialize_player()
        self.search_results_page.initialize_search_results_page()
        self.settings_page.initialize_settings_page()
        self.subscribed_channels_page.initialize()
        self.edit_channel_page.initialize_edit_channel_page()
        self.downloads_page.initialize_downloads_page()
        self.home_page.initialize_home_page()
        self.loading_page.initialize_loading_page()
        self.discovering_page.initialize_discovering_page()
        self.discovered_page.initialize_discovered_page()
        self.trust_page.initialize_trust_page()

        self.stackedWidget.setCurrentIndex(PAGE_LOADING)

        # Create the system tray icon
        if QSystemTrayIcon.isSystemTrayAvailable():
            self.tray_icon = QSystemTrayIcon()
            use_monochrome_icon = get_gui_setting(self.gui_settings,
                                                  "use_monochrome_icon",
                                                  False,
                                                  is_bool=True)
            self.update_tray_icon(use_monochrome_icon)

        self.hide_left_menu_playlist()
        self.left_menu_button_debug.setHidden(True)
        self.top_menu_button.setHidden(True)
        self.left_menu.setHidden(True)
        self.trust_button.setHidden(True)
        self.settings_button.setHidden(True)
        self.add_torrent_button.setHidden(True)
        self.top_search_bar.setHidden(True)

        # Set various icons
        self.top_menu_button.setIcon(QIcon(get_image_path('menu.png')))

        self.search_completion_model = QStringListModel()
        completer = QCompleter()
        completer.setModel(self.search_completion_model)
        completer.setCompletionMode(QCompleter.UnfilteredPopupCompletion)
        self.item_delegate = QStyledItemDelegate()
        completer.popup().setItemDelegate(self.item_delegate)
        completer.popup().setStyleSheet("""
        QListView {
            background-color: #404040;
        }

        QListView::item {
            color: #D0D0D0;
            padding-top: 5px;
            padding-bottom: 5px;
        }

        QListView::item:hover {
            background-color: #707070;
        }
        """)
        self.top_search_bar.setCompleter(completer)

        # Toggle debug if developer mode is enabled
        self.window().left_menu_button_debug.setHidden(not get_gui_setting(
            self.gui_settings, "debug", False, is_bool=True))

        self.core_manager.start()

        self.core_manager.events_manager.received_search_result_channel.connect(
            self.search_results_page.received_search_result_channel)
        self.core_manager.events_manager.received_search_result_torrent.connect(
            self.search_results_page.received_search_result_torrent)
        self.core_manager.events_manager.torrent_finished.connect(
            self.on_torrent_finished)
        self.core_manager.events_manager.new_version_available.connect(
            self.on_new_version_available)
        self.core_manager.events_manager.tribler_started.connect(
            self.on_tribler_started)

        # Install signal handler for ctrl+c events
        def sigint_handler(*_):
            self.close_tribler()

        signal.signal(signal.SIGINT, sigint_handler)

        self.installEventFilter(self.video_player_page)

        self.show()

    def update_tray_icon(self, use_monochrome_icon):
        if use_monochrome_icon:
            self.tray_icon.setIcon(
                QIcon(QPixmap(get_image_path('monochrome_tribler.png'))))
        else:
            self.tray_icon.setIcon(
                QIcon(QPixmap(get_image_path('tribler.png'))))
        self.tray_icon.show()

    def on_torrent_finished(self, torrent_info):
        self.window().tray_icon.showMessage(
            "Download finished",
            "Download of %s has finished." % torrent_info["name"])

    def show_loading_screen(self):
        self.top_menu_button.setHidden(True)
        self.left_menu.setHidden(True)
        self.trust_button.setHidden(True)
        self.settings_button.setHidden(True)
        self.add_torrent_button.setHidden(True)
        self.top_search_bar.setHidden(True)
        self.stackedWidget.setCurrentIndex(PAGE_LOADING)

    def on_tribler_started(self):
        self.tribler_started = True

        self.top_menu_button.setHidden(False)
        self.left_menu.setHidden(False)
        self.trust_button.setHidden(False)
        self.settings_button.setHidden(False)
        self.add_torrent_button.setHidden(False)
        self.top_search_bar.setHidden(False)

        # fetch the variables, needed for the video player port
        self.request_mgr = TriblerRequestManager()
        self.request_mgr.perform_request("variables", self.received_variables)

        self.downloads_page.start_loading_downloads()
        self.home_page.load_popular_torrents()
        if not self.gui_settings.value(
                "first_discover",
                False) and not self.core_manager.use_existing_core:
            self.window().gui_settings.setValue("first_discover", True)
            self.discovering_page.is_discovering = True
            self.stackedWidget.setCurrentIndex(PAGE_DISCOVERING)
        else:
            self.clicked_menu_button_home()

    def process_uri_request(self):
        """
        Process a URI request if we have one in the queue.
        """
        if len(self.pending_uri_requests) == 0:
            return

        uri = self.pending_uri_requests.pop()
        if uri.startswith('file') or uri.startswith('magnet'):
            self.start_download_from_uri(uri)

    def perform_start_download_request(self,
                                       uri,
                                       anon_download,
                                       safe_seeding,
                                       destination,
                                       selected_files,
                                       total_files=0,
                                       callback=None):
        selected_files_uri = ""
        if len(selected_files) != total_files:  # Not all files included
            selected_files_uri = u'&' + u''.join(
                u"selected_files[]=%s&" % file for file in selected_files)[:-1]

        anon_hops = int(self.tribler_settings['Tribler']
                        ['default_number_hops']) if anon_download else 0
        safe_seeding = 1 if safe_seeding else 0
        post_data = "uri=%s&anon_hops=%d&safe_seeding=%d&destination=%s%s" % (
            uri, anon_hops, safe_seeding, destination, selected_files_uri)
        post_data = post_data.encode(
            'utf-8')  # We need to send bytes in the request, not unicode

        request_mgr = TriblerRequestManager()
        self.pending_requests[request_mgr.request_id] = request_mgr
        request_mgr.perform_request(
            "downloads",
            callback if callback else self.on_download_added,
            method='PUT',
            data=post_data)

        # Save the download location to the GUI settings
        current_settings = get_gui_setting(self.gui_settings,
                                           "recent_download_locations", "")
        recent_locations = current_settings.split(
            ",") if len(current_settings) > 0 else []
        encoded_destination = destination.encode('hex')
        if encoded_destination in recent_locations:
            recent_locations.remove(encoded_destination)
        recent_locations.insert(0, encoded_destination)

        if len(recent_locations) > 5:
            recent_locations = recent_locations[:5]

        self.gui_settings.setValue("recent_download_locations",
                                   ','.join(recent_locations))

    def on_new_version_available(self, version):
        if version == str(self.gui_settings.value('last_reported_version')):
            return

        self.dialog = ConfirmationDialog(
            self, "New version available",
            "Version %s of Tribler is available.Do you want to visit the website to "
            "download the newest version?" % version,
            [('IGNORE', BUTTON_TYPE_NORMAL), ('LATER', BUTTON_TYPE_NORMAL),
             ('OK', BUTTON_TYPE_NORMAL)])
        self.dialog.button_clicked.connect(
            lambda action: self.on_new_version_dialog_done(version, action))
        self.dialog.show()

    def on_new_version_dialog_done(self, version, action):
        if action == 0:  # ignore
            self.gui_settings.setValue("last_reported_version", version)
        elif action == 2:  # ok
            import webbrowser
            webbrowser.open("https://tribler.org")

        self.dialog.setParent(None)
        self.dialog = None

    def read_settings(self):
        self.gui_settings = QSettings()
        center = QApplication.desktop().availableGeometry(self).center()
        pos = self.gui_settings.value(
            "pos",
            QPoint(center.x() - self.width() * 0.5,
                   center.y() - self.height() * 0.5))
        size = self.gui_settings.value("size", self.size())

        self.move(pos)
        self.resize(size)

    def on_search_text_change(self, text):
        self.search_suggestion_mgr = TriblerRequestManager()
        self.search_suggestion_mgr.perform_request(
            "search/completions?q=%s" % text,
            self.on_received_search_completions)

    def on_received_search_completions(self, completions):
        self.received_search_completions.emit(completions)
        self.search_completion_model.setStringList(completions["completions"])

    def received_variables(self, variables):
        self.video_player_page.video_player_port = variables["variables"][
            "ports"]["video~port"]
        self.fetch_settings()

    def fetch_settings(self):
        self.request_mgr = TriblerRequestManager()
        self.request_mgr.perform_request("settings",
                                         self.received_settings,
                                         capture_errors=False)

    def received_settings(self, settings):
        # If we cannot receive the settings, stop Tribler with an option to send the crash report.
        if 'error' in settings:
            raise RuntimeError(
                TriblerRequestManager.get_message_from_error(settings))
        else:
            self.tribler_settings = settings['settings']

        # Disable various components based on the settings
        if not self.tribler_settings['search_community']['enabled']:
            self.window().top_search_bar.setHidden(True)
        if not self.tribler_settings['video']['enabled']:
            self.left_menu_button_video_player.setHidden(True)

        # process pending file requests (i.e. someone clicked a torrent file when Tribler was closed)
        # We do this after receiving the settings so we have the default download location.
        self.process_uri_request()

    def on_top_search_button_click(self):
        self.left_menu_button_search.setChecked(True)
        self.has_search_results = True
        self.clicked_menu_button_search()
        self.search_results_page.perform_search(self.top_search_bar.text())
        self.search_request_mgr = TriblerRequestManager()
        self.search_request_mgr.perform_request(
            "search?q=%s" % self.top_search_bar.text(), None)

    def on_settings_button_click(self):
        self.deselect_all_menu_buttons()
        self.stackedWidget.setCurrentIndex(PAGE_SETTINGS)
        self.settings_page.load_settings()
        self.navigation_stack = []
        self.hide_left_menu_playlist()

    def on_trust_button_click(self):
        self.deselect_all_menu_buttons()
        self.stackedWidget.setCurrentIndex(PAGE_TRUST)
        self.trust_page.load_trust_statistics()
        self.navigation_stack = []
        self.hide_left_menu_playlist()

    def on_add_torrent_button_click(self, pos):
        menu = TriblerActionMenu(self)

        browse_files_action = QAction('Import torrent from file', self)
        browse_directory_action = QAction('Import torrents from directory',
                                          self)
        add_url_action = QAction('Import torrent from magnet/URL', self)

        browse_files_action.triggered.connect(self.on_add_torrent_browse_file)
        browse_directory_action.triggered.connect(
            self.on_add_torrent_browse_dir)
        add_url_action.triggered.connect(self.on_add_torrent_from_url)

        menu.addAction(browse_files_action)
        menu.addAction(browse_directory_action)
        menu.addAction(add_url_action)

        menu.exec_(self.mapToGlobal(self.add_torrent_button.pos()))

    def on_add_torrent_browse_file(self):
        filenames = QFileDialog.getOpenFileNames(
            self, "Please select the .torrent file", "",
            "Torrent files (*.torrent)")
        if len(filenames[0]) > 0:
            [
                self.pending_uri_requests.append(u"file:%s" % filename)
                for filename in filenames[0]
            ]
            self.process_uri_request()

    def start_download_from_uri(self, uri):
        self.download_uri = uri

        if get_gui_setting(self.gui_settings,
                           "ask_download_settings",
                           True,
                           is_bool=True):
            self.dialog = StartDownloadDialog(self.window().stackedWidget,
                                              self.download_uri)
            self.dialog.button_clicked.connect(self.on_start_download_action)
            self.dialog.show()
            self.start_download_dialog_active = True
        else:
            self.window().perform_start_download_request(
                self.download_uri,
                get_gui_setting(self.gui_settings,
                                "default_anonymity_enabled",
                                True,
                                is_bool=True),
                get_gui_setting(self.gui_settings,
                                "default_safeseeding_enabled",
                                True,
                                is_bool=True),
                self.tribler_settings['downloadconfig']['saveas'], [], 0)
            self.process_uri_request()

    def on_start_download_action(self, action):
        if action == 1:
            self.window().perform_start_download_request(
                self.download_uri,
                self.dialog.dialog_widget.anon_download_checkbox.isChecked(),
                self.dialog.dialog_widget.safe_seed_checkbox.isChecked(),
                self.dialog.dialog_widget.destination_input.currentText(),
                self.dialog.get_selected_files(),
                self.dialog.dialog_widget.files_list_view.topLevelItemCount())

        self.dialog.request_mgr.cancel_request(
        )  # To abort the torrent info request
        self.dialog.setParent(None)
        self.dialog = None
        self.start_download_dialog_active = False

        if action == 0:  # We do this after removing the dialog since process_uri_request is blocking
            self.process_uri_request()

    def on_add_torrent_browse_dir(self):
        chosen_dir = QFileDialog.getExistingDirectory(
            self, "Please select the directory containing the .torrent files",
            "", QFileDialog.ShowDirsOnly)

        if len(chosen_dir) != 0:
            self.selected_torrent_files = [
                torrent_file
                for torrent_file in glob.glob(chosen_dir + "/*.torrent")
            ]
            self.dialog = ConfirmationDialog(
                self, "Add torrents from directory",
                "Are you sure you want to add %d torrents to Tribler?" %
                len(self.selected_torrent_files),
                [('ADD', BUTTON_TYPE_NORMAL), ('CANCEL', BUTTON_TYPE_CONFIRM)])
            self.dialog.button_clicked.connect(
                self.on_confirm_add_directory_dialog)
            self.dialog.show()

    def on_confirm_add_directory_dialog(self, action):
        if action == 0:
            for torrent_file in self.selected_torrent_files:
                escaped_uri = quote_plus(
                    (u"file:%s" % torrent_file).encode('utf-8'))
                self.perform_start_download_request(
                    escaped_uri,
                    get_gui_setting(self.gui_settings,
                                    "default_anonymity_enabled",
                                    True,
                                    is_bool=True),
                    get_gui_setting(self.gui_settings,
                                    "default_safeseeding_enabled",
                                    True,
                                    is_bool=True),
                    self.tribler_settings['downloadconfig']['saveas'], [], 0)

        self.dialog.setParent(None)
        self.dialog = None

    def on_add_torrent_from_url(self):
        self.dialog = ConfirmationDialog(
            self,
            "Add torrent from URL/magnet link",
            "Please enter the URL/magnet link in the field below:",
            [('ADD', BUTTON_TYPE_NORMAL), ('CANCEL', BUTTON_TYPE_CONFIRM)],
            show_input=True)
        self.dialog.dialog_widget.dialog_input.setPlaceholderText(
            'URL/magnet link')
        self.dialog.button_clicked.connect(
            self.on_torrent_from_url_dialog_done)
        self.dialog.show()

    def on_torrent_from_url_dialog_done(self, action):
        uri = self.dialog.dialog_widget.dialog_input.text()

        # Remove first dialog
        self.dialog.setParent(None)
        self.dialog = None

        if action == 0:
            self.start_download_from_uri(uri)

    def on_download_added(self, result):
        if len(self.pending_uri_requests
               ) == 0:  # Otherwise, we first process the remaining requests.
            self.window().left_menu_button_downloads.click()
        else:
            self.process_uri_request()

    def on_top_menu_button_click(self):
        if self.left_menu.isHidden():
            self.left_menu.show()
        else:
            self.left_menu.hide()

    def deselect_all_menu_buttons(self, except_select=None):
        for button in self.menu_buttons:
            if button == except_select:
                button.setEnabled(False)
                continue
            button.setEnabled(True)

            if button == self.left_menu_button_search and not self.has_search_results:
                button.setEnabled(False)

            button.setChecked(False)

    def clicked_menu_button_home(self):
        self.deselect_all_menu_buttons(self.left_menu_button_home)
        self.stackedWidget.setCurrentIndex(PAGE_HOME)
        self.navigation_stack = []
        self.hide_left_menu_playlist()

    def clicked_menu_button_search(self):
        self.deselect_all_menu_buttons(self.left_menu_button_search)
        self.stackedWidget.setCurrentIndex(PAGE_SEARCH_RESULTS)
        self.navigation_stack = []
        self.hide_left_menu_playlist()

    def clicked_menu_button_discovered(self):
        self.deselect_all_menu_buttons(self.left_menu_button_discovered)
        self.stackedWidget.setCurrentIndex(PAGE_DISCOVERED)
        self.discovered_page.load_discovered_channels()
        self.navigation_stack = []
        self.hide_left_menu_playlist()

    def clicked_menu_button_my_channel(self):
        self.deselect_all_menu_buttons(self.left_menu_button_my_channel)
        self.stackedWidget.setCurrentIndex(PAGE_EDIT_CHANNEL)
        self.edit_channel_page.load_my_channel_overview()
        self.navigation_stack = []
        self.hide_left_menu_playlist()

    def clicked_menu_button_video_player(self):
        self.deselect_all_menu_buttons(self.left_menu_button_video_player)
        self.stackedWidget.setCurrentIndex(PAGE_VIDEO_PLAYER)
        self.navigation_stack = []
        self.show_left_menu_playlist()

    def clicked_menu_button_downloads(self):
        self.deselect_all_menu_buttons(self.left_menu_button_downloads)
        self.stackedWidget.setCurrentIndex(PAGE_DOWNLOADS)
        self.navigation_stack = []
        self.hide_left_menu_playlist()

    def clicked_menu_button_debug(self):
        self.debug_window = DebugWindow(self.tribler_settings)
        self.debug_window.show()

    def clicked_menu_button_subscriptions(self):
        self.deselect_all_menu_buttons(self.left_menu_button_subscriptions)
        self.subscribed_channels_page.load_subscribed_channels()
        self.stackedWidget.setCurrentIndex(PAGE_SUBSCRIBED_CHANNELS)
        self.navigation_stack = []
        self.hide_left_menu_playlist()

    def hide_left_menu_playlist(self):
        self.left_menu_seperator.setHidden(True)
        self.left_menu_playlist_label.setHidden(True)
        self.left_menu_playlist.setHidden(True)

    def show_left_menu_playlist(self):
        self.left_menu_seperator.setHidden(False)
        self.left_menu_playlist_label.setHidden(False)
        self.left_menu_playlist.setHidden(False)

    def on_channel_item_click(self, channel_list_item):
        list_widget = channel_list_item.listWidget()
        from TriblerGUI.widgets.channel_list_item import ChannelListItem
        if isinstance(list_widget.itemWidget(channel_list_item),
                      ChannelListItem):
            channel_info = channel_list_item.data(Qt.UserRole)
            self.channel_page.initialize_with_channel(channel_info)
            self.navigation_stack.append(self.stackedWidget.currentIndex())
            self.stackedWidget.setCurrentIndex(PAGE_CHANNEL_DETAILS)

    def on_playlist_item_click(self, playlist_list_item):
        list_widget = playlist_list_item.listWidget()
        from TriblerGUI.widgets.playlist_list_item import PlaylistListItem
        if isinstance(list_widget.itemWidget(playlist_list_item),
                      PlaylistListItem):
            playlist_info = playlist_list_item.data(Qt.UserRole)
            self.playlist_page.initialize_with_playlist(playlist_info)
            self.navigation_stack.append(self.stackedWidget.currentIndex())
            self.stackedWidget.setCurrentIndex(PAGE_PLAYLIST_DETAILS)

    def on_page_back_clicked(self):
        prev_page = self.navigation_stack.pop()
        self.stackedWidget.setCurrentIndex(prev_page)

    def on_edit_channel_clicked(self):
        self.stackedWidget.setCurrentIndex(PAGE_EDIT_CHANNEL)
        self.navigation_stack = []
        self.channel_page.on_edit_channel_clicked()

    def resizeEvent(self, _):
        # Resize home page cells
        cell_width = self.home_page_table_view.width(
        ) / 3 - 3  # We have some padding to the right
        cell_height = cell_width / 2 + 60

        for i in range(0, 3):
            self.home_page_table_view.setColumnWidth(i, cell_width)
            self.home_page_table_view.setRowHeight(i, cell_height)

        self.resize_event.emit()

    def exit_full_screen(self):
        self.top_bar.show()
        self.left_menu.show()
        self.video_player_page.is_full_screen = False
        self.showNormal()

    def close_tribler(self):
        if not self.core_manager.shutting_down:
            self.show_loading_screen()

            self.gui_settings.setValue("pos", self.pos())
            self.gui_settings.setValue("size", self.size())

            if self.core_manager.use_existing_core:
                # Don't close the core that we are using
                QApplication.quit()

            self.core_manager.stop()
            self.core_manager.shutting_down = True
            self.downloads_page.stop_loading_downloads()

    def closeEvent(self, close_event):
        self.close_tribler()
        close_event.ignore()

    def keyReleaseEvent(self, event):
        if event.key() == Qt.Key_Escape:
            self.escape_pressed.emit()
            if self.isFullScreen():
                self.exit_full_screen()
Beispiel #44
0
class MainWindow(QMainWindow):
    def __init__(self):
        super(MainWindow, self).__init__()

        self.setStyleSheet(myStyleSheet(self))
        self.MaxRecentFiles = 5
        self.windowList = []
        self.recentFileActs = []
        self.curFile = ''
        self.setAcceptDrops(True)
        self. settings = QSettings("QTextEdit", "QTextEdit")
        self.myeditor = QTextEdit()
        #assert(self.locale().language() == QLocale.German)
        self.myeditor.setAcceptRichText(False)
        self.myeditor.setUndoRedoEnabled(True)
        self.myeditor.setStyleSheet(myStyleSheet(self))
        self.myeditor.setContextMenuPolicy(Qt.CustomContextMenu)
        self.myeditor.customContextMenuRequested.connect(self.contextMenuRequested)

        self.createActions()
        self.createToolBars()
        self.createMenus()
        self.createStatusBar()

        self.setWindowIcon(QIcon.fromTheme("gnome-documents"))

        self.readSettings()
        self.myeditor.document().contentsChanged.connect(self.documentWasModified)
        self.setCurrentFile('')
        self.setCentralWidget(self.myeditor)
        self.myeditor.setFocus()

    def closeEvent(self, event):
        if self.maybeSave():
            self.writeSettings()
            event.accept()
        else:
            event.ignore()

    def newFile(self):
        if self.maybeSave():
            self.myeditor.clear()
            self.setCurrentFile('')

    def open(self):
        if self.maybeSave():
            documents = QStandardPaths.standardLocations(QStandardPaths.DocumentsLocation)[0]
            fileName, _ = QFileDialog.getOpenFileName(self, "open File", documents, "Text Files (*.txt *.csv *.sh *.py) ;; all Files (*.*)")
            if fileName:
                self.loadFile(fileName)
            else:
                self.statusBar().showMessage("cancelled", 3000)

    def save(self):
        if not self.myeditor.toPlainText() == "":
            if self.myeditor.document().isModified():
                if self.curFile:
                    return self.saveFile(self.curFile)
                    self.setCurrentFile(fileName)
                else:
                    return self.saveAs()
            else:
                self.statusBar().showMessage("File '" + self.curFile + "' already saved", 3000)
        else:
            self.statusBar().showMessage("no Text")

    def saveAs(self):
        if not self.myeditor.toPlainText() == "":
            if self.curFile:
                fileName, _ = QFileDialog.getSaveFileName(self, "Save as...", self.curFile, "Text Files (*.txt)")
            else:
                documents = QStandardPaths.standardLocations(QStandardPaths.DocumentsLocation)[0]
                fileName, _ = QFileDialog.getSaveFileName(self, "Save as...", documents + "/newDocument.txt", "Text Files (*.txt)" )
            if fileName:
                return self.saveFile(fileName)

            return False
        else:
            self.statusBar().showMessage("no Text")

    def contextMenuRequested(self, point):
        cmenu = QMenu()
        cmenu = self.myeditor.createStandardContextMenu()
        if not self.myeditor.textCursor().selectedText() == "":
            cmenu.addSeparator()
            cmenu.addAction(QIcon.fromTheme("edit-find-and-replace"),"replace all occurrences", self.replaceThis)
        cmenu.exec_(self.myeditor.mapToGlobal(point))    

    def replaceThis(self):
        if not self.myeditor.textCursor().selectedText() == "":
            rtext = self.myeditor.textCursor().selectedText()
            dlg = QInputDialog(self, Qt.Dialog)
            dlg.setOkButtonText("Replace")
            text = dlg.getText(self, "Replace","replace '" + rtext + "' with:", QLineEdit.Normal, "")
            oldtext = self.myeditor.document().toPlainText()
            if not (text[0] == ""):
                newtext = oldtext.replace(rtext, text[0])
                self.myeditor.setPlainText(newtext)
                self.myeditor.document().setModified(True)

    def about(self):
        link = "<p><a title='Axel Schneider' href='http://goodoldsongs.jimdo.com' target='_blank'>Axel Schneider</a></p>"
        title = "über QTextEdit"
        message =  ("<span style='text-shadow: #2e3436 2px 2px 2px; color: #6169e1; font-size: 24pt;font-weight: bold;'><strong>QTextEdit 1.2</strong></span></p><br><br>created by<h2 >" + link + "</h2> with PyQt5" 
                    "<br><br>Copyright © 2018 The Qt Company Ltd and other contributors." 
                    "<br>Qt and the Qt logo are trademarks of The Qt Company Ltd.")
        msg = QMessageBox(QMessageBox.Information, title, message, QMessageBox.NoButton, self, Qt.Dialog|Qt.NoDropShadowWindowHint).show()

    def documentWasModified(self):
        self.setWindowModified(self.myeditor.document().isModified())

    def createActions(self):
        self.newAct = QAction(QIcon.fromTheme('document-new'), "&Neu", self,
                shortcut=QKeySequence.New, statusTip="new Document",
                triggered=self.newFile)

        self.openAct = QAction(QIcon.fromTheme('document-open'), "open File",
                self, shortcut=QKeySequence.Open,
                statusTip="open File", triggered=self.open)

        self.saveAct = QAction(QIcon.fromTheme('document-save'), "Save", self,
                shortcut=QKeySequence.Save,
                statusTip="save Document", triggered=self.save)

        self.saveAsAct = QAction(QIcon.fromTheme('document-save-as'),"Save as...", self,
                shortcut=QKeySequence.SaveAs,
                statusTip="save Document to new filename",
                triggered=self.saveAs)

        self.exitAct = QAction(QIcon.fromTheme('application-exit'),"Exit", self, shortcut="Ctrl+Q",
                statusTip="exit", triggered=self.close)

        self.cutAct = QAction(QIcon.fromTheme('edit-cut'), "Cut", self,
                shortcut=QKeySequence.Cut,
                statusTip="Cut",
                triggered=self.myeditor.cut)

        self.copyAct = QAction(QIcon.fromTheme('edit-copy'), "Copy", self,
                shortcut=QKeySequence.Copy,
                statusTip="Copy",
                triggered=self.myeditor.copy)

        self.pasteAct = QAction(QIcon.fromTheme('edit-paste'), "Paste",
                self, shortcut=QKeySequence.Paste,
                statusTip="Paste",
                triggered=self.myeditor.paste)

        self.undoAct = QAction(QIcon.fromTheme('edit-undo'), "Undo",
                self, shortcut=QKeySequence.Undo,
                statusTip="Undo",
                triggered=self.myeditor.undo)

        self.redoAct = QAction(QIcon.fromTheme('edit-redo'), "Redo",
                self, shortcut=QKeySequence.Redo,
                statusTip="Redo",
                triggered=self.myeditor.redo)

        self.aboutAct = QAction(QIcon.fromTheme('help-about'),"Info", self,
                statusTip="about QTextEdit",
                triggered=self.about)

        self.aboutQtAct = QAction(QIcon.fromTheme('help-about'),"über Qt", self,
                statusTip="über Qt",
                triggered=QApplication.instance().aboutQt)

        self.repAllAct = QPushButton("replace all") 
        self.repAllAct.setFixedWidth(100)
        self.repAllAct.setIcon(QIcon.fromTheme("edit-find-and-replace"))
        self.repAllAct.setStatusTip("replace all")
        self.repAllAct.clicked.connect(self.replaceAll)

        self.cutAct.setEnabled(False)
        self.copyAct.setEnabled(False)
        self.myeditor.copyAvailable.connect(self.cutAct.setEnabled)
        self.myeditor.copyAvailable.connect(self.copyAct.setEnabled)
        self.undoAct.setEnabled(False)
        self.redoAct.setEnabled(False)
        self.myeditor.undoAvailable.connect(self.undoAct.setEnabled)
        self.myeditor.redoAvailable.connect(self.redoAct.setEnabled)

        ### print preview
        self.printPreviewAct = QAction("Print Preview", self, shortcut=QKeySequence.Print,statusTip="Print Preview", triggered=self.handlePrintPreview)
        self.printPreviewAct.setIcon(QIcon.fromTheme("document-print-preview"))
        ### print
        self.printAct = QAction("print Document", self, shortcut=QKeySequence.Print,statusTip="print Document", triggered=self.handlePrint)
        self.printAct.setIcon(QIcon.fromTheme("document-print"))

        for i in range(self.MaxRecentFiles):
            self.recentFileActs.append(
                   QAction(self, visible=False,
                            triggered=self.openRecentFile))

    def findText(self):
        word = self.findfield.text()
        if self.myeditor.find(word):
            self.statusBar().showMessage("found '" + word + "'", 2000)
        else:
            self.myeditor.moveCursor(QTextCursor.Start)            
            if self.myeditor.find(word):
                return
            else:
                 self.statusBar().showMessage("found nothing", 3000)

    def replaceAll(self):
        oldtext = self.findfield.text()
        newtext = self.replacefield.text()
        if not oldtext == "":
            h = self.myeditor.toHtml().replace(oldtext, newtext)
            self.myeditor.setText(h)
            self.setModified(True)
            self.statusBar().showMessage("all replaced", 3000)
        else:
            self.statusBar().showMessage("nothing to replace", 3000)
        
    def replaceOne(self):
        oldtext = self.findfield.text()
        newtext = self.replacefield.text()
        if not oldtext == "":
            h = self.myeditor.toHtml().replace(oldtext, newtext, 1)
            self.myeditor.setText(h)
            self.setModified(True)
            self.statusBar().showMessage("1 replaced", 3000)
        else:
            self.statusBar().showMessage("nothing to replace", 3000)

    def openRecentFile(self):
        action = self.sender()
        if action:
            if (self.maybeSave()):
                self.loadFile(action.data())

    def createMenus(self):
        self.fileMenu = self.menuBar().addMenu("&File")
        self.separatorAct = self.fileMenu.addSeparator()
        self.fileMenu.addAction(self.newAct)
        self.fileMenu.addAction(self.openAct)
        self.fileMenu.addAction(self.saveAct)
        self.fileMenu.addAction(self.saveAsAct)
        self.fileMenu.addSeparator()
        for i in range(self.MaxRecentFiles):
            self.fileMenu.addAction(self.recentFileActs[i])
        self.updateRecentFileActions()
        self.fileMenu.addSeparator()
        self.clearRecentAct = QAction("clear List", self, triggered=self.clearRecentFiles)
        self.clearRecentAct.setIcon(QIcon.fromTheme("edit-clear"))
        self.fileMenu.addAction(self.clearRecentAct)
        self.fileMenu.addSeparator()
        self.fileMenu.addAction(self.exitAct)

        self.editMenu = self.menuBar().addMenu("&Edit")
        self.editMenu.addAction(self.undoAct)
        self.editMenu.addAction(self.redoAct)
        self.editMenu.addSeparator();
        self.editMenu.addAction(self.cutAct)
        self.editMenu.addAction(self.copyAct)
        self.editMenu.addAction(self.pasteAct)

        self.menuBar().addSeparator()

        self.helpMenu = self.menuBar().addMenu("&Help")
        self.helpMenu.addAction(self.aboutAct)

    def createToolBars(self):
        self.fileToolBar = self.addToolBar("File")
        self.fileToolBar.setIconSize(QSize(16, 16))
        self.fileToolBar.addAction(self.newAct)
        self.fileToolBar.addAction(self.openAct)
        self.fileToolBar.addAction(self.saveAct)
        self.fileToolBar.addAction(self.saveAsAct)
        self.fileToolBar.addSeparator()
        self.fileToolBar.addAction(self.printPreviewAct)
        self.fileToolBar.addAction(self.printAct)
        self.fileToolBar.setStyleSheet("QToolBar { border: 0px }")
        self.fileToolBar.setMovable(False)
        self.setContextMenuPolicy(Qt.NoContextMenu)

        self.editToolBar = self.addToolBar("Edit")
        self.editToolBar.setIconSize(QSize(16, 16))
        self.editToolBar.addAction(self.undoAct)
        self.editToolBar.addAction(self.redoAct)
        self.editToolBar.addSeparator()
        self.editToolBar.addAction(self.cutAct)
        self.editToolBar.addAction(self.copyAct)
        self.editToolBar.addAction(self.pasteAct)
        self.editToolBar.setMovable(False)
        self.editToolBar.setStyleSheet("QToolBar { border: 0px }")

        ### find / replace toolbar
        self.addToolBarBreak()
        self.findToolBar = self.addToolBar("Find")
        self.findToolBar.setIconSize(QSize(16, 16))
        self.findfield = QLineEdit()
        self.findfield.addAction(QIcon.fromTheme("edit-find"), 0)
        self.findfield.setClearButtonEnabled(True)
        self.findfield.setFixedWidth(200)
        self.findfield.setPlaceholderText("find")
        self.findfield.setStatusTip("press RETURN to find")
        self.findfield.setText("")
        self.findfield.returnPressed.connect(self.findText)
        self.findToolBar.addWidget(self.findfield)
        self.replacefield = QLineEdit()
        self.replacefield.addAction(QIcon.fromTheme("edit-find-replace"), 0)
        self.replacefield.setClearButtonEnabled(True)
        self.replacefield.setFixedWidth(200)
        self.replacefield.setPlaceholderText("replace with")
        self.replacefield.setStatusTip("press RETURN to replace first only")
        self.replacefield.returnPressed.connect(self.replaceOne)
        self.findToolBar.addSeparator() 
        self.findToolBar.addWidget(self.replacefield)
        self.findToolBar.addSeparator()
        self.findToolBar.addWidget(self.repAllAct)
        self.findToolBar.setMovable(False)
        self.findToolBar.setStyleSheet("QToolBar { border: 0px }")

    def createStatusBar(self):
        self.statusBar().setStyleSheet(myStyleSheet(self))
        self.statusBar().showMessage("Welcome")
        self.DigitalClock = DigitalClock()
        self.DigitalClock.setStyleSheet("QLCDNumber {padding: 2px, 2px 2px 2px; border: 0px solid #2e3436; color: #3465a4; background-color: transparent }")
        self.statusBar().addPermanentWidget(self.DigitalClock)

    def readSettings(self):
        pos = self.settings.value("pos", QPoint(200, 200))
        size = self.settings.value("size", QSize(400, 400))
        self.resize(size)
        self.move(pos)

    def writeSettings(self):
        self.settings.setValue("pos", self.pos())
        self.settings.setValue("size", self.size())

    def maybeSave(self):
        if self.myeditor.document().isModified():
            ret = QMessageBox.warning(self, "QTextEdit Message",
                    "Document was changed.\nSave changes?",
                    QMessageBox.Save | QMessageBox.Discard | QMessageBox.Cancel, defaultButton = QMessageBox.Save)
            if ret == QMessageBox.Save:
                return self.save()
            if ret == QMessageBox.Cancel:
                return False
        return True

    def loadFile(self, fileName):
        file = QFile(fileName)
        if not file.open(QFile.ReadOnly | QFile.Text):
            QMessageBox.warning(self, "Message",
                    "Cannot read file %s:\n%s." % (fileName, file.errorString()))
            return

        infile = QTextStream(file)
        QApplication.setOverrideCursor(Qt.WaitCursor)
        self.myeditor.setPlainText(infile.readAll())
        QApplication.restoreOverrideCursor()

        self.setCurrentFile(fileName)
        self.statusBar().showMessage("File '" +  fileName + "' loaded", 3000)

    def saveFile(self, fileName):
        file = QFile(fileName)
        if not file.open(QFile.WriteOnly | QFile.Text):
            QMessageBox.warning(self, "Message",
                    "Cannot write file %s:\n%s." % (fileName, file.errorString()))
            return False

        outfile = QTextStream(file)
        QApplication.setOverrideCursor(Qt.WaitCursor)
        outfile << self.myeditor.toPlainText()
        QApplication.restoreOverrideCursor()

        self.setCurrentFile(fileName);
        self.statusBar().showMessage("File '" +  fileName + "' saved", 3000)
        return True

    def setCurrentFile(self, fileName):
        self.curFile = fileName
        self.myeditor.document().setModified(False)
        self.setWindowModified(False)

        if self.curFile:
            self.setWindowTitle(self.strippedName(self.curFile) + "[*]")
        else:
            self.setWindowTitle('New.txt' + "[*]")

        files = self.settings.value('recentFileList', [])
        if not files == "":
            try:
                files.remove(fileName)
            except ValueError:
                pass
    
            if fileName:
                files.insert(0, fileName)
                del files[self.MaxRecentFiles:]
    
                self.settings.setValue('recentFileList', files)
                self.updateRecentFileActions()

    def updateRecentFileActions(self):
        mytext = ""
        files = self.settings.value('recentFileList', [])
        numRecentFiles = min(len(files), self.MaxRecentFiles)
#        if not files == "":
        for i in range(numRecentFiles):
            text = "&%d %s" % (i + 1, self.strippedName(files[i]))
            self.recentFileActs[i].setText(text)
            self.recentFileActs[i].setData(files[i])
            self.recentFileActs[i].setVisible(True)
            self.recentFileActs[i].setIcon(QIcon.fromTheme("text-x-generic"))
        
        for j in range(numRecentFiles, self.MaxRecentFiles):
            self.recentFileActs[j].setVisible(False)

        self.separatorAct.setVisible((numRecentFiles > 0))
            
    def clearRecentFiles(self, fileName):
        self.settings.clear()
        self.updateRecentFileActions()

    def strippedName(self, fullFileName):
        return QFileInfo(fullFileName).fileName()

    def msgbox(self, message):
        QMessageBox.warning(self, "Message", message)

    def handlePrint(self):
        if self.myeditor.toPlainText() == "":
            self.statusBar().showMessage("no Text to print")
            self.msgbox("kein Text zum Drucken")
        else:
            dialog = QtPrintSupport.QPrintDialog()
            if dialog.exec_() == QDialog.Accepted:
                self.handlePaintRequest(dialog.printer())
                self.statusBar().showMessage("Document printed")
            
    def handlePrintPreview(self):
        if self.myeditor.toPlainText() == "":
            self.statusBar().showMessage("no text to preview")
            self.msgbox("kein Text für Vorschau")
        else:
            dialog = QtPrintSupport.QPrintPreviewDialog()
            dialog.setGeometry(10, 0, self.width() - 60, self.height() - 60)
            dialog.paintRequested.connect(self.handlePaintRequest)
            dialog.exec_()
            self.statusBar().showMessage("Preview closed")

    def handlePaintRequest(self, printer):
        printer.setDocName(self.curFile)
        document = self.myeditor.document()
        document.print_(printer)

    def dragEnterEvent(self, event):
        if event.mimeData().hasUrls():
            event.accept()
        else:
            event.ignore()

    def dropEvent(self, event):
        f = str(event.mimeData().urls()[0].toLocalFile())
        self.loadFile(f)
Beispiel #45
0
class TriblerWindow(QMainWindow):
    resize_event = pyqtSignal()
    escape_pressed = pyqtSignal()
    tribler_crashed = pyqtSignal(str)
    received_search_completions = pyqtSignal(object)

    def __init__(self, core_args=None, core_env=None, api_port=None, api_key=None):
        QMainWindow.__init__(self)
        self._logger = logging.getLogger(self.__class__.__name__)

        QCoreApplication.setOrganizationDomain("nl")
        QCoreApplication.setOrganizationName("TUDelft")
        QCoreApplication.setApplicationName("Tribler")

        self.setWindowIcon(QIcon(QPixmap(get_image_path('tribler.png'))))

        self.gui_settings = QSettings('nl.tudelft.tribler')
        api_port = api_port or int(get_gui_setting(self.gui_settings, "api_port", DEFAULT_API_PORT))
        api_key = api_key or get_gui_setting(self.gui_settings, "api_key", hexlify(os.urandom(16)).encode('utf-8'))
        self.gui_settings.setValue("api_key", api_key)

        api_port = get_first_free_port(start=api_port, limit=100)
        request_manager.port, request_manager.key = api_port, api_key

        self.tribler_started = False
        self.tribler_settings = None
        # TODO: move version_id to tribler_common and get core version in the core crash message
        self.tribler_version = version_id
        self.debug_window = None

        self.error_handler = ErrorHandler(self)
        self.core_manager = CoreManager(api_port, api_key, self.error_handler)
        self.pending_requests = {}
        self.pending_uri_requests = []
        self.download_uri = None
        self.dialog = None
        self.create_dialog = None
        self.chosen_dir = None
        self.new_version_dialog = None
        self.start_download_dialog_active = False
        self.selected_torrent_files = []
        self.has_search_results = False
        self.last_search_query = None
        self.last_search_time = None
        self.start_time = time.time()
        self.token_refresh_timer = None
        self.shutdown_timer = None
        self.add_torrent_url_dialog_active = False

        sys.excepthook = self.error_handler.gui_error

        uic.loadUi(get_ui_file_path('mainwindow.ui'), self)
        TriblerRequestManager.window = self
        self.tribler_status_bar.hide()

        self.token_balance_widget.mouseReleaseEvent = self.on_token_balance_click

        def on_state_update(new_state):
            self.loading_text_label.setText(new_state)

        connect(self.core_manager.core_state_update, on_state_update)

        self.magnet_handler = MagnetHandler(self.window)
        QDesktopServices.setUrlHandler("magnet", self.magnet_handler, "on_open_magnet_link")

        self.debug_pane_shortcut = QShortcut(QKeySequence("Ctrl+d"), self)
        connect(self.debug_pane_shortcut.activated, self.clicked_menu_button_debug)
        self.import_torrent_shortcut = QShortcut(QKeySequence("Ctrl+o"), self)
        connect(self.import_torrent_shortcut.activated, self.on_add_torrent_browse_file)
        self.add_torrent_url_shortcut = QShortcut(QKeySequence("Ctrl+i"), self)
        connect(self.add_torrent_url_shortcut.activated, self.on_add_torrent_from_url)

        connect(self.top_search_bar.clicked, self.clicked_search_bar)

        # Remove the focus rect on OS X
        for widget in self.findChildren(QLineEdit) + self.findChildren(QListWidget) + self.findChildren(QTreeWidget):
            widget.setAttribute(Qt.WA_MacShowFocusRect, 0)

        self.menu_buttons = [
            self.left_menu_button_downloads,
            self.left_menu_button_discovered,
            self.left_menu_button_trust_graph,
            self.left_menu_button_popular,
        ]
        hide_xxx = get_gui_setting(self.gui_settings, "family_filter", True, is_bool=True)
        self.search_results_page.initialize_content_page(hide_xxx=hide_xxx)
        self.search_results_page.channel_torrents_filter_input.setHidden(True)

        self.settings_page.initialize_settings_page()
        self.downloads_page.initialize_downloads_page()
        self.loading_page.initialize_loading_page()
        self.discovering_page.initialize_discovering_page()

        self.discovered_page.initialize_content_page(hide_xxx=hide_xxx)

        self.popular_page.initialize_content_page(hide_xxx=hide_xxx, controller_class=PopularContentTableViewController)

        self.trust_page.initialize_trust_page()
        self.trust_graph_page.initialize_trust_graph()

        self.stackedWidget.setCurrentIndex(PAGE_LOADING)

        # Create the system tray icon
        if QSystemTrayIcon.isSystemTrayAvailable():
            self.tray_icon = QSystemTrayIcon()
            use_monochrome_icon = get_gui_setting(self.gui_settings, "use_monochrome_icon", False, is_bool=True)
            self.update_tray_icon(use_monochrome_icon)

            # Create the tray icon menu
            menu = self.create_add_torrent_menu()
            show_downloads_action = QAction('Show downloads', self)
            connect(show_downloads_action.triggered, self.clicked_menu_button_downloads)
            token_balance_action = QAction('Show token balance', self)
            connect(token_balance_action.triggered, lambda _: self.on_token_balance_click(None))
            quit_action = QAction('Quit Tribler', self)
            connect(quit_action.triggered, self.close_tribler)
            menu.addSeparator()
            menu.addAction(show_downloads_action)
            menu.addAction(token_balance_action)
            menu.addSeparator()
            menu.addAction(quit_action)
            self.tray_icon.setContextMenu(menu)
        else:
            self.tray_icon = None

        self.left_menu_button_debug.setHidden(True)
        self.top_menu_button.setHidden(True)
        self.left_menu.setHidden(True)
        self.token_balance_widget.setHidden(True)
        self.settings_button.setHidden(True)
        self.add_torrent_button.setHidden(True)
        self.top_search_bar.setHidden(True)

        # Set various icons
        self.top_menu_button.setIcon(QIcon(get_image_path('menu.png')))

        self.search_completion_model = QStringListModel()
        completer = QCompleter()
        completer.setModel(self.search_completion_model)
        completer.setCompletionMode(QCompleter.UnfilteredPopupCompletion)
        self.item_delegate = QStyledItemDelegate()
        completer.popup().setItemDelegate(self.item_delegate)
        completer.popup().setStyleSheet(
            """
        QListView {
            background-color: #404040;
        }

        QListView::item {
            color: #D0D0D0;
            padding-top: 5px;
            padding-bottom: 5px;
        }

        QListView::item:hover {
            background-color: #707070;
        }
        """
        )
        self.top_search_bar.setCompleter(completer)

        # Toggle debug if developer mode is enabled
        self.window().left_menu_button_debug.setHidden(
            not get_gui_setting(self.gui_settings, "debug", False, is_bool=True)
        )

        # Start Tribler
        self.core_manager.start(core_args=core_args, core_env=core_env)

        connect(self.core_manager.events_manager.torrent_finished, self.on_torrent_finished)
        connect(self.core_manager.events_manager.new_version_available, self.on_new_version_available)
        connect(self.core_manager.events_manager.tribler_started, self.on_tribler_started)
        connect(self.core_manager.events_manager.low_storage_signal, self.on_low_storage)
        connect(self.core_manager.events_manager.tribler_shutdown_signal, self.on_tribler_shutdown_state_update)
        connect(self.core_manager.events_manager.config_error_signal, self.on_config_error_signal)

        # Install signal handler for ctrl+c events
        def sigint_handler(*_):
            self.close_tribler()

        signal.signal(signal.SIGINT, sigint_handler)

        # Resize the window according to the settings
        center = QApplication.desktop().availableGeometry(self).center()
        pos = self.gui_settings.value("pos", QPoint(center.x() - self.width() * 0.5, center.y() - self.height() * 0.5))
        size = self.gui_settings.value("size", self.size())

        self.move(pos)
        self.resize(size)

        self.show()

        self.add_to_channel_dialog = AddToChannelDialog(self.window())

        self.add_torrent_menu = self.create_add_torrent_menu()
        self.add_torrent_button.setMenu(self.add_torrent_menu)

        self.channels_menu_list = self.findChild(ChannelsMenuListWidget, "channels_menu_list")

        connect(self.channels_menu_list.itemClicked, self.open_channel_contents_page)

        # The channels content page is only used to show subscribed channels, so we always show xxx
        # contents in it.
        connect(
            self.core_manager.events_manager.node_info_updated,
            lambda data: self.channels_menu_list.reload_if_necessary([data]),
        )
        connect(self.left_menu_button_new_channel.clicked, self.create_new_channel)

    def create_new_channel(self, checked):
        # TODO: DRY this with tablecontentmodel, possibly using QActions

        def create_channel_callback(channel_name):
            TriblerNetworkRequest(
                "channels/mychannel/0/channels",
                self.channels_menu_list.load_channels,
                method='POST',
                raw_data=json.dumps({"name": channel_name}) if channel_name else None,
            )

        NewChannelDialog(self, create_channel_callback)

    def open_channel_contents_page(self, channel_list_item):
        if not channel_list_item.flags() & Qt.ItemIsEnabled:
            return

        self.channel_contents_page.initialize_root_model_from_channel_info(channel_list_item.channel_info)
        self.stackedWidget.setCurrentIndex(PAGE_CHANNEL_CONTENTS)
        self.deselect_all_menu_buttons()

    def update_tray_icon(self, use_monochrome_icon):
        if not QSystemTrayIcon.isSystemTrayAvailable() or not self.tray_icon:
            return

        if use_monochrome_icon:
            self.tray_icon.setIcon(QIcon(QPixmap(get_image_path('monochrome_tribler.png'))))
        else:
            self.tray_icon.setIcon(QIcon(QPixmap(get_image_path('tribler.png'))))
        self.tray_icon.show()

    def delete_tray_icon(self):
        if self.tray_icon:
            try:
                self.tray_icon.deleteLater()
            except RuntimeError:
                # The tray icon might have already been removed when unloading Qt.
                # This is due to the C code actually being asynchronous.
                logging.debug("Tray icon already removed, no further deletion necessary.")
            self.tray_icon = None

    def on_low_storage(self, _):
        """
        Dealing with low storage space available. First stop the downloads and the core manager and ask user to user to
        make free space.
        :return:
        """

        def close_tribler_gui():
            self.close_tribler()
            # Since the core has already stopped at this point, it will not terminate the GUI.
            # So, we quit the GUI separately here.
            if not QApplication.closingDown():
                QApplication.quit()

        self.downloads_page.stop_loading_downloads()
        self.core_manager.stop(False)
        close_dialog = ConfirmationDialog(
            self.window(),
            tr("<b>CRITICAL ERROR</b>"),
            tr(
                "You are running low on disk space (<100MB). Please make sure to have "
                "sufficient free space available and restart Tribler again."
            ),
            [(tr("Close Tribler"), BUTTON_TYPE_NORMAL)],
        )
        connect(close_dialog.button_clicked, lambda _: close_tribler_gui())
        close_dialog.show()

    def on_torrent_finished(self, torrent_info):
        if "hidden" not in torrent_info or not torrent_info["hidden"]:
            self.tray_show_message(tr("Download finished"), tr("Download of %s has finished.") % {torrent_info['name']})

    def show_loading_screen(self):
        self.top_menu_button.setHidden(True)
        self.left_menu.setHidden(True)
        self.token_balance_widget.setHidden(True)
        self.settings_button.setHidden(True)
        self.add_torrent_button.setHidden(True)
        self.top_search_bar.setHidden(True)
        self.stackedWidget.setCurrentIndex(PAGE_LOADING)

    def tray_set_tooltip(self, message):
        """
        Set a tooltip message for the tray icon, if possible.

        :param message: the message to display on hover
        """
        if self.tray_icon:
            try:
                self.tray_icon.setToolTip(message)
            except RuntimeError as e:
                logging.error("Failed to set tray tooltip: %s", str(e))

    def tray_show_message(self, title, message):
        """
        Show a message at the tray icon, if possible.

        :param title: the title of the message
        :param message: the message to display
        """
        if self.tray_icon:
            try:
                self.tray_icon.showMessage(title, message)
            except RuntimeError as e:
                logging.error("Failed to set tray message: %s", str(e))

    def on_tribler_started(self, version):
        if self.tribler_started:
            logging.warning("Received duplicate Tribler Core started event")
            return

        self.tribler_started = True
        self.tribler_version = version

        self.top_menu_button.setHidden(False)
        self.left_menu.setHidden(False)
        self.token_balance_widget.setHidden(False)
        self.settings_button.setHidden(False)
        self.add_torrent_button.setHidden(False)
        self.top_search_bar.setHidden(False)

        self.fetch_settings()

        self.downloads_page.start_loading_downloads()

        self.setAcceptDrops(True)
        self.setWindowTitle(f"Tribler {self.tribler_version}")

        autocommit_enabled = (
            get_gui_setting(self.gui_settings, "autocommit_enabled", True, is_bool=True) if self.gui_settings else True
        )
        self.channel_contents_page.initialize_content_page(autocommit_enabled=autocommit_enabled, hide_xxx=False)

        hide_xxx = get_gui_setting(self.gui_settings, "family_filter", True, is_bool=True)
        self.discovered_page.initialize_root_model(
            DiscoveredChannelsModel(
                channel_info={"name": tr("Discovered channels")}, endpoint_url="channels", hide_xxx=hide_xxx
            )
        )
        connect(self.core_manager.events_manager.discovered_channel, self.discovered_page.model.on_new_entry_received)

        self.popular_page.initialize_root_model(
            PopularTorrentsModel(channel_info={"name": "Popular torrents"}, hide_xxx=hide_xxx)
        )
        self.popular_page.explanation_text.setText(
            tr("This page show the list of popular torrents collected by Tribler during the last 24 hours.")
        )
        self.popular_page.explanation_container.setHidden(False)

        self.add_to_channel_dialog.load_channel(0)

        if not self.gui_settings.value("first_discover", False) and not self.core_manager.use_existing_core:
            connect(self.core_manager.events_manager.discovered_channel, self.stop_discovering)
            self.window().gui_settings.setValue("first_discover", True)
            self.discovering_page.is_discovering = True
            self.stackedWidget.setCurrentIndex(PAGE_DISCOVERING)
        else:
            self.clicked_menu_button_discovered()
            self.left_menu_button_discovered.setChecked(True)

        self.channels_menu_list.load_channels()

    def stop_discovering(self, response):
        if not self.discovering_page.is_discovering:
            return
        disconnect(self.core_manager.events_manager.discovered_channel, self.stop_discovering)
        self.discovering_page.is_discovering = False
        if self.stackedWidget.currentIndex() == PAGE_DISCOVERING:
            self.clicked_menu_button_discovered()
            self.left_menu_button_discovered.setChecked(True)

    def on_events_started(self, json_dict):
        self.setWindowTitle(f"Tribler {json_dict['version']}")

    def show_status_bar(self, message):
        self.tribler_status_bar_label.setText(message)
        self.tribler_status_bar.show()

    def hide_status_bar(self):
        self.tribler_status_bar.hide()

    def process_uri_request(self):
        """
        Process a URI request if we have one in the queue.
        """
        if len(self.pending_uri_requests) == 0:
            return

        uri = self.pending_uri_requests.pop()

        if uri.startswith('file') or uri.startswith('magnet'):
            self.start_download_from_uri(uri)

    def update_recent_download_locations(self, destination):
        # Save the download location to the GUI settings
        current_settings = get_gui_setting(self.gui_settings, "recent_download_locations", "")
        recent_locations = current_settings.split(",") if len(current_settings) > 0 else []
        if isinstance(destination, str):
            destination = destination.encode('utf-8')
        encoded_destination = hexlify(destination)
        if encoded_destination in recent_locations:
            recent_locations.remove(encoded_destination)
        recent_locations.insert(0, encoded_destination)

        if len(recent_locations) > 5:
            recent_locations = recent_locations[:5]

        self.gui_settings.setValue("recent_download_locations", ','.join(recent_locations))

    def perform_start_download_request(
        self,
        uri,
        anon_download,
        safe_seeding,
        destination,
        selected_files,
        total_files=0,
        add_to_channel=False,
        callback=None,
    ):
        # Check if destination directory is writable
        is_writable, error = is_dir_writable(destination)
        if not is_writable:
            gui_error_message = tr(
                "Insufficient write permissions to <i>%s</i> directory. Please add proper "
                "write permissions on the directory and add the torrent again. %s"
            ) % (destination, error)
            ConfirmationDialog.show_message(
                self.window(), tr("Download error <i>%s</i>") % uri, gui_error_message, "OK"
            )
            return

        selected_files_list = []
        if len(selected_files) != total_files:  # Not all files included
            selected_files_list = [filename for filename in selected_files]

        anon_hops = int(self.tribler_settings['download_defaults']['number_hops']) if anon_download else 0
        safe_seeding = 1 if safe_seeding else 0
        post_data = {
            "uri": uri,
            "anon_hops": anon_hops,
            "safe_seeding": safe_seeding,
            "destination": destination,
            "selected_files": selected_files_list,
        }
        TriblerNetworkRequest(
            "downloads", callback if callback else self.on_download_added, method='PUT', data=post_data
        )

        self.update_recent_download_locations(destination)

        if add_to_channel:

            def on_add_button_pressed(channel_id):
                post_data = {}
                if uri.startswith("file:"):
                    with open(uri[5:], "rb") as torrent_file:
                        post_data['torrent'] = b64encode(torrent_file.read()).decode('utf8')
                elif uri.startswith("magnet:"):
                    post_data['uri'] = uri

                if post_data:
                    TriblerNetworkRequest(
                        f"channels/mychannel/{channel_id}/torrents",
                        lambda _: self.tray_show_message(tr("Channel update"), tr("Torrent(s) added to your channel")),
                        method='PUT',
                        data=post_data,
                    )

            self.window().add_to_channel_dialog.show_dialog(on_add_button_pressed, confirm_button_text="Add torrent")

    def on_new_version_available(self, version):
        if version == str(self.gui_settings.value('last_reported_version')):
            return

        # To prevent multiple dialogs on top of each other,
        # close any existing dialog first.
        if self.new_version_dialog:
            self.new_version_dialog.close_dialog()
            self.new_version_dialog = None

        self.new_version_dialog = ConfirmationDialog(
            self,
            tr("New version available"),
            tr("Version %s of Tribler is available.Do you want to visit the " "website to download the newest version?")
            % version,
            [(tr("IGNORE"), BUTTON_TYPE_NORMAL), (tr("LATER"), BUTTON_TYPE_NORMAL), (tr("OK"), BUTTON_TYPE_NORMAL)],
        )
        connect(self.new_version_dialog.button_clicked, lambda action: self.on_new_version_dialog_done(version, action))
        self.new_version_dialog.show()

    def on_new_version_dialog_done(self, version, action):
        if action == 0:  # ignore
            self.gui_settings.setValue("last_reported_version", version)
        elif action == 2:  # ok
            import webbrowser

            webbrowser.open("https://tribler.org")
        if self.new_version_dialog:
            self.new_version_dialog.close_dialog()
            self.new_version_dialog = None

    def on_search_text_change(self, text):
        # We do not want to bother the database on petty 1-character queries
        if len(text) < 2:
            return
        TriblerNetworkRequest(
            "search/completions", self.on_received_search_completions, url_params={'q': sanitize_for_fts(text)}
        )

    def on_received_search_completions(self, completions):
        if completions is None:
            return
        self.received_search_completions.emit(completions)
        self.search_completion_model.setStringList(completions["completions"])

    def fetch_settings(self):
        TriblerNetworkRequest("settings", self.received_settings, capture_core_errors=False)

    def received_settings(self, settings):
        if not settings:
            return
        # If we cannot receive the settings, stop Tribler with an option to send the crash report.
        if 'error' in settings:
            raise RuntimeError(TriblerRequestManager.get_message_from_error(settings))

        # If there is any pending dialog (likely download dialog or error dialog of setting not available),
        # close the dialog
        if self.dialog:
            self.dialog.close_dialog()
            self.dialog = None

        self.tribler_settings = settings['settings']

        self.downloads_all_button.click()

        # process pending file requests (i.e. someone clicked a torrent file when Tribler was closed)
        # We do this after receiving the settings so we have the default download location.
        self.process_uri_request()

        # Set token balance refresh timer and load the token balance
        self.token_refresh_timer = QTimer()
        connect(self.token_refresh_timer.timeout, self.load_token_balance)
        self.token_refresh_timer.start(60000)

        self.load_token_balance()

    def on_top_search_button_click(self):
        current_ts = time.time()
        query = self.top_search_bar.text()

        if (
            self.last_search_query
            and self.last_search_time
            and self.last_search_query == self.top_search_bar.text()
            and current_ts - self.last_search_time < 1
        ):
            logging.info("Same search query already sent within 500ms so dropping this one")
            return

        if not query:
            return

        self.has_search_results = True
        self.search_results_page.initialize_root_model(
            SearchResultsModel(
                channel_info={"name": (tr("Search results for %s") % query) if len(query) < 50 else f"{query[:50]}..."},
                endpoint_url="search",
                hide_xxx=get_gui_setting(self.gui_settings, "family_filter", True, is_bool=True),
                text_filter=to_fts_query(query),
                type_filter=[REGULAR_TORRENT, CHANNEL_TORRENT, COLLECTION_NODE],
            )
        )

        self.clicked_search_bar()

        # Trigger remote search
        self.search_results_page.preview_clicked()

        self.last_search_query = query
        self.last_search_time = current_ts

    def on_settings_button_click(self):
        self.deselect_all_menu_buttons()
        self.stackedWidget.setCurrentIndex(PAGE_SETTINGS)
        self.settings_page.load_settings()

    def on_token_balance_click(self, _):
        self.raise_window()
        self.deselect_all_menu_buttons()
        self.stackedWidget.setCurrentIndex(PAGE_TRUST)
        self.load_token_balance()
        self.trust_page.load_history()

    def load_token_balance(self):
        TriblerNetworkRequest("bandwidth/statistics", self.received_bandwidth_statistics, capture_core_errors=False)

    def received_bandwidth_statistics(self, statistics):
        if not statistics or "statistics" not in statistics:
            return

        self.trust_page.received_bandwidth_statistics(statistics)

        statistics = statistics["statistics"]
        balance = statistics["total_given"] - statistics["total_taken"]
        self.set_token_balance(balance)

        # If trust page is currently visible, then load the graph as well
        if self.stackedWidget.currentIndex() == PAGE_TRUST:
            self.trust_page.load_history()

    def set_token_balance(self, balance):
        if abs(balance) > 1024 ** 4:  # Balance is over a TB
            balance /= 1024.0 ** 4
            self.token_balance_label.setText(f"{balance:.1f} TB")
        elif abs(balance) > 1024 ** 3:  # Balance is over a GB
            balance /= 1024.0 ** 3
            self.token_balance_label.setText(f"{balance:.1f} GB")
        else:
            balance /= 1024.0 ** 2
            self.token_balance_label.setText("%d MB" % balance)

    def raise_window(self):
        self.setWindowState(self.windowState() & ~Qt.WindowMinimized | Qt.WindowActive)
        self.raise_()
        self.activateWindow()

    def create_add_torrent_menu(self):
        """
        Create a menu to add new torrents. Shows when users click on the tray icon or the big plus button.
        """
        menu = TriblerActionMenu(self)

        browse_files_action = QAction(tr("Import torrent from file"), self)
        browse_directory_action = QAction(tr("Import torrent(s) from directory"), self)
        add_url_action = QAction(tr("Import torrent from magnet/URL"), self)
        create_torrent_action = QAction(tr("Create torrent from file(s)"), self)

        connect(browse_files_action.triggered, self.on_add_torrent_browse_file)
        connect(browse_directory_action.triggered, self.on_add_torrent_browse_dir)
        connect(add_url_action.triggered, self.on_add_torrent_from_url)
        connect(create_torrent_action.triggered, self.on_create_torrent)

        menu.addAction(browse_files_action)
        menu.addAction(browse_directory_action)
        menu.addAction(add_url_action)
        menu.addSeparator()
        menu.addAction(create_torrent_action)

        return menu

    def on_create_torrent(self, checked):
        if self.create_dialog:
            self.create_dialog.close_dialog()

        self.create_dialog = CreateTorrentDialog(self)
        connect(self.create_dialog.create_torrent_notification, self.on_create_torrent_updates)
        self.create_dialog.show()

    def on_create_torrent_updates(self, update_dict):
        self.tray_show_message(tr("Torrent updates"), update_dict['msg'])

    def on_add_torrent_browse_file(self, index):
        filenames = QFileDialog.getOpenFileNames(
            self, tr("Please select the .torrent file"), QDir.homePath(), tr("Torrent files%s") % " (*.torrent)"
        )
        if len(filenames[0]) > 0:
            for filename in filenames[0]:
                self.pending_uri_requests.append(f"file:{quote(filename)}")
            self.process_uri_request()

    def start_download_from_uri(self, uri):
        uri = uri.decode('utf-8') if isinstance(uri, bytes) else uri
        self.download_uri = uri

        if get_gui_setting(self.gui_settings, "ask_download_settings", True, is_bool=True):
            # FIXME: instead of using this workaround, make sure the settings are _available_ by this moment
            # If tribler settings is not available, fetch the settings and inform the user to try again.
            if not self.tribler_settings:
                self.fetch_settings()
                self.dialog = ConfirmationDialog.show_error(
                    self,
                    tr("Download Error"),
                    tr("Tribler settings is not available yet. Fetching it now. Please try again later."),
                )
                # By re-adding the download uri to the pending list, the request is re-processed
                # when the settings is received
                self.pending_uri_requests.append(uri)
                return
            # Clear any previous dialog if exists
            if self.dialog:
                self.dialog.close_dialog()
                self.dialog = None

            self.dialog = StartDownloadDialog(self, self.download_uri)
            connect(self.dialog.button_clicked, self.on_start_download_action)
            self.dialog.show()
            self.start_download_dialog_active = True
        else:
            # FIXME: instead of using this workaround, make sure the settings are _available_ by this moment
            # In the unlikely scenario that tribler settings are not available yet, try to fetch settings again and
            # add the download uri back to self.pending_uri_requests to process again.
            if not self.tribler_settings:
                self.fetch_settings()
                if self.download_uri not in self.pending_uri_requests:
                    self.pending_uri_requests.append(self.download_uri)
                return

            self.window().perform_start_download_request(
                self.download_uri,
                self.window().tribler_settings['download_defaults']['anonymity_enabled'],
                self.window().tribler_settings['download_defaults']['safeseeding_enabled'],
                self.tribler_settings['download_defaults']['saveas'],
                [],
            )
            self.process_uri_request()

    def on_start_download_action(self, action):
        if action == 1:
            if self.dialog and self.dialog.dialog_widget:
                self.window().perform_start_download_request(
                    self.download_uri,
                    self.dialog.dialog_widget.anon_download_checkbox.isChecked(),
                    self.dialog.dialog_widget.safe_seed_checkbox.isChecked(),
                    self.dialog.dialog_widget.destination_input.currentText(),
                    self.dialog.get_selected_files(),
                    self.dialog.dialog_widget.files_list_view.topLevelItemCount(),
                    add_to_channel=self.dialog.dialog_widget.add_to_channel_checkbox.isChecked(),
                )
            else:
                ConfirmationDialog.show_error(
                    self, tr("Tribler UI Error"), tr("Something went wrong. Please try again.")
                )
                logging.exception("Error while trying to download. Either dialog or dialog.dialog_widget is None")

        if self.dialog:
            self.dialog.close_dialog()
            self.dialog = None
            self.start_download_dialog_active = False

        if action == 0:  # We do this after removing the dialog since process_uri_request is blocking
            self.process_uri_request()

    def on_add_torrent_browse_dir(self, checked):
        chosen_dir = QFileDialog.getExistingDirectory(
            self,
            tr("Please select the directory containing the .torrent files"),
            QDir.homePath(),
            QFileDialog.ShowDirsOnly,
        )
        self.chosen_dir = chosen_dir
        if len(chosen_dir) != 0:
            self.selected_torrent_files = [torrent_file for torrent_file in glob.glob(chosen_dir + "/*.torrent")]
            self.dialog = ConfirmationDialog(
                self,
                tr("Add torrents from directory"),
                tr("Add %s torrent files from the following directory to your Tribler channel: \n\n%s")
                % (len(self.selected_torrent_files), chosen_dir),
                [(tr("ADD"), BUTTON_TYPE_NORMAL), (tr("CANCEL"), BUTTON_TYPE_CONFIRM)],
                checkbox_text=tr("Add torrents to My Channel"),
            )
            connect(self.dialog.button_clicked, self.on_confirm_add_directory_dialog)
            self.dialog.show()

    def on_confirm_add_directory_dialog(self, action):
        if action == 0:
            if self.dialog.checkbox.isChecked():
                # TODO: add recursive directory scanning
                def on_add_button_pressed(channel_id):
                    TriblerNetworkRequest(
                        f"collections/mychannel/{channel_id}/torrents",
                        lambda _: self.tray_show_message(
                            tr("Channels update"), tr("%s added to your channel") % self.chosen_dir
                        ),
                        method='PUT',
                        data={"torrents_dir": self.chosen_dir},
                    )

                self.window().add_to_channel_dialog.show_dialog(
                    on_add_button_pressed, confirm_button_text=tr("Add torrent(s)")
                )

            for torrent_file in self.selected_torrent_files:
                self.perform_start_download_request(
                    f"file:{torrent_file}",
                    self.window().tribler_settings['download_defaults']['anonymity_enabled'],
                    self.window().tribler_settings['download_defaults']['safeseeding_enabled'],
                    self.tribler_settings['download_defaults']['saveas'],
                    [],
                )

        if self.dialog:
            self.dialog.close_dialog()
            self.dialog = None

    def on_add_torrent_from_url(self, checked=False):
        # Make sure that the window is visible (this action might be triggered from the tray icon)
        self.raise_window()

        if not self.add_torrent_url_dialog_active:
            self.dialog = ConfirmationDialog(
                self,
                tr("Add torrent from URL/magnet link"),
                tr("Please enter the URL/magnet link in the field below:"),
                [(tr("ADD"), BUTTON_TYPE_NORMAL), (tr("CANCEL"), BUTTON_TYPE_CONFIRM)],
                show_input=True,
            )
            self.dialog.dialog_widget.dialog_input.setPlaceholderText(tr("URL/magnet link"))
            self.dialog.dialog_widget.dialog_input.setFocus()
            connect(self.dialog.button_clicked, self.on_torrent_from_url_dialog_done)
            self.dialog.show()
            self.add_torrent_url_dialog_active = True

    def on_torrent_from_url_dialog_done(self, action):
        self.add_torrent_url_dialog_active = False
        if self.dialog and self.dialog.dialog_widget:
            uri = self.dialog.dialog_widget.dialog_input.text().strip()

            # If the URI is a 40-bytes hex-encoded infohash, convert it to a valid magnet link
            if len(uri) == 40:
                valid_ih_hex = True
                try:
                    int(uri, 16)
                except ValueError:
                    valid_ih_hex = False

                if valid_ih_hex:
                    uri = "magnet:?xt=urn:btih:" + uri

            # Remove first dialog
            self.dialog.close_dialog()
            self.dialog = None

            if action == 0:
                self.start_download_from_uri(uri)

    def on_download_added(self, result):
        if not result:
            return
        if len(self.pending_uri_requests) == 0:  # Otherwise, we first process the remaining requests.
            self.window().left_menu_button_downloads.click()
        else:
            self.process_uri_request()

    def on_top_menu_button_click(self):
        if self.left_menu.isHidden():
            self.left_menu.show()
        else:
            self.left_menu.hide()

    def deselect_all_menu_buttons(self, except_select=None):
        for button in self.menu_buttons:
            if button == except_select:
                button.setEnabled(False)
                continue
            button.setEnabled(True)
            button.setChecked(False)

    def clicked_search_bar(self, checked=False):
        query = self.top_search_bar.text()
        if query and self.has_search_results:
            self.deselect_all_menu_buttons()
            if self.stackedWidget.currentIndex() == PAGE_SEARCH_RESULTS:
                self.search_results_page.go_back_to_level(0)
            self.stackedWidget.setCurrentIndex(PAGE_SEARCH_RESULTS)

    def clicked_menu_button_discovered(self):
        self.deselect_all_menu_buttons()
        self.left_menu_button_discovered.setChecked(True)
        if self.stackedWidget.currentIndex() == PAGE_DISCOVERED:
            self.discovered_page.go_back_to_level(0)
            self.discovered_page.reset_view()
        self.stackedWidget.setCurrentIndex(PAGE_DISCOVERED)
        self.discovered_page.content_table.setFocus()

    def clicked_menu_button_popular(self):
        self.deselect_all_menu_buttons()
        self.left_menu_button_popular.setChecked(True)
        # We want to reset the view every time to show updates
        self.popular_page.go_back_to_level(0)
        self.popular_page.reset_view()
        self.stackedWidget.setCurrentIndex(PAGE_POPULAR)
        self.popular_page.content_table.setFocus()

    def clicked_menu_button_trust_graph(self):
        self.deselect_all_menu_buttons(self.left_menu_button_trust_graph)
        self.stackedWidget.setCurrentIndex(PAGE_TRUST_GRAPH_PAGE)

    def clicked_menu_button_downloads(self, checked):
        self.deselect_all_menu_buttons(self.left_menu_button_downloads)
        self.raise_window()
        self.left_menu_button_downloads.setChecked(True)
        self.stackedWidget.setCurrentIndex(PAGE_DOWNLOADS)

    def clicked_menu_button_debug(self, index=False):
        if not self.debug_window:
            self.debug_window = DebugWindow(self.tribler_settings, self.gui_settings, self.tribler_version)
        self.debug_window.show()

    def resizeEvent(self, _):
        # This thing here is necessary to send the resize event to dialogs, etc.
        self.resize_event.emit()

    def close_tribler(self, checked=False):
        if self.core_manager.shutting_down:
            return

        def show_force_shutdown():
            self.window().force_shutdown_btn.show()

        self.delete_tray_icon()
        self.show_loading_screen()
        self.hide_status_bar()
        self.loading_text_label.setText(tr("Shutting down..."))
        if self.debug_window:
            self.debug_window.setHidden(True)

        self.shutdown_timer = QTimer()
        connect(self.shutdown_timer.timeout, show_force_shutdown)
        self.shutdown_timer.start(SHUTDOWN_WAITING_PERIOD)

        self.gui_settings.setValue("pos", self.pos())
        self.gui_settings.setValue("size", self.size())

        if self.core_manager.use_existing_core:
            # Don't close the core that we are using
            QApplication.quit()

        self.core_manager.stop()
        self.core_manager.shutting_down = True
        self.downloads_page.stop_loading_downloads()
        request_manager.clear()

        # Stop the token balance timer
        if self.token_refresh_timer:
            self.token_refresh_timer.stop()

    def closeEvent(self, close_event):
        self.close_tribler()
        close_event.ignore()

    def dragEnterEvent(self, e):
        file_urls = [_qurl_to_path(url) for url in e.mimeData().urls()] if e.mimeData().hasUrls() else []

        if any(os.path.isfile(filename) for filename in file_urls):
            e.accept()
        else:
            e.ignore()

    def dropEvent(self, e):
        file_urls = (
            [(_qurl_to_path(url), url.toString()) for url in e.mimeData().urls()] if e.mimeData().hasUrls() else []
        )

        for filename, fileurl in file_urls:
            if os.path.isfile(filename):
                self.start_download_from_uri(fileurl)

        e.accept()

    def clicked_force_shutdown(self):
        process_checker = ProcessChecker()
        if process_checker.already_running:
            core_pid = process_checker.get_pid_from_lock_file()
            os.kill(int(core_pid), 9)
        # Stop the Qt application
        QApplication.quit()

    def clicked_skip_conversion(self):
        self.dialog = ConfirmationDialog(
            self,
            tr("Abort the conversion of Channels database"),
            tr(
                "The upgrade procedure is now <b>converting your personal channel</b> and channels "
                "collected by the previous installation of Tribler.<br>"
                "Are you sure you want to abort the conversion process?<br><br>"
                "<p style='color:red'><b> !!! WARNING !!! <br>"
                "You will lose your personal channel and subscribed channels if you ABORT now! </b> </p> <br>"
            ),
            [(tr("ABORT"), BUTTON_TYPE_CONFIRM), (tr("CONTINUE"), BUTTON_TYPE_NORMAL)],
        )
        connect(self.dialog.button_clicked, self.on_skip_conversion_dialog)
        self.dialog.show()

    def on_channel_subscribe(self, channel_info):
        patch_data = [{"public_key": channel_info['public_key'], "id": channel_info['id'], "subscribed": True}]
        TriblerNetworkRequest(
            "metadata",
            lambda data: self.core_manager.events_manager.node_info_updated.emit(data[0]),
            raw_data=json.dumps(patch_data),
            method='PATCH',
        )

    def on_channel_unsubscribe(self, channel_info):
        def _on_unsubscribe_action(action):
            if action == 0:
                patch_data = [{"public_key": channel_info['public_key'], "id": channel_info['id'], "subscribed": False}]
                TriblerNetworkRequest(
                    "metadata",
                    lambda data: self.core_manager.events_manager.node_info_updated.emit(data[0]),
                    raw_data=json.dumps(patch_data),
                    method='PATCH',
                )
            if self.dialog:
                self.dialog.close_dialog()
                self.dialog = None

        self.dialog = ConfirmationDialog(
            self,
            tr("Unsubscribe from channel"),
            tr("Are you sure you want to <b>unsubscribe</b> from channel<br/>")
            + '\"'
            + f"<b>{channel_info['name']}</b>"
            + '\"'
            + tr("<br/>and remove its contents?"),
            [(tr("UNSUBSCRIBE"), BUTTON_TYPE_NORMAL), (tr("CANCEL"), BUTTON_TYPE_CONFIRM)],
        )
        connect(self.dialog.button_clicked, _on_unsubscribe_action)
        self.dialog.show()

    def on_channel_delete(self, channel_info):
        def _on_delete_action(action):
            if action == 0:
                delete_data = [{"public_key": channel_info['public_key'], "id": channel_info['id']}]
                TriblerNetworkRequest(
                    "metadata",
                    lambda data: self.core_manager.events_manager.node_info_updated.emit(data[0]),
                    raw_data=json.dumps(delete_data),
                    method='DELETE',
                )
            if self.dialog:
                self.dialog.close_dialog()
                self.dialog = None

        self.dialog = ConfirmationDialog(
            self,
            tr("Delete channel"),
            tr("Are you sure you want to <b>delete</b> your personal channel<br/>")
            + '\"'
            + f"<b>{channel_info['name']}</b>"
            + '\"'
            + tr("<br/>and all its contents?"),
            [(tr("DELETE"), BUTTON_TYPE_NORMAL), (tr("CANCEL"), BUTTON_TYPE_CONFIRM)],
        )
        connect(self.dialog.button_clicked, _on_delete_action)
        self.dialog.show()

    def on_skip_conversion_dialog(self, action):
        if action == 0:
            TriblerNetworkRequest("upgrader", lambda _: None, data={"skip_db_upgrade": True}, method='POST')

        if self.dialog:
            self.dialog.close_dialog()
            self.dialog = None

    def on_tribler_shutdown_state_update(self, state):
        self.loading_text_label.setText(state)

    def on_config_error_signal(self, stacktrace):
        self._logger.error(f"Config error: {stacktrace}")
        user_message = tr(
            "Tribler recovered from a corrupted config. Please check your settings and update if necessary."
        )
        ConfirmationDialog.show_error(self, tr("Tribler config error"), user_message)
class Window(QMainWindow):
    def __init__(self, user):
        super().__init__()
        self.id_user = user
        self.widget = Wewnatrz(self)
        self.title = 'Wykaz narzędzi'
        self.width = 1440
        self.height = 900
        # Odpowiedzialne za utrzymanie rozmiaru i pozycji
        self.settings = QSettings('Kuźnia Jawor', 'PBPZ')
        geometry = self.settings.value('geometria', bytes('', 'utf-8'))
        self.restoreGeometry(geometry)

        # Edycja podwietlenia głównego okna
        paleta = self.palette()
        paleta.setColor(QPalette.Highlight, QColor(233, 107, 57))
        self.setPalette(paleta)

        self.initUI()

    # Odpowiedzialne za utrzymanie rozmiaru i pozycji
    def closeEvent(self, event):
        geometry = self.saveGeometry()
        self.settings.setValue('geometria', geometry)
        super(Window, self).closeEvent(event)

    def initUI(self):
        normy_lista = (
            'Normy',
            'SELECT * FROM detale',
            'Baza nie zawiera żadnych norm. Plik nie zostanie zapisany.',
        )

        self.setWindowTitle(self.title)
        self.setWindowIcon(QIcon('icons/cow.png'))
        self.resize(self.width, self.height)
        center(self)
        self.setCentralWidget(self.widget)  # centrowanie widżetu na pełneokno

        # Wyswietlanie
        # todo zaproponowanie skrótów
        wysw_act1 = QAction('Wyświetl normy pozycji', self)
        # wysw_act1.setShortcut('Ctrl+Q')
        wysw_act1.triggered.connect(self.norma)
        wysw_act2 = QAction('Wyświetl narzędzia pozycji', self)
        # wysw_act2.setShortcut('Ctrl+Q')
        wysw_act2.triggered.connect(self.wyswietl)

        # Wydruk
        wydr_act1 = QAction('Wyeksportuj normy do pliku', self)
        # wydr_act1.setShortcut('Ctrl+Q')
        wydr_act1.triggered.connect(
            lambda checked, normyl=normy_lista: self.wybor_norma(
                normyl)
        )
        wydr_act2 = QAction('Wyeksportuj wykaz narzędzi do pliku', self)
        # wydr_act2.setShortcut('Ctrl+Q')
        # wydr_act2.triggered.connect(
        #     lambda checked, pozl=None: self.wybor(pozl)
        # )
        wydr_act2.triggered.connect(self.wybor)

        # Opcje
        # TODO Dodać opcję zapisu do Dropboxa i pobrania bazy jedynie dla odpowiednich użytkowników
        opcje_act1 = QAction('Zmiana hasła', self)
        # wydr_act1.setShortcut('Ctrl+Q')
        opcje_act1.triggered.connect(self.uzytkownik)
        opcje_act2 = QAction('Dodaj użytkownika', self)
        opcje_act2.triggered.connect(self.nowy_uzytkownik)
        opcje_act3 = QAction('Informacje o autorze', self)
        # opcje_act2.setShortcut('Ctrl+Q')
        opcje_act3.triggered.connect(self.about)
        opcje_act4 = QAction('Usuń konto', self)
        opcje_act4.triggered.connect(self.usun_konto)
        opcje_act5 = QAction('Lista użytkowników', self)
        opcje_act5.triggered.connect(self.lista_uz)
        opcje_act6 = QAction('Zmiana nazwy użytkownika', self)
        opcje_act6.triggered.connect(self.zm_loginu)
        opcje_act7 = QAction('Zgłoś problem', self)
        opcje_act7.triggered.connect(self.problem)
        opcje_act8 = QAction('Wyślij bazę na Dropboxa', self)
        opcje_act8.triggered.connect(self.drp_backup)
        opcje_act9 = QAction('Pobierz bazę z Dropboxa', self)
        opcje_act9.triggered.connect(self.drp_download)

        menubar = self.menuBar()
        wyswietlanie = menubar.addMenu('Wyświetl')
        wydrukowanie = menubar.addMenu('Wyeksportuj')
        opcje = menubar.addMenu('Opcje')
        wyswietlanie.addAction(wysw_act1)
        wyswietlanie.addAction(wysw_act2)
        wydrukowanie.addAction(wydr_act1)
        wydrukowanie.addAction(wydr_act2)
        opcje.addAction(opcje_act1)
        opcje.addAction(opcje_act6)
        opcje.addAction(opcje_act4)
        if id_user[0] == 1:
            opcje.addSeparator()
            opcje.addAction(opcje_act2)
            opcje.addAction(opcje_act5)
            opcje.addAction(opcje_act8)
            opcje.addAction(opcje_act9)
        opcje.addSeparator()
        opcje.addAction(opcje_act7)
        opcje.addAction(opcje_act3)

        self.show()

    def problem(self):
        tekst, ok = QInputDialog.getMultiLineText(
            self,
            'Zgłoś problem',
            'Wpisz poniżej rodzaj problemu')
        if ok and tekst:
            wysylanie(tekst, self.id_user[0])

    def drp_download(self):
        download()

    def drp_backup(self):
        backup()

    def norma(self):
        from norma import Norma
        nor = Norma(self)
        self.setCentralWidget(nor)

    def wyswietl(self):
        wysw = Wyswietl(self)
        self.setCentralWidget(wysw)

    def nowy_uzytkownik(self):
        text, ok = QInputDialog.getText(self, 'Dodaj użytkownika',
                                        'Wprowadź nowego użytkownika:')
        if ok and text:
            dodaj_uzytkownik(text)
        self.statusBar().showMessage("Dodano nowego użytkownika", 10000)

    def zm_loginu(self):
        text, ok = QInputDialog.getText(self, 'Zmiana nazwy użytkownika',
                                        'Wprowadź nową nazwę użytkownika:')
        if ok and text:
            zmiana_uzytkownik(text, id_user)
        self.statusBar().showMessage("Zmieniono nazwę użytkownika", 10000)

    def uzytkownik(self):
        text, ok = QInputDialog.getText(self, 'Zmiana hasła',
                                        'Wprowadź nowe hasło:',
                                        QLineEdit.Password)
        if ok and text:
            opcje_uzytkownik(text, id_user)
            self.statusBar().showMessage("Zmieniono hasło", 10000)

    def lista_uz(self):
        from lista_uz import Ui_Form
        from widget import Ui_H_Form
        query = 'SELECT "nazwa_uz" FROM "uzytkownicy" ORDER BY "iduzytkownicy" ASC;'
        loginy = multipolaczenie(query)

        self.Form = QtWidgets.QWidget()
        self.Form.setWindowIcon(QIcon('icons/cow.png'))
        self.Form.setWindowTitle('Lista użytkowników')
        self.ui = Ui_Form()
        self.ui.setupUi(self.Form)
        self.Form.show()

        # Lista składana klas dla każdego użytkownika
        self.ui2 = [Ui_H_Form() for i in loginy]

        # Przypisanie każdego użytkownika do widoku
        for i, login in enumerate(loginy):
            self.H_Form = QtWidgets.QWidget()
            self.ui2[i].setupUi(self.H_Form)
            self.ui2[i].label.setText(login[0])
            self.ui.verticalLayout_2.addWidget(self.H_Form)

    def usun_konto(self):
        msg = QMessageBox(self)
        msg.setIcon(QMessageBox.Warning)
        msg.setText('Czy na pewno chcesz usunąć swoje konto?')
        msg.setWindowTitle('Usuwanie konta')
        msg.addButton('Tak', QMessageBox.YesRole)
        msg.addButton('Nie', QMessageBox.NoRole)
        msg = msg.exec_()
        if not msg and id_user[0] != 1:
            query = 'DELETE FROM "uzytkownicy" WHERE "iduzytkownicy" IS ("' + str(
                id_user[0]) + '");'
            polaczenie(query)
            self.statusBar().showMessage("Usunięto użytkownika", 10000)

    def about(self):
        self.window = QMainWindow()
        from o_mnie import Ui_O_mnie
        self.ui = Ui_O_mnie()
        self.ui.setupUi(self.window)
        self.window.show()

    # uzytk = Uzytkownik(self)
    # self.setCentralWidget(uzytk)

    def wybor(self):
        poz_lista = [
            'Wykaz narzędzi ',
            "SELECT * FROM ",
            'Baza nie zawiera żadnych pozycji. Plik nie zostanie zapisany.',
        ]

        lista_poz = []
        lista_poz.append('Brak')
        from narzedzia_poz import naglowki
        for i in naglowki():
            if "/" in i[0]:
                lista_poz.append(i[0])
        inp = QInputDialog(self)
        inp.setWhatsThis('Wybierz pozycję aby eksportować do pliku')
        inp.setLabelText('Wybierz pozycję:')
        inp.setWindowTitle('Pozycje')
        inp.setComboBoxItems(lista_poz)
        inp.setCancelButtonText('Anuluj')

        if inp.exec_() == QDialog.Accepted:
            print(inp.textValue())
            poz_lista[0] += inp.textValue()
            poz_lista[1] += "'" + inp.textValue() + "'"
            if inp.textValue() != 'Brak':
                self.export(poz_lista)
                self.statusBar().showMessage(
                    "Wyeksportowano do pliku", 10000)
            else:
                QMessageBox.critical(self, 'Wybierz pozycję',
                                     'Nie wybrano żadnej pozycji!',
                                     QMessageBox.Ok,
                                     QMessageBox.Ok)

    def wybor_norma(self, lista):
        item, ok = QInputDialog.getItem(self, 'Wybierz', 'Typ:',
                                        ['Odkuwki', 'Kołnierze'], 0, False)
        if ok and item:
            if item == 'Kołnierze':
                lista = list(lista)
                lista[1] = 'SELECT * FROM kolnierze'
                lista = tuple(lista)
        else:
            return

        self.export(lista)
        self.statusBar().showMessage(
            "Wyeksportowano do pliku", 10000)

    def export(self, lista_arg):
        options = QFileDialog.Options()
        file_name, _ = QFileDialog.getSaveFileName(
            self,
            "Zapisywanie jako",
            os.path.expanduser("~") + '/desktop/' + lista_arg[0].replace('/',
                                                                         '-'),
            "Skoroszyt programu Excel (*.xlsx)",
            options=options
        )
        if file_name:
            print(file_name)

            import sqlite3
            sciezka = czy_istnieje()
            conn = sqlite3.connect(sciezka)
            cursor = conn.cursor()
            mysel = cursor.execute(lista_arg[1])
            dane = mysel.fetchall()
            if not dane:
                QMessageBox.warning(self, 'Pusta zawartość',
                                    lista_arg[2],
                                    QMessageBox.Ok,
                                    QMessageBox.Ok)
            else:
                from xlsxwriter import Workbook
                workbook = Workbook(file_name)
                worksheet = workbook.add_worksheet()
                for i, row in enumerate(dane):
                    for j, value in enumerate(row):
                        if j == 0:
                            continue
                        worksheet.write(i, j, value)
                workbook.close()

                if 'Normy' in lista_arg:
                    stylizacja(file_name)
                    pass
                else:
                    styl_pozycje(file_name, lista_arg[0][-7:])
Beispiel #47
0
    def save_settings(self):
        settings = QSettings(CONFIG_FILE_NAME, QSettings.IniFormat)

        settings.setValue('BoolValue1', int(self.checkBox1.isChecked()))
        settings.setValue('BoolValue2', int(self.checkBox2.isChecked()))
        settings.setValue('BoolValue3', int(self.checkBox3.isChecked()))
        settings.setValue('BoolValue4', int(self.checkBox4.isChecked()))
        settings.setValue('BoolValue5', int(self.checkBox5.isChecked()))
        settings.setValue('BoolValue6', int(self.checkBox6.isChecked()))
        settings.setValue('BoolValue7', int(self.checkBox7.isChecked()))

        settings.setValue('BoolValue_1', int(self.checkBox.isChecked()))
        settings.setValue('BoolValue_2', int(self.checkBox_2.isChecked()))
        settings.setValue('BoolValue_3', int(self.checkBox_3.isChecked()))
        settings.setValue('BoolValue_4', int(self.checkBox_4.isChecked()))
        settings.setValue('BoolValue_5', int(self.checkBox_5.isChecked()))
        settings.setValue('BoolValue_6', int(self.checkBox_6.isChecked()))
        settings.setValue('BoolValue_7', int(self.checkBox_7.isChecked()))

        settings.setValue('BoolValue__1', int(self.checkBox__1.isChecked()))
        settings.setValue('BoolValue__2', int(self.checkBox__2.isChecked()))
        settings.setValue('BoolValue__3', int(self.checkBox__3.isChecked()))
        settings.setValue('BoolValue__4', int(self.checkBox__4.isChecked()))
        settings.setValue('BoolValue__5', int(self.checkBox__5.isChecked()))
        settings.setValue('BoolValue__6', int(self.checkBox__6.isChecked()))
        settings.setValue('BoolValue__7', int(self.checkBox__7.isChecked()))
Beispiel #48
0
def story_save_state():
    settings = QSettings("rlbotgui", "story_save")
    serialized = CURRENT_STATE.__dict__
    settings.setValue("save", serialized)
    return serialized
Beispiel #49
0
class AppWindow(QMainWindow):
    onRestart = pyqtSignal(name='onRestart')
    onSystemUIElementCreated = pyqtSignal(str, QWidget, name='onSystemUIElementCreated')
    onSystemUIElementRemoved = pyqtSignal(str, name='onSystemUIElementRemoved')

    def __init__(self, dwarf_args, flags=None):
        super(AppWindow, self).__init__(flags)

        self.dwarf_args = dwarf_args

        self.session_manager = SessionManager(self)
        self.session_manager.sessionCreated.connect(self.session_created)
        self.session_manager.sessionStopped.connect(self.session_stopped)
        self.session_manager.sessionClosed.connect(self.session_closed)

        self._tab_order = [
            'debug', 'modules', 'ranges', 'jvm-inspector', 'jvm-debugger'
        ]

        self._is_newer_dwarf = False
        self.q_settings = QSettings("dwarf_window_pos.ini", QSettings.IniFormat)

        self.menu = self.menuBar()
        self.view_menu = None

        self._initialize_ui_elements()

        self.setWindowTitle(
            'Dwarf - A debugger for reverse engineers, crackers and security analyst'
        )

        # load external assets
        _app = QApplication.instance()

        self.remove_tmp_dir()

        # themes
        self.prefs = Prefs()
        utils.set_theme(self.prefs.get('dwarf_ui_theme', 'black'), self.prefs)

        # load font
        if os.path.exists(utils.resource_path('assets/Anton.ttf')):
            QFontDatabase.addApplicationFont(
                utils.resource_path('assets/Anton.ttf'))
        if os.path.exists(utils.resource_path('assets/OpenSans-Regular.ttf')):
            QFontDatabase.addApplicationFont(
                utils.resource_path('assets/OpenSans-Regular.ttf'))
            font = QFont("OpenSans", 9, QFont.Normal)
            # TODO: add settingsdlg
            font_size = self.prefs.get('dwarf_ui_font_size', 12)
            font.setPixelSize(font_size)
            _app.setFont(font)
            if os.path.exists(utils.resource_path('assets/OpenSans-Bold.ttf')):
                QFontDatabase.addApplicationFont(
                    utils.resource_path('assets/OpenSans-Bold.ttf'))

        # mainwindow statusbar
        self.progressbar = QProgressBar()
        self.progressbar.setRange(0, 0)
        self.progressbar.setVisible(False)
        self.progressbar.setFixedHeight(15)
        self.progressbar.setFixedWidth(100)
        self.progressbar.setTextVisible(False)
        self.progressbar.setValue(30)
        self.statusbar = QStatusBar(self)
        self.statusbar.setAutoFillBackground(False)
        self.statusbar.addPermanentWidget(self.progressbar)
        self.statusbar.setObjectName("statusbar")
        self.setStatusBar(self.statusbar)

        self.main_tabs = QTabWidget(self)
        self.main_tabs.setMovable(False)
        self.main_tabs.setTabsClosable(True)
        self.main_tabs.setAutoFillBackground(True)
        self.main_tabs.tabCloseRequested.connect(self._on_close_tab)
        self.setCentralWidget(self.main_tabs)

        # pluginmanager
        self.plugin_manager = PluginManager(self)
        self.plugin_manager.reload_plugins()

        if self.dwarf_args.package is None:
            self.welcome_window = WelcomeDialog(self)
            self.welcome_window.setModal(True)
            self.welcome_window.onIsNewerVersion.connect(
                self._enable_update_menu)
            self.welcome_window.onUpdateComplete.connect(
                self._on_dwarf_updated)
            self.welcome_window.setWindowTitle(
                'Welcome to Dwarf - A debugger for reverse engineers, crackers and security analyst'
            )
            self.welcome_window.onSessionSelected.connect(self._start_session)
            # wait for welcome screen
            self.hide()
            self.welcome_window.show()
        else:
            if dwarf_args.package is not None:
                if dwarf_args.type is None:
                    # no device given check if package is local path
                    if os.path.exists(dwarf_args.package):
                        print('* Starting new LocalSession')
                        self._start_session('local')
                    else:
                        print('use -t to set sessiontype')
                        exit(0)
                else:
                    print('* Starting new Session')
                    self._start_session(dwarf_args.type)

    def _initialize_ui_elements(self):
        # dockwidgets
        self.watchers_dwidget = None
        self.hooks_dwiget = None
        self.bookmarks_dwiget = None
        self.registers_dock = None
        self.console_dock = None
        self.backtrace_dock = None
        self.threads_dock = None
        # panels
        self.asm_panel = None
        self.backtrace_panel = None
        self.bookmarks_panel = None
        self.console_panel = None
        self.context_panel = None
        self.debug_panel = None
        self.contexts_list_panel = None
        self.data_panel = None
        self.ftrace_panel = None
        self.hooks_panel = None
        self.java_inspector_panel = None
        self.java_explorer_panel = None
        self.java_trace_panel = None
        self.modules_panel = None
        self.ranges_panel = None
        self.search_panel = None
        self.smali_panel = None
        self.watchers_panel = None
        self.welcome_window = None

        self._ui_elems = []

    def _setup_main_menu(self):
        self.menu = self.menuBar()
        dwarf_menu = QMenu('Dwarf', self)
        theme = QMenu('Theme', dwarf_menu)
        theme.addAction('Black')
        theme.addAction('Dark')
        theme.addAction('Light')
        theme.triggered.connect(self._set_theme)
        dwarf_menu.addMenu(theme)
        dwarf_menu.addSeparator()

        dwarf_bin_path = None
        if sys.platform == 'linux':
            dwarf_bin_path = os.path.join('/'.join(os.path.realpath(__file__).split('/')[:-2]), 'bin/dwarf')
            if not os.path.exists(dwarf_bin_path):
                dwarf_menu.addAction('Create launcher', utils.create_launcher)
                dwarf_menu.addSeparator()

        if self._is_newer_dwarf:
            dwarf_menu.addAction('Update', self._update_dwarf)
        dwarf_menu.addAction('Close', self.session_manager.session.stop)
        self.menu.addMenu(dwarf_menu)

        session = self.session_manager.session
        if session is not None:
            session_menu = session.main_menu
            if isinstance(session_menu, list):
                for menu in session_menu:
                    self.menu.addMenu(menu)
            else:
                self.menu.addMenu(session_menu)

        # plugins
        if self.plugin_manager.plugins:
            self.plugin_menu = QMenu('Plugins', self)
            for plugin in self.plugin_manager.plugins:
                plugin_instance = self.plugin_manager.plugins[plugin]
                plugin_sub_menu = self.plugin_menu.addMenu(plugin_instance.name)

                try:
                    actions = plugin_instance.__get_top_menu_actions__()
                    for action in actions:
                        plugin_sub_menu.addAction(action)
                except:
                    pass

                if not plugin_sub_menu.isEmpty():
                    plugin_sub_menu.addSeparator()

                about = plugin_sub_menu.addAction('About')
                about.triggered.connect(
                    lambda x, item=plugin: self._show_plugin_about(item))

            if not self.plugin_menu.isEmpty():
                self.menu.addMenu(self.plugin_menu)

        self.view_menu = QMenu('View', self)
        self.panels_menu = QMenu('Panels', self.view_menu)
        self.panels_menu.addAction(
            'Search',
            lambda: self.show_main_tab('search'),
            shortcut=QKeySequence(Qt.CTRL + Qt.Key_F3))

        self.view_menu.addMenu(self.panels_menu)

        self.debug_view_menu = self.view_menu.addMenu('Debug')

        self.view_menu.addSeparator()

        self.view_menu.addAction('Hide all', self._hide_all_widgets, shortcut=QKeySequence(Qt.CTRL + Qt.Key_F1))
        self.view_menu.addAction('Show all', self._show_all_widgets, shortcut=QKeySequence(Qt.CTRL + Qt.Key_F2))

        self.view_menu.addSeparator()

        self.menu.addMenu(self.view_menu)

        if self.dwarf_args.debug_script:
            debug_menu = QMenu('Debug', self)
            debug_menu.addAction('Reload core', self._menu_reload_core)
            debug_menu.addAction('Debug dwarf js core', self._menu_debug_dwarf_js)
            self.menu.addMenu(debug_menu)

        # tools
        _tools = self.prefs.get('tools')
        if _tools:
            tools_menu = QMenu('Tools', self)

            for _tool in _tools:
                if _tool and _tool['name']:
                    if _tool['name'] == 'sep':
                        tools_menu.addSeparator()
                        continue

                    _cmd = _tool['cmd']

                    tools_menu.addAction(_tool['name'])

            if not tools_menu.isEmpty():
                tools_menu.triggered.connect(self._execute_tool)
                self.menu.addMenu(tools_menu)

        about_menu = QMenu('About', self)
        about_menu.addAction('Dwarf on GitHub', self._menu_github)
        about_menu.addAction('Documention', self._menu_documentation)
        about_menu.addAction('Api', self._menu_api)
        about_menu.addAction('Slack', self._menu_slack)
        about_menu.addSeparator()

        about_menu.addAction('Info', self._show_about_dlg)
        self.menu.addMenu(about_menu)

    def _show_plugin_about(self, plugin):
        plugin = self.plugin_manager.plugins[plugin]
        if plugin:
            info = plugin.__get_plugin_info__()

            version = utils.safe_read_map(info, 'version', '')
            description = utils.safe_read_map(info, 'description', '')
            author = utils.safe_read_map(info, 'author', '')
            homepage = utils.safe_read_map(info, 'homepage', '')
            license_ = utils.safe_read_map(info, 'license', '')

            utils.show_message_box(
                'Name: {0}\nVersion: {1}\nDescription: {2}\nAuthor: {3}\nHomepage: {4}\nLicense: {5}'.
                    format(plugin.name, version, description, author, homepage, license_))

    def _enable_update_menu(self):
        self._is_newer_dwarf = True

    def _update_dwarf(self):
        if self.welcome_window:
            self.welcome_window._update_dwarf()

    def _on_close_tab(self, index):
        tab_text = self.main_tabs.tabText(index)
        if tab_text:
            tab_text = tab_text.lower()
            if tab_text in self.session_manager.session.non_closable:
                return
            try:
                self._ui_elems.remove(tab_text)
            except ValueError:  # recheck ValueError: list.remove(x): x not in list
                pass
            self.main_tabs.removeTab(index)

            self.onSystemUIElementRemoved.emit(tab_text)

    def _handle_tab_change(self):
        for index in range(self.main_tabs.count()):
            tab_name = self.main_tabs.tabText(index).lower().replace(' ', '-')
            if tab_name in self.session_manager.session.non_closable:
                self.main_tabs.tabBar().setTabButton(index, QTabBar.RightSide,
                                                     None)

                if tab_name in self._tab_order:
                    should_index = self._tab_order.index(tab_name)
                    if index != should_index:
                        self.main_tabs.tabBar().moveTab(index, should_index)

    def _on_dwarf_updated(self):
        self.onRestart.emit()

    def remove_tmp_dir(self):
        if os.path.exists('.tmp'):
            shutil.rmtree('.tmp', ignore_errors=True)

    def _execute_tool(self, qaction):
        if qaction:
            _tools = self.prefs.get('tools')
            if _tools:
                for _tool in _tools:
                    if _tool and _tool['name'] and _tool['name'] != 'sep':
                        if qaction.text() == _tool['name']:
                            try:
                                import subprocess
                                subprocess.Popen(_tool['cmd'], creationflags=subprocess.CREATE_NEW_CONSOLE)
                            except:
                                pass
                            break

    def _set_theme(self, qaction):
        if qaction:
            utils.set_theme(qaction.text(), self.prefs)

    def _hide_all_widgets(self):
        self.watchers_dwidget.hide()
        self.hooks_dwiget.hide()
        self.bookmarks_dwiget.hide()
        self.registers_dock.hide()
        self.console_dock.hide()
        self.backtrace_dock.hide()
        self.threads_dock.hide()

    def _show_all_widgets(self):
        self.watchers_dwidget.show()
        self.hooks_dwiget.show()
        self.bookmarks_dwiget.show()
        self.registers_dock.show()
        self.console_dock.show()
        self.backtrace_dock.show()
        self.threads_dock.show()

    def _menu_reload_core(self):
        self.dwarf.script.exports.reload()

    def _menu_debug_dwarf_js(self):
        you_know_what_to_do = json.loads(
            self.dwarf.script.exports.debugdwarfjs())
        return you_know_what_to_do

    def show_main_tab(self, name):
        name = name.lower()
        # elem doesnt exists? create it
        if name not in self._ui_elems:
            self._create_ui_elem(name)

        index = 0
        name = name.join(name.split()).lower()
        if name == 'ranges':
            index = self.main_tabs.indexOf(self.ranges_panel)
        elif name == 'search':
            index = self.main_tabs.indexOf(self.search_panel)
        elif name == 'modules':
            index = self.main_tabs.indexOf(self.modules_panel)
        elif name == 'data':
            index = self.main_tabs.indexOf(self.data_panel)
        elif name == 'java-trace':
            index = self.main_tabs.indexOf(self.java_trace_panel)
        elif name == 'jvm-inspector':
            index = self.main_tabs.indexOf(self.java_inspector_panel)
        elif name == 'jvm-debugger':
            index = self.main_tabs.indexOf(self.java_explorer_panel)
        elif name == 'smali':
            index = self.main_tabs.indexOf(self.smali_panel)

        self.main_tabs.setCurrentIndex(index)

    def jump_to_address(self, ptr, view=0, show_panel=True):
        if show_panel:
            self.show_main_tab('debug')
        self.debug_panel.jump_to_address(ptr, view=view)

    @pyqtSlot(name='mainMenuGitHub')
    def _menu_github(self):
        QDesktopServices.openUrl(QUrl('https://github.com/iGio90/Dwarf'))

    @pyqtSlot(name='mainMenuApi')
    def _menu_api(self):
        QDesktopServices.openUrl(QUrl('http://www.giovanni-rocca.com/dwarf/javascript/'))

    @pyqtSlot(name='mainMenuDocumentation')
    def _menu_documentation(self):
        QDesktopServices.openUrl(QUrl('http://www.giovanni-rocca.com/dwarf/'))

    @pyqtSlot(name='mainMenuSlack')
    def _menu_slack(self):
        QDesktopServices.openUrl(
            QUrl('https://join.slack.com/t/resecret/shared_invite'
                 '/enQtMzc1NTg4MzE3NjA1LTlkNzYxNTIwYTc2ZTYyOWY1MT'
                 'Q1NzBiN2ZhYjQwYmY0ZmRhODQ0NDE3NmRmZjFiMmE1MDYwN'
                 'WJlNDVjZDcwNGE'))

    def _show_about_dlg(self):
        about_dlg = AboutDialog(self)
        about_dlg.show()

    def _create_ui_elem(self, elem):
        elem = elem.lower()

        if not isinstance(elem, str):
            return

        if elem not in self._ui_elems:
            self._ui_elems.append(elem)

        elem_wiget = None

        if elem == 'watchers':
            from ui.session_widgets.watchers import WatchersWidget
            self.watchers_dwidget = QDockWidget('Watchers', self)
            self.watchers_panel = WatchersWidget(self)
            # dont respond to dblclick mem cant be shown
            # self.watchers_panel.onItemDoubleClicked.connect(
            #    self._on_watcher_clicked)
            self.watchers_panel.onItemRemoved.connect(
                self._on_watcher_removeditem)
            self.watchers_panel.onItemAdded.connect(self._on_watcher_added)
            self.watchers_dwidget.setWidget(self.watchers_panel)
            self.watchers_dwidget.setObjectName('WatchersWidget')
            self.addDockWidget(Qt.LeftDockWidgetArea, self.watchers_dwidget)
            self.view_menu.addAction(self.watchers_dwidget.toggleViewAction())
            elem_wiget = self.watchers_panel
        elif elem == 'hooks':
            from ui.session_widgets.hooks import HooksWidget
            self.hooks_dwiget = QDockWidget('Breakpoints', self)
            self.hooks_panel = HooksWidget(self)
            self.hooks_panel.onHookRemoved.connect(self._on_hook_removed)
            self.hooks_dwiget.setWidget(self.hooks_panel)
            self.hooks_dwiget.setObjectName('HooksWidget')
            self.addDockWidget(Qt.LeftDockWidgetArea, self.hooks_dwiget)
            self.view_menu.addAction(self.hooks_dwiget.toggleViewAction())
            elem_wiget = self.hooks_panel
        elif elem == 'bookmarks':
            from ui.session_widgets.bookmarks import BookmarksWidget
            self.bookmarks_dwiget = QDockWidget('Boomarks', self)
            self.bookmarks_panel = BookmarksWidget(self)
            self.bookmarks_dwiget.setWidget(self.bookmarks_panel)
            self.bookmarks_dwiget.setObjectName('BookmarksWidget')
            self.addDockWidget(Qt.LeftDockWidgetArea, self.bookmarks_dwiget)
            self.view_menu.addAction(self.bookmarks_dwiget.toggleViewAction())
            elem_wiget = self.bookmarks_panel
        elif elem == 'registers':
            from ui.session_widgets.context import ContextWidget
            self.registers_dock = QDockWidget('Context', self)
            self.context_panel = ContextWidget(self)
            self.registers_dock.setWidget(self.context_panel)
            self.registers_dock.setObjectName('ContextWidget')
            self.addDockWidget(Qt.RightDockWidgetArea, self.registers_dock)
            self.view_menu.addAction(self.registers_dock.toggleViewAction())
            elem_wiget = self.context_panel
        elif elem == 'debug':
            from ui.panels.panel_debug import QDebugPanel
            self.debug_panel = QDebugPanel(self)
            self.main_tabs.addTab(self.debug_panel, 'Debug')
            elem_wiget = self.debug_panel
        elif elem == 'jvm-debugger':
            from ui.panels.panel_java_explorer import JavaExplorerPanel
            self.java_explorer_panel = JavaExplorerPanel(self)
            self.main_tabs.addTab(self.java_explorer_panel, 'JVM debugger')
            self.main_tabs.tabBar().moveTab(
                self.main_tabs.indexOf(self.java_explorer_panel), 1)
            elem_wiget = self.java_explorer_panel
        elif elem == 'jvm-inspector':
            from ui.panels.panel_java_inspector import JavaInspector
            self.java_inspector_panel = JavaInspector(self)
            self.main_tabs.addTab(self.java_inspector_panel, 'JVM inspector')
            elem_wiget = self.java_inspector_panel
        elif elem == 'console':
            from ui.session_widgets.console import ConsoleWidget
            self.console_dock = QDockWidget('Console', self)
            self.console_panel = ConsoleWidget(self)
            if self.dwarf_args.script and len(self.dwarf_args.script) > 0 and os.path.exists(self.dwarf_args.script):
                with open(self.dwarf_args.script, 'r') as f:
                    self.console_panel.get_js_console().script_file = self.dwarf_args.script
                    self.console_panel.get_js_console().function_content = f.read()
            self.dwarf.onLogToConsole.connect(self._log_js_output)
            self.dwarf.onLogEvent.connect(self._log_event)
            self.console_dock.setWidget(self.console_panel)
            self.console_dock.setObjectName('ConsoleWidget')
            self.addDockWidget(Qt.BottomDockWidgetArea, self.console_dock)
            self.view_menu.addAction(self.console_dock.toggleViewAction())
            elem_wiget = self.console_panel
        elif elem == 'backtrace':
            from ui.session_widgets.backtrace import BacktraceWidget
            self.backtrace_dock = QDockWidget('Backtrace', self)
            self.backtrace_panel = BacktraceWidget(self)
            self.backtrace_dock.setWidget(self.backtrace_panel)
            self.backtrace_dock.setObjectName('BacktraceWidget')
            self.backtrace_panel.onShowMemoryRequest.connect(self._on_showmemory_request)
            self.addDockWidget(Qt.RightDockWidgetArea, self.backtrace_dock)
            self.view_menu.addAction(self.backtrace_dock.toggleViewAction())
            elem_wiget = self.backtrace_panel
        elif elem == 'threads':
            from ui.session_widgets.threads import ThreadsWidget
            self.threads_dock = QDockWidget('Threads', self)
            self.contexts_list_panel = ThreadsWidget(self)
            self.dwarf.onThreadResumed.connect(
                self.contexts_list_panel.resume_tid)
            self.contexts_list_panel.onItemDoubleClicked.connect(
                self._manually_apply_context)
            self.threads_dock.setWidget(self.contexts_list_panel)
            self.threads_dock.setObjectName('ThreadPanel')
            self.addDockWidget(Qt.RightDockWidgetArea, self.threads_dock)
            self.view_menu.addAction(self.threads_dock.toggleViewAction())
            elem_wiget = self.contexts_list_panel
        elif elem == 'modules':
            from ui.panels.panel_modules import ModulesPanel
            self.modules_panel = ModulesPanel(self)
            self.modules_panel.onModuleSelected.connect(
                self._on_module_dblclicked)
            self.modules_panel.onModuleFuncSelected.connect(
                self._on_modulefunc_dblclicked)
            self.modules_panel.onAddHook.connect(self._on_addmodule_hook)
            self.modules_panel.onDumpBinary.connect(self._on_dumpmodule)
            self.main_tabs.addTab(self.modules_panel, 'Modules')
            elem_wiget = self.modules_panel
        elif elem == 'ranges':
            from ui.panels.panel_ranges import RangesPanel
            self.ranges_panel = RangesPanel(self)
            self.ranges_panel.onItemDoubleClicked.connect(
                self._range_dblclicked)
            self.ranges_panel.onDumpBinary.connect(self._on_dumpmodule)
            # connect to watcherpanel func
            self.ranges_panel.onAddWatcher.connect(
                self.watchers_panel.do_addwatcher_dlg)
            self.main_tabs.addTab(self.ranges_panel, 'Ranges')
            elem_wiget = self.ranges_panel
        elif elem == 'search':
            from ui.panels.panel_search import SearchPanel
            self.search_panel = SearchPanel(self)
            self.main_tabs.addTab(self.search_panel, 'Search')
            elem_wiget = self.search_panel
        elif elem == 'data':
            from ui.panels.panel_data import DataPanel
            self.data_panel = DataPanel(self)
            self.main_tabs.addTab(self.data_panel, 'Data')
            elem_wiget = self.data_panel
        elif elem == 'java-trace':
            from ui.panels.panel_java_trace import JavaTracePanel
            self.java_trace_panel = JavaTracePanel(self)
            self.main_tabs.addTab(self.java_trace_panel, 'JVM tracer')
            elem_wiget = self.java_trace_panel
        elif elem == 'smali':
            from ui.panels.panel_smali import SmaliPanel
            self.smali_panel = SmaliPanel()
            self.main_tabs.addTab(self.smali_panel, 'Smali')
            elem_wiget = self.smali_panel
        else:
            print('no handler for elem: ' + elem)

        # make tabs unclosable and sort
        self._handle_tab_change()

        if elem_wiget is not None:
            self.onSystemUIElementCreated.emit(elem, elem_wiget)

        # TODO: remove add @2x
        for item in self.findChildren(QDockWidget):
            if item:
                if 'darwin' in sys.platform:
                    item.setStyleSheet(
                        'QDockWidget::title { padding-left:-30px; }'
                    )

    def set_status_text(self, txt):
        self.statusbar.showMessage(txt)

    # ************************************************************************
    # **************************** Properties ********************************
    # ************************************************************************
    @property
    def disassembly(self):
        return self.asm_panel

    @property
    def backtrace(self):
        return self.backtrace_panel

    @property
    def console(self):
        return self.console_panel

    @property
    def context(self):
        return self.context_panel

    @property
    def threads(self):
        return self.contexts_list_panel

    @property
    def ftrace(self):
        return self.ftrace_panel

    @property
    def hooks(self):
        return self.hooks_panel

    @property
    def java_inspector(self):
        return self.java_inspector_panel

    @property
    def java_explorer(self):
        return self.java_explorer_panel

    @property
    def modules(self):
        return self.modules_panel

    @property
    def ranges(self):
        return self.ranges_panel

    @property
    def watchers(self):
        return self.watchers_panel

    @property
    def dwarf(self):
        if self.session_manager.session is not None:
            return self.session_manager.session.dwarf
        else:
            return None

    # ************************************************************************
    # **************************** Handlers **********************************
    # ************************************************************************
    # session handlers
    def _start_session(self, session_type, session_data=None):
        if self.welcome_window is not None:
            self.welcome_window.close()
        self.session_manager.create_session(
            session_type, session_data=session_data)

    def _restore_session(self, session_data):
        if 'session' in session_data:
            session_type = session_data['session']
            self.dwarf_args.package = session_data['package']
            self.dwarf_args.spawn = True
            self._start_session(session_type, session_data=session_data)

    def session_created(self):
        # session init done create ui for it
        session = self.session_manager.session
        self._setup_main_menu()
        for ui_elem in session.session_ui_sections:
            ui_elem = ui_elem.join(ui_elem.split()).lower()
            self._create_ui_elem(ui_elem)

        self.dwarf.onProcessAttached.connect(self._on_attached)
        self.dwarf.onProcessDetached.connect(self._on_detached)
        self.dwarf.onScriptLoaded.connect(self._on_script_loaded)

        # hookup
        self.dwarf.onSetRanges.connect(self._on_setranges)
        self.dwarf.onSetModules.connect(self._on_setmodules)

        self.dwarf.onAddNativeHook.connect(self._on_add_hook)
        self.dwarf.onApplyContext.connect(self._apply_context)
        self.dwarf.onThreadResumed.connect(self.on_tid_resumed)

        self.dwarf.onSetData.connect(self._on_set_data)

        self.session_manager.start_session(self.dwarf_args)
        ui_state = self.q_settings.value('dwarf_ui_state')
        if ui_state:
            self.restoreGeometry(ui_state)
        window_state = self.q_settings.value('dwarf_ui_window', self.saveState())
        if window_state:
            self.restoreState(window_state)

        self.showMaximized()

    def session_stopped(self):
        self.remove_tmp_dir()
        self.menu.clear()

        self.main_tabs.clear()

        # actually we need to kill this. needs a refactor
        if self.java_trace_panel is not None:
            self.java_trace_panel = None

        for elem in self._ui_elems:
            if elem == 'watchers':
                self.watchers_panel.clear_list()
                self.watchers_panel.close()
                self.watchers_panel = None
                self.removeDockWidget(self.watchers_dwidget)
                self.watchers_dwidget = None
            elif elem == 'hooks':
                self.hooks_panel.close()
                self.hooks_panel = None
                self.removeDockWidget(self.hooks_dwiget)
                self.hooks_dwiget = None
            elif elem == 'registers':
                self.context_panel.close()
                self.context_panel = None
                self.removeDockWidget(self.registers_dock)
                self.registers_dock = None
            elif elem == 'debug':
                self.debug_panel.close()
                self.debug_panel = None
                self.main_tabs.removeTab(0)
                # self.main_tabs
            elif elem == 'jvm-debugger':
                self.java_explorer_panel.close()
                self.java_explorer_panel = None
                self.removeDockWidget(self.watchers_dwidget)
            elif elem == 'console':
                self.console_panel.close()
                self.console_panel = None
                self.removeDockWidget(self.console_dock)
                self.console_dock = None
            elif elem == 'backtrace':
                self.backtrace_panel.close()
                self.backtrace_panel = None
                self.removeDockWidget(self.backtrace_dock)
            elif elem == 'threads':
                self.contexts_list_panel.close()
                self.contexts_list_panel = None
                self.removeDockWidget(self.threads_dock)
                self.threads_dock = None
            elif elem == 'bookmarks':
                self.bookmarks_panel.close()
                self.bookmarks_panel = None
                self.removeDockWidget(self.bookmarks_dwiget)
                self.bookmarks_dwiget = None

        self._initialize_ui_elements()

    def session_closed(self):
        self._initialize_ui_elements()
        self.hide()
        if self.welcome_window is not None:
            self.welcome_window.exec()

        # close if it was a commandline session
        if self.welcome_window is None:
            if self.dwarf_args.package:
                self.close()

    # ui handler
    def closeEvent(self, event):
        """ Window closed
            save stuff or whatever at exit

            detaches dwarf
        """
        # save windowstuff
        self.q_settings.setValue('dwarf_ui_state', self.saveGeometry())
        self.q_settings.setValue('dwarf_ui_window', self.saveState())

        if self.dwarf:
            try:
                self.dwarf.detach()
            except:
                pass
        super().closeEvent(event)

    def _on_watcher_clicked(self, ptr):
        """ Address in Watcher/Hookpanel was clicked
            show Memory
        """
        if '.' in ptr:  # java_hook
            file_path = ptr.replace('.', os.path.sep)
            if os.path.exists('.tmp/smali/' + file_path + '.smali'):
                if self.smali_panel is None:
                    self._create_ui_elem('smali')
                self.smali_panel.set_file('.tmp/smali/' + file_path + '.smali')
                self.show_main_tab('smali')
        else:
            self.jump_to_address(ptr)

    def _on_watcher_added(self, ptr):
        """ Watcher Entry was added
        """
        try:
            # set highlight
            self.debug_panel.memory_panel.add_highlight(
                HighLight('watcher', ptr, self.dwarf.pointer_size))
        except HighlightExistsError:
            pass

    def _on_watcher_removeditem(self, ptr):
        """ Watcher Entry was removed
            remove highlight too
        """
        self.debug_panel.memory_panel.remove_highlight(ptr)

    def _on_module_dblclicked(self, data):
        """ Module in ModulePanel was doubleclicked
        """
        addr, size = data
        addr = utils.parse_ptr(addr)
        self.jump_to_address(addr)

    def _on_modulefunc_dblclicked(self, ptr):
        """ Function in ModulePanel was doubleclicked
        """
        ptr = utils.parse_ptr(ptr)
        self.jump_to_address(ptr)

    def _on_dumpmodule(self, data):
        """ DumpBinary MenuItem in ModulePanel was selected
        """
        ptr, size = data
        ptr = utils.parse_ptr(ptr)
        size = int(size, 10)
        self.dwarf.dump_memory(ptr=ptr, length=size)

    def _disassemble_range(self, dwarf_range):
        """ Disassemble MenuItem in Hexview was selected
        """
        if dwarf_range:
            if self.asm_panel is None:
                self._create_ui_elem('disassembly')

            self.asm_panel.disassemble(dwarf_range)
            self.show_main_tab('disassembly')

    def _range_dblclicked(self, ptr):
        """ Range in RangesPanel was doubleclicked
        """
        ptr = utils.parse_ptr(ptr)
        self.jump_to_address(ptr)

    # dwarf handlers
    def _log_js_output(self, output):
        if self.console_panel is not None:
            time_prefix = True
            if len(output.split('\n')) > 1 or len(output.split('<br />')) > 1:
                time_prefix = False
            self.console_panel.get_js_console().log(output, time_prefix=time_prefix)

    def _log_event(self, output):
        if self.console_panel is not None:
            self.console_panel.get_events_console().log(output)

    def _on_setranges(self, ranges):
        """ Dwarf wants to set Ranges
            only hooked up to switch tab or create ui
            its connected in panel after creation
        """
        if self.ranges_panel is None:
            self.show_main_tab('ranges')
            # forward only now to panel it connects after creation
            self.ranges_panel.set_ranges(ranges)

    def _on_setmodules(self, modules):
        """ Dwarf wants to set Modules
            only hooked up to switch tab or create ui
            its connected in panel after creation
        """
        if self.modules_panel is None:
            self._create_ui_elem('modules')
            self.modules_panel.set_modules(modules)

        if self.modules_panel is not None:
            self.show_main_tab('modules')

    def _manually_apply_context(self, context):
        """
        perform additional operation if the context has been manually applied from the context list
        """
        self._apply_context(context, manual=True)

    def _apply_context(self, context, manual=False):
        # update current context tid
        # this should be on top as any further api from js needs to be executed on that thread
        reason = context['reason']
        is_initial_setup = reason == -1
        if manual or (self.dwarf.context_tid and not is_initial_setup):
            self.dwarf.context_tid = context['tid']

        if is_initial_setup:
            self.debug_panel.on_context_setup()

        if 'context' in context:
            if not manual:
                self.threads.add_context(context)

            is_java = context['is_java']
            if is_java:
                if self.java_explorer_panel is None:
                    self._create_ui_elem('jvm-debugger')
                self.context_panel.set_context(context['ptr'], 1,
                                               context['context'])
                self.java_explorer_panel._set_handle_arg(-1)
                self.show_main_tab('jvm-debugger')
            else:
                self.context_panel.set_context(context['ptr'], 0, context['context'])

                if reason == 2:
                    # native on load
                    if self.debug_panel.memory_panel_range is None:
                        base = context['moduleBase']
                        self.jump_to_address(base)
                else:
                    if 'pc' in context['context']:
                        if self.debug_panel.disassembly_panel_range is None or manual:
                            self.jump_to_address(context['context']['pc']['value'], view=1)

        if 'backtrace' in context:
            self.backtrace_panel.set_backtrace(context['backtrace'])

    def _on_add_hook(self, hook):
        try:
            # set highlight
            ptr = hook.get_ptr()
            ptr = utils.parse_ptr(ptr)
            self.debug_panel.memory_panel.add_highlight(
                HighLight('hook', ptr, self.dwarf.pointer_size))
        except HighlightExistsError:
            pass

    def _on_hook_removed(self, ptr):
        ptr = utils.parse_ptr(ptr)
        self.debug_panel.memory_panel.remove_highlight(ptr)

    def _on_addmodule_hook(self, data):
        ptr, name = data
        self.dwarf.hook_native(ptr, own_input=name)

    def on_tid_resumed(self, tid):
        if self.dwarf:
            if self.dwarf.context_tid == tid:
                # clear backtrace
                if 'backtrace' in self._ui_elems:
                    if self.backtrace_panel is not None:
                        self.backtrace_panel.clear()

                # remove thread
                if 'threads' in self._ui_elems:
                    if self.contexts_list_panel is not None:
                        self.contexts_list_panel.resume_tid(tid)

                # clear registers
                if 'registers' in self._ui_elems:
                    if self.context_panel is not None:
                        self.context_panel.clear()

                # clear jvm explorer
                if 'jvm-debugger' in self._ui_elems:
                    if self.java_explorer_panel is not None:
                        self.java_explorer_panel.clear_panel()

                # invalidate dwarf context tid
                self.dwarf.context_tid = 0

    def _on_set_data(self, data):
        if not isinstance(data, list):
            return

        if self.data_panel is None:
            self.show_main_tab('data')

        if self.data_panel is not None:
            self.data_panel.append_data(data[0], data[1], data[2])

    def show_progress(self, text):
        self.progressbar.setVisible(True)
        self.set_status_text(text)

    def hide_progress(self):
        self.progressbar.setVisible(False)
        self.set_status_text('')

    def _on_attached(self, data):
        self.setWindowTitle('Dwarf - Attached to %s (%s)' % (data[1], data[0]))

    def _on_detached(self, data):
        reason = data[1]

        if reason == 'application-requested':
            self.session_manager.session.stop()
            return 0

        if self.dwarf is not None:
            ret = QDialogDetached.show_dialog(self.dwarf, data[0], data[1], data[2])
            if ret == 0:
                self.dwarf.restart_proc()
            elif ret == 1:
                self.session_manager.session.stop()

        return 0

    def _on_script_loaded(self):
        # restore the loaded session if any
        self.session_manager.restore_session()

    def on_add_bookmark(self, ptr):
        """
        provide ptr as int
        """
        if self.bookmarks_panel is not None:
            self.bookmarks_panel._create_bookmark(ptr=hex(ptr))

    def _on_showmemory_request(self, ptr):
        # its simple ptr show in memorypanel
        if isinstance(ptr, str):
            ptr = utils.parse_ptr(ptr)
            self.jump_to_address(ptr, 0)

        elif isinstance(ptr, list):
            # TODO: extend
            caller, ptr = ptr
            ptr = utils.parse_ptr(ptr)
            if caller == 'backtrace' or caller == 'bt':
                # jumpto in disasm
                self.jump_to_address(ptr, 1)
Beispiel #50
0
 def closeEvent(self, event):
     # save dialog geometry
     settings = QSettings()
     settings.setValue("/Qgis2threejs/propdlg/geometry",
                       self.saveGeometry())
     QDialog.closeEvent(self, event)
class ConverterFrame(Ui_Frame):
    def __init__(self):
        self.frame = None
        self.file_queue = Queue()
        self.conversion = None
        self.progress_dialog = None
        self.settings = QSettings()
        self.thread = QThread()
        self.converter = file_converter.ConverterController()

    def setupUi(self, frame):
        super().setupUi(frame)
        self.frame = frame

        # Configure table
        self.tableView.horizontalHeader().setSectionsClickable(False)
        self.tableView.setSelectionMode(QAbstractItemView.SingleSelection)
        self.tableView.setSelectionBehavior(QAbstractItemView.SelectRows)
        self.tableView.horizontalHeader().setDefaultAlignment(Qt.AlignLeft)
        if QSysInfo.productType() == 'windows' and QSysInfo.productVersion() == '10':
            self.tableView.horizontalHeader().setStyleSheet(
                'border-top: 0px; '
                'border-left: 0px; '
                'border-right: 0px; '
                'border-bottom: 1px solid gray;')

        # Define models
        self.data_file_container = table_model.DataFileContainer()
        self.dec_model = declination_model.Declination()
        self.tilt_model = TiltCurveModel(
            application_directory() / 'Calibration Tables')

        # Connect models
        self.tableView.setModel(self.data_file_container)
        self.tableView.resizeColumnsToContents()
        self.comboBox_tilt_tables.setModel(self.tilt_model)

        self.file_loader = file_loader.FileLoader(self.file_queue)
        self._connect_signals_to_slots()
        restore_last_session(self)

    def _connect_signals_to_slots(self):
        self.pushButton_add.clicked.connect(self.add_files)
        self.file_loader.file_loaded_signal.connect(self.file_loaded)
        self.file_loader.file_error_signal.connect(self.file_error)
        self.pushButton_remove.clicked.connect(self.delete_row)
        self.pushButton_clear.clicked.connect(self.data_file_container.clear)
        self.pushButton_convert.clicked.connect(self.convert_files)
        self.pushButton_browse.clicked.connect(self.choose_output_directory)
        self.pushButton_output_options.clicked.connect(
            lambda: OptionsDialog(self.frame).exec_())
        self.buttonGroup.buttonToggled.connect(
            self.toggle_output_file_button_group)
        self.comboBox_output_type.currentIndexChanged.connect(
            self.change_output_type_slot)
        self.pushButton_help.clicked.connect(dialogs.about_declination)
        self.lineEdit_declination.textChanged.connect(self.declination_changed)
        self.dec_model.update_signal.connect(self.update_declination)
        self.data_file_container.rowsInserted.connect(self.enable_buttons)
        self.data_file_container.rowsRemoved.connect(self.enable_buttons)
        self.data_file_container.modelReset.connect(self.enable_buttons)

    def enable_buttons(self):
        state = True if len(self.data_file_container) > 0 else False
        buttons = [
            self.pushButton_remove,
            self.pushButton_clear,
            self.pushButton_convert]
        for button in buttons:
            button.setEnabled(state)

    """
    Methods for loading files
    """
    # slot
    def add_files(self):
        directory = self.settings.value('last_directory', '', type=str)
        file_paths = dialogs.open_lid_file(directory)
        if not file_paths[0]:
            return
        directory = Path(file_paths[0][0]).parent
        self.settings.setValue('last_directory', str(directory))
        self.file_queue.put(file_paths[0])
        self.file_loader.run()

    # slot
    def delete_row(self):
        row_objects = self.tableView.selectionModel().selectedRows()
        for row in row_objects:
            self.data_file_container.delete(row.row())

    # slot
    def file_loaded(self, file):
        if file.header_error:
            dialogs.header_error(file.filename, file.header_error)
        self.data_file_container.add_file(file)

    # slot
    def file_error(self, message):
        dialogs.error_message('Load Error', message)

    def _start_thread(self):
        self.file_loader.moveToThread(self.thread)
        self.file_loader.finished_signal.connect(self.thread.quit)
        self.thread.start()

    """
    Convert files
    """
    def convert_files(self):
        self.remove_error_files()
        parameters = self._read_output_options()
        terminate_conditions = [
            lambda: self.check_error_states(),
            lambda: parameters['output_directory'] == 'error',
            lambda: len(self.data_file_container) == 0,
            lambda: (parameters['calibration'] is not None
                     and not dialogs.confirm_custom_cal()),
            lambda: (self.data_file_container.unconverted() == 0
                     and not self.reset_converted())
        ]

        if self.check_terminate_conditions(terminate_conditions):
            return

        save_session(self)
        self.converter.model = self.data_file_container
        self.converter.parameters = parameters
        self.converter.convert()

    def check_terminate_conditions(self, conditions):
        for condition in conditions:
            if condition():
                return True
        return False

    def reset_converted(self):
        if self.data_file_container.convertable() > 0:
            if dialogs.prompt_mark_unconverted():
                self.data_file_container.reset_converted()
                return True
        return False

    def remove_error_files(self):
        if self.data_file_container.errors():
            answer = dialogs.ask_remove_error_files()
            if answer == 'Remove':
                self.data_file_container.remove_error_files()
            elif answer == 'Retry':
                self.data_file_container.reset_errors()

    def check_error_states(self):
        if self.dec_model.error_state:
            dialogs.error_message('Error', 'Please correct declination')
            return True
        return False

    # slot
    def change_output_type_slot(self):
        state = self.comboBox_output_type.currentText() == 'Current'
        self.comboBox_tilt_tables.setEnabled(state)
        disabled = ['Discrete Channels', 'Cable Attitude']
        state = self.comboBox_output_type.currentText() in disabled
        self.dec_model.set_enabled(not state)

    def set_combobox(self, combobox, value):
        ind = combobox.findText(value)
        ind = 0 if ind == -1 else ind
        combobox.setCurrentIndex(ind)

    def choose_output_directory(self):
        directory = QFileDialog.getExistingDirectory(
            caption='Select output directory')
        self.lineEdit_output_folder.setText(directory)

    def toggle_output_file_button_group(self):
        state = False if self.radioButton_output_same.isChecked() else True
        self.lineEdit_output_folder.setEnabled(state)
        self.pushButton_browse.setEnabled(state)

    def _read_output_options(self):
        parameters = default_parameters()
        app_data = self.settings.value('output_options', {}, type=dict)
        parameters['output_directory'] = self._get_output_directory()
        parameters['time_format'] = app_data.get('time_format', 'iso8601')
        parameters['average'] = app_data.get('average_bursts', True)
        custom_cal_path = app_data.get('custom_cal', None)
        if custom_cal_path:
            try:
                custom_cal = make_from_calibration_file(custom_cal_path)
                parameters['calibration'] = custom_cal
            except:
                pass
        split_size = app_data.get('split', 'Do not split output files')
        if split_size != 'Do not split output files':
            parameters['split'] = int(split_size.split(' ')[0])

        if self.comboBox_output_type.currentText() == 'Current':
            parameters['output_type'] = 'current'
            parameters['tilt_curve'] = \
                self.comboBox_tilt_tables.currentData()
        else:
            output_type = OUTPUT_TYPE.get(
                self.comboBox_output_type.currentText(),
                'discrete')
            parameters['output_type'] = output_type

        parameters['output_format'] = app_data.get('output_format', 'csv')
        parameters['declination'] = self.dec_model.declination_value()
        return parameters

    """
    Methods for declination
    """
    # slot
    def declination_changed(self):
        self.dec_model.declination = self.lineEdit_declination.text()

    # slot
    def update_declination(self):
        self.lineEdit_declination.setText(str(self.dec_model.declination))
        show_error(self.lineEdit_declination, self.dec_model.error_state)
        self.lineEdit_declination.setEnabled(self.dec_model.enabled)

    def _get_output_directory(self):
        if self.radioButton_output_directory.isChecked():
            directory = self.lineEdit_output_folder.text()
            if not os.path.isdir(directory):
                QMessageBox.warning(
                                    self.frame,
                                    'Select Folder',
                                    'You must select a valid output path')
                return 'error'
            return directory

    def confirm_quit(self):
        if len(self.data_file_container) == 0:
            return True
        status = [file.status for file in self.data_file_container]
        if any([True for s in status if s == 'unconverted']):
            return dialogs.confirm_quit()
        else:
            return True
 def writeSettings(self):
     settings = QSettings("Trolltech", "Pamac installer")
     settings.setValue("pos", self.pos())
     settings.setValue("size", self.size())
Beispiel #53
0
 def setTranslation(self, index):
     path = self.cmbTranslation.currentData()
     # Save settings
     sttgs = QSettings(qApp.organizationName(), qApp.applicationName())
     sttgs.setValue("applicationTranslation", path)
Beispiel #54
0
class MainWindow(QMainWindow):
    def __init__(self, parent=None):
        QMainWindow.__init__(self, parent)
        self.settings = QSettings()

        self.is_visible = True
        self.is_expanded = True
        self.is_move_action = False
        self.should_confirm_close = False
        self.setWindowFlags(Qt.FramelessWindowHint | Qt.WindowStaysOnTopHint
                            | Qt.Tool)
        self.setAttribute(Qt.WA_NoSystemBackground, True)
        self.setAttribute(Qt.WA_TranslucentBackground, True)
        self.setAttribute(Qt.WA_QuitOnClose)
        self.setWindowIcon(QIcon(join(config.ASSETS_DIR, "droptopus.png")))
        self.setWindowTitle("Droptopus")

        self.miniwin = MiniWindow(self)
        self.frame = DropFrame(self)
        self.frame.show()

        self.readSettings()

        self.content = QStackedWidget()
        self.setCentralWidget(self.content)
        self.content.addWidget(self.frame)
        self.content.addWidget(self.miniwin)

        self.setAcceptDrops(True)
        self.setMouseTracking(True)
        self.collapse()

    def contextMenuEvent(self, event):
        menu = QMenu(self)
        label = ("Expand", "Collapse")[self.is_expanded]
        expand_action = menu.addAction(label)
        about_action = menu.addAction("About")
        menu.addSeparator()
        quit_action = menu.addAction("Quit")
        action = menu.exec_(self.mapToGlobal(event.pos()))
        if action == expand_action:
            if self.is_expanded:
                self.collapse()
            else:
                self.expand()
        elif action == about_action:
            self.showAbout()
        elif action == quit_action:
            self.should_confirm_close = True
            self.close()

    def expand(self):
        if self.is_expanded:
            return
        self.is_expanded = True
        self.setAcceptDrops(False)
        self.content.hide()
        expanded = self.frame.sizeHint()
        self.setMinimumSize(expanded)
        self.content.setCurrentWidget(self.frame)
        self.content.show()
        self.resize(expanded)

        # on OSX the window will not automatically stay inside the screen like on Linux
        # we have to do it manually
        screen_rect = QDesktopWidget().screenGeometry()
        window_rect = self.frameGeometry()
        intersection = window_rect & screen_rect
        dx = window_rect.width() - intersection.width()
        dy = window_rect.height() - intersection.height()
        unseen = window_rect & intersection
        if dx != 0 or dy != 0:
            if window_rect.left() > screen_rect.left():
                dx = dx * -1
            if window_rect.bottom() > screen_rect.bottom():
                dy = dy * -1
            self.move(window_rect.left() + dx, window_rect.top() + dy)

    def collapse(self):
        if not self.is_expanded:
            return
        self.is_expanded = False
        self.setAcceptDrops(True)
        self.content.hide()
        mini = self.miniwin.sizeHint()
        self.setMinimumSize(mini)
        self.move(self.anchor)
        self.content.setCurrentWidget(self.miniwin)
        self.content.show()
        self.resize(mini)

    def showAbout(self):
        about = AboutDialog(self)
        about.setModal(True)
        about.show()

    def mouseReleaseEvent(self, event):
        self.is_move_action = False

    def mousePressEvent(self, event):
        if not event.button() == Qt.LeftButton:
            return
        self.is_move_action = True
        self.offset = event.pos()

    def mouseMoveEvent(self, event):
        if not self.is_move_action:
            return
        x = event.globalX()
        y = event.globalY()
        x_w = self.offset.x()
        y_w = self.offset.y()
        self.move(x - x_w, y - y_w)
        if self.content.currentWidget() == self.miniwin:
            self.anchor = self.pos()

    def writeSettings(self):
        self.settings.beginGroup("MainWindow")
        self.settings.setValue("anchor", self.anchor)
        self.settings.endGroup()

    def readSettings(self):
        self.settings.beginGroup("MainWindow")
        saved_anchor = self.settings.value("anchor", None)
        if saved_anchor != None:
            self.anchor = saved_anchor
        else:
            rect = QDesktopWidget().screenGeometry()
            mini = self.miniwin.sizeHint()
            self.anchor = QPoint(rect.right() - mini.width(),
                                 rect.bottom() - mini.height())
        self.settings.endGroup()

    def userReallyWantsToQuit(self):
        if not self.should_confirm_close:
            return True
        reply = QMessageBox.question(
            self,
            "Close Droptopus",
            "Are you sure you want to close the application?",
            QMessageBox.Yes,
            QMessageBox.No,
        )
        return reply == QMessageBox.Yes

    def closeEvent(self, event):
        if self.userReallyWantsToQuit():
            self.writeSettings()
            event.accept()
        else:
            event.ignore()

    # def dragMoveEvent(self, event):
    #    super(MainWindow, self).dragMoveEvent(event)

    def dragEnterEvent(self, event):
        if not self.is_expanded:
            QTimer.singleShot(200, self.expand)
        else:
            super(MainWindow, self).dragEnterEvent(event)

    def mouseDoubleClickEvent(self, event):
        if self.is_expanded:
            self.collapse()
        else:
            self.expand()

    def event(self, evt):
        et = evt.type()
        if et == events.COLLAPSE_WINDOW:
            evt.accept()
            self.collapse()
            return True
        if evt.type() == events.RELOAD_WIDGETS:
            evt.accept()
            if self.is_expanded:
                self.resize(self.sizeHint())
        if et == events.EXPAND_WINDOW:
            evt.accept()
            self.expand()
            return True
        elif et == events.CLOSE_WINDOW:
            evt.accept()
            self.should_confirm_close = True
            self.close()
            return True
        return super(MainWindow, self).event(evt)
Beispiel #55
0
 def closeEvent(self, _):
     self.closeHelp()
     settings = QSettings()
     #save window geometry
     settings.setValue("autosaveGeometry", self.saveGeometry())
Beispiel #56
0
class AppSettings:
    def __init__(self):
        self.settings: QSettings = None
        self.app_name: str = None
        self.app_dir: Union[Path, Any] = None
        self.docs_location: Path = Path(
            QStandardPaths.writableLocation(QStandardPaths.DocumentsLocation))
        self.data: LiteDataStore = None

    def init(self):
        self.app_name = qApp.applicationName().lower()
        self.app_dir = Path(
            QStandardPaths.writableLocation(QStandardPaths.AppConfigLocation))
        self.app_dir.mkdir(exist_ok=True)
        settings_file = f"{self.app_name}.ini"
        self.settings = QSettings(
            self.app_dir.joinpath(settings_file).as_posix(),
            QSettings.IniFormat)
        self.settings.sync()
        self.data = LiteDataStore(self.app_dir)

    def init_logger(self):
        log_file = f"{self.app_name}.log"
        handlers = [
            logging.handlers.RotatingFileHandler(
                self.app_dir.joinpath(log_file),
                maxBytes=1000000,
                backupCount=1),
            logging.StreamHandler(),
        ]

        logging.basicConfig(
            handlers=handlers,
            format="%(asctime)s - %(filename)s:%(lineno)d - %(message)s",
            datefmt="%Y-%m-%d %H:%M:%S",
            level=logging.DEBUG,
        )
        logging.captureWarnings(capture=True)

    def save_window_state(self, geometry, window_state):
        self.settings.setValue("geometry", geometry)
        self.settings.setValue("windowState", window_state)
        self.settings.sync()

    def save_configuration(self, app_config: AppConfig):
        self.settings.setValue(AppConfig.ITEM_CHECK, app_config.item_checked)
        self.settings.sync()

    def load_configuration(self):
        app_config = AppConfig()
        app_config.item_checked = self.settings.value(
            AppConfig.ITEM_CHECK,
            app_config.item_checked,
        )
        return app_config

    def geometry(self):
        return self.settings.value("geometry", None)

    def window_state(self):
        return self.settings.value("windowState", None)
Beispiel #57
0
class Backup:
    '''
    A utility to store and restore settings for use in testing. Be careful not to lose data.
    '''
    setname = 'settings.zst'

    def __init__(self, backuploc=None, theDate=None):
        '''
        Store the directory settings in self. The initial strings for the DB are in settings. If initialize is
        called, they are gone. Likeise, restoration will depend on reinitializing settings
        '''

        self.settings = QSettings('zero_substance', 'structjour')
        self.apisettings = QSettings('zero_substance/stockapi', 'structjour')
        self.chartsettings = QSettings('zero_substance/chart', 'structjour')

        if backuploc is None:
            if not os.path.exists(self.settings.value('journal')):
                msg = f"Journal location {self.settings.value('journal')} does not exist"
                logging.error(msg)
                raise ValueError(msg)
            self.rootdir = os.path.normpath(
                os.path.join(self.settings.value('journal'), 'backup'))
        else:
            self.rootdir = backuploc
        d = pd.Timestamp(
            theDate) if theDate is not None else pd.Timestamp.now()
        self.bdir = os.path.join(self.rootdir,
                                 d.strftime("backup_%Y%m%d_%H.%M.%S"))

        self.bu_settings = os.path.join(self.bdir, self.setname)

        self.dbtrade = self.settings.value('tradeDb')
        self.dbstructjour = self.settings.value('structjourDb')

        self.setkeys = []
        self.setvals = []
        self.apisetkeys = []
        self.apisetvals = []

        # print(self.bu_settings)

    def initializeSettings(self):
        '''
        Remove all settings except zero_substance/structjour/journal
        '''
        for key in self.settings.allKeys():
            if key != 'journal':
                self.settings.remove(key)
        self.apisettings.clear()
        self.chartsettings.clear()
        self.settings.sync()
        self.apisettings.sync()
        self.chartsettings.sync()

    def createDir(self):
        try:
            if not os.path.exists(self.rootdir):
                os.mkdir(self.rootdir)
            if not os.path.exists(self.bdir):
                os.mkdir(self.bdir)
        except Exception as ex:
            logging.error(ex)
            logging.error('Failed to create backup directory. ' + str(ex))
            raise ValueError(ex)
        pass

    def removePickle(self):
        if os.path.exists(self.bu_settings):
            os.remove(self.bu_settings)

    def initializeVars(self):
        self.setkeys = []
        self.setvals = []

        self.apisetkeys = []
        self.apisetvals = []

        self.chartkeys = []
        self.chartvals = []

    def backupDatabase(self, theDir=None):
        '''
        Helper method for backup.
        '''
        self.bdir = self.bdir if theDir is None else theDir
        if not os.path.exists(self.bdir):
            raise ValueError(f'Backup directory {self.bdir} does not exist')

        dbtrade2 = os.path.split(self.dbtrade)[1]
        dbstructjour2 = os.path.split(self.dbstructjour)[1]
        dbtrade2 = os.path.normpath(os.path.join(self.bdir, dbtrade2))
        dbstructjour2 = os.path.normpath(os.path.join(self.bdir,
                                                      dbstructjour2))
        copyfile(self.dbtrade, dbtrade2)
        logging.info(f'Trade database has been backed up to {dbtrade2}')
        if dbtrade2 != dbstructjour2:
            copyfile(self.dbstructjour, dbstructjour2)
            logging.info(
                f'Structjour database has been backed up to {dbstructjour2}')

    def restoreDatabase(self, theDir=None):
        self.bdir = self.bdir if theDir is None else theDir
        if not os.path.exists(self.bdir):
            raise ValueError(f'Backup directory {self.bdir} does not exist.')
        dbtrade = self.settings.value('tradeDb')
        dbstructjour = self.settings.value('structjourDb')

        dbt = os.path.join(self.bdir, os.path.split(dbtrade)[1])
        dbs = os.path.join(self.bdir, os.path.split(dbstructjour)[1])

        if os.path.exists(dbt):
            copyfile(dbt, dbtrade)
            logging.info(f'Db restored {dbt}')
        else:
            logging.error(f'Backup file {dbt} does not exist.')
        if dbs != dbt:
            if os.path.exists(dbs):
                copyfile(dbs, dbstructjour)
                logging.info(f'Db restored {dbs}')
            else:
                logging.error(f'Backup file {dbt} does not exist.')

    def storeSettings(self, replacePickle=False):
        self.createDir()
        if os.path.exists(self.bu_settings):
            if not replacePickle:
                return
        self.initializeVars()
        self.setkeys = self.settings.allKeys()
        for k in self.setkeys:
            self.setvals.append(self.settings.value(k))

        self.apisetkeys = self.apisettings.allKeys()
        for k in self.apisetkeys:
            self.apisetvals.append(self.apisettings.value(k))

        self.chartkeys = self.chartsettings.allKeys()
        for k in self.chartkeys:
            self.chartvals.append(self.chartsettings.value(k))

        setsnkeys = [
            self.setkeys, self.setvals, self.apisetkeys, self.apisetvals,
            self.chartkeys, self.chartvals
        ]

        with open(self.bu_settings, "wb") as f:
            '''Cannot pickle qsettings objects- so we pickle a list'''
            pickle.dump((setsnkeys), f)

        logging.info(
            f'Settings have been backed up to file {self.bu_settings}')

    def restoreSettings(self, theDir=None):
        theDir = self.mostRecent() if theDir is None else theDir
        bu_settings = os.path.join(theDir, self.setname)
        if os.path.exists(bu_settings):
            with open(bu_settings, "rb") as f:
                setsnkeys = pickle.load(f)
                for k, v in zip(setsnkeys[0], setsnkeys[1]):
                    self.settings.setValue(k, v)

                for k2, v2 in zip(setsnkeys[2], setsnkeys[3]):
                    self.apisettings.setValue(k2, v2)

                for k2, v2 in zip(setsnkeys[4], setsnkeys[5]):
                    self.chartsettings.setValue(k2, v2)
            logging.info(f'Settings backed up to file {bu_settings}')

        else:
            logging.error(f'No settings backup found at {bu_settings}')

    def backup(self):
        self.storeSettings()
        self.backupDatabase()

    def restore(self, theDir=None):
        self.bdir = self.mostRecent() if theDir is None else theDir
        self.bdir = os.path.normpath(self.bdir)
        if not os.path.exists(self.bdir):
            raise ValueError(f'Backup directory {self.bdir} does not exist')
        self.restoreSettings(self.bdir)
        self.restoreDatabase(self.bdir)

    def mostRecent(self):

        thedirs = os.listdir(self.rootdir)
        maxdate = ''
        maxdir = None
        for thedir in thedirs:
            if thedir.startswith('backup_2'):
                d = thedir[7:].replace('.', ':')
                if d > maxdate:
                    maxdir = thedir

        return os.path.join(self.rootdir, maxdir) if maxdir is not None else ''

    def _clearJournalDir(self):
        '''For Testing ONLY. TODO implement a seperate backup/restore for this one string'''
        # jdir = self.settings('journal')
        self.settings.remove('journal')

    def _restoreJournalDir(self):
        '''For Testing'''
        pass
Beispiel #58
0
 def saveSettings(self):
     s = QSettings()
     s.setValue("experimental-features", self.experimentalFeatures.isChecked())
Beispiel #59
0
class InitialPrompt(QDialog):
    databaseSelected = pyqtSignal()

    def __init__(self, parent=None):
        super(InitialPrompt, self).__init__(parent)
        self.init()

    def init(self):
        self._settings = QSettings("Raul Sangonzalo", "Musician Suite")

        os.chdir(os.path.dirname(os.path.abspath(__file__)))
        resourcesPath = os.getcwd()
        resourcesPath = os.path.join(resourcesPath, "resources")
        self.MAIN_ICON = QIcon(os.path.join(resourcesPath, "test.ico"))
        self.setWindowTitle("Musician Suite")
        self.setWindowIcon(self.MAIN_ICON)
        mainLayout = QVBoxLayout(self)
        label = QLabel(
            "<p>Welcome to <b>Musician Suite 0.1b</b>.</p></br> Select an existing database or create a new one."
        )

        buttonLayout = QHBoxLayout(self)

        newButton = QPushButton("New")
        importButton = QPushButton("Import")

        newButton.clicked.connect(self.createDatabase)
        importButton.clicked.connect(self.importDatabase)

        buttonLayout.addWidget(newButton)
        buttonLayout.addStretch(1)
        buttonLayout.addWidget(importButton)

        mainLayout.addWidget(label)
        mainLayout.addLayout(buttonLayout)

    def closeEvent(self, event):
        sys.exit(1)

    def createDatabase(
            self
    ):  # different handling, so make sure db is appended at the end
        try:
            fileDialog = QFileDialog(filter="SQLite music database (*.db)")
            fileDialog.setAcceptMode(QFileDialog.AcceptSave)
            fileDialog.setDefaultSuffix("db")
            fileDialog.setOptions(QFileDialog.DontUseNativeDialog)
            fileDialog.exec()
            dbName = fileDialog.selectedFiles()
            if dbName[0] != '':
                print(dbName)
                self._settings.setValue("currentDatabase", dbName[0])
                createTables()
                print("yes!")
                self.databaseSelected.emit()
        except Exception as e:
            self._settings.setValue("currentDatabase", None)
            QMessageBox.warning(None, "Error", "%s" % e)

    def importDatabase(self):
        dbName = QFileDialog().getOpenFileName(
            self,
            filter="SQLite music database (*.db)",
            options=QFileDialog.DontUseNativeDialog)
        if dbName[0] != '':
            self._settings.setValue("currentDatabase", dbName[0])
            self.databaseSelected.emit()
Beispiel #60
0
class MainWindow(QMainWindow):
    """Show the main window of SCCT."""

    EXIT_CODE_REBOOT = -123

    def __init__(self, controller, app, showChangelog):
        """Init the main window."""
        try:
            super().__init__()

            self._save = True
            self.tlock = TriggerLock()
            self.controller = controller
            self.game_list = {}

            with self.tlock:
                self.createFormMatchDataBox()
            self.createTabs()
            self.createHorizontalGroupBox()
            self.createBackgroundTasksBox()

            self.createMenuBar()

            mainLayout = QVBoxLayout()
            mainLayout.addWidget(self.tabs, 0)
            mainLayout.addWidget(self.fromMatchDataBox, 1)
            mainLayout.addWidget(self.backgroundTasksBox, 0)
            mainLayout.addWidget(self.horizontalGroupBox, 0)

            self.setWindowTitle(
                "WarCraft III – Meta Plays Casting Tool v{}".format(
                    hwctool.__version__))

            self.window = QWidget()
            self.window.setLayout(mainLayout)
            self.setCentralWidget(self.window)

            # self.size
            self.statusBar()

            self.leds = dict()
            for scope in self.controller.websocketThread.get_primary_scopes():
                self.leds[scope] = LedIndicator(self)

            for key, led in self.leds.items():
                self.controller.toogleLEDs(0, key, self)
                self.statusBar().addPermanentWidget(led)

            self.app = app
            self.controller.setView(self)
            self.controller.refreshButtonStatus()

            self.processEvents()
            self.settings = QSettings(ClientConfig.APP_NAME,
                                      ClientConfig.COMPANY_NAME)
            self.restoreGeometry(
                self.settings.value("geometry", self.saveGeometry()))
            self.restoreState(
                self.settings.value("windowState", self.saveState()))

            self.mysubwindows = dict()

            self.show()
            self.raise_()

            if showChangelog:
                self.openChangelog()

        except Exception as e:
            module_logger.exception("message")

    # def showAbout(self):
    #     """Show subwindow with about info."""
    #     html = markdown2.markdown_path(
    #         hwctool.settings.getResFile("about.md"))

    #     html = html.replace("%VERSION%", hwctool.__version__)
    #     if(not hwctool.__new_version__):
    #         new_version = _("Halo Wars Casting Tool is up to date.")
    #     else:
    #         new_version = _("The new version {} is available!").format(
    #             hwctool.__latest_version__)
    #     html = html.replace('%NEW_VERSION%', new_version)

    #     # use self as parent here
    #     QMessageBox.about(
    #         self, _("Halo Wars Casting Tool - About"), html)

    def closeEvent(self, event):
        """Close and clean up window."""
        try:
            try:
                for name, window in self.mysubwindows.items():
                    if (window and window.isVisible()):
                        window.close()
            finally:
                self.settings.setValue("geometry", self.saveGeometry())
                self.settings.setValue("windowState", self.saveState())
                self.controller.cleanUp(self._save)
                QMainWindow.closeEvent(self, event)
                # event.accept()
        except Exception as e:
            module_logger.exception("message")

    def updateGame(self, title):
        """updates game played"""
        self.setWindowTitle("{} – Meta Plays Casting Tool v{}".format(
            title, hwctool.__version__))  #change title
        hwctool.settings.races = hwctool.settings.game_races[
            title]  #update races
        hwctool.settings.current_game = title  #update current game

        #uncheck, check
        for item in self.game_list.keys():
            self.game_list[item].setChecked(False)

        self.game_list[title].setChecked(True)

        #updates dropdown menu for players
        max_no_sets = hwctool.settings.max_no_sets
        for player_idx in range(max_no_sets):
            for team_idx in range(2):
                self.cb_race[team_idx][player_idx].clear()
                for race in hwctool.settings.races:
                    self.cb_race[team_idx][player_idx].addItem(race)

        #update styles
        self.openStyleDialog()

    def createMenuBar(self):
        """Create the menu bar."""
        try:
            menubar = self.menuBar()

            # BROWSER SOURCES
            self.createBrowserSrcMenu()

            #SETTINGS
            settingsMenu = menubar.addMenu(_('Settings'))
            # apiAct = QAction(QIcon(hwctool.settings.getResFile(
            #     'browser.png')), _('Browser Sources'), self)
            # apiAct.setToolTip(
            #     _('Edit Settings for all Browser Sources'))
            # apiAct.triggered.connect(self.openBrowserSourcesDialog)
            # settingsMenu.addAction(apiAct)

            apiAct = QAction(QIcon(hwctool.settings.getResFile('twitch.png')),
                             _('Twitch'), self)
            apiAct.setToolTip(
                _('Edit Intro-Settings and API-Settings'
                  ' for Twitch'))
            apiAct.triggered.connect(self.openApiDialog)
            settingsMenu.addAction(apiAct)

            # styleAct = QAction(QIcon(hwctool.settings.getResFile(
            #     'pantone.png')), _('Styles'), self)
            # styleAct.setToolTip('')
            # styleAct.triggered.connect(self.openStyleDialog)
            # settingsMenu.addAction(styleAct)

            apiAct = QAction(QIcon(hwctool.settings.getResFile('browser.png')),
                             _('Intro settings'), self)
            apiAct.setToolTip(_('Edit Settings for all Browser Sources'))
            apiAct.triggered.connect(self.openBrowserSourcesDialog)
            settingsMenu.addAction(apiAct)

            styleAct = QAction(
                QIcon(hwctool.settings.getResFile('pantone.png')),
                _('Source styles'), self)
            styleAct.setToolTip('')
            styleAct.triggered.connect(self.openStyleDialog)
            settingsMenu.addAction(styleAct)

            ProfileMenu(self, self.controller)

            infoMenu = menubar.addMenu(_('Info && Links'))

            myAct = QAction(QIcon(hwctool.settings.getResFile('folder.png')),
                            _('Open log folder'), self)
            myAct.triggered.connect(lambda: os.startfile(
                hwctool.settings.getAbsPath(hwctool.settings.getLogDir())))
            infoMenu.addAction(myAct)

            infoMenu.addSeparator()

            websiteAct = QAction(
                QIcon(hwctool.settings.getResFile('github.ico')),
                'Github - Meta Plays Casting Tool', self)
            websiteAct.triggered.connect(lambda: self.controller.openURL(
                "https://github.com/FluffyMaguro/MetaPlaysCastingTool/"))
            infoMenu.addAction(websiteAct)

            ixAct = QAction(QIcon(hwctool.settings.getResFile('icon.png')),
                            'Meta Plays (website)', self)
            ixAct.triggered.connect(
                lambda: self.controller.openURL("https://meta-plays.com/"))
            infoMenu.addAction(ixAct)

            websiteAct = QAction(
                QIcon(hwctool.settings.getResFile('favicon.jpg')),
                'Maguro.one (website)', self)
            websiteAct.triggered.connect(
                lambda: self.controller.openURL("https://www.maguro.one/"))
            infoMenu.addAction(websiteAct)

            infoMenu.addSeparator()

            websiteAct = QAction(
                QIcon(hwctool.settings.getResFile('hwct.ico')),
                'StarCraft Casting Tool - Docs', self)
            websiteAct.triggered.connect(lambda: self.controller.openURL(
                "https://teampheenix.github.io/StarCraft-Casting-Tool/"))
            infoMenu.addAction(websiteAct)

            myAct = QAction(QIcon(hwctool.settings.getResFile('patreon.png')),
                            _('StarCraft Casting Tool - Patreon'), self)
            myAct.triggered.connect(lambda: self.controller.openURL(
                "https://www.patreon.com/StarCraftCastingTool"))
            infoMenu.addAction(myAct)

            myAct = QAction(QIcon(hwctool.settings.getResFile('donate.ico')),
                            _('StarCraft Casting Tool - PayPal'), self)
            myAct.triggered.connect(lambda: self.controller.openURL(
                "https://paypal.me/StarCraftCastingTool"))
            infoMenu.addAction(myAct)

            #Choose the game
            gameMenu = menubar.addMenu(_('Game'))

            icon_dict = {
                'StarCraft II': 'SC2.png',
                'WarCraft III': 'WC3.png',
                'Age of Empires IV': 'AOEIV.png',
                'Age of Empires Online': 'AOEO.png',
                'Age of Mythology': 'AOM.png',
                'Halo Wars 2': 'HW.png',
                'SpellForce 3': 'SF3.png'
            }
            for game in hwctool.settings.game_races:
                if game in icon_dict:
                    myAct = QAction(QIcon(
                        hwctool.settings.getResFile(icon_dict[game])),
                                    _(game),
                                    self,
                                    checkable=True)
                else:
                    myAct = QAction(QIcon(
                        hwctool.settings.getResFile('loading.png')),
                                    _(game),
                                    self,
                                    checkable=True)

                myAct.triggered.connect(partial(self.updateGame, game))
                gameMenu.addAction(myAct)
                self.game_list[game] = myAct

        except Exception as e:
            module_logger.exception("message")

    def createBrowserSrcMenu(self):
        menubar = self.menuBar()
        main_menu = menubar.addMenu(_('Browser Sources'))

        srcs = []
        srcs.append({
            'name': _('Intro'),
            'file': 'intro.html',
            'settings': lambda: self.openBrowserSourcesDialog('intro')
        })
        srcs.append({'name': _('Score'), 'file': 'score.html'})

        act = QAction(QIcon(hwctool.settings.getResFile('folder.png')),
                      _('Open Folder'), self)
        act.triggered.connect(lambda: os.startfile(
            hwctool.settings.getAbsPath(hwctool.settings.casting_html_dir)))
        main_menu.addAction(act)
        main_menu.addSeparator()

        for src in srcs:
            myMenu = QMenu(src['name'], self)
            sub = src.get('sub', False)
            if sub:
                for icon in sub:
                    mySubMenu = QMenu(icon['name'], self)
                    icon['file'] = os.path.join(
                        hwctool.settings.casting_html_dir, icon['file'])
                    act = QAction(
                        QIcon(hwctool.settings.getResFile('html.png')),
                        _('Open in Browser'), self)
                    act.triggered.connect(
                        lambda x, file=icon['file']: self.controller.openURL(
                            hwctool.settings.getAbsPath(file)))
                    mySubMenu.addAction(act)
                    act = QAction(
                        QIcon(hwctool.settings.getResFile('copy.png')),
                        _('Copy URL to Clipboard'), self)
                    act.triggered.connect(
                        lambda x, file=icon['file']: QApplication.clipboard(
                        ).setText(hwctool.settings.getAbsPath(file)))
                    mySubMenu.addAction(act)
                    if icon.get('settings', None) is not None:
                        act = QAction(
                            QIcon(hwctool.settings.getResFile('browser.png')),
                            _('Settings'), self)
                        act.triggered.connect(icon['settings'])
                        mySubMenu.addAction(act)
                    myMenu.addMenu(mySubMenu)
            else:
                src['file'] = os.path.join(hwctool.settings.casting_html_dir,
                                           src['file'])
                act = QAction(QIcon(hwctool.settings.getResFile('html.png')),
                              _('Open in Browser'), self)
                act.triggered.connect(
                    lambda x, file=src['file']: self.controller.openURL(
                        hwctool.settings.getAbsPath(file)))
                myMenu.addAction(act)
                act = QAction(QIcon(hwctool.settings.getResFile('copy.png')),
                              _('Copy URL to Clipboard'), self)
                act.triggered.connect(
                    lambda x, file=src['file']: QApplication.clipboard(
                    ).setText(hwctool.settings.getAbsPath(file)))
                myMenu.addAction(act)

            if src.get('settings', None) is not None:
                act = QAction(
                    QIcon(hwctool.settings.getResFile('browser.png')),
                    _('Settings'), self)
                act.triggered.connect(src['settings'])
                myMenu.addAction(act)
            main_menu.addMenu(myMenu)

        main_menu.addSeparator()

        # apiAct = QAction(QIcon(hwctool.settings.getResFile(
        #     'browser.png')), _('Settings'), self)
        # apiAct.setToolTip(
        #     _('Edit Settings for all Browser Sources'))
        # apiAct.triggered.connect(self.openBrowserSourcesDialog)
        # main_menu.addAction(apiAct)

        # styleAct = QAction(QIcon(hwctool.settings.getResFile(
        #     'pantone.png')), _('Styles'), self)
        # styleAct.setToolTip('')
        # styleAct.triggered.connect(self.openStyleDialog)
        # main_menu.addAction(styleAct)

    def openApiDialog(self):
        """Open subwindow with connection settings."""
        self.mysubwindows['connections'] = SubwindowConnections()
        self.mysubwindows['connections'].createWindow(self)
        self.mysubwindows['connections'].show()

    def openStyleDialog(self):
        """Open subwindow with style settings."""
        self.mysubwindows['styles'] = SubwindowStyles()
        self.mysubwindows['styles'].createWindow(self)
        self.mysubwindows['styles'].show()

    def openBrowserSourcesDialog(self, tab=''):
        """Open subwindow with browser sources settings."""
        self.mysubwindows['browser'] = SubwindowBrowserSources()
        self.mysubwindows['browser'].createWindow(self, tab)
        self.mysubwindows['browser'].show()

    def openReadme(self):
        """Open subwindow with readme viewer."""
        self.mysubwindows['readme'] = SubwindowMarkdown()
        self.mysubwindows['readme'].createWindow(
            self, _("Readme"), hwctool.settings.getResFile('readme.ico'),
            hwctool.settings.getResFile("../README.md"))
        self.mysubwindows['readme'].show()

    def openChangelog(self):
        """Open subwindow with readme viewer."""
        self.mysubwindows['changelog'] = SubwindowMarkdown()
        self.mysubwindows['changelog'].createWindow(
            self, "Halo Wars Casting Tool " + _("Changelog"),
            hwctool.settings.getResFile("changelog.png"),
            hwctool.settings.getResFile("../CHANGELOG.md"))
        self.mysubwindows['changelog'].show()

    def changeLanguage(self, language):
        """Change the language."""
        hwctool.settings.config.parser.set("SCT", "language", language)
        self.restart()

    def createTabs(self):
        """Create tabs in main window."""
        try:
            # Initialize tab screen
            self.tabs = QTabWidget()
            self.tab2 = QWidget()
            # self.tabs.resize(300,200)

            # Add tabs
            self.tabs.addTab(self.tab2, _("Custom Match"))

            # Create second tab

            self.tab2.layout = QVBoxLayout()

            container = QHBoxLayout()

            label = QLabel()
            label.setMinimumWidth(self.labelWidth)
            container.addWidget(label, 0)

            label = QLabel(_("Match Format:"))
            label.setMinimumWidth(80)
            container.addWidget(label, 0)

            container.addWidget(QLabel(_("Best of")), 0)

            self.cb_bestof = QComboBox()
            for idx in range(0, hwctool.settings.max_no_sets):
                self.cb_bestof.addItem(str(idx + 1))
            self.cb_bestof.setCurrentIndex(3)
            string = _('"Best of 6/4": First, a Bo5/3 is played and the'
                       ' ace map gets extended to a Bo3 if needed;'
                       ' Best of 2: Bo3 with only two maps played.')
            self.cb_bestof.setToolTip(string)
            self.cb_bestof.setMaximumWidth(40)
            self.cb_bestof.currentIndexChanged.connect(self.changeBestOf)
            container.addWidget(self.cb_bestof, 0)

            container.addWidget(QLabel(_(" but at least")), 0)

            self.cb_minSets = QComboBox()

            self.cb_minSets.setToolTip(
                _('Minimum number of maps played (even if the match'
                  ' is decided already)'))
            self.cb_minSets.setMaximumWidth(40)
            container.addWidget(self.cb_minSets, 0)
            container.addWidget(QLabel(" " + _("maps") + "  "), 0)
            self.cb_minSets.currentIndexChanged.connect(
                lambda idx: self.highlightApplyCustom())

            ###### APPLY BUTTON
            label = QLabel("")
            container.addWidget(label, 1)
            self.applycustom_is_highlighted = False
            self.pb_applycustom = QToolButton()
            action = QAction(_("Apply Format"))
            action.triggered.connect(self.applycustom_click)
            self.pb_applycustom.setDefaultAction(action)
            self.pb_applycustom.setFixedWidth(100)
            container.addWidget(self.pb_applycustom, 0)
            self.defaultButtonPalette = self.pb_applycustom.palette()
            self.tab2.layout.addLayout(container)

            ###### RESET BUTTON
            label = QLabel("")
            container.addWidget(label, 1)
            self.pb_resetdata = QPushButton(_("Reset Match Data"))
            self.pb_resetdata.setFixedWidth(100)
            self.pb_resetdata.clicked.connect(self.resetdata_click)
            container.addWidget(self.pb_resetdata, 0)
            self.tab2.layout.addLayout(container)
            self.tab2.setLayout(self.tab2.layout)

            ###### SPACING
            container.insertSpacing(-1, 100)

            ########## REMOVED CUSTOM URL

            # container = QHBoxLayout()
            # label = QLabel()
            # label.setMinimumWidth(self.labelWidth)
            # container.addWidget(label, 0)
            # label = QLabel(_("Match-URL:"))
            # label.setMinimumWidth(80)
            # container.addWidget(label, 0)

            self.le_url_custom = MonitoredLineEdit()
            # self.le_url_custom.setAlignment(Qt.AlignCenter)
            # self.le_url_custom.setToolTip(
            #     _('Optionally specify the Match-URL,'
            #       ' e.g., for Nightbot commands'))
            # self.le_url_custom.setPlaceholderText(
            #     _("Specify the Match-URL of your Custom Match"))

            # completer = QCompleter(
            #     ["http://"], self.le_url_custom)
            # completer.setCaseSensitivity(Qt.CaseInsensitive)
            # completer.setCompletionMode(
            #     QCompleter.UnfilteredPopupCompletion)
            # completer.setWrapAround(True)
            # self.le_url_custom.setCompleter(completer)
            # self.le_url_custom.setMinimumWidth(360)
            # self.le_url_custom.textModified.connect(self.highlightApplyCustom)
            # container.addWidget(self.le_url_custom, 11)

        except Exception as e:
            module_logger.exception("message")

    def changeBestOf(self, bestof):
        """Change the minimum sets combo box on change of BoX."""
        bestof = bestof + 1
        self.cb_minSets.clear()
        self.highlightApplyCustom()
        for idx in range(0, bestof):
            self.cb_minSets.addItem(str(idx + 1))
            if bestof == 2:
                self.cb_minSets.setCurrentIndex(1)
            else:
                self.cb_minSets.setCurrentIndex(int((bestof - 1) / 2))

    def updatePlayerCompleters(self):
        """Refresh the completer for the player line edits."""
        list = ["TBD"] + self.controller.historyManager.getPlayerList()
        for player_idx in range(self.max_no_sets):
            for team_idx in range(2):
                completer = QCompleter(list,
                                       self.le_player[team_idx][player_idx])
                completer.setCaseSensitivity(Qt.CaseInsensitive)
                completer.setCompletionMode(QCompleter.InlineCompletion)
                completer.setWrapAround(True)
                self.le_player[team_idx][player_idx].setCompleter(completer)

    def createFormMatchDataBox(self):
        """Create the froms for the match data."""
        try:

            self.max_no_sets = hwctool.settings.max_no_sets
            self.scoreWidth = 35
            self.raceWidth = 100
            self.labelWidth = 25
            self.mimumLineEditWidth = 130

            self.fromMatchDataBox = QGroupBox(_("Match Data"))
            layout2 = QVBoxLayout()

            self.le_league = MonitoredLineEdit()
            self.le_league.setText("League TBD")
            self.le_league.setAlignment(Qt.AlignCenter)
            self.le_league.setPlaceholderText("League TBD")
            self.le_league.textModified.connect(self.league_changed)
            policy = QSizePolicy()
            policy.setHorizontalStretch(3)
            policy.setHorizontalPolicy(QSizePolicy.Expanding)
            policy.setVerticalStretch(1)
            policy.setVerticalPolicy(QSizePolicy.Fixed)
            self.le_league.setSizePolicy(policy)
            self.le_player = [[
                MonitoredLineEdit() for x in range(self.max_no_sets)
            ] for y in range(2)]
            self.cb_race = [[QComboBox() for x in range(self.max_no_sets)]
                            for y in range(2)]
            self.sl_score = [
                QSlider(Qt.Horizontal) for y in range(self.max_no_sets)
            ]
            self.label_set = [
                QLabel('#{}'.format(y + 1), self)
                for y in range(self.max_no_sets)
            ]
            self.setContainer = [
                QHBoxLayout() for y in range(self.max_no_sets)
            ]

            container = QGridLayout()

            button = QPushButton()
            pixmap = QIcon(hwctool.settings.getResFile('update.png'))
            button.setIcon(pixmap)
            button.clicked.connect(lambda: self.controller.swapTeams())
            button.setFixedWidth(self.labelWidth)
            button.setToolTip(_("Swap players."))
            container.addWidget(button, 0, 0, 1, 1)

            label = QLabel(_("League:"))
            label.setAlignment(Qt.AlignCenter)
            label.setFixedWidth(self.raceWidth)
            container.addWidget(label, 0, 1, 1, 1)

            container.addWidget(self.le_league, 0, 2, 1, 3)

            label = QLabel("")
            label.setFixedWidth(self.raceWidth)
            container.addWidget(label, 0, 5, 1, 1)

            layout2.addLayout(container)

            for player_idx in range(self.max_no_sets):
                for team_idx in range(2):
                    self.cb_race[team_idx][player_idx].\
                        currentIndexChanged.connect(
                        lambda idx,
                        t=team_idx,
                        p=player_idx: self.race_changed(t, p))
                    self.le_player[team_idx][player_idx].textModified.connect(
                        lambda t=team_idx, p=player_idx: self.player_changed(
                            t, p))
                    self.le_player[team_idx][player_idx].setText("TBD")
                    self.le_player[team_idx][player_idx].setAlignment(
                        Qt.AlignCenter)
                    self.le_player[team_idx][player_idx].setPlaceholderText(
                        _("Player {} of team {}").format(
                            player_idx + 1, team_idx + 1))
                    self.le_player[team_idx][player_idx].setMinimumWidth(
                        self.mimumLineEditWidth)

                    for race in hwctool.settings.races:
                        self.cb_race[team_idx][player_idx].addItem(race)

                    self.cb_race[team_idx][player_idx].setFixedWidth(
                        self.raceWidth)

                self.sl_score[player_idx].setMinimum(-1)
                self.sl_score[player_idx].setMaximum(1)
                self.sl_score[player_idx].setValue(0)
                self.sl_score[player_idx].setTickPosition(
                    QSlider.TicksBothSides)
                self.sl_score[player_idx].setTickInterval(1)
                self.sl_score[player_idx].setTracking(False)
                self.sl_score[player_idx].valueChanged.connect(
                    lambda x, player_idx=player_idx: self.sl_changed(
                        player_idx, x))
                self.sl_score[player_idx].setToolTip(_('Set the score'))
                self.sl_score[player_idx].setFixedWidth(self.scoreWidth)

                self.setContainer[player_idx] = QHBoxLayout()
                # self.label_set[player_idx].setText("#" + str(player_idx + 1))
                self.label_set[player_idx].setAlignment(Qt.AlignCenter)
                self.label_set[player_idx].setFixedWidth(self.labelWidth)
                self.setContainer[player_idx].addWidget(
                    self.label_set[player_idx], 0)
                self.setContainer[player_idx].addWidget(
                    self.cb_race[0][player_idx], 0)
                self.setContainer[player_idx].addWidget(
                    self.le_player[0][player_idx], 4)
                self.setContainer[player_idx].addWidget(
                    self.sl_score[player_idx], 0)
                self.setContainer[player_idx].addWidget(
                    self.le_player[1][player_idx], 4)
                self.setContainer[player_idx].addWidget(
                    self.cb_race[1][player_idx], 0)
                layout2.addLayout(self.setContainer[player_idx])

            layout2.addItem(
                QSpacerItem(0, 0, QSizePolicy.Minimum, QSizePolicy.Expanding))
            self.fromMatchDataBox.setLayout(layout2)

            self.updatePlayerCompleters()

        except Exception as e:
            module_logger.exception("message")

    def createHorizontalGroupBox(self):
        """Create horizontal group box for tasks."""
        try:
            self.horizontalGroupBox = QGroupBox(_("Tasks"))
            layout = QHBoxLayout()

            self.pb_twitchupdate = QPushButton(_("Update Twitch Title"))
            self.pb_twitchupdate.clicked.connect(self.updatetwitch_click)

            # self.pb_nightbotupdate = QPushButton(
            #     _("Update Nightbot"))
            # self.pb_nightbotupdate.clicked.connect(self.updatenightbot_click)

            self.pb_resetscore = QPushButton(_("Reset Score"))
            self.pb_resetscore.clicked.connect(self.resetscore_click)

            layout.addWidget(self.pb_twitchupdate)
            # layout.addWidget(self.pb_nightbotupdate)
            layout.addWidget(self.pb_resetscore)

            self.horizontalGroupBox.setLayout(layout)

        except Exception as e:
            module_logger.exception("message")

    def createBackgroundTasksBox(self):
        """Create group box for background tasks."""
        try:
            self.backgroundTasksBox = QGroupBox(_("Background Tasks"))

            self.cb_autoTwitch = QCheckBox(_("Auto Twitch Update"))
            self.cb_autoTwitch.setChecked(False)
            self.cb_autoTwitch.stateChanged.connect(self.autoTwitch_change)

            # self.cb_autoNightbot = QCheckBox(
            #     _("Auto Nightbot Update"))
            # self.cb_autoNightbot.setChecked(False)
            # self.cb_autoNightbot.stateChanged.connect(
            #     self.autoNightbot_change)

            layout = QGridLayout()

            layout.addWidget(self.cb_autoTwitch, 0, 0)
            # layout.addWidget(self.cb_autoNightbot, 0, 1)

            self.backgroundTasksBox.setLayout(layout)

        except Exception as e:
            module_logger.exception("message")

    def autoTwitch_change(self):
        """Handle change of auto twitch check box."""
        try:
            if (self.cb_autoTwitch.isChecked()):
                self.controller.autoRequestsThread.activateTask('twitch')
            else:
                self.controller.autoRequestsThread.deactivateTask('twitch')
        except Exception as e:
            module_logger.exception("message")

    # def autoNightbot_change(self):
    #     """Handle change of auto twitch check box."""
    #     try:
    #         if(self.cb_autoNightbot.isChecked()):
    #             self.controller.autoRequestsThread.activateTask('nightbot')
    #         else:
    #             self.controller.autoRequestsThread.deactivateTask('nightbot')
    #     except Exception as e:
    #         module_logger.exception("message")

    def autoUpdate_change(self):
        """Handle change of auto score update check box."""
        try:
            if (self.cb_autoUpdate.isChecked()):
                self.controller.runSC2ApiThread("updateScore")
            else:
                self.controller.stopSC2ApiThread("updateScore")
        except Exception as e:
            module_logger.exception("message")

    def autoToggleScore_change(self):
        """Handle change of toggle score check box."""
        try:
            if (self.cb_autoToggleScore.isChecked()):
                self.controller.runSC2ApiThread("toggleScore")
            else:
                self.controller.stopSC2ApiThread("toggleScore")
        except Exception as e:
            module_logger.exception("message")

    def autoToggleProduction_change(self):
        """Handle change of toggle production tab check box."""
        try:
            if (self.cb_autoToggleProduction.isChecked()):
                self.controller.runSC2ApiThread("toggleProduction")
            else:
                self.controller.stopSC2ApiThread("toggleProduction")
        except Exception as e:
            module_logger.exception("message")

    def applyCustomFormat(self, format):
        """Handle click to apply custom format."""
        QApplication.setOverrideCursor(Qt.WaitCursor)
        try:
            with self.tlock:
                self.controller.matchData.applyCustomFormat(format)
                self.controller.updateForms()
                self.resizeWindow()
            self.highlightApplyCustom(False)
        except Exception as e:
            module_logger.exception("message")
        finally:
            QApplication.restoreOverrideCursor()

    def applycustom_click(self):
        """Handle click to apply custom match."""
        QApplication.setOverrideCursor(Qt.WaitCursor)
        try:
            with self.tlock:
                self.statusBar().showMessage(_('Applying Custom Match...'))
                msg = self.controller.applyCustom(
                    int(self.cb_bestof.currentText()), False, True,
                    int(self.cb_minSets.currentText()),
                    self.le_url_custom.text().strip())
                self.statusBar().showMessage(msg)
            self.highlightApplyCustom(False)
        except Exception as e:
            module_logger.exception("message")
        finally:
            QApplication.restoreOverrideCursor()

    def resetdata_click(self):
        """Handle click to reset the data."""
        QApplication.setOverrideCursor(Qt.WaitCursor)
        try:
            with self.tlock:
                msg = self.controller.resetData()
                self.statusBar().showMessage(msg)
        except Exception as e:
            module_logger.exception("message")
        finally:
            QApplication.restoreOverrideCursor()

    def openBrowser_click(self):
        """Handle request to open URL in browser."""
        try:
            url = self.le_url.text()
            self.controller.openURL(url)
        except Exception as e:
            module_logger.exception("message")

    # def updatenightbot_click(self):
    #     """Handle click to change nightbot command."""
    #     try:
    #         self.statusBar().showMessage(_('Updating Nightbot Command...'))
    #         msg = self.controller.updateNightbotCommand()
    #         self.statusBar().showMessage(msg)
    #     except Exception as e:
    #         module_logger.exception("message")

    def updatetwitch_click(self):
        """Handle click to change twitch title."""
        try:
            self.statusBar().showMessage(_('Updating Twitch Title...'))
            msg = self.controller.updateTwitchTitle()
            self.statusBar().showMessage(msg)
        except Exception as e:
            module_logger.exception("message")

    def resetscore_click(self, myteam=False):
        """Handle click to reset the score."""
        try:
            self.statusBar().showMessage(_('Resetting Score...'))
            with self.tlock:
                for set_idx in range(self.max_no_sets):
                    self.sl_score[set_idx].setValue(0)
                    self.controller.matchData.setMapScore(set_idx,
                                                          0,
                                                          overwrite=True)
                if myteam:
                    self.sl_team.setValue(0)
                    self.controller.matchData.setMyTeam(0)
                if not self.controller.resetWarning():
                    self.statusBar().showMessage('')

        except Exception as e:
            module_logger.exception("message")

    def setScore(self, idx, score, allkill=True):
        """Handle change of the score."""
        try:
            if (self.sl_score[idx].value() == 0):
                self.statusBar().showMessage(_('Updating Score...'))
                with self.tlock:
                    self.sl_score[idx].setValue(score)
                    self.controller.matchData.setMapScore(idx, score, True)
                    if not self.controller.resetWarning():
                        self.statusBar().showMessage('')
                return True
            else:
                return False
        except Exception as e:
            module_logger.exception("message")

    def league_changed(self):
        if not self.tlock.trigger():
            return
        self.controller.matchData.setLeague(self.le_league.text())

    def sl_changed(self, set_idx, value):
        """Handle a new score value."""
        try:
            if self.tlock.trigger():
                if set_idx == -1:
                    self.controller.matchData.setMyTeam(value)
                else:
                    self.controller.matchData.setMapScore(set_idx, value, True)
        except Exception as e:
            module_logger.exception("message")

    def player_changed(self, team_idx, player_idx):
        """Handle a change of player names."""
        if not self.tlock.trigger():
            return
        try:
            player = self.le_player[team_idx][player_idx].text().strip()
            race = self.cb_race[team_idx][player_idx].currentText()
            if (player_idx == 0 and self.controller.matchData.getSolo()):
                for p_idx in range(1, self.max_no_sets):
                    self.le_player[team_idx][p_idx].setText(player)
                    self.player_changed(team_idx, p_idx)
            self.controller.historyManager.insertPlayer(player, race)
            self.controller.matchData.setPlayer(
                team_idx, player_idx,
                self.le_player[team_idx][player_idx].text())

            if race == "Random":
                new_race = self.controller.historyManager.getRace(player)
                if new_race != "Random":
                    index = self.cb_race[team_idx][player_idx].findText(
                        new_race, Qt.MatchFixedString)
                    if index >= 0:
                        self.cb_race[team_idx][player_idx].setCurrentIndex(
                            index)
            elif player.lower() == "tbd":
                self.cb_race[team_idx][player_idx].setCurrentIndex(0)
            self.updatePlayerCompleters()
        except Exception as e:
            module_logger.exception("message")

    def race_changed(self, team_idx, player_idx):
        """Handle a change of player names."""
        if not self.tlock.trigger():
            return
        player = self.le_player[team_idx][player_idx].text().strip()
        race = self.cb_race[team_idx][player_idx].currentText()
        self.controller.historyManager.insertPlayer(player, race)
        self.controller.matchData.setRace(
            team_idx, player_idx,
            self.cb_race[team_idx][player_idx].currentText())
        try:
            if (player_idx == 0 and self.controller.matchData.getSolo()):
                race = self.cb_race[team_idx][0].currentText()
                for player_idx in range(1, self.max_no_sets):
                    index = self.cb_race[team_idx][player_idx].findText(
                        race, Qt.MatchFixedString)
                    if index >= 0:
                        self.cb_race[team_idx][player_idx].setCurrentIndex(
                            index)

        except Exception as e:
            module_logger.exception("message")

    def highlightApplyCustom(self, highlight=True, force=False):
        if not force and not self.tlock.trigger():
            return
        try:
            if self.applycustom_is_highlighted == highlight:
                return highlight
        except AttributeError:
            return False

        if highlight:
            myPalette = self.pb_applycustom.palette()
            myPalette.setColor(QPalette.Background, Qt.darkRed)
            myPalette.setColor(QPalette.ButtonText, Qt.darkRed)
            self.pb_applycustom.setPalette(myPalette)
        else:
            self.pb_applycustom.setPalette(self.defaultButtonPalette)

        self.applycustom_is_highlighted = highlight
        return highlight

    def resizeWindow(self):
        """Resize the window height to size hint."""
        if (not self.isMaximized()):
            self.processEvents()
            self.resize(self.width(), self.sizeHint().height())

    def processEvents(self):
        """Process ten PyQt5 events."""
        for i in range(0, 10):
            self.app.processEvents()

    def restart(self, save=True):
        """Restart the main window."""
        self._save = save
        self.close()
        self.app.exit(self.EXIT_CODE_REBOOT)