Ejemplo n.º 1
0
 def testSignal(self):
     o = QWidget()
     act = QAction(o)
     self._called = False
     act.triggered.connect(self._cb)
     act.trigger()
     self.assert_(self._called)
Ejemplo n.º 2
0
    def __init__(self,parent = None):
        QLabel.__init__(self, parent)
        self.headers = []
        self.position = 0
        self.viewWidth = 800
        self.viewHeight = 100
        self.hideFlag = False
        self.w = 180
        self.h = 40
        self.t = 10
        self.setMouseTracking(True)

        self.setContextMenuPolicy(QtCore.Qt.CustomContextMenu)
        self.customContextMenuRequested.connect(self.createHeaderMenus)

        self.deleteAct = QAction('Hide', self)
        self.deleteAct.setStatusTip('Hide this life-line')
        self.deleteAct.triggered.connect(self.hideLifeLine)

        self.groupAct = QAction('Make a cluster', self)
        self.groupAct.setStatusTip('Make a cluster of multiple life-lines')
        self.groupAct.triggered.connect(self.showClusterDialog)

        self.scatterAct = QAction('Scatter', self)
        self.scatterAct.setStatusTip('Scatter this cluster')
        self.scatterAct.triggered.connect(self.scatterCluster)
 def testPythonStringAsQKeySequence(self):
     '''Passes a Python string to an argument expecting a QKeySequence.'''
     keyseq = py3k.unicode_('Ctrl+A')
     action = QAction(None)
     action.setShortcut(keyseq)
     shortcut = action.shortcut()
     self.assert_(isinstance(shortcut, QKeySequence))
     self.assertEqual(shortcut.toString(), keyseq)
Ejemplo n.º 4
0
 def testSetShortcut(self):
     # Somehow an exception was leaking from the constructor
     # and appearing in setShortcut.
     o = QWidget()
     action = QAction('aaaa', o)
     shortcut = 'Ctrl+N'
     action.setShortcut(shortcut)
     s2 = action.shortcut()
     self.assertEqual(s2, shortcut)
Ejemplo n.º 5
0
    def __init__(self,diagramView):
        QtCore.QObject.__init__(self)
        self.actHide = QAction('Hide message', self)
        self.actHide.setStatusTip('Hide this message line')
        self.actHide.triggered.connect(self.hideOneMessage)

        self.actHideAll = QAction('Hide all', self)
        self.actHideAll.setStatusTip('Hide all the messages')
        self.actHideAll.triggered.connect(self.hideAllMessage)

        self.actViewCode = QAction('View code', self)
        self.actViewCode.setStatusTip('View source code of the message')
        self.actViewCode.triggered.connect(self.openCodeViewer)

        self.actCloseBody = QAction('Close body', self)
        self.actCloseBody.setStatusTip('View source code of the message')
        self.actCloseBody.triggered.connect(self.closeBody)

        self.diagramView = diagramView
Ejemplo n.º 6
0
    def __init__(self):
        super(MainWindow, self).__init__()

        self.cameraInfo = QCameraInfo.defaultCamera()
        self.camera = QCamera(self.cameraInfo)
        self.camera.setCaptureMode(QCamera.CaptureStillImage)
        self.imageCapture = QCameraImageCapture(self.camera)
        self.imageCapture.imageCaptured.connect(self.imageCaptured)
        self.imageCapture.imageSaved.connect(self.imageSaved)
        self.currentPreview = QImage()

        toolBar = QToolBar()
        self.addToolBar(toolBar)

        fileMenu = self.menuBar().addMenu("&File")
        shutterIcon = QIcon(os.path.join(os.path.dirname(__file__),
                            "shutter.svg"))
        self.takePictureAction = QAction(shutterIcon, "&Take Picture", self,
                                         shortcut="Ctrl+T",
                                         triggered=self.takePicture)
        self.takePictureAction.setToolTip("Take Picture")
        fileMenu.addAction(self.takePictureAction)
        toolBar.addAction(self.takePictureAction)

        exitAction = QAction(QIcon.fromTheme("application-exit"), "E&xit",
                             self, shortcut="Ctrl+Q", triggered=self.close)
        fileMenu.addAction(exitAction)

        aboutMenu = self.menuBar().addMenu("&About")
        aboutQtAction = QAction("About &Qt", self, triggered=qApp.aboutQt)
        aboutMenu.addAction(aboutQtAction)

        self.tabWidget = QTabWidget()
        self.setCentralWidget(self.tabWidget)

        self.cameraViewfinder = QCameraViewfinder()
        self.camera.setViewfinder(self.cameraViewfinder)
        self.tabWidget.addTab(self.cameraViewfinder, "Viewfinder")

        if self.camera.status() != QCamera.UnavailableStatus:
            name = self.cameraInfo.description()
            self.setWindowTitle("PySide2 Camera Example (" + name + ")")
            self.statusBar().showMessage("Starting: '" + name + "'", 5000)
            self.camera.start()
        else:
            self.setWindowTitle("PySide2 Camera Example")
            self.takePictureAction.setEnabled(False)
            self.statusBar().showMessage("Camera unavailable", 5000)
Ejemplo n.º 7
0
class MessageMenu(QtCore.QObject):
   
    actHide = None
    actHideAll = None
    actViewCode = None
    actCloseBody = None
    diagramView = None
 
    def __init__(self,diagramView):
        QtCore.QObject.__init__(self)
        self.actHide = QAction('Hide message', self)
        self.actHide.setStatusTip('Hide this message line')
        self.actHide.triggered.connect(self.hideOneMessage)

        self.actHideAll = QAction('Hide all', self)
        self.actHideAll.setStatusTip('Hide all the messages')
        self.actHideAll.triggered.connect(self.hideAllMessage)

        self.actViewCode = QAction('View code', self)
        self.actViewCode.setStatusTip('View source code of the message')
        self.actViewCode.triggered.connect(self.openCodeViewer)

        self.actCloseBody = QAction('Close body', self)
        self.actCloseBody.setStatusTip('View source code of the message')
        self.actCloseBody.triggered.connect(self.closeBody)

        self.diagramView = diagramView

    def hideOneMessage(self):
        self.diagramView.activateHide(True)

    def hideAllMessage(self):
        self.diagramView.hideAllMessageSelected()

    def openCodeViewer(self):
        self.diagramView.openCodeViewer()

    def closeBody(self):
        self.diagramView.closeCurrentHighLightedBody()

    def createHeaderMenus(self):
        pass
        """
Ejemplo n.º 8
0
class MVCPlaybackControlGUI(PlaybackControlConsole):
    """
    GUI implementation of MVCPlaybackControlBase
    """
    nameFiltersChanged = Signal("QStringList")

    def __init__(self, config):
        assertMainThread()
        super().__init__(config)

        # state
        self.preventSeek = False
        self.beginTime = None
        self.timeRatio = 1.0

        # gui
        srv = Services.getService("MainWindow")
        config.configLoaded.connect(self.restoreState)
        config.configAboutToSave.connect(self.saveState)
        self.config = config
        playbackMenu = srv.menuBar().addMenu("&Playback")

        style = QApplication.style()
        self.actStart = QAction(
            QIcon.fromTheme("media-playback-start",
                            style.standardIcon(QStyle.SP_MediaPlay)),
            "Start Playback", self)
        self.actPause = QAction(
            QIcon.fromTheme("media-playback-pause",
                            style.standardIcon(QStyle.SP_MediaPause)),
            "Pause Playback", self)
        self.actPause.setEnabled(False)
        self.actStepFwd = QAction(
            QIcon.fromTheme("media-seek-forward",
                            style.standardIcon(QStyle.SP_MediaSeekForward)),
            "Step Forward", self)
        self.actStepBwd = QAction(
            QIcon.fromTheme("media-seek-backward",
                            style.standardIcon(QStyle.SP_MediaSeekBackward)),
            "Step Backward", self)
        self.actSeekEnd = QAction(
            QIcon.fromTheme("media-skip-forward",
                            style.standardIcon(QStyle.SP_MediaSkipForward)),
            "Seek End", self)
        self.actSeekBegin = QAction(
            QIcon.fromTheme("media-skip-backward",
                            style.standardIcon(QStyle.SP_MediaSkipBackward)),
            "Seek Begin", self)
        self.actSetTimeFactor = {
            r: QAction("x 1/%d" %
                       (1 / r), self) if r < 1 else QAction("x %d" % r, self)
            for r in (1 / 8, 1 / 4, 1 / 2, 1, 2, 4, 8)
        }

        # pylint: disable=unnecessary-lambda
        # let's stay on the safe side and do not use emit as a slot...
        self.actStart.triggered.connect(self.startPlayback)
        self.actPause.triggered.connect(self.pausePlayback)
        self.actStepFwd.triggered.connect(
            lambda: self.stepForward(self.selectedStream()))
        self.actStepBwd.triggered.connect(
            lambda: self.stepBackward(self.selectedStream()))
        self.actSeekEnd.triggered.connect(self.seekEnd)
        self.actSeekBegin.triggered.connect(self.seekBeginning)

        # pylint: enable=unnecessary-lambda

        def setTimeFactor(newFactor):
            logger.debug("new time factor %f", newFactor)
            self.setTimeFactor(newFactor)

        for r in self.actSetTimeFactor:
            logger.debug("adding action for time factor %f", r)
            self.actSetTimeFactor[r].triggered.connect(
                functools.partial(setTimeFactor, r))

        self.dockWidget = srv.newDockWidget("PlaybackControl", None,
                                            Qt.LeftDockWidgetArea)
        self.dockWidgetContents = QWidget(self.dockWidget)
        self.dockWidget.setWidget(self.dockWidgetContents)
        toolLayout = QBoxLayout(QBoxLayout.TopToBottom,
                                self.dockWidgetContents)
        toolLayout.setContentsMargins(0, 0, 0, 0)
        toolBar = QToolBar()
        toolLayout.addWidget(toolBar)
        toolBar.addAction(self.actSeekBegin)
        toolBar.addAction(self.actStepBwd)
        toolBar.addAction(self.actStart)
        toolBar.addAction(self.actPause)
        toolBar.addAction(self.actStepFwd)
        toolBar.addAction(self.actSeekEnd)
        playbackMenu.addAction(self.actSeekBegin)
        playbackMenu.addAction(self.actStepBwd)
        playbackMenu.addAction(self.actStart)
        playbackMenu.addAction(self.actPause)
        playbackMenu.addAction(self.actStepFwd)
        playbackMenu.addAction(self.actSeekEnd)
        playbackMenu.addSeparator()
        for r in self.actSetTimeFactor:
            playbackMenu.addAction(self.actSetTimeFactor[r])
        self.timeRatioLabel = QLabel("x 1")
        self.timeRatioLabel.addActions(list(self.actSetTimeFactor.values()))
        self.timeRatioLabel.setContextMenuPolicy(Qt.ActionsContextMenu)
        toolBar.addSeparator()
        toolBar.addWidget(self.timeRatioLabel)
        contentsLayout = QGridLayout()
        toolLayout.addLayout(contentsLayout, 10)
        # now we add a position view
        self.positionSlider = QSlider(Qt.Horizontal, self.dockWidgetContents)
        self.beginLabel = QLabel(parent=self.dockWidgetContents)
        self.beginLabel.setAlignment(Qt.AlignLeft | Qt.AlignCenter)
        self.currentLabel = QLabel(parent=self.dockWidgetContents)
        self.currentLabel.setAlignment(Qt.AlignHCenter | Qt.AlignCenter)
        self.endLabel = QLabel(parent=self.dockWidgetContents)
        self.endLabel.setAlignment(Qt.AlignRight | Qt.AlignCenter)
        contentsLayout.addWidget(self.beginLabel, 0, 0, alignment=Qt.AlignLeft)
        contentsLayout.addWidget(self.currentLabel,
                                 0,
                                 1,
                                 alignment=Qt.AlignHCenter)
        contentsLayout.addWidget(self.endLabel, 0, 2, alignment=Qt.AlignRight)
        contentsLayout.addWidget(self.positionSlider, 1, 0, 1, 3)
        self.positionSlider.setTracking(False)
        self.positionSlider.valueChanged.connect(self.onSliderValueChanged,
                                                 Qt.DirectConnection)
        self.positionSlider.sliderMoved.connect(self.displayPosition)

        # file browser
        self.browser = BrowserWidget(self.dockWidget)
        self.nameFiltersChanged.connect(self._onNameFiltersChanged,
                                        Qt.QueuedConnection)
        contentsLayout.addWidget(self.browser, 3, 0, 1, 3)
        contentsLayout.setRowStretch(3, 100)
        self.browser.activated.connect(self.browserActivated)

        self.actShowAllFiles = QAction("Show all files")
        self.actShowAllFiles.setCheckable(True)
        self.actShowAllFiles.setChecked(False)
        self.actShowAllFiles.toggled.connect(self._onShowAllFiles)
        playbackMenu.addSeparator()
        playbackMenu.addAction(self.actShowAllFiles)

        self.actGroupStream = QActionGroup(self)
        self.actGroupStream.setExclusionPolicy(
            QActionGroup.ExclusionPolicy.ExclusiveOptional)
        playbackMenu.addSeparator()
        self.actGroupStreamMenu = playbackMenu.addMenu("Step Stream")
        self._selectedStream = None

        self.recentSeqs = [QAction() for i in range(10)]
        playbackMenu.addSeparator()
        recentMenu = playbackMenu.addMenu("Recent")
        for a in self.recentSeqs:
            a.setVisible(False)
            a.triggered.connect(self.openRecent)
            recentMenu.addAction(a)

        self._supportedFeaturesChanged(set(), set())

    def __del__(self):
        logger.internal("deleting playback control")

    def _onNameFiltersChanged(self, nameFilt):
        self.browser.setFilter(nameFilt)
        if isinstance(nameFilt, str):
            nameFilt = [nameFilt]
        for a in self.recentSeqs:
            if a.isVisible():
                m = QDir.match(nameFilt, Path(a.data()).name)
                a.setEnabled(m)

    def _onShowAllFiles(self, enabled):
        self.fileSystemModel.setNameFilterDisables(enabled)

    def _supportedFeaturesChanged(self, featureset, nameFilters):
        """
        overwritten from MVCPlaybackControlBase. This function is called
        from multiple threads, but not at the same time.

        :param featureset: the current featureset
        :return:
        """
        assertMainThread()
        self.featureset = featureset
        self.actStepFwd.setEnabled("stepForward" in featureset)
        self.actStepBwd.setEnabled("stepBackward" in featureset)
        self.actSeekBegin.setEnabled("seekBeginning" in featureset)
        self.actSeekEnd.setEnabled("seekEnd" in featureset)
        self.positionSlider.setEnabled("seekTime" in featureset)
        self.browser.setEnabled("setSequence" in featureset)
        self.timeRatioLabel.setEnabled("setTimeFactor" in featureset)
        for f in self.actSetTimeFactor:
            self.actSetTimeFactor[f].setEnabled("setTimeFactor" in featureset)
        self.timeRatioLabel.setEnabled("setTimeFactor" in featureset)
        self.timeRatioLabel.setEnabled("setTimeFactor" in featureset)
        self.timeRatioLabel.setEnabled("setTimeFactor" in featureset)
        self.timeRatioLabel.setEnabled("setTimeFactor" in featureset)
        if "startPlayback" not in featureset:
            self.actStart.setEnabled(False)
        if "pausePlayback" not in featureset:
            self.actPause.setEnabled(False)
        logger.debug("current feature set: %s", featureset)
        logger.debug("Setting name filters of browser: %s", list(nameFilters))
        self.nameFiltersChanged.emit(list(nameFilters))
        super()._supportedFeaturesChanged(featureset, nameFilters)

    def scrollToCurrent(self):
        """
        Scrolls to the current item in the browser

        :return:
        """
        assertMainThread()
        c = self.browser.current()
        if c is not None:
            self.browser.scrollTo(c)

    def _sequenceOpened(self, filename, begin, end, streams):
        """
        Notifies about an opened sequence.

        :param filename: the filename which has been opened
        :param begin: timestamp of sequence's first sample
        :param end: timestamp of sequence's last sample
        :param streams: list of streams in the sequence
        :return: None
        """
        assertMainThread()
        self.beginTime = begin
        self.preventSeek = True
        self.positionSlider.setRange(0, (end - begin) // 1000000)
        self.preventSeek = False
        self.beginLabel.setText(self._timeToString(0))
        self.endLabel.setText(self._timeToString((end - begin) // 1000000))
        self._currentTimestampChanged(begin)
        try:
            self.browser.blockSignals(True)
            self.browser.setActive(filename)
            self.browser.scrollTo(filename)
        finally:
            self.browser.blockSignals(False)
        self._selectedStream = None
        for a in self.actGroupStream.actions():
            logger.debug("Remove stream group action: %s", a.data())
            self.actGroupStream.removeAction(a)
        for stream in streams:
            act = QAction(stream, self.actGroupStream)
            act.triggered.connect(
                lambda cstream=stream: self.setSelectedStream(cstream))
            act.setCheckable(True)
            act.setChecked(False)
            logger.debug("Add stream group action: %s", act.data())
            self.actGroupStreamMenu.addAction(act)
        QTimer.singleShot(250, self.scrollToCurrent)
        super()._sequenceOpened(filename, begin, end, streams)

    @staticmethod
    def _splitTime(milliseconds):
        hours = milliseconds // (60 * 60 * 1000)
        milliseconds -= hours * (60 * 60 * 1000)
        minutes = milliseconds // (60 * 1000)
        milliseconds -= minutes * (60 * 1000)
        seconds = milliseconds // 1000
        milliseconds -= seconds * 1000
        return hours, minutes, seconds, milliseconds

    @staticmethod
    def _timeToString(milliseconds):
        return "%02d:%02d:%02d.%03d" % (
            MVCPlaybackControlGUI._splitTime(milliseconds))

    def _currentTimestampChanged(self, currentTime):
        """
        Notifies about a changed timestamp

        :param currentTime: the new current timestamp
        :return: None
        """
        assertMainThread()
        if self.beginTime is None:
            self.currentLabel.setText("")
        else:
            sliderVal = (currentTime - self.beginTime
                         ) // 1000000  # nanoseconds to milliseconds
            self.preventSeek = True
            self.positionSlider.setValue(sliderVal)
            self.preventSeek = False
            self.positionSlider.blockSignals(False)
            self.currentLabel.setEnabled(True)
            self.currentLabel.setText(self._timeToString(sliderVal))
        super()._currentTimestampChanged(currentTime)

    def onSliderValueChanged(self, value):
        """
        Slot called whenever the slider value is changed.

        :param value: the new slider value
        :return:
        """
        assertMainThread()
        if self.beginTime is None or self.preventSeek:
            return
        if self.actStart.isEnabled():
            ts = self.beginTime + value * 1000000
            self.seekTime(ts)
        else:
            logger.warning("Can't seek while playing.")

    def displayPosition(self, value):
        """
        Slot called when the slider is moved. Displays the position without actually seeking to it.

        :param value: the new slider value.
        :return:
        """
        assertMainThread()
        if self.beginTime is None:
            return
        if self.positionSlider.isSliderDown():
            ts = self.beginTime // 1000000 + value
            self.currentLabel.setEnabled(False)
            self.currentLabel.setText(self._timeToString(ts))

    def _playbackStarted(self):
        """
        Notifies about starting playback

        :return: None
        """
        assertMainThread()
        self.actStart.setEnabled(False)
        if "pausePlayback" in self.featureset:
            self.actPause.setEnabled(True)
        super()._playbackStarted()

    def _playbackPaused(self):
        """
        Notifies about pause playback

        :return: None
        """
        assertMainThread()
        logger.debug("playbackPaused received")
        if "startPlayback" in self.featureset:
            self.actStart.setEnabled(True)
        self.actPause.setEnabled(False)
        super()._playbackPaused()

    def openRecent(self):
        """
        Called when the user clicks on a recent sequence.

        :return:
        """
        assertMainThread()
        action = self.sender()
        self.browser.setActive(action.data())

    def browserActivated(self, filename):
        """
        Called when the user activated a file.

        :param filename: the new filename
        :return:
        """
        assertMainThread()
        if filename is not None and Path(filename).is_file():
            foundIdx = None
            for i, a in enumerate(self.recentSeqs):
                if a.data() == filename:
                    foundIdx = i
            if foundIdx is None:
                foundIdx = len(self.recentSeqs) - 1
            for i in range(foundIdx, 0, -1):
                self.recentSeqs[i].setText(self.recentSeqs[i - 1].text())
                self.recentSeqs[i].setData(self.recentSeqs[i - 1].data())
                logger.debug("%d data: %s", i, self.recentSeqs[i - 1].data())
                self.recentSeqs[i].setVisible(
                    self.recentSeqs[i - 1].data() is not None)
            self.recentSeqs[0].setText(self.compressFileName(filename))
            self.recentSeqs[0].setData(filename)
            self.recentSeqs[0].setVisible(True)
            self.setSequence(filename)

    def _timeRatioChanged(self, newRatio):
        """
        Notifies about a changed playback time ratio,

        :param newRatio the new playback ratio as a float
        :return: None
        """
        assertMainThread()
        self.timeRatio = newRatio
        logger.debug("new timeRatio: %f", newRatio)
        for r in [1 / 8, 1 / 4, 1 / 2, 1, 2, 4, 8]:
            if abs(newRatio / r - 1) < 0.01:
                self.timeRatioLabel.setText(("x 1/%d" %
                                             (1 / r)) if r < 1 else ("x %d" %
                                                                     r))
                return
        self.timeRatioLabel.setText("%.2f" % newRatio)
        super()._timeRatioChanged(newRatio)

    def selectedStream(self):
        """
        Returns the user-selected stream (for forward/backward stepping)

        :return:
        """
        return self._selectedStream

    def setSelectedStream(self, stream):
        """
        Sets the user-selected stream (for forward/backward stepping)

        :param stream the stream name.
        :return:
        """
        self._selectedStream = stream

    def _defineProperties(self):
        propertyCollection = self.config.guiState()
        propertyCollection.defineProperty("PlaybackControl_showAllFiles", 0,
                                          "show all files setting")
        propertyCollection.defineProperty("PlaybackControl_folder", "",
                                          "current folder name")
        propertyCollection.defineProperty("PlaybackControl_recent", "",
                                          "recent opened sequences")

    def saveState(self):
        """
        Saves the state of the playback control

        :return:
        """
        assertMainThread()
        self._defineProperties()
        propertyCollection = self.config.guiState()
        showAllFiles = self.actShowAllFiles.isChecked()
        folder = self.browser.folder()
        logger.debug("Storing current folder: %s", folder)
        try:
            propertyCollection.setProperty("PlaybackControl_showAllFiles",
                                           int(showAllFiles))
            propertyCollection.setProperty("PlaybackControl_folder", folder)
            recentFiles = [
                a.data() for a in self.recentSeqs if a.data() is not None
            ]
            propertyCollection.setProperty("PlaybackControl_recent",
                                           "|".join(recentFiles))
        except PropertyCollectionPropertyNotFound:
            pass

    def restoreState(self):
        """
        Restores the state of the playback control from the given property collection

        :param propertyCollection: a PropertyCollection instance
        :return:
        """
        assertMainThread()
        self._defineProperties()
        propertyCollection = self.config.guiState()
        showAllFiles = propertyCollection.getProperty(
            "PlaybackControl_showAllFiles")
        self.actShowAllFiles.setChecked(bool(showAllFiles))
        folder = propertyCollection.getProperty("PlaybackControl_folder")
        if Path(folder).is_dir():
            logger.debug("Setting current file: %s", folder)
            self.browser.setFolder(folder)
        recentFiles = propertyCollection.getProperty("PlaybackControl_recent")
        idx = 0
        for f in recentFiles.split("|"):
            if f != "" and Path(f).is_file():
                self.recentSeqs[idx].setData(f)
                self.recentSeqs[idx].setText(self.compressFileName(f))
                self.recentSeqs[idx].setVisible(True)
                self.recentSeqs[idx].setEnabled(False)
                idx += 1
                if idx >= len(self.recentSeqs):
                    break
        for a in self.recentSeqs[idx:]:
            a.setData(None)
            a.setText("")
            a.setVisible(False)

    @staticmethod
    def compressFileName(filename):
        """
        Compresses long path names with an ellipsis (...)

        :param filename: the original path name as a Path or string instance
        :return: the compressed path name as a string instance
        """
        p = Path(filename)
        parts = tuple(p.parts)
        if len(parts) >= 6:
            p = Path(*parts[:2]) / "..." / Path(*parts[-2:])
        return str(p)
Ejemplo n.º 9
0
 def settings_action(self):
     act = QAction(QIcon('exit.png'), 'Settings', self)
     act.setStatusTip('Set connecting and other properties')
     act.triggered.connect(self.settings)
     return act
    def __init__(self):
        super(MainWindow, self).__init__()

        self.playlist = QMediaPlaylist()
        self.player = QMediaPlayer()

        # Setting QToolBar
        toolBar = QToolBar()
        self.addToolBar(toolBar)

        fileMenu = self.menuBar().addMenu("&File")
        openAction = QAction(QIcon.fromTheme("document-open"),
                             "&Open...",
                             self,
                             shortcut=QKeySequence.Open,
                             triggered=self.open)
        fileMenu.addAction(openAction)
        exitAction = QAction(QIcon.fromTheme("application-exit"),
                             "E&xit",
                             self,
                             shortcut="Ctrl+Q",
                             triggered=self.close)
        fileMenu.addAction(exitAction)

        playMenu = self.menuBar().addMenu("&Play")
        playIcon = self.style().standardIcon(QStyle.SP_MediaPlay)
        self.playAction = toolBar.addAction(playIcon, "Play")
        self.playAction.triggered.connect(self.player.play)
        playMenu.addAction(self.playAction)

        previousIcon = self.style().standardIcon(QStyle.SP_MediaSkipBackward)
        self.previousAction = toolBar.addAction(previousIcon, "Previous")
        self.previousAction.triggered.connect(self.previousClicked)
        playMenu.addAction(self.previousAction)

        pauseIcon = self.style().standardIcon(QStyle.SP_MediaPause)
        self.pauseAction = toolBar.addAction(pauseIcon, "Pause")
        self.pauseAction.triggered.connect(self.player.pause)
        playMenu.addAction(self.pauseAction)

        nextIcon = self.style().standardIcon(QStyle.SP_MediaSkipForward)
        self.nextAction = toolBar.addAction(nextIcon, "Next")
        self.nextAction.triggered.connect(self.playlist.next)
        playMenu.addAction(self.nextAction)

        stopIcon = self.style().standardIcon(QStyle.SP_MediaStop)
        self.stopAction = toolBar.addAction(stopIcon, "Stop")
        self.stopAction.triggered.connect(self.player.stop)
        playMenu.addAction(self.stopAction)

        # Setting the QSlider
        self.volSlider = QSlider()
        self.volSlider.setOrientation(Qt.Horizontal)
        self.volSlider.setMinimum(0)
        self.volSlider.setMaximum(100)
        self.volSlider.setFixedWidth(120)
        self.volSlider.setValue(self.player.volume())
        self.volSlider.setTickInterval(10)
        self.volSlider.setTickPosition(QSlider.TicksBelow)
        self.volSlider.setToolTip("Volume")
        self.volSlider.valueChanged.connect(self.player.setVolume)
        toolBar.addWidget(self.volSlider)

        aboutMenu = self.menuBar().addMenu("&About")
        aboutQtAct = QAction("About &Qt", self, triggered=QApplication.aboutQt)
        aboutMenu.addAction(aboutQtAct)

        self.videoWidget = QVideoWidget()
        self.setCentralWidget(self.videoWidget)
        self.player.setPlaylist(self.playlist)
        self.player.stateChanged.connect(self.updateButtons)
        self.player.setVideoOutput(self.videoWidget)

        self.updateButtons(self.player.state())
Ejemplo n.º 11
0
class QLiberationWindow(QMainWindow):
    def __init__(self):
        super(QLiberationWindow, self).__init__()

        self.info_panel = None
        self.setGame(persistency.restore_game())

        self.setGeometry(300, 100, 270, 100)
        self.setWindowTitle("DCS Liberation - v" + CONST.VERSION_STRING)
        self.setWindowIcon(QIcon("./resources/icon.png"))
        self.statusBar().showMessage('Ready')

        self.initUi()
        self.initActions()
        self.initMenuBar()
        self.initToolbar()
        self.connectSignals()
        self.onGameGenerated(self.game)

        screen = QDesktopWidget().screenGeometry()
        self.setGeometry(0, 0, screen.width(), screen.height())
        self.setWindowState(Qt.WindowMaximized)

    def initUi(self):

        self.liberation_map = QLiberationMap(self.game)
        self.info_panel = QInfoPanel(self.game)

        hbox = QSplitter(Qt.Horizontal)
        hbox.addWidget(self.info_panel)
        hbox.addWidget(self.liberation_map)
        hbox.setSizes([2, 8])

        vbox = QVBoxLayout()
        vbox.setMargin(0)
        vbox.addWidget(QTopPanel(self.game))
        vbox.addWidget(hbox)

        central_widget = QWidget()
        central_widget.setLayout(vbox)
        self.setCentralWidget(central_widget)

    def connectSignals(self):
        GameUpdateSignal.get_instance().gameupdated.connect(self.setGame)
        GameUpdateSignal.get_instance().debriefingReceived.connect(
            self.onDebriefing)

    def initActions(self):
        self.newGameAction = QAction("&New Game", self)
        self.newGameAction.setIcon(QIcon(CONST.ICONS["New"]))
        self.newGameAction.triggered.connect(self.newGame)
        self.newGameAction.setShortcut('CTRL+N')

        self.openAction = QAction("&Open", self)
        self.openAction.setIcon(QIcon(CONST.ICONS["Open"]))
        self.openAction.triggered.connect(self.openFile)
        self.openAction.setShortcut('CTRL+O')

        self.saveGameAction = QAction("&Save", self)
        self.saveGameAction.setIcon(QIcon(CONST.ICONS["Save"]))
        self.saveGameAction.triggered.connect(self.saveGame)
        self.saveGameAction.setShortcut('CTRL+S')

        self.saveAsAction = QAction("Save &As", self)
        self.saveAsAction.setIcon(QIcon(CONST.ICONS["Save"]))
        self.saveAsAction.triggered.connect(self.saveGameAs)
        self.saveAsAction.setShortcut('CTRL+A')

        self.showAboutDialogAction = QAction("&About DCS Liberation", self)
        self.showAboutDialogAction.setIcon(QIcon.fromTheme("help-about"))
        self.showAboutDialogAction.triggered.connect(self.showAboutDialog)

        self.showLiberationPrefDialogAction = QAction("&Preferences", self)
        self.showLiberationPrefDialogAction.setIcon(
            QIcon.fromTheme("help-about"))
        self.showLiberationPrefDialogAction.triggered.connect(
            self.showLiberationDialog)

    def initToolbar(self):
        self.tool_bar = self.addToolBar("File")
        self.tool_bar.addAction(self.newGameAction)
        self.tool_bar.addAction(self.openAction)
        self.tool_bar.addAction(self.saveGameAction)

    def initMenuBar(self):
        self.menu = self.menuBar()

        file_menu = self.menu.addMenu("&File")
        file_menu.addAction(self.newGameAction)
        file_menu.addAction(self.openAction)
        file_menu.addSeparator()
        file_menu.addAction(self.saveGameAction)
        file_menu.addAction(self.saveAsAction)
        file_menu.addSeparator()
        file_menu.addAction(self.showLiberationPrefDialogAction)
        file_menu.addSeparator()
        #file_menu.addAction("Close Current Game", lambda: self.closeGame()) # Not working
        file_menu.addAction("E&xit", lambda: self.exit())

        displayMenu = self.menu.addMenu("&Display")

        tg_cp_visibility = QAction('&Control Point', displayMenu)
        tg_cp_visibility.setCheckable(True)
        tg_cp_visibility.setChecked(True)
        tg_cp_visibility.toggled.connect(
            lambda: QLiberationMap.set_display_rule(
                "cp", tg_cp_visibility.isChecked()))

        tg_go_visibility = QAction('&Ground Objects', displayMenu)
        tg_go_visibility.setCheckable(True)
        tg_go_visibility.setChecked(True)
        tg_go_visibility.toggled.connect(
            lambda: QLiberationMap.set_display_rule(
                "go", tg_go_visibility.isChecked()))

        tg_line_visibility = QAction('&Lines', displayMenu)
        tg_line_visibility.setCheckable(True)
        tg_line_visibility.setChecked(True)
        tg_line_visibility.toggled.connect(
            lambda: QLiberationMap.set_display_rule(
                "lines", tg_line_visibility.isChecked()))

        tg_event_visibility = QAction('&Events', displayMenu)
        tg_event_visibility.setCheckable(True)
        tg_event_visibility.setChecked(True)
        tg_event_visibility.toggled.connect(
            lambda: QLiberationMap.set_display_rule(
                "events", tg_event_visibility.isChecked()))

        tg_sam_visibility = QAction('&SAM Range', displayMenu)
        tg_sam_visibility.setCheckable(True)
        tg_sam_visibility.setChecked(True)
        tg_sam_visibility.toggled.connect(
            lambda: QLiberationMap.set_display_rule(
                "sam", tg_sam_visibility.isChecked()))

        tg_flight_path_visibility = QAction('&Flight Paths', displayMenu)
        tg_flight_path_visibility.setCheckable(True)
        tg_flight_path_visibility.setChecked(False)
        tg_flight_path_visibility.toggled.connect(
            lambda: QLiberationMap.set_display_rule(
                "flight_paths", tg_flight_path_visibility.isChecked()))

        displayMenu.addAction(tg_go_visibility)
        displayMenu.addAction(tg_cp_visibility)
        displayMenu.addAction(tg_line_visibility)
        displayMenu.addAction(tg_event_visibility)
        displayMenu.addAction(tg_sam_visibility)
        displayMenu.addAction(tg_flight_path_visibility)

        help_menu = self.menu.addMenu("&Help")
        help_menu.addAction(
            "&Discord Server", lambda: webbrowser.open_new_tab(
                "https://" + "discord.gg" + "/" + "bKrt" + "rkJ"))
        help_menu.addAction(
            "&Github Repository", lambda: webbrowser.open_new_tab(
                "https://github.com/khopa/dcs_liberation"))
        help_menu.addAction(
            "&Releases", lambda: webbrowser.open_new_tab(
                "https://github.com/Khopa/dcs_liberation/releases"))
        help_menu.addAction("&Online Manual",
                            lambda: webbrowser.open_new_tab(URLS["Manual"]))
        help_menu.addAction(
            "&ED Forum Thread",
            lambda: webbrowser.open_new_tab(URLS["ForumThread"]))
        help_menu.addAction("Report an &issue",
                            lambda: webbrowser.open_new_tab(URLS["Issues"]))

        help_menu.addSeparator()
        help_menu.addAction(self.showAboutDialogAction)

    def newGame(self):
        wizard = NewGameWizard(self)
        wizard.show()
        wizard.accepted.connect(
            lambda: self.onGameGenerated(wizard.generatedGame))

    def openFile(self):
        file = QFileDialog.getOpenFileName(
            self,
            "Select game file to open",
            dir=persistency._dcs_saved_game_folder,
            filter="*.liberation")
        if file is not None:
            game = persistency.load_game(file[0])
            self.setGame(game)
            GameUpdateSignal.get_instance().updateGame(self.game)

    def saveGame(self):
        logging.info("Saving game")

        if self.game.savepath:
            persistency.save_game(self.game)
            GameUpdateSignal.get_instance().updateGame(self.game)
        else:
            self.saveGameAs()

    def saveGameAs(self):
        file = QFileDialog.getSaveFileName(
            self,
            "Save As",
            dir=persistency._dcs_saved_game_folder,
            filter="*.liberation")
        if file is not None:
            self.game.savepath = file[0]
            persistency.save_game(self.game)

    def onGameGenerated(self, game: Game):
        logging.info("On Game generated")
        self.game = game
        GameUpdateSignal.get_instance().updateGame(self.game)

    def closeGame(self):
        self.game = None
        GameUpdateSignal.get_instance().updateGame(self.game)

    def exit(self):
        sys.exit(0)

    def setGame(self, game: Game):
        self.game = game
        if self.info_panel:
            self.info_panel.setGame(game)

    def showAboutDialog(self):
        text = "<h3>DCS Liberation " + CONST.VERSION_STRING + "</h3>" + \
               "<b>Source code :</b> https://github.com/khopa/dcs_liberation" + \
               "<h4>Authors</h4>" + \
               "<p>DCS Liberation was originally developed by <b>shdwp</b>, DCS Liberation 2.0 is a partial rewrite based on this work by <b>Khopa</b>." \
               "<h4>Contributors</h4>" + \
               "shdwp, Khopa, Wrycu, calvinmorrow, JohanAberg, Deus, root0fall, Captain Cody" + \
               "<h4>Special Thanks  :</h4>" \
               "<b>rp-</b> <i>for the pydcs framework</i><br/>"\
               "<b>Grimes (mrSkortch)</b> & <b>Speed</b> <i>for the MIST framework</i><br/>"\
               "<b>Ciribob </b> <i>for the JTACAutoLase.lua script</i><br/>"
        about = QMessageBox()
        about.setWindowTitle("About DCS Liberation")
        about.setIcon(QMessageBox.Icon.Information)
        about.setText(text)
        logging.info(about.textFormat())
        about.exec_()

    def showLiberationDialog(self):
        self.subwindow = QLiberationPreferencesWindow()
        self.subwindow.show()

    def onDebriefing(self, debrief: DebriefingSignal):
        logging.info("On Debriefing")
        self.debriefing = QDebriefingWindow(debrief.debriefing,
                                            debrief.gameEvent, debrief.game)
        self.debriefing.show()
Ejemplo n.º 12
0
    def toolbar(self):
        toolbar = QToolBar("My main toolbar")
        toolbar.setIconSize(QSize(16, 16))
        self.addToolBar(toolbar)

        mouse = QAction(QIcon('./icons/icons-01.png'),
                        'mouse',
                        self,
                        checkable=True)
        mouse.setStatusTip('mouse')
        mouse.triggered.connect(lambda: self.set_pointer('mouse'))

        square = QAction(QIcon('./icons/icons_Square.png'),
                         'square',
                         self,
                         checkable=True)
        square.setStatusTip('square')
        square.triggered.connect(lambda: self.set_pointer('square'))

        circle = QAction(QIcon('./icons_Circle.png'),
                         'circle',
                         self,
                         checkable=True)
        circle.setStatusTip('circle')
        circle.triggered.connect(lambda: self.set_pointer('circle'))

        crosshair = QAction(QIcon('./icons/icons_Crosshair.png'),
                            'crosshair',
                            self,
                            checkable=True)
        crosshair.setStatusTip('crosshair')
        crosshair.triggered.connect(lambda: self.set_pointer('cross'))

        brush = QAction(QIcon('./icons/icons_Brush.png'),
                        'brush',
                        self,
                        checkable=True)
        brush.setStatusTip('crosshair')
        brush.triggered.connect(lambda: self.set_pointer('brush'))

        group = QActionGroup(self, exclusive=True)

        for action in (mouse, square, circle, crosshair, brush):
            toolbar.addAction(action)
            group.addAction(action)

        annotations = QAction(QIcon('./icons/icons_Circle.png'),
                              'Annot',
                              self,
                              checkable=True)
        annotations.setStatusTip('Toggle annotations')
        annotations.triggered.connect(self.toggel_annot)
        toolbar.addAction(annotations)

        clear = QAction(QIcon('./icons/icons_Square.png'), 'Clear', self)
        clear.setStatusTip('Clear annotations')
        clear.triggered.connect(self.clear_annot)
        toolbar.addAction(clear)

        self.setStatusBar(QStatusBar(self))
Ejemplo n.º 13
0
    def toolbar_menus(self):
        """ Affiche la barre d'icônes permettant de diriger les robots et de les sélectionner"""

        # Toolbar
        toolbar = QToolBar("Game toolbar")
        self.addToolBar(toolbar)

        # Flèche gauche
        button_West = QAction(QIcon(ICON_PATH + "arrow-180.png"), "West", self)
        button_West.setStatusTip("Aller à gauche")
        button_West.triggered.connect(self.onButtonWestClick)
        button_West.setCheckable(False)
        button_West.setShortcut(QKeySequence("Left"))
        toolbar.addAction(button_West)

        # Flèche droite
        button_East = QAction(QIcon(ICON_PATH + "arrow.png"), "Est", self)
        button_East.setStatusTip("Aller à droite")
        button_East.triggered.connect(self.onButtonEastClick)
        button_East.setCheckable(False)
        button_East.setShortcut(QKeySequence("Right"))
        toolbar.addAction(button_East)

        # Flèche Haut
        button_North = QAction(QIcon(ICON_PATH + "arrow-090.png"), "North",
                               self)
        button_North.setStatusTip("Aller vers le haut")
        button_North.triggered.connect(self.onButtonNorthClick)
        button_North.setCheckable(False)
        button_North.setShortcut(QKeySequence("Up"))
        toolbar.addAction(button_North)

        # Flèche Bas
        button_South = QAction(QIcon(ICON_PATH + "arrow-270.png"), "South",
                               self)
        button_South.setStatusTip("Aller vers le Bas")
        button_South.triggered.connect(self.onButtonSouthClick)
        button_South.setCheckable(False)
        button_South.setShortcut(QKeySequence("Down"))
        toolbar.addAction(button_South)

        # Selection robot actif
        button_Red = QPushButton("&Red")
        button_Red.setIcon(QIcon(ICON_PATH + "icon_R.png"))
        button_Red.setAutoExclusive(True)
        button_Red.setCheckable(True)
        button_Red.setShortcut(QKeySequence("R"))
        button_Red.toggled.connect(self.onButtonRedClick)

        button_Green = QPushButton("&Green")
        button_Green.setIcon(QIcon(ICON_PATH + "icon_G.png"))
        button_Green.setAutoExclusive(True)
        button_Green.setCheckable(True)
        button_Green.setShortcut(QKeySequence("G"))
        button_Green.toggled.connect(self.onButtonGreenClick)

        button_Blue = QPushButton("&Blue")
        button_Blue.setIcon(QIcon(ICON_PATH + "icon_B.png"))
        button_Blue.setAutoExclusive(True)
        button_Blue.setCheckable(True)
        button_Blue.setShortcut(QKeySequence("B"))
        button_Blue.toggled.connect(self.onButtonBlueClick)

        button_Yellow = QPushButton("&Yellow")
        button_Yellow.setIcon(QIcon(ICON_PATH + "icon_Y.png"))
        button_Yellow.setAutoExclusive(True)
        button_Yellow.setCheckable(True)
        button_Yellow.setShortcut(QKeySequence("Y"))
        button_Yellow.toggled.connect(self.onButtonYellowClick)

        # Boutton d'annulation (revient en arrière d'un coup)
        button_undo = QPushButton("&Undo")
        button_undo.setIcon(QIcon(ICON_PATH + "undo.jpg"))
        button_undo.setAutoExclusive(False)
        button_undo.setCheckable(False)
        button_undo.setShortcut(QKeySequence("U"))
        button_undo.clicked.connect(self.onButtonUndoClick)

        # Boutton d'indice : lance le solveur pour donner l'indice du prochain coup à effectuer
        button_tip = QPushButton("&Tip")
        button_tip.setIcon(QIcon(ICON_PATH + "icon_tip.png"))
        button_tip.setAutoExclusive(False)
        button_tip.setCheckable(False)
        button_tip.setShortcut(QKeySequence("T"))
        button_tip.clicked.connect(self.onButtonTipClick)

        # Boutton Solution : lance le solveur pour afficher une liste d'actions à effectuer pour résoudre le jeu
        button_solution = QPushButton("&Solution")
        button_solution.setIcon(QIcon(ICON_PATH + "icon_solution.png"))
        button_solution.setAutoExclusive(False)
        button_solution.setCheckable(False)
        button_solution.setShortcut(QKeySequence("S"))
        button_solution.clicked.connect(self.onButtonSolutionClick)

        toolbar.addWidget(button_Red)
        toolbar.addWidget(button_Green)
        toolbar.addWidget(button_Blue)
        toolbar.addWidget(button_Yellow)
        toolbar.addWidget(button_undo)
        toolbar.addWidget(button_tip)
        toolbar.addWidget(button_solution)
Ejemplo n.º 14
0
 def testNewCtor(self):
     o = QWidget()
     self._called = False
     myAction = QAction("&Quit", o, triggered=self._cb)
     myAction.trigger()
     self.assert_(self._called)
Ejemplo n.º 15
0
    def __init__(self, qt_application=None):
        self.qt_application = qt_application
        # 实例化配置管理类
        self.settings_manage = SettingsManage()
        self.__setting = self.settings_manage.get()

        # 实例化windows命令处理类
        self.wsl2 = WinCmd()

        # 初始化启动脚本
        if not isfile(self.wsl2.WSL_VBS_PATH):
            copyfile(self.wsl2.WSL_VBS_PATH_TEMP, self.wsl2.WSL_VBS_PATH)
        if not isfile(self.wsl2.WSL_BAT_PATH):
            self.settings_manage.save_file_content(
                self.wsl2.WSL_BAT_PATH,
                self.__setting.get('wsl_bat_content', ''))
        # 加载UI文件
        self.ui = QUiLoader().load(ResourcePath.resource_path('lib/wsl2.ui'))

        # 设置界面图标
        app_icon = QIcon(ResourcePath.resource_path("lib/logo.ico"))
        self.ui.setWindowIcon(app_icon)

        # 设置选中状态
        self.ui.auto_start_wsl.setChecked(
            self.__setting.get('auto_start_wsl', False))
        self.ui.fire_wall_open.setChecked(
            self.__setting.get('fire_wall_open', False))
        self.ui.fire_wall_close.setChecked(
            self.__setting.get('fire_wall_close', False))

        # 设置文本框的值
        self.ui.port_text.appendPlainText('\n'.join(
            self.__setting.get('ports', [])))
        self.ui.bat_text.appendPlainText(self.wsl2.get_bat_script())

        # 按钮监听
        self.ui.get_wsl2_ip.clicked.connect(self.__get_wsl2_ip)
        self.ui.port_add.clicked.connect(self.__port_add)
        self.ui.port_del.clicked.connect(self.__port_del)
        self.ui.port_info.clicked.connect(self.__port_info)
        self.ui.wsl_l_v.clicked.connect(self.__wsl_l_v)
        self.ui.port_reset.clicked.connect(self.__port_reset)
        self.ui.end_wsl.clicked.connect(self.__end_wsl)
        self.ui.start_wsl.clicked.connect(self.__start_wsl)
        self.ui.start_wsl_all.clicked.connect(self.start_wsl_all)
        self.ui.save_settings.clicked.connect(self.__save_settings)
        self.ui.save_settings_ports.clicked.connect(self.__save_settings)

        # 设置系统托盘图标的菜单
        tp_icon = QIcon(ResourcePath.resource_path("lib/logo.ico"))
        self.tp = QSystemTrayIcon(self.ui)
        self.tp.setIcon(tp_icon)

        self.ui_hide = QAction(icon=tp_icon,
                               text='隐藏(Hide)',
                               triggered=self.ui.hide)
        self.ui_show = QAction(icon=tp_icon,
                               text='显示(Show)',
                               triggered=self.ui.show)
        self.ui_exit = QAction(icon=tp_icon,
                               text='退出(Exit)',
                               triggered=self.__quit_app)
        self.tp_menu = QMenu()
        self.tp_menu.addAction(self.ui_hide)
        self.tp_menu.addAction(self.ui_show)
        self.tp_menu.addAction(self.ui_exit)
        self.tp.setContextMenu(self.tp_menu)
        self.tp.activated.connect(self.__tp_connect_action)
        self.tp.show()
        self.tp.showMessage('WSL2AutoPortForward', 'WSL2端口自动转发工具已启动',
                            QSystemTrayIcon.MessageIcon.Information)
Ejemplo n.º 16
0
    def setUpMenus(self) -> None:
        menuBar = QMenuBar()
        fileMenu = menuBar.addMenu('File')
        importMenu = fileMenu.addMenu('Import')
        exportMenu = fileMenu.addMenu('Export')
        flowMenu = menuBar.addMenu('Flow')
        viewMenu = menuBar.addMenu('View')
        helpMenu = menuBar.addMenu('Help')
        aAppendEmpty = QAction('Add frame', fileMenu)
        aAppendEmpty.setStatusTip('Create an empty dataframe in the workbench')
        aQuit = QAction('Quit', fileMenu)
        aLoadCsv = OperationAction(CsvLoader, fileMenu, 'From csv',
                                   self.rect().center(),
                                   self.centralWidget().workbenchModel)
        self.aWriteCsv = OperationAction(CsvWriter,
                                         fileMenu,
                                         'To csv',
                                         self.rect().center(),
                                         w=self.centralWidget().workbenchModel)
        aLoadPickle = OperationAction(PickleLoader, fileMenu, 'From pickle',
                                      self.rect().center(),
                                      self.centralWidget().workbenchModel)
        self.aWritePickle = OperationAction(
            PickleWriter,
            fileMenu,
            'To pickle',
            self.mapToGlobal(self.rect().center()),
            w=self.centralWidget().workbenchModel)
        aCompareFrames = QAction('Compare dataframes', viewMenu)
        aLogDir = QAction('Open log directory', helpMenu)
        aClearLogs = QAction('Delete old logs', helpMenu)
        fileMenu.addActions([aAppendEmpty, aQuit])
        exportMenu.addActions([self.aWriteCsv, self.aWritePickle])
        importMenu.addActions([aLoadCsv, aLoadPickle])

        self._aStartFlow = QAction('Execute', flowMenu)
        self._aResetFlow = QAction('Reset', flowMenu)
        aSaveFlow = QAction('Save', flowMenu)
        aLoadFlow = QAction('Load', flowMenu)
        flowMenu.addActions(
            [self._aStartFlow, self._aResetFlow, aSaveFlow, aLoadFlow])
        viewMenu.addAction(aCompareFrames)
        helpMenu.addActions([aLogDir, aClearLogs])

        self.setMenuBar(menuBar)

        # Tips
        aLoadCsv.setStatusTip('Load a csv file in the workbench')
        aLoadPickle.setStatusTip('Load a Pickle file in the workbench')
        self.aWriteCsv.setStatusTip('Write a dataframe to a csv file')
        self.aWritePickle.setStatusTip(
            'Serializes a dataframe into a pickle file')
        aCompareFrames.setStatusTip('Open two dataframes side by side')
        self._aStartFlow.setStatusTip('Start flow-graph execution')
        self._aResetFlow.setStatusTip('Reset the node status in flow-graph')
        aLogDir.setStatusTip('Open the folder containing all logs')
        aClearLogs.setStatusTip('Delete older logs and keep the last 5')

        # Connect
        aAppendEmpty.triggered.connect(
            self.centralWidget().workbenchModel.appendEmptyRow)
        aQuit.triggered.connect(self.close)
        self._aStartFlow.triggered.connect(
            self.centralWidget().controller.executeFlow)
        self._aResetFlow.triggered.connect(
            self.centralWidget().controller.resetFlowStatus)
        aCompareFrames.triggered.connect(self.openComparePanel)
        aLogDir.triggered.connect(self.openLogDirectory)
        aClearLogs.triggered.connect(self.clearLogDir)
        aSaveFlow.triggered.connect(self.saveFlow)
        aLoadFlow.triggered.connect(self.readFlow)

        aLoadCsv.stateChanged.connect(self.operationStateChanged)
        aLoadPickle.stateChanged.connect(self.operationStateChanged)
        self.aWriteCsv.stateChanged.connect(self.operationStateChanged)
        self.aWritePickle.stateChanged.connect(self.operationStateChanged)
Ejemplo n.º 17
0
class MainWindow(QMainWindow):
    def __init__(self):
        super(MainWindow, self).__init__()

        self.mdiArea = QMdiArea()
        self.mdiArea.setHorizontalScrollBarPolicy(Qt.ScrollBarAsNeeded)
        self.mdiArea.setVerticalScrollBarPolicy(Qt.ScrollBarAsNeeded)
        self.setCentralWidget(self.mdiArea)

        self.mdiArea.subWindowActivated.connect(self.updateMenus)
        self.windowMapper = QSignalMapper(self)
        self.windowMapper.mapped[QWidget].connect(self.setActiveSubWindow)

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

        self.readSettings()

        self.setWindowTitle("MDI")

    def closeEvent(self, event):
        self.mdiArea.closeAllSubWindows()
        if self.mdiArea.currentSubWindow():
            event.ignore()
        else:
            self.writeSettings()
            event.accept()

    def newFile(self):
        child = self.createMdiChild()
        child.newFile()
        child.show()

    def open(self):
        fileName, _ = QFileDialog.getOpenFileName(self)
        if fileName:
            existing = self.findMdiChild(fileName)
            if existing:
                self.mdiArea.setActiveSubWindow(existing)
                return

            child = self.createMdiChild()
            if child.loadFile(fileName):
                self.statusBar().showMessage("File loaded", 2000)
                child.show()
            else:
                child.close()

    def save(self):
        if self.activeMdiChild() and self.activeMdiChild().save():
            self.statusBar().showMessage("File saved", 2000)

    def saveAs(self):
        if self.activeMdiChild() and self.activeMdiChild().saveAs():
            self.statusBar().showMessage("File saved", 2000)

    def cut(self):
        if self.activeMdiChild():
            self.activeMdiChild().cut()

    def copy(self):
        if self.activeMdiChild():
            self.activeMdiChild().copy()

    def paste(self):
        if self.activeMdiChild():
            self.activeMdiChild().paste()

    def about(self):
        QMessageBox.about(self, "About MDI",
                "The <b>MDI</b> example demonstrates how to write multiple "
                "document interface applications using Qt.")

    def updateMenus(self):
        hasMdiChild = (self.activeMdiChild() is not None)
        self.saveAct.setEnabled(hasMdiChild)
        self.saveAsAct.setEnabled(hasMdiChild)
        self.pasteAct.setEnabled(hasMdiChild)
        self.closeAct.setEnabled(hasMdiChild)
        self.closeAllAct.setEnabled(hasMdiChild)
        self.tileAct.setEnabled(hasMdiChild)
        self.cascadeAct.setEnabled(hasMdiChild)
        self.nextAct.setEnabled(hasMdiChild)
        self.previousAct.setEnabled(hasMdiChild)
        self.separatorAct.setVisible(hasMdiChild)

        hasSelection = (self.activeMdiChild() is not None and
                        self.activeMdiChild().textCursor().hasSelection())
        self.cutAct.setEnabled(hasSelection)
        self.copyAct.setEnabled(hasSelection)

    def updateWindowMenu(self):
        self.windowMenu.clear()
        self.windowMenu.addAction(self.closeAct)
        self.windowMenu.addAction(self.closeAllAct)
        self.windowMenu.addSeparator()
        self.windowMenu.addAction(self.tileAct)
        self.windowMenu.addAction(self.cascadeAct)
        self.windowMenu.addSeparator()
        self.windowMenu.addAction(self.nextAct)
        self.windowMenu.addAction(self.previousAct)
        self.windowMenu.addAction(self.separatorAct)

        windows = self.mdiArea.subWindowList()
        self.separatorAct.setVisible(len(windows) != 0)

        for i, window in enumerate(windows):
            child = window.widget()

            text = "%d %s" % (i + 1, child.userFriendlyCurrentFile())
            if i < 9:
                text = '&' + text

            action = self.windowMenu.addAction(text)
            action.setCheckable(True)
            action.setChecked(child is self.activeMdiChild())
            action.triggered.connect(self.windowMapper.map)
            self.windowMapper.setMapping(action, window)

    def createMdiChild(self):
        child = MdiChild()
        self.mdiArea.addSubWindow(child)

        child.copyAvailable.connect(self.cutAct.setEnabled)
        child.copyAvailable.connect(self.copyAct.setEnabled)

        return child

    def createActions(self):

        self.newAct = QAction(QIcon.fromTheme("document-new", QIcon(':/images/new.png')), "&New", self,
                shortcut=QKeySequence.New, statusTip="Create a new file",
                triggered=self.newFile)

        self.openAct = QAction(QIcon.fromTheme("document-open", QIcon(':/images/open.png')), "&Open...", self,
                shortcut=QKeySequence.Open, statusTip="Open an existing file",
                triggered=self.open)

        self.saveAct = QAction(QIcon.fromTheme("document-save", QIcon(':/images/save.png')), "&Save", self,
                shortcut=QKeySequence.Save,
                statusTip="Save the document to disk", triggered=self.save)

        self.saveAsAct = QAction("Save &As...", self,
                shortcut=QKeySequence.SaveAs,
                statusTip="Save the document under a new name",
                triggered=self.saveAs)

        self.exitAct = QAction("E&xit", self, shortcut=QKeySequence.Quit,
                statusTip="Exit the application",
                triggered=QApplication.instance().closeAllWindows)

        self.cutAct = QAction(QIcon.fromTheme("edit-cut", QIcon(':/images/cut.png')), "Cu&t", self,
                shortcut=QKeySequence.Cut,
                statusTip="Cut the current selection's contents to the clipboard",
                triggered=self.cut)

        self.copyAct = QAction(QIcon.fromTheme("edit-copy", QIcon(':/images/copy.png')), "&Copy", self,
                shortcut=QKeySequence.Copy,
                statusTip="Copy the current selection's contents to the clipboard",
                triggered=self.copy)

        self.pasteAct = QAction(QIcon.fromTheme("edit-paste", QIcon(':/images/paste.png')), "&Paste", self,
                shortcut=QKeySequence.Paste,
                statusTip="Paste the clipboard's contents into the current selection",
                triggered=self.paste)

        self.closeAct = QAction("Cl&ose", self,
                statusTip="Close the active window",
                triggered=self.mdiArea.closeActiveSubWindow)

        self.closeAllAct = QAction("Close &All", self,
                statusTip="Close all the windows",
                triggered=self.mdiArea.closeAllSubWindows)

        self.tileAct = QAction("&Tile", self, statusTip="Tile the windows",
                triggered=self.mdiArea.tileSubWindows)

        self.cascadeAct = QAction("&Cascade", self,
                statusTip="Cascade the windows",
                triggered=self.mdiArea.cascadeSubWindows)

        self.nextAct = QAction("Ne&xt", self, shortcut=QKeySequence.NextChild,
                statusTip="Move the focus to the next window",
                triggered=self.mdiArea.activateNextSubWindow)

        self.previousAct = QAction("Pre&vious", self,
                shortcut=QKeySequence.PreviousChild,
                statusTip="Move the focus to the previous window",
                triggered=self.mdiArea.activatePreviousSubWindow)

        self.separatorAct = QAction(self)
        self.separatorAct.setSeparator(True)

        self.aboutAct = QAction("&About", self,
                statusTip="Show the application's About box",
                triggered=self.about)

        self.aboutQtAct = QAction("About &Qt", self,
                statusTip="Show the Qt library's About box",
                triggered=QApplication.instance().aboutQt)

    def createMenus(self):
        self.fileMenu = self.menuBar().addMenu("&File")
        self.fileMenu.addAction(self.newAct)
        self.fileMenu.addAction(self.openAct)
        self.fileMenu.addAction(self.saveAct)
        self.fileMenu.addAction(self.saveAsAct)
        self.fileMenu.addSeparator()
        action = self.fileMenu.addAction("Switch layout direction")
        action.triggered.connect(self.switchLayoutDirection)
        self.fileMenu.addAction(self.exitAct)

        self.editMenu = self.menuBar().addMenu("&Edit")
        self.editMenu.addAction(self.cutAct)
        self.editMenu.addAction(self.copyAct)
        self.editMenu.addAction(self.pasteAct)

        self.windowMenu = self.menuBar().addMenu("&Window")
        self.updateWindowMenu()
        self.windowMenu.aboutToShow.connect(self.updateWindowMenu)

        self.menuBar().addSeparator()

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

    def createToolBars(self):
        self.fileToolBar = self.addToolBar("File")
        self.fileToolBar.addAction(self.newAct)
        self.fileToolBar.addAction(self.openAct)
        self.fileToolBar.addAction(self.saveAct)

        self.editToolBar = self.addToolBar("Edit")
        self.editToolBar.addAction(self.cutAct)
        self.editToolBar.addAction(self.copyAct)
        self.editToolBar.addAction(self.pasteAct)

    def createStatusBar(self):
        self.statusBar().showMessage("Ready")

    def readSettings(self):
        settings = QSettings('Trolltech', 'MDI Example')
        pos = settings.value('pos', QPoint(200, 200))
        size = settings.value('size', QSize(400, 400))
        self.move(pos)
        self.resize(size)

    def writeSettings(self):
        settings = QSettings('Trolltech', 'MDI Example')
        settings.setValue('pos', self.pos())
        settings.setValue('size', self.size())

    def activeMdiChild(self):
        activeSubWindow = self.mdiArea.activeSubWindow()
        if activeSubWindow:
            return activeSubWindow.widget()
        return None

    def findMdiChild(self, fileName):
        canonicalFilePath = QFileInfo(fileName).canonicalFilePath()

        for window in self.mdiArea.subWindowList():
            if window.widget().currentFile() == canonicalFilePath:
                return window
        return None

    def switchLayoutDirection(self):
        if self.layoutDirection() == Qt.LeftToRight:
            QApplication.setLayoutDirection(Qt.RightToLeft)
        else:
            QApplication.setLayoutDirection(Qt.LeftToRight)

    def setActiveSubWindow(self, window):
        if window:
            self.mdiArea.setActiveSubWindow(window)
Ejemplo n.º 18
0
 def do_add_action(self, name):
     action = QAction(name, self.menu)
     self.menu.insertAction(self.sep, action)
     action.setCheckable(True)
     self.actGroup.addAction(action)
     return action
Ejemplo n.º 19
0
    def createActions(self):

        self.newAct = QAction(QIcon.fromTheme("document-new", QIcon(':/images/new.png')), "&New", self,
                shortcut=QKeySequence.New, statusTip="Create a new file",
                triggered=self.newFile)

        self.openAct = QAction(QIcon.fromTheme("document-open", QIcon(':/images/open.png')), "&Open...", self,
                shortcut=QKeySequence.Open, statusTip="Open an existing file",
                triggered=self.open)

        self.saveAct = QAction(QIcon.fromTheme("document-save", QIcon(':/images/save.png')), "&Save", self,
                shortcut=QKeySequence.Save,
                statusTip="Save the document to disk", triggered=self.save)

        self.saveAsAct = QAction("Save &As...", self,
                shortcut=QKeySequence.SaveAs,
                statusTip="Save the document under a new name",
                triggered=self.saveAs)

        self.exitAct = QAction("E&xit", self, shortcut=QKeySequence.Quit,
                statusTip="Exit the application",
                triggered=QApplication.instance().closeAllWindows)

        self.cutAct = QAction(QIcon.fromTheme("edit-cut", QIcon(':/images/cut.png')), "Cu&t", self,
                shortcut=QKeySequence.Cut,
                statusTip="Cut the current selection's contents to the clipboard",
                triggered=self.cut)

        self.copyAct = QAction(QIcon.fromTheme("edit-copy", QIcon(':/images/copy.png')), "&Copy", self,
                shortcut=QKeySequence.Copy,
                statusTip="Copy the current selection's contents to the clipboard",
                triggered=self.copy)

        self.pasteAct = QAction(QIcon.fromTheme("edit-paste", QIcon(':/images/paste.png')), "&Paste", self,
                shortcut=QKeySequence.Paste,
                statusTip="Paste the clipboard's contents into the current selection",
                triggered=self.paste)

        self.closeAct = QAction("Cl&ose", self,
                statusTip="Close the active window",
                triggered=self.mdiArea.closeActiveSubWindow)

        self.closeAllAct = QAction("Close &All", self,
                statusTip="Close all the windows",
                triggered=self.mdiArea.closeAllSubWindows)

        self.tileAct = QAction("&Tile", self, statusTip="Tile the windows",
                triggered=self.mdiArea.tileSubWindows)

        self.cascadeAct = QAction("&Cascade", self,
                statusTip="Cascade the windows",
                triggered=self.mdiArea.cascadeSubWindows)

        self.nextAct = QAction("Ne&xt", self, shortcut=QKeySequence.NextChild,
                statusTip="Move the focus to the next window",
                triggered=self.mdiArea.activateNextSubWindow)

        self.previousAct = QAction("Pre&vious", self,
                shortcut=QKeySequence.PreviousChild,
                statusTip="Move the focus to the previous window",
                triggered=self.mdiArea.activatePreviousSubWindow)

        self.separatorAct = QAction(self)
        self.separatorAct.setSeparator(True)

        self.aboutAct = QAction("&About", self,
                statusTip="Show the application's About box",
                triggered=self.about)

        self.aboutQtAct = QAction("About &Qt", self,
                statusTip="Show the Qt library's About box",
                triggered=QApplication.instance().aboutQt)
Ejemplo n.º 20
0
class MainWindow(QMainWindow):
    def __init__(self, url):
        super(MainWindow, self).__init__()

        self.progress = 0

        fd = QFile(":/jquery.min.js")

        if fd.open(QIODevice.ReadOnly | QFile.Text):
            self.jQuery = QTextStream(fd).readAll()
            fd.close()
        else:
            self.jQuery = ''

        QNetworkProxyFactory.setUseSystemConfiguration(True)

        self.view = QWebView(self)
        self.view.load(url)
        self.view.loadFinished.connect(self.adjustLocation)
        self.view.titleChanged.connect(self.adjustTitle)
        self.view.loadProgress.connect(self.setProgress)
        self.view.loadFinished.connect(self.finishLoading)

        self.locationEdit = QLineEdit(self)
        self.locationEdit.setSizePolicy(QSizePolicy.Expanding,
                self.locationEdit.sizePolicy().verticalPolicy())
        self.locationEdit.returnPressed.connect(self.changeLocation)

        toolBar = self.addToolBar("Navigation")
        toolBar.addAction(self.view.pageAction(QWebPage.Back))
        toolBar.addAction(self.view.pageAction(QWebPage.Forward))
        toolBar.addAction(self.view.pageAction(QWebPage.Reload))
        toolBar.addAction(self.view.pageAction(QWebPage.Stop))
        toolBar.addWidget(self.locationEdit)

        viewMenu = self.menuBar().addMenu("&View")
        viewSourceAction = QAction("Page Source", self)
        viewSourceAction.triggered.connect(self.viewSource)
        viewMenu.addAction(viewSourceAction)

        effectMenu = self.menuBar().addMenu("&Effect")
        effectMenu.addAction("Highlight all links", self.highlightAllLinks)

        self.rotateAction = QAction(
                self.style().standardIcon(QStyle.SP_FileDialogDetailedView),
                "Turn images upside down", self, checkable=True)
        self.rotateAction.toggled.connect(self.rotateImages)
        effectMenu.addAction(self.rotateAction)

        toolsMenu = self.menuBar().addMenu("&Tools")
        toolsMenu.addAction("Remove GIF images", self.removeGifImages)
        toolsMenu.addAction("Remove all inline frames",
                self.removeInlineFrames)
        toolsMenu.addAction("Remove all object elements",
                self.removeObjectElements)
        toolsMenu.addAction("Remove all embedded elements",
                self.removeEmbeddedElements)
        self.setCentralWidget(self.view)

    def viewSource(self):
        accessManager = self.view.page().networkAccessManager()
        request = QNetworkRequest(self.view.url())
        reply = accessManager.get(request)
        reply.finished.connect(self.slotSourceDownloaded)

    def slotSourceDownloaded(self):
        reply = self.sender()
        self.textEdit = QTextEdit()
        self.textEdit.setAttribute(Qt.WA_DeleteOnClose)
        self.textEdit.show()
        self.textEdit.setPlainText(QTextStream(reply).readAll())
        self.textEdit.resize(600, 400)
        reply.deleteLater()

    def adjustLocation(self):
        self.locationEdit.setText(self.view.url().toString())

    def changeLocation(self):
        url = QUrl.fromUserInput(self.locationEdit.text())
        self.view.load(url)
        self.view.setFocus()

    def adjustTitle(self):
        if 0 < self.progress < 100:
            self.setWindowTitle("%s (%s%%)" % (self.view.title(), self.progress))
        else:
            self.setWindowTitle(self.view.title())

    def setProgress(self, p):
        self.progress = p
        self.adjustTitle()

    def finishLoading(self):
        self.progress = 100
        self.adjustTitle()
        self.view.page().mainFrame().evaluateJavaScript(self.jQuery)
        self.rotateImages(self.rotateAction.isChecked())

    def highlightAllLinks(self):
        code = """$('a').each(
                    function () {
                        $(this).css('background-color', 'yellow') 
                    } 
                  )"""
        self.view.page().mainFrame().evaluateJavaScript(code)

    def rotateImages(self, invert):
        if invert:
            code = """
                $('img').each(
                    function () {
                        $(this).css('-webkit-transition', '-webkit-transform 2s'); 
                        $(this).css('-webkit-transform', 'rotate(180deg)') 
                    } 
                )"""
        else:
            code = """
                $('img').each(
                    function () { 
                        $(this).css('-webkit-transition', '-webkit-transform 2s'); 
                        $(this).css('-webkit-transform', 'rotate(0deg)') 
                    } 
                )"""

        self.view.page().mainFrame().evaluateJavaScript(code)

    def removeGifImages(self):
        code = "$('[src*=gif]').remove()"
        self.view.page().mainFrame().evaluateJavaScript(code)

    def removeInlineFrames(self):
        code = "$('iframe').remove()"
        self.view.page().mainFrame().evaluateJavaScript(code)

    def removeObjectElements(self):
        code = "$('object').remove()"
        self.view.page().mainFrame().evaluateJavaScript(code)

    def removeEmbeddedElements(self):
        code = "$('embed').remove()"
        self.view.page().mainFrame().evaluateJavaScript(code)
Ejemplo n.º 21
0
class MainWindow(QMainWindow):
    def __init__(self):
        super(MainWindow, self).__init__()

        self.cameraInfo = QCameraInfo.defaultCamera()
        self.camera = QCamera(self.cameraInfo)
        self.camera.setCaptureMode(QCamera.CaptureStillImage)
        self.imageCapture = QCameraImageCapture(self.camera)
        self.imageCapture.imageCaptured.connect(self.imageCaptured)
        self.imageCapture.imageSaved.connect(self.imageSaved)
        self.currentPreview = QImage()

        toolBar = QToolBar()
        self.addToolBar(toolBar)

        fileMenu = self.menuBar().addMenu("&File")
        shutterIcon = QIcon(os.path.join(os.path.dirname(__file__),
                            "shutter.svg"))
        self.takePictureAction = QAction(shutterIcon, "&Take Picture", self,
                                         shortcut="Ctrl+T",
                                         triggered=self.takePicture)
        self.takePictureAction.setToolTip("Take Picture")
        fileMenu.addAction(self.takePictureAction)
        toolBar.addAction(self.takePictureAction)

        exitAction = QAction(QIcon.fromTheme("application-exit"), "E&xit",
                             self, shortcut="Ctrl+Q", triggered=self.close)
        fileMenu.addAction(exitAction)

        aboutMenu = self.menuBar().addMenu("&About")
        aboutQtAction = QAction("About &Qt", self, triggered=qApp.aboutQt)
        aboutMenu.addAction(aboutQtAction)

        self.tabWidget = QTabWidget()
        self.setCentralWidget(self.tabWidget)

        self.cameraViewfinder = QCameraViewfinder()
        self.camera.setViewfinder(self.cameraViewfinder)
        self.tabWidget.addTab(self.cameraViewfinder, "Viewfinder")

        if self.camera.status() != QCamera.UnavailableStatus:
            name = self.cameraInfo.description()
            self.setWindowTitle("PySide2 Camera Example (" + name + ")")
            self.statusBar().showMessage("Starting: '" + name + "'", 5000)
            self.camera.start()
        else:
            self.setWindowTitle("PySide2 Camera Example")
            self.takePictureAction.setEnabled(False)
            self.statusBar().showMessage("Camera unavailable", 5000)

    def nextImageFileName(self):
        picturesLocation = QStandardPaths.writableLocation(QStandardPaths.PicturesLocation)
        dateString = QDate.currentDate().toString("yyyyMMdd")
        pattern = picturesLocation + "/pyside2_camera_" + dateString + "_{:03d}.jpg"
        n = 1
        while True:
            result = pattern.format(n)
            if not os.path.exists(result):
                return result
            n = n + 1
        return None

    def takePicture(self):
        self.currentPreview = QImage()
        self.camera.searchAndLock()
        self.imageCapture.capture(self.nextImageFileName())
        self.camera.unlock()

    def imageCaptured(self, id, previewImage):
        self.currentPreview = previewImage

    def imageSaved(self, id, fileName):
        index = self.tabWidget.count()
        imageView = ImageView(self.currentPreview, fileName)
        self.tabWidget.addTab(imageView, "Capture #{}".format(index))
        self.tabWidget.setCurrentIndex(index)
Ejemplo n.º 22
0
    def initMenuBar(self):
        self.menu = self.menuBar()

        file_menu = self.menu.addMenu("&File")
        file_menu.addAction(self.newGameAction)
        file_menu.addAction(self.openAction)
        file_menu.addSeparator()
        file_menu.addAction(self.saveGameAction)
        file_menu.addAction(self.saveAsAction)
        file_menu.addSeparator()
        file_menu.addAction(self.showLiberationPrefDialogAction)
        file_menu.addSeparator()
        #file_menu.addAction("Close Current Game", lambda: self.closeGame()) # Not working
        file_menu.addAction("E&xit", lambda: self.exit())

        displayMenu = self.menu.addMenu("&Display")

        tg_cp_visibility = QAction('&Control Point', displayMenu)
        tg_cp_visibility.setCheckable(True)
        tg_cp_visibility.setChecked(True)
        tg_cp_visibility.toggled.connect(
            lambda: QLiberationMap.set_display_rule(
                "cp", tg_cp_visibility.isChecked()))

        tg_go_visibility = QAction('&Ground Objects', displayMenu)
        tg_go_visibility.setCheckable(True)
        tg_go_visibility.setChecked(True)
        tg_go_visibility.toggled.connect(
            lambda: QLiberationMap.set_display_rule(
                "go", tg_go_visibility.isChecked()))

        tg_line_visibility = QAction('&Lines', displayMenu)
        tg_line_visibility.setCheckable(True)
        tg_line_visibility.setChecked(True)
        tg_line_visibility.toggled.connect(
            lambda: QLiberationMap.set_display_rule(
                "lines", tg_line_visibility.isChecked()))

        tg_event_visibility = QAction('&Events', displayMenu)
        tg_event_visibility.setCheckable(True)
        tg_event_visibility.setChecked(True)
        tg_event_visibility.toggled.connect(
            lambda: QLiberationMap.set_display_rule(
                "events", tg_event_visibility.isChecked()))

        tg_sam_visibility = QAction('&SAM Range', displayMenu)
        tg_sam_visibility.setCheckable(True)
        tg_sam_visibility.setChecked(True)
        tg_sam_visibility.toggled.connect(
            lambda: QLiberationMap.set_display_rule(
                "sam", tg_sam_visibility.isChecked()))

        tg_flight_path_visibility = QAction('&Flight Paths', displayMenu)
        tg_flight_path_visibility.setCheckable(True)
        tg_flight_path_visibility.setChecked(False)
        tg_flight_path_visibility.toggled.connect(
            lambda: QLiberationMap.set_display_rule(
                "flight_paths", tg_flight_path_visibility.isChecked()))

        displayMenu.addAction(tg_go_visibility)
        displayMenu.addAction(tg_cp_visibility)
        displayMenu.addAction(tg_line_visibility)
        displayMenu.addAction(tg_event_visibility)
        displayMenu.addAction(tg_sam_visibility)
        displayMenu.addAction(tg_flight_path_visibility)

        help_menu = self.menu.addMenu("&Help")
        help_menu.addAction(
            "&Discord Server", lambda: webbrowser.open_new_tab(
                "https://" + "discord.gg" + "/" + "bKrt" + "rkJ"))
        help_menu.addAction(
            "&Github Repository", lambda: webbrowser.open_new_tab(
                "https://github.com/khopa/dcs_liberation"))
        help_menu.addAction(
            "&Releases", lambda: webbrowser.open_new_tab(
                "https://github.com/Khopa/dcs_liberation/releases"))
        help_menu.addAction("&Online Manual",
                            lambda: webbrowser.open_new_tab(URLS["Manual"]))
        help_menu.addAction(
            "&ED Forum Thread",
            lambda: webbrowser.open_new_tab(URLS["ForumThread"]))
        help_menu.addAction("Report an &issue",
                            lambda: webbrowser.open_new_tab(URLS["Issues"]))

        help_menu.addSeparator()
        help_menu.addAction(self.showAboutDialogAction)
Ejemplo n.º 23
0
class OpenProjectDialog(QDialog):
    """A dialog that let's user select a project to open either by choosing
    an old .proj file or by choosing a project directory."""
    def __init__(self, toolbox):
        """

        Args:
            toolbox (ToolboxUI): QMainWindow instance
        """
        from ..ui import open_project_dialog  # pylint: disable=import-outside-toplevel

        super().__init__(
            parent=toolbox,
            f=Qt.Dialog)  # Setting the parent inherits the stylesheet
        self._toolbox = toolbox
        # Set up the user interface from Designer file
        self.ui = open_project_dialog.Ui_Dialog()
        self.ui.setupUi(self)
        self.combobox_context_menu = None
        # Ensure this dialog is garbage-collected when closed
        self.setAttribute(Qt.WA_DeleteOnClose)
        # QActions for keyboard shortcuts
        self.go_root_action = QAction(self)
        self.go_home_action = QAction(self)
        self.go_documents_action = QAction(self)
        self.go_desktop_action = QAction(self)
        self.set_keyboard_shortcuts()
        self.selected_path = ""
        self.cb_ss = self.ui.comboBox_current_path.styleSheet()
        self.file_model = CustomQFileSystemModel()
        self.file_model.setFilter(QDir.AllDirs | QDir.NoDotAndDotDot)
        self.icon_provider = ProjectDirectoryIconProvider()
        self.file_model.setIconProvider(self.icon_provider)
        self.file_model.setRootPath(QDir.rootPath())
        self.ui.treeView_file_system.setModel(self.file_model)
        self.file_model.sort(0, Qt.AscendingOrder)
        # Enable validator (experimental, not very useful here)
        # Validator prevents typing Invalid strings to combobox. (not in use)
        # When text in combobox is Intermediate, the validator prevents emitting
        # currentIndexChanged signal when enter is pressed.
        # Pressing enter still triggers the done() slot of the QDialog.
        self.validator = DirValidator()
        self.ui.comboBox_current_path.setValidator(self.validator)
        self.ui.comboBox_current_path.setInsertPolicy(QComboBox.NoInsert)
        # Override QCombobox keyPressEvent to catch the Enter key press
        self.ui.comboBox_current_path.keyPressEvent = self.combobox_key_press_event
        # Read recent project directories and populate combobox
        recents = self._toolbox.qsettings().value(
            "appSettings/recentProjectStorages", defaultValue=None)
        if recents:
            recents_lst = str(recents).split("\n")
            self.ui.comboBox_current_path.insertItems(0, recents_lst)
            # Set start index to most recent project storage or to root if it does not exist
            p = self.ui.comboBox_current_path.itemText(0)
            if os.path.isdir(p):
                start_index = self.file_model.index(p)
            else:
                start_index = self.file_model.index(QDir.rootPath())
        else:
            start_index = self.file_model.index(QDir.rootPath())
            self.ui.comboBox_current_path.setCurrentIndex(-1)
        self.file_model.directoryLoaded.connect(self.expand_and_resize)
        # Start browsing to start index immediately when dialog is shown
        self.ui.treeView_file_system.setCurrentIndex(start_index)
        self.connect_signals()

    def set_keyboard_shortcuts(self):
        """Creates keyboard shortcuts for the 'Root', 'Home', etc. buttons."""
        self.go_root_action.setShortcut(QKeySequence(Qt.Key_F1))
        self.addAction(self.go_root_action)
        self.go_home_action.setShortcut(QKeySequence(Qt.Key_F2))
        self.addAction(self.go_home_action)
        self.go_documents_action.setShortcut(QKeySequence(Qt.Key_F3))
        self.addAction(self.go_documents_action)
        self.go_desktop_action.setShortcut(QKeySequence(Qt.Key_F4))
        self.addAction(self.go_desktop_action)

    def connect_signals(self):
        """Connects signals to slots."""
        self.ui.toolButton_root.clicked.connect(self.go_root)
        self.ui.toolButton_home.clicked.connect(self.go_home)
        self.ui.toolButton_documents.clicked.connect(self.go_documents)
        self.ui.toolButton_desktop.clicked.connect(self.go_desktop)
        self.ui.comboBox_current_path.editTextChanged.connect(
            self.combobox_text_edited)
        self.ui.comboBox_current_path.currentIndexChanged.connect(
            self.current_index_changed)
        self.ui.comboBox_current_path.customContextMenuRequested.connect(
            self.show_context_menu)
        self.validator.changed.connect(self.validator_state_changed)
        self.ui.treeView_file_system.clicked.connect(self.set_selected_path)
        self.ui.treeView_file_system.selectionModel().currentChanged.connect(
            self.current_changed)
        self.go_root_action.triggered.connect(self.go_root)
        self.go_home_action.triggered.connect(self.go_home)
        self.go_documents_action.triggered.connect(self.go_documents)
        self.go_desktop_action.triggered.connect(self.go_desktop)

    @Slot(str)
    def expand_and_resize(self, p):
        """Expands, resizes, and scrolls the tree view to the current directory
        when the file model has finished loading the path. Slot for the file
        model's directoryLoaded signal. The directoryLoaded signal is emitted only
        if the directory has not been cached already.

        Args:
             p (str): Directory that has been loaded
        """
        current_index = self.ui.treeView_file_system.currentIndex()
        self.ui.treeView_file_system.expand(current_index)
        self.ui.treeView_file_system.scrollTo(
            current_index, hint=QAbstractItemView.PositionAtTop)
        self.ui.treeView_file_system.resizeColumnToContents(0)
        self.set_selected_path(current_index)

    def combobox_key_press_event(self, e):
        """Interrupts Enter and Return key presses when QComboBox is in focus.
        This is needed to prevent showing the 'Not a valid Spine Toolbox project'
        Notifier every time Enter is pressed.

        Args:
            e (QKeyEvent): Received key press event.
        """
        if e.key() == Qt.Key_Enter or e.key() == Qt.Key_Return:
            state = self.ui.comboBox_current_path.validator().state
            fm_current_index = self.ui.treeView_file_system.currentIndex()
            if state == QValidator.Intermediate:
                # Remove path from qsettings
                self.remove_directory_from_recents(
                    os.path.abspath(self.selection()),
                    self._toolbox.qsettings())
                # Remove path from combobox as well
                cb_index = self.ui.comboBox_current_path.findText(
                    os.path.abspath(self.selection()))
                if cb_index == -1:
                    pass
                    # logging.error("{0} not found in combobox")
                else:
                    self.ui.comboBox_current_path.removeItem(cb_index)
                notification = Notification(self, "Path does not exist")
                notification.show()
            elif state == QValidator.Acceptable:
                p = self.ui.comboBox_current_path.currentText()
                fm_index = self.file_model.index(p)
                if not fm_current_index == fm_index:
                    self.ui.treeView_file_system.collapseAll()
                    self.ui.treeView_file_system.setCurrentIndex(fm_index)
                    self.ui.treeView_file_system.expand(fm_index)
                    self.ui.treeView_file_system.scrollTo(
                        fm_index, hint=QAbstractItemView.PositionAtTop)
                else:
                    project_json_fp = os.path.abspath(
                        os.path.join(self.selection(), ".spinetoolbox",
                                     "project.json"))
                    if os.path.isfile(project_json_fp):
                        self.done(QDialog.Accepted)
            else:
                # INVALID (or None). Happens if Enter key is pressed and the combobox text has not been edited yet.
                pass
            e.accept()
        else:
            QComboBox.keyPressEvent(self.ui.comboBox_current_path, e)

    @Slot()
    def validator_state_changed(self):
        """Changes the combobox border color according to the current state of the validator."""
        state = self.ui.comboBox_current_path.validator().state
        if state == QValidator.Acceptable:
            self.ui.comboBox_current_path.setStyleSheet(self.cb_ss)
        elif state == QValidator.Intermediate:
            ss = "QComboBox {border: 1px solid #ff704d}"
            self.ui.comboBox_current_path.setStyleSheet(ss)
        else:  # Invalid. This is never returned (on purpose).
            ss = "QComboBox {border: 1px solid #ff3300}"
            self.ui.comboBox_current_path.setStyleSheet(ss)

    @Slot(int)
    def current_index_changed(self, i):
        """Combobox selection changed. This slot is processed when a new item
        is selected from the drop-down list. This is not processed when new
        item txt is QValidotor.Intermediate.

        Args:
            i (int): Selected row in combobox
        """
        p = self.ui.comboBox_current_path.itemText(i)
        if not os.path.isdir(p):
            self.remove_directory_from_recents(p, self._toolbox.qsettings())
            return
        fm_index = self.file_model.index(p)
        self.ui.treeView_file_system.collapseAll()
        self.ui.treeView_file_system.setCurrentIndex(fm_index)
        self.ui.treeView_file_system.expand(fm_index)
        self.ui.treeView_file_system.scrollTo(
            fm_index, hint=QAbstractItemView.PositionAtTop)

    @Slot("QModelIndex", "QModelIndex", name="current_changed")
    def current_changed(self, current, previous):
        """Processed when the current item in file system tree view has been
        changed with keyboard or mouse. Updates the text in combobox.

        Args:
            current (QModelIndex): Currently selected index
            previous (QModelIndex): Previously selected index
        """
        self.set_selected_path(current)

    @Slot("QModelIndex", name="set_selected_path")
    def set_selected_path(self, index):
        """Sets the text in the combobox as the selected path in the file system tree view.

        Args:
            index (QModelIndex): The index which was mouse clicked.
        """
        if not index.isValid():
            return
        selected_path = os.path.abspath(self.file_model.filePath(index))
        self.ui.comboBox_current_path.setCurrentText(
            selected_path)  # Emits editTextChanged signal
        self.selected_path = selected_path

    @Slot(str)
    def combobox_text_edited(self, text):
        """Updates selected path when combobox text is edited.
        Note: pressing enter in combobox does not trigger this.
        """
        self.selected_path = text

    def selection(self):
        """Returns the selected path from dialog."""
        return os.path.abspath(self.selected_path)

    @Slot(bool, name="go_root")
    def go_root(self, checked=False):
        """Slot for the 'Root' button. Scrolls the treeview to show and select the user's root directory.

        Note: We need to expand and scroll the tree view here after setCurrentIndex
        just in case the directory has been loaded already.
        """
        self.ui.comboBox_current_path.setCurrentIndex(-1)
        root_index = self.file_model.index(QDir.rootPath())
        self.ui.treeView_file_system.collapseAll()
        self.ui.treeView_file_system.setCurrentIndex(root_index)
        self.ui.treeView_file_system.expand(root_index)
        self.ui.treeView_file_system.scrollTo(
            root_index, hint=QAbstractItemView.PositionAtTop)

    @Slot(bool, name="go_home")
    def go_home(self, checked=False):
        """Slot for the 'Home' button. Scrolls the treeview to show and select the user's home directory."""
        self.ui.comboBox_current_path.setCurrentIndex(-1)
        home_index = self.file_model.index(QDir.homePath())
        self.ui.treeView_file_system.collapseAll()
        self.ui.treeView_file_system.setCurrentIndex(home_index)
        self.ui.treeView_file_system.expand(home_index)
        self.ui.treeView_file_system.scrollTo(
            home_index, hint=QAbstractItemView.PositionAtTop)

    @Slot(bool, name="go_documents")
    def go_documents(self, checked=False):
        """Slot for the 'Documents' button. Scrolls the treeview to show and select the user's documents directory."""
        docs = QStandardPaths.writableLocation(
            QStandardPaths.DocumentsLocation)
        if not docs:
            return
        self.ui.comboBox_current_path.setCurrentIndex(-1)
        docs_index = self.file_model.index(docs)
        self.ui.treeView_file_system.collapseAll()
        self.ui.treeView_file_system.setCurrentIndex(docs_index)
        self.ui.treeView_file_system.expand(docs_index)
        self.ui.treeView_file_system.scrollTo(
            docs_index, hint=QAbstractItemView.PositionAtTop)

    @Slot(bool, name="go_desktop")
    def go_desktop(self, checked=False):
        """Slot for the 'Desktop' button. Scrolls the treeview to show and select the user's desktop directory."""
        desktop = QStandardPaths.writableLocation(
            QStandardPaths.DesktopLocation)  # Return a list
        if not desktop:
            return
        self.ui.comboBox_current_path.setCurrentIndex(-1)
        desktop_index = self.file_model.index(desktop)
        self.ui.treeView_file_system.collapseAll()
        self.ui.treeView_file_system.setCurrentIndex(desktop_index)
        self.ui.treeView_file_system.expand(desktop_index)
        self.ui.treeView_file_system.scrollTo(
            desktop_index, hint=QAbstractItemView.PositionAtTop)

    def done(self, r):
        """Checks that selected path exists and is a valid
        Spine Toolbox directory when ok button is clicked or
        when enter is pressed without the combobox being in focus.

        Args:
            r (int) Return code
        """
        if r == QDialog.Accepted:
            if not os.path.isdir(self.selection()):
                notification = Notification(self, "Path does not exist")
                notification.show()
                return
            project_json_fp = os.path.abspath(
                os.path.join(self.selection(), ".spinetoolbox",
                             "project.json"))
            if not os.path.isfile(project_json_fp):
                notification = Notification(
                    self, "Not a valid Spine Toolbox project")
                notification.show()
                return
            # self.selection() now contains a valid Spine Toolbox project directory.
            # Add the parent directory of selected directory to qsettings
            self.update_recents(
                os.path.abspath(os.path.join(self.selection(),
                                             os.path.pardir)),
                self._toolbox.qsettings())
        super().done(r)

    @staticmethod
    def update_recents(entry, qsettings):
        """Adds a new entry to QSettings variable that remembers the five most recent project storages.

        Args:
            entry (str): Abs. path to a directory that most likely contains other Spine Toolbox Projects as well.
                First entry is also used as the initial path for File->New Project dialog.
            qsettings (QSettings): Toolbox qsettings object
        """
        recents = qsettings.value("appSettings/recentProjectStorages",
                                  defaultValue=None)
        if not recents:
            updated_recents = entry
        else:
            recents = str(recents)
            recents_list = recents.split("\n")
            # Add path only if it's not in the list already
            if entry not in recents_list:
                recents_list.insert(0, entry)
                if len(recents_list) > 5:
                    recents_list.pop()
            else:
                # If entry was on the list, move it as the first item
                recents_list.insert(
                    0, recents_list.pop(recents_list.index(entry)))
            updated_recents = "\n".join(recents_list)
        # Save updated recent paths
        qsettings.setValue("appSettings/recentProjectStorages",
                           updated_recents)
        qsettings.sync()  # Commit change immediately

    @staticmethod
    def remove_directory_from_recents(p, qsettings):
        """Removes directory from the recent project storages.

        Args:
            p (str): Full path to a project directory
            qsettings (QSettings): Toolbox qsettings object
        """
        recents = qsettings.value("appSettings/recentProjectStorages",
                                  defaultValue=None)
        if not recents:
            return
        recents = str(recents)
        recents_list = recents.split("\n")
        if p in recents_list:
            recents_list.pop(recents_list.index(p))
        updated_recents = "\n".join(recents_list)
        # Save updated recent paths
        qsettings.setValue("appSettings/recentProjectStorages",
                           updated_recents)
        qsettings.sync()  # Commit change immediately

    @Slot("QPoint")
    def show_context_menu(self, pos):
        """Shows the context menu for the QCombobox with a 'Clear history' entry.

        Args:
            pos (QPoint): Mouse position
        """
        # ind = self.ui.comboBox_current_path.indexAt(pos)
        global_pos = self.ui.comboBox_current_path.mapToGlobal(pos)
        # if not ind.isValid():
        self.combobox_context_menu = OpenProjectDialogComboBoxContextMenu(
            self, global_pos)
        action = self.combobox_context_menu.get_action()
        if action == "Clear history":
            self.ui.comboBox_current_path.clear()
            self._toolbox.qsettings().setValue(
                "appSettings/recentProjectStorages", "")
            self.go_root()
        else:  # No option selected
            pass
        self.combobox_context_menu.deleteLater()
        self.combobox_context_menu = None

    def closeEvent(self, event=None):
        """Handles dialog closing.

        Args:
            event (QCloseEvent): Close event
        """
        if event:
            event.accept()
Ejemplo n.º 24
0
    def initActions(self):
        self.newGameAction = QAction("&New Game", self)
        self.newGameAction.setIcon(QIcon(CONST.ICONS["New"]))
        self.newGameAction.triggered.connect(self.newGame)
        self.newGameAction.setShortcut('CTRL+N')

        self.openAction = QAction("&Open", self)
        self.openAction.setIcon(QIcon(CONST.ICONS["Open"]))
        self.openAction.triggered.connect(self.openFile)
        self.openAction.setShortcut('CTRL+O')

        self.saveGameAction = QAction("&Save", self)
        self.saveGameAction.setIcon(QIcon(CONST.ICONS["Save"]))
        self.saveGameAction.triggered.connect(self.saveGame)
        self.saveGameAction.setShortcut('CTRL+S')

        self.saveAsAction = QAction("Save &As", self)
        self.saveAsAction.setIcon(QIcon(CONST.ICONS["Save"]))
        self.saveAsAction.triggered.connect(self.saveGameAs)
        self.saveAsAction.setShortcut('CTRL+A')

        self.showAboutDialogAction = QAction("&About DCS Liberation", self)
        self.showAboutDialogAction.setIcon(QIcon.fromTheme("help-about"))
        self.showAboutDialogAction.triggered.connect(self.showAboutDialog)

        self.showLiberationPrefDialogAction = QAction("&Preferences", self)
        self.showLiberationPrefDialogAction.setIcon(
            QIcon.fromTheme("help-about"))
        self.showLiberationPrefDialogAction.triggered.connect(
            self.showLiberationDialog)
Ejemplo n.º 25
0
    def __init__(self, toolbox):
        """

        Args:
            toolbox (ToolboxUI): QMainWindow instance
        """
        from ..ui import open_project_dialog  # pylint: disable=import-outside-toplevel

        super().__init__(
            parent=toolbox,
            f=Qt.Dialog)  # Setting the parent inherits the stylesheet
        self._toolbox = toolbox
        # Set up the user interface from Designer file
        self.ui = open_project_dialog.Ui_Dialog()
        self.ui.setupUi(self)
        self.combobox_context_menu = None
        # Ensure this dialog is garbage-collected when closed
        self.setAttribute(Qt.WA_DeleteOnClose)
        # QActions for keyboard shortcuts
        self.go_root_action = QAction(self)
        self.go_home_action = QAction(self)
        self.go_documents_action = QAction(self)
        self.go_desktop_action = QAction(self)
        self.set_keyboard_shortcuts()
        self.selected_path = ""
        self.cb_ss = self.ui.comboBox_current_path.styleSheet()
        self.file_model = CustomQFileSystemModel()
        self.file_model.setFilter(QDir.AllDirs | QDir.NoDotAndDotDot)
        self.icon_provider = ProjectDirectoryIconProvider()
        self.file_model.setIconProvider(self.icon_provider)
        self.file_model.setRootPath(QDir.rootPath())
        self.ui.treeView_file_system.setModel(self.file_model)
        self.file_model.sort(0, Qt.AscendingOrder)
        # Enable validator (experimental, not very useful here)
        # Validator prevents typing Invalid strings to combobox. (not in use)
        # When text in combobox is Intermediate, the validator prevents emitting
        # currentIndexChanged signal when enter is pressed.
        # Pressing enter still triggers the done() slot of the QDialog.
        self.validator = DirValidator()
        self.ui.comboBox_current_path.setValidator(self.validator)
        self.ui.comboBox_current_path.setInsertPolicy(QComboBox.NoInsert)
        # Override QCombobox keyPressEvent to catch the Enter key press
        self.ui.comboBox_current_path.keyPressEvent = self.combobox_key_press_event
        # Read recent project directories and populate combobox
        recents = self._toolbox.qsettings().value(
            "appSettings/recentProjectStorages", defaultValue=None)
        if recents:
            recents_lst = str(recents).split("\n")
            self.ui.comboBox_current_path.insertItems(0, recents_lst)
            # Set start index to most recent project storage or to root if it does not exist
            p = self.ui.comboBox_current_path.itemText(0)
            if os.path.isdir(p):
                start_index = self.file_model.index(p)
            else:
                start_index = self.file_model.index(QDir.rootPath())
        else:
            start_index = self.file_model.index(QDir.rootPath())
            self.ui.comboBox_current_path.setCurrentIndex(-1)
        self.file_model.directoryLoaded.connect(self.expand_and_resize)
        # Start browsing to start index immediately when dialog is shown
        self.ui.treeView_file_system.setCurrentIndex(start_index)
        self.connect_signals()
Ejemplo n.º 26
0
 def open_dcm_action(self):
     act = QAction(QIcon('exit.png'), 'Open dicom', self)
     act.setStatusTip('Open dicom images')
     act.triggered.connect(self.open_dcm)
     return act
Ejemplo n.º 27
0
    def create_management_actions(self):
        manageAct = QAction(QIcon("images/settings.png"),
                            self.tr("&Manage filters"), self)
        # manageAct.setShortcuts(QKeySequence.Open)
        manageAct.setStatusTip(self.tr("Manage added filters"))
        manageAct.triggered.connect(self.manage_filters)

        docker_conf_action = QAction(QIcon("images/docker.png"),
                                     self.tr("&Docker"), self)
        # docker_conf_action.setShortcuts()
        docker_conf_action.setStatusTip(self.tr("Docker"))
        docker_conf_action.triggered.connect(self.docker_conf)

        apparmor_conf_action = QAction(QIcon("images/apparmor.png"),
                                       self.tr("&Apparmor"), self)
        # apparmor_conf_action.setShortcuts()
        apparmor_conf_action.setStatusTip(self.tr("Apparmor"))
        apparmor_conf_action.triggered.connect(self.apparmor_conf)

        seccomp_conf_action = QAction(QIcon("images/lock.png"),
                                      self.tr("&Seccomp"), self)
        # docker_conf_action.setShortcuts()
        seccomp_conf_action.setStatusTip(self.tr("Seccomp"))
        seccomp_conf_action.triggered.connect(self.seccomp_conf)

        return [
            manageAct, docker_conf_action, apparmor_conf_action,
            seccomp_conf_action
        ]
Ejemplo n.º 28
0
    def __init__(self, owner):
        super(self.__class__, self).__init__(owner)
        Ui_download.__init__(self)
        self.setupUi(self)
        self.owner = weakref.ref(owner)
        self.downloadingList = []  # 正在下载列表
        self.downloadList = []  # 下载队列
        self.downloadDict = {}  # bookId :downloadInfo
        self.convertList = []
        self.convertingList = []

        self.tableWidget.horizontalHeader().setSectionResizeMode(
            QHeaderView.Stretch)
        self.tableWidget.setSelectionBehavior(QAbstractItemView.SelectRows)
        self.tableWidget.setEditTriggers(QAbstractItemView.NoEditTriggers)
        self.tableWidget.setContextMenuPolicy(Qt.CustomContextMenu)
        self.tableWidget.setColumnCount(10)
        self.tableWidget.setHorizontalHeaderLabels([
            "id", "标题", "下载状态", "下载进度", "下载章节", "下载速度", "转码进度", "转码章节", "转码耗时",
            "转码状态"
        ])

        self.timer = QTimer(self.tableWidget)
        self.timer.setInterval(1000)
        self.timer.timeout.connect(self.UpdateTable)
        self.timer.start()

        # self.settings = QSettings('download.ini', QSettings.IniFormat)
        # self.InitSetting()

        self.tableWidget.customContextMenuRequested.connect(self.SelectMenu)

        self.openDirAction = QAction("打开目录", self)
        self.openDirAction.triggered.connect(self.ClickOpenFilePath)

        self.pauseAction = QAction("暂停", self)
        self.pauseAction.triggered.connect(self.ClickPause)

        self.removeAction = QAction("刪除记录", self)
        self.removeAction.triggered.connect(self.DelRecording)

        self.removeFileAction = QAction("刪除记录和文件", self)
        self.removeFileAction.triggered.connect(self.DelRecordingAndFile)

        self.openDirAction = QAction("打开目录", self)
        self.openDirAction.triggered.connect(self.ClickOpenFilePath)

        self.selectEpsAction = QAction("选择下载章节", self)
        self.selectEpsAction.triggered.connect(self.ClickDownloadEps)

        self.startAction = QAction("开始", self)
        self.startAction.triggered.connect(self.ClickStart)

        self.startConvertAction = QAction("开始转码", self)
        self.startConvertAction.triggered.connect(self.ClickConvertStart)

        self.pauseConvertAction = QAction("暂停转码", self)
        self.pauseConvertAction.triggered.connect(self.ClickConvertPause)

        self.tableWidget.doubleClicked.connect(self.OpenBookInfo)

        self.tableWidget.horizontalHeader().sectionClicked.connect(self.Sort)
        self.order = {}

        self.autoConvert = True
        self.db = DownloadDb()

        datas = self.db.LoadDownload(self)
        for task in datas.values():
            self.downloadDict[task.bookId] = task
            rowCont = self.tableWidget.rowCount()
            task.tableRow = rowCont
            if task.status != DownloadInfo.Success:
                task.status = DownloadInfo.Pause
            if task.convertStatus != DownloadInfo.ConvertSuccess:
                task.convertStatus = DownloadInfo.Pause
            self.tableWidget.insertRow(rowCont)
            self.UpdateTableItem(task)
Ejemplo n.º 29
0
 def __init__(self):
     super().__init__()
     self.setWindowTitle("Cobaya input generator for Cosmology")
     self.setStyleSheet("* {font-size:%s;}" % font_size)
     # Menu bar for defaults
     self.menubar = QMenuBar()
     defaults_menu = self.menubar.addMenu(
         '&Show defaults and bibliography for a component...')
     menu_actions = {}
     for kind in kinds:
         submenu = defaults_menu.addMenu(subfolders[kind])
         components = get_available_internal_class_names(kind)
         menu_actions[kind] = {}
         for component in components:
             menu_actions[kind][component] = QAction(component, self)
             menu_actions[kind][component].setData((kind, component))
             menu_actions[kind][component].triggered.connect(
                 self.show_defaults)
             submenu.addAction(menu_actions[kind][component])
     # Main layout
     self.menu_layout = QVBoxLayout()
     self.menu_layout.addWidget(self.menubar)
     self.setLayout(self.menu_layout)
     self.layout = QHBoxLayout()
     self.menu_layout.addLayout(self.layout)
     self.layout_left = QVBoxLayout()
     self.layout.addLayout(self.layout_left)
     self.layout_output = QVBoxLayout()
     self.layout.addLayout(self.layout_output)
     # LEFT: Options
     self.options = QWidget()
     self.layout_options = QVBoxLayout()
     self.options.setLayout(self.layout_options)
     self.options_scroll = QScrollArea()
     self.options_scroll.setWidget(self.options)
     self.options_scroll.setWidgetResizable(True)
     self.layout_left.addWidget(self.options_scroll)
     self.combos = dict()
     for group, fields in _combo_dict_text:
         group_box = QGroupBox(group)
         self.layout_options.addWidget(group_box)
         group_layout = QVBoxLayout(group_box)
         for a, desc in fields:
             self.combos[a] = QComboBox()
             # Combo box label only if not single element in group
             if len(fields) > 1:
                 label = QLabel(desc)
                 group_layout.addWidget(label)
             group_layout.addWidget(self.combos[a])
             self.combos[a].addItems([
                 text(k, v) for k, v in getattr(input_database, a).items()
             ])
     # PLANCK NAMES CHECKBOX TEMPORARILY DISABLED
     #                if a == "theory":
     #                    # Add Planck-naming checkbox
     #                    self.planck_names = QCheckBox(
     #                        "Keep common parameter names "
     #                        "(useful for fast CLASS/CAMB switching)")
     #                    group_layout.addWidget(self.planck_names)
     # Connect to refreshers -- needs to be after adding all elements
     for field, combo in self.combos.items():
         if field == "preset":
             combo.currentIndexChanged.connect(self.refresh_preset)
         else:
             combo.currentIndexChanged.connect(self.refresh)
     #        self.planck_names.stateChanged.connect(self.refresh_keep_preset)
     # RIGHT: Output + buttons
     self.display_tabs = QTabWidget()
     self.display = {}
     for k in ["yaml", "python", "bibliography"]:
         self.display[k] = QTextEdit()
         self.display[k].setLineWrapMode(QTextEdit.NoWrap)
         self.display[k].setFontFamily("mono")
         self.display[k].setCursorWidth(0)
         self.display[k].setReadOnly(True)
         self.display_tabs.addTab(self.display[k], k)
     self.display["covmat"] = QWidget()
     covmat_tab_layout = QVBoxLayout()
     self.display["covmat"].setLayout(covmat_tab_layout)
     self.covmat_text = QLabel()
     self.covmat_text.setWordWrap(True)
     self.covmat_table = QTableWidget(0, 0)
     self.covmat_table.setEditTriggers(
         QAbstractItemView.NoEditTriggers)  # ReadOnly!
     covmat_tab_layout.addWidget(self.covmat_text)
     covmat_tab_layout.addWidget(self.covmat_table)
     self.display_tabs.addTab(self.display["covmat"], "covariance matrix")
     self.layout_output.addWidget(self.display_tabs)
     # Buttons
     self.buttons = QHBoxLayout()
     self.save_button = QPushButton('Save as...', self)
     self.copy_button = QPushButton('Copy to clipboard', self)
     self.buttons.addWidget(self.save_button)
     self.buttons.addWidget(self.copy_button)
     self.save_button.released.connect(self.save_file)
     self.copy_button.released.connect(self.copy_clipb)
     self.layout_output.addLayout(self.buttons)
     self.save_dialog = QFileDialog()
     self.save_dialog.setFileMode(QFileDialog.AnyFile)
     self.save_dialog.setAcceptMode(QFileDialog.AcceptSave)
     self.read_settings()
     self.show()
Ejemplo n.º 30
0
    def __init__(self, config):
        assertMainThread()
        super().__init__(config)

        # state
        self.preventSeek = False
        self.beginTime = None
        self.timeRatio = 1.0

        # gui
        srv = Services.getService("MainWindow")
        config.configLoaded.connect(self.restoreState)
        config.configAboutToSave.connect(self.saveState)
        self.config = config
        playbackMenu = srv.menuBar().addMenu("&Playback")

        style = QApplication.style()
        self.actStart = QAction(
            QIcon.fromTheme("media-playback-start",
                            style.standardIcon(QStyle.SP_MediaPlay)),
            "Start Playback", self)
        self.actPause = QAction(
            QIcon.fromTheme("media-playback-pause",
                            style.standardIcon(QStyle.SP_MediaPause)),
            "Pause Playback", self)
        self.actPause.setEnabled(False)
        self.actStepFwd = QAction(
            QIcon.fromTheme("media-seek-forward",
                            style.standardIcon(QStyle.SP_MediaSeekForward)),
            "Step Forward", self)
        self.actStepBwd = QAction(
            QIcon.fromTheme("media-seek-backward",
                            style.standardIcon(QStyle.SP_MediaSeekBackward)),
            "Step Backward", self)
        self.actSeekEnd = QAction(
            QIcon.fromTheme("media-skip-forward",
                            style.standardIcon(QStyle.SP_MediaSkipForward)),
            "Seek End", self)
        self.actSeekBegin = QAction(
            QIcon.fromTheme("media-skip-backward",
                            style.standardIcon(QStyle.SP_MediaSkipBackward)),
            "Seek Begin", self)
        self.actSetTimeFactor = {
            r: QAction("x 1/%d" %
                       (1 / r), self) if r < 1 else QAction("x %d" % r, self)
            for r in (1 / 8, 1 / 4, 1 / 2, 1, 2, 4, 8)
        }

        # pylint: disable=unnecessary-lambda
        # let's stay on the safe side and do not use emit as a slot...
        self.actStart.triggered.connect(self.startPlayback)
        self.actPause.triggered.connect(self.pausePlayback)
        self.actStepFwd.triggered.connect(
            lambda: self.stepForward(self.selectedStream()))
        self.actStepBwd.triggered.connect(
            lambda: self.stepBackward(self.selectedStream()))
        self.actSeekEnd.triggered.connect(self.seekEnd)
        self.actSeekBegin.triggered.connect(self.seekBeginning)

        # pylint: enable=unnecessary-lambda

        def setTimeFactor(newFactor):
            logger.debug("new time factor %f", newFactor)
            self.setTimeFactor(newFactor)

        for r in self.actSetTimeFactor:
            logger.debug("adding action for time factor %f", r)
            self.actSetTimeFactor[r].triggered.connect(
                functools.partial(setTimeFactor, r))

        self.dockWidget = srv.newDockWidget("PlaybackControl", None,
                                            Qt.LeftDockWidgetArea)
        self.dockWidgetContents = QWidget(self.dockWidget)
        self.dockWidget.setWidget(self.dockWidgetContents)
        toolLayout = QBoxLayout(QBoxLayout.TopToBottom,
                                self.dockWidgetContents)
        toolLayout.setContentsMargins(0, 0, 0, 0)
        toolBar = QToolBar()
        toolLayout.addWidget(toolBar)
        toolBar.addAction(self.actSeekBegin)
        toolBar.addAction(self.actStepBwd)
        toolBar.addAction(self.actStart)
        toolBar.addAction(self.actPause)
        toolBar.addAction(self.actStepFwd)
        toolBar.addAction(self.actSeekEnd)
        playbackMenu.addAction(self.actSeekBegin)
        playbackMenu.addAction(self.actStepBwd)
        playbackMenu.addAction(self.actStart)
        playbackMenu.addAction(self.actPause)
        playbackMenu.addAction(self.actStepFwd)
        playbackMenu.addAction(self.actSeekEnd)
        playbackMenu.addSeparator()
        for r in self.actSetTimeFactor:
            playbackMenu.addAction(self.actSetTimeFactor[r])
        self.timeRatioLabel = QLabel("x 1")
        self.timeRatioLabel.addActions(list(self.actSetTimeFactor.values()))
        self.timeRatioLabel.setContextMenuPolicy(Qt.ActionsContextMenu)
        toolBar.addSeparator()
        toolBar.addWidget(self.timeRatioLabel)
        contentsLayout = QGridLayout()
        toolLayout.addLayout(contentsLayout, 10)
        # now we add a position view
        self.positionSlider = QSlider(Qt.Horizontal, self.dockWidgetContents)
        self.beginLabel = QLabel(parent=self.dockWidgetContents)
        self.beginLabel.setAlignment(Qt.AlignLeft | Qt.AlignCenter)
        self.currentLabel = QLabel(parent=self.dockWidgetContents)
        self.currentLabel.setAlignment(Qt.AlignHCenter | Qt.AlignCenter)
        self.endLabel = QLabel(parent=self.dockWidgetContents)
        self.endLabel.setAlignment(Qt.AlignRight | Qt.AlignCenter)
        contentsLayout.addWidget(self.beginLabel, 0, 0, alignment=Qt.AlignLeft)
        contentsLayout.addWidget(self.currentLabel,
                                 0,
                                 1,
                                 alignment=Qt.AlignHCenter)
        contentsLayout.addWidget(self.endLabel, 0, 2, alignment=Qt.AlignRight)
        contentsLayout.addWidget(self.positionSlider, 1, 0, 1, 3)
        self.positionSlider.setTracking(False)
        self.positionSlider.valueChanged.connect(self.onSliderValueChanged,
                                                 Qt.DirectConnection)
        self.positionSlider.sliderMoved.connect(self.displayPosition)

        # file browser
        self.browser = BrowserWidget(self.dockWidget)
        self.nameFiltersChanged.connect(self._onNameFiltersChanged,
                                        Qt.QueuedConnection)
        contentsLayout.addWidget(self.browser, 3, 0, 1, 3)
        contentsLayout.setRowStretch(3, 100)
        self.browser.activated.connect(self.browserActivated)

        self.actShowAllFiles = QAction("Show all files")
        self.actShowAllFiles.setCheckable(True)
        self.actShowAllFiles.setChecked(False)
        self.actShowAllFiles.toggled.connect(self._onShowAllFiles)
        playbackMenu.addSeparator()
        playbackMenu.addAction(self.actShowAllFiles)

        self.actGroupStream = QActionGroup(self)
        self.actGroupStream.setExclusionPolicy(
            QActionGroup.ExclusionPolicy.ExclusiveOptional)
        playbackMenu.addSeparator()
        self.actGroupStreamMenu = playbackMenu.addMenu("Step Stream")
        self._selectedStream = None

        self.recentSeqs = [QAction() for i in range(10)]
        playbackMenu.addSeparator()
        recentMenu = playbackMenu.addMenu("Recent")
        for a in self.recentSeqs:
            a.setVisible(False)
            a.triggered.connect(self.openRecent)
            recentMenu.addAction(a)

        self._supportedFeaturesChanged(set(), set())
Ejemplo n.º 31
0
class MainWindow(QMainWindow):
    sequence_number = 1
    window_list = []
    dict_modified = False
    max_recent_files = 5

    def __init__(self, regex_map, file_name='', dict_src='regex_map.json'):
        super().__init__()

        self.setAttribute(Qt.WA_DeleteOnClose)
        self.is_untitled = True
        self.cur_file = ''
        self.dict_src = dict_src
        self.regex_map = regex_map
        self.text_edit = MyPlainTextEdit(regex_map)
        self.mode_label = QLabel('Insert Mode')
        self.mode_label.setAlignment(
            Qt.AlignRight
            | Qt.AlignVCenter)  # Prevents minor shift on toggling.
        self.md_text_edit = QTextEdit()
        self.md_text_edit.setReadOnly(True)
        self.setCentralWidget(self.text_edit)

        self.create_actions()
        self.create_menus()
        self.create_status_bar()
        self.create_dock_widget()

        QApplication.processEvents()  # fixes status bar color issue.

        self.read_settings(
        )  # must go after processEvents() or `size` is overwritten for some reason

        # self.text_edit.document().contentsChanged.connect(self.document_was_modified)
        self.text_edit.textChanged.connect(self.document_was_modified)
        self.text_edit.entry_default_set.connect(self.handle_entry_default_set)
        self.text_edit.mode_toggled.connect(self.mode_label.setText)

        if file_name:
            self.load_file(file_name)
        else:
            self.set_current_file('')

    def closeEvent(self, event):
        if self.maybe_save():
            self.write_settings()
            event.accept()
        else:
            event.ignore()

    def document_was_modified(self):
        self.setWindowModified(True)

    def update_markdown_viewer(self):
        """Updates contents and viewport of the dock widget."""
        self.md_text_edit.document().setMarkdown(
            self.text_edit.document().toPlainText())
        md_cur = self.md_text_edit.textCursor()
        md_cur.movePosition(QTextCursor.End)
        # This strategy could be problematic for large documents, as the lengths diverge. Not especially testable.
        md_cur.setPosition(
            min(md_cur.position(),
                self.text_edit.textCursor().position())
        )  # len(md) <= len(plaintext)
        self.md_text_edit.setTextCursor(md_cur)

    def new_file(self):
        other = MainWindow(self.regex_map)
        MainWindow.window_list.append(other)
        other.move(self.x() + 40, self.y() + 40)
        other.show()

    def open_file(self, file_name: str):
        """
        Handles opening a file: checking if already open, if we need a new MainWindow, or can safely overwrite.
        :param file_name: A canonical (or absolute?) file path.
        :return:
        """
        existing = self.find_main_window(file_name)
        if existing is not None:
            existing.show()
            existing.raise_()
            existing.activateWindow()
            return

        if self.is_untitled and self.text_edit.document().isEmpty(
        ) and not self.isWindowModified():
            self.load_file(file_name)
        else:
            other = MainWindow(self.regex_map, file_name)
            if other.is_untitled:  # impossible?
                del other
                return

            MainWindow.window_list.append(other)
            other.move(self.x() + 40, self.y() + 40)
            other.show()

    def open_recent(self):
        """Only use as slot for QAction with data() set to a canonical (or absolute?) file name."""
        # ref: https://stackoverflow.com/questions/21974449/extract-menu-action-data-in-receiving-function-or-slot
        action = self.sender()
        if action:
            self.open_file(action.data())

    def open(self):
        file_name, _ = QFileDialog.getOpenFileName(
            self, filter="Text files (*.txt *.md)")
        if file_name:
            self.open_file(file_name)

    def about(self):
        about_dialog = QMessageBox(QMessageBox.Information, "OneHandTextEdit",
                                   "<h2>OneHandTextEdit</h2>",
                                   QMessageBox.Close, self)
        # TODO: set in deploy
        # icon = QPixmap("/Users/Scott/Desktop/128.png")
        # if not icon.isNull():
        #     about_dialog.setIconPixmap(icon)
        about_dialog.setInformativeText("""
            <b>v 0.1.0</b>
            <br>
            license: <a href='https://www.gnu.org/licenses/gpl-3.0.txt'>GNU GPL 3.0</a>
            <br>
            inspiration: <a href='https://blog.xkcd.com/2007/08/14/mirrorboard-a-one-handed-keyboard-layout-for-the-lazy/'>xkcd</a>
            """)
        about_dialog.exec_()

    def print_(self, printer: QPrinter, text_edit: Union[QTextEdit,
                                                         MyPlainTextEdit]):
        """
        Prints text at any resolution with one-inch margins.

        :param printer: A configured printer (put through QPrintDialog probably)
        :param text_edit: The text editor.
        :return: None. Side-effect: Prints the document.
        """
        doc_clone = text_edit.document().clone()
        printer.setPageMargins(25.4, 25.4, 25.4, 25.4,
                               QPrinter.Millimeter)  # 1 inch margins
        doc_clone.documentLayout().setPaintDevice(printer)
        doc_clone.setPageSize(printer.pageRect().size())
        doc_clone.print_(printer)

    def print_with_setup(self, text_edit: Union[QTextEdit, MyPlainTextEdit]):
        """
        Get printer settings from the user, then print at High Resolution with those settings or cancel.

        :param text_edit: A text editor containing a `document()` QTextDocument.
        :return: None. Side effect: modal dialog, possibly printing.
        """
        if text_edit == self.md_text_edit:
            self.update_markdown_viewer()
        printer = QPrinter(QPrinter.HighResolution)
        print_dialog = QPrintDialog(printer, self)
        if print_dialog.exec_() == QDialog.Accepted:
            self.print_(printer, text_edit)

    def print_preview(self, text_edit: Union[QTextEdit, MyPlainTextEdit]):
        """
        Print preview a given text editor's `document()` at High Resolution.

        :param text_edit: A text editor containing a `document()` QTextDocument.
        :return: None. Side effect: modal print preview.
        """
        if text_edit == self.md_text_edit:
            self.update_markdown_viewer()
        printer = QPrinter(QPrinter.HighResolution)
        ppd = QPrintPreviewDialog(printer)
        ppd.paintRequested.connect(lambda: self.print_(printer, text_edit))
        ppd.exec_()

    # Format
    def set_markdown_font(self):
        (ok, font) = QFontDialog.getFont(self.md_text_edit.font(), self,
                                         "Markdown Font")
        self.md_text_edit.setFont(font)

    # noinspection PyAttributeOutsideInit
    def create_actions(self):
        # File
        self.new_act = QAction("&New",
                               self,
                               statusTip="Create a new file",
                               triggered=self.new_file)
        self.new_act.setShortcuts(
            [QKeySequence.New,
             QKeySequence(Qt.CTRL + Qt.Key_B)])

        self.open_act = QAction("&Open...",
                                self,
                                statusTip="Open an existing file",
                                triggered=self.open)
        self.open_act.setShortcuts(
            [QKeySequence.Open,
             QKeySequence(Qt.CTRL + Qt.Key_T)])

        self.save_act = QAction("&Save",
                                self,
                                statusTip="Save the document to disk",
                                triggered=self.save)
        self.save_act.setShortcuts(
            [QKeySequence.Save,
             QKeySequence(Qt.CTRL + Qt.Key_L)])

        self.save_as_act = QAction(
            "Save &As...",
            self,
            statusTip="Save the document under a new name",
            triggered=self.save_as)
        self.save_as_act.setShortcuts(
            [QKeySequence.SaveAs,
             QKeySequence(Qt.CTRL + Qt.SHIFT + Qt.Key_L)])

        self.recent_file_acts = []
        for i in range(MainWindow.max_recent_files):
            self.recent_file_acts.append(
                QAction(self, visible=False, triggered=self.open_recent))

        self.clear_recent_files_act = QAction(
            "Clear Menu",
            self,
            enabled=False,
            triggered=self.clear_recent_files)

        self.print_act = QAction("&Print...",
                                 self,
                                 statusTip="Print the document",
                                 triggered=functools.partial(
                                     self.print_with_setup,
                                     text_edit=self.text_edit))
        self.print_act.setShortcuts(
            [QKeySequence.Print,
             QKeySequence(Qt.CTRL + Qt.Key_R)])

        self.print_markdown_act = QAction("Print &Markdown...",
                                          self,
                                          triggered=functools.partial(
                                              self.print_with_setup,
                                              text_edit=self.md_text_edit))
        self.print_markdown_act.setShortcuts([
            QKeySequence(Qt.CTRL + Qt.SHIFT + Qt.Key_P),
            QKeySequence(Qt.CTRL + Qt.SHIFT + Qt.Key_R)
        ])

        self.print_preview_act = QAction("Print Preview...",
                                         self,
                                         triggered=functools.partial(
                                             self.print_preview,
                                             text_edit=self.text_edit))

        self.print_preview_markdown_act = QAction(
            "Print Markdown Preview...",
            self,
            triggered=functools.partial(self.print_preview,
                                        text_edit=self.md_text_edit))

        self.close_act = QAction("&Close",
                                 self,
                                 statusTip="Close this window",
                                 triggered=self.close)
        self.close_act.setShortcuts([
            QKeySequence(Qt.CTRL + Qt.Key_W),
            QKeySequence(Qt.CTRL + Qt.Key_BracketRight)
        ])

        self.exit_act = QAction(
            "E&xit",
            self,
            statusTip="Exit the application",
            triggered=QApplication.instance().closeAllWindows)
        self.exit_act.setShortcuts([
            QKeySequence(Qt.CTRL + Qt.Key_Q),
            QKeySequence(Qt.CTRL + Qt.Key_BracketLeft)
        ])

        # Edit
        self.undo_act = QAction("Undo",
                                self,
                                enabled=False,
                                triggered=self.text_edit.undo)
        self.undo_act.setShortcuts(
            [QKeySequence.Undo,
             QKeySequence(Qt.CTRL + Qt.Key_Slash)])

        self.redo_act = QAction("Redo",
                                self,
                                enabled=False,
                                triggered=self.text_edit.redo)
        self.redo_act.setShortcuts(
            [QKeySequence.Redo,
             QKeySequence(Qt.CTRL + Qt.Key_Y)])

        self.cut_act = QAction(
            "Cu&t",
            self,
            enabled=False,
            statusTip="Cut the current selection's contents to the clipboard",
            triggered=self.text_edit.cut)
        self.cut_act.setShortcuts(
            [QKeySequence.Cut,
             QKeySequence(Qt.CTRL + Qt.Key_Period)])

        self.copy_act = QAction(
            "&Copy",
            self,
            enabled=False,
            statusTip="Copy the current selection's contents to the clipboard",
            triggered=self.text_edit.copy)
        self.copy_act.setShortcuts(
            [QKeySequence.Copy,
             QKeySequence(Qt.CTRL + Qt.Key_Comma)])

        self.paste_act = QAction(
            "&Paste",
            self,
            statusTip=
            "Paste the clipboard's contents into the current selection",
            triggered=self.text_edit.paste)
        self.paste_act.setShortcuts(
            [QKeySequence.Paste,
             QKeySequence(Qt.CTRL + Qt.Key_M)])

        self.select_all_act = QAction("Select All",
                                      self,
                                      triggered=self.text_edit.selectAll)
        self.select_all_act.setShortcuts(
            [QKeySequence.SelectAll,
             QKeySequence(Qt.CTRL + Qt.Key_Semicolon)])

        self.find_and_replace_act = QAction(
            "Find and Replace...",
            self,
            triggered=self.show_find_and_replace_dialog)
        self.find_and_replace_act.setShortcuts(
            [QKeySequence.Find,
             QKeySequence(Qt.CTRL + Qt.SHIFT + Qt.Key_J)])

        # About
        self.about_act = QAction("&About",
                                 self,
                                 statusTip="Show the application's About box",
                                 triggered=self.about)

        self.about_Qt_act = QAction(
            "About &Qt",
            self,
            statusTip="Show the Qt library's About box",
            triggered=QApplication.instance().aboutQt)

        # View
        self.zoom_in_act = QAction("Zoom In",
                                   self,
                                   triggered=self.text_edit.zoomIn,
                                   shortcut=QKeySequence.ZoomIn)

        self.zoom_out_act = QAction("Zoom Out",
                                    self,
                                    triggered=self.text_edit.zoomOut,
                                    shortcut=QKeySequence.ZoomOut)

        # Format
        self.md_font_act = QAction("Markdown Font...",
                                   self,
                                   triggered=self.set_markdown_font)

        # Dictionary
        self.add_word_act = QAction("Add Word...",
                                    self,
                                    statusTip="Add a word to the dictionary",
                                    triggered=self.show_add_word_dialog)
        self.add_word_act.setShortcuts([
            QKeySequence(Qt.CTRL + Qt.Key_J),
            QKeySequence(Qt.CTRL + Qt.Key_G)
        ])

        self.delete_word_act = QAction(
            "Delete Word...",
            self,
            statusTip="Delete a word from the dictionary",
            triggered=self.show_del_word_dialog)
        self.delete_word_act.setShortcuts([
            QKeySequence(Qt.CTRL + Qt.Key_D),
            QKeySequence(Qt.CTRL + Qt.Key_U)
        ])

        self.toggle_mode_act = QAction(
            "Switch Mode", self, triggered=self.text_edit.handle_mode_toggle)
        self.toggle_mode_act.setShortcuts([
            QKeySequence(Qt.CTRL + Qt.Key_I),
            QKeySequence(Qt.CTRL + Qt.Key_E)
        ])

        # Connections
        self.text_edit.copyAvailable.connect(self.cut_act.setEnabled)
        self.text_edit.copyAvailable.connect(self.copy_act.setEnabled)
        self.text_edit.undoAvailable.connect(self.undo_act.setEnabled)
        self.text_edit.redoAvailable.connect(self.redo_act.setEnabled)

    # noinspection PyAttributeOutsideInit
    def create_menus(self):
        self.file_menu = self.menuBar().addMenu("&File")
        self.file_menu.addAction(self.new_act)
        self.file_menu.addAction(self.open_act)

        self.recent_file_submenu = self.file_menu.addMenu("Open Recent")
        for act in self.recent_file_acts:
            self.recent_file_submenu.addAction(act)
        self.recent_file_submenu.addSeparator()
        self.recent_file_submenu.addAction(self.clear_recent_files_act)
        self.update_recent_file_actions()

        self.file_menu.addAction(self.save_act)
        self.file_menu.addAction(self.save_as_act)
        self.file_menu.addSeparator()
        self.print_submenu = self.file_menu.addMenu("&Print")
        self.print_submenu.addAction(self.print_act)
        self.print_submenu.addAction(self.print_markdown_act)
        self.print_submenu.addAction(self.print_preview_act)
        self.print_submenu.addAction(self.print_preview_markdown_act)

        self.file_menu.addSeparator()
        self.file_menu.addAction(self.close_act)
        self.file_menu.addAction(self.exit_act)
        # End file menu

        self.edit_menu = self.menuBar().addMenu("&Edit")
        self.edit_menu.addAction(self.undo_act)
        self.edit_menu.addAction(self.redo_act)
        self.edit_menu.addSeparator()
        self.edit_menu.addAction(self.cut_act)
        self.edit_menu.addAction(self.copy_act)
        self.edit_menu.addAction(self.paste_act)
        self.edit_menu.addAction(self.select_all_act)
        self.edit_menu.addSeparator()
        self.edit_menu.addAction(self.find_and_replace_act)

        self.format_menu = self.menuBar().addMenu("For&mat")
        self.font_submenu = self.format_menu.addMenu("&Font")
        self.font_submenu.addAction(self.md_font_act)

        self.view_menu = self.menuBar().addMenu("&View")
        self.view_menu.addAction(self.zoom_in_act)
        self.view_menu.addAction(self.zoom_out_act)

        self.dict_menu = self.menuBar().addMenu('&Dictionary')
        self.dict_menu.addAction(self.add_word_act)
        self.dict_menu.addAction(self.delete_word_act)
        self.dict_menu.addSeparator()
        self.dict_menu.addAction(self.toggle_mode_act)

        self.menuBar().addSeparator()

        self.help_menu = self.menuBar().addMenu("&Help")
        self.help_menu.addAction(self.about_act)
        self.help_menu.addAction(self.about_Qt_act)

    def create_dock_widget(self):
        """
        Sets up a dock widget for Markdown hot previewing, hidden by default.
        :return: None
        """
        dock = QDockWidget("Markdown Viewer", self)
        dock.setWidget(self.md_text_edit)
        dock.visibilityChanged.connect(
            lambda visible: visible and self.update_markdown_viewer(
            ))  # precludes slowdowns
        self.addDockWidget(Qt.BottomDockWidgetArea, dock)
        dock_act = dock.toggleViewAction()
        dock_act.setShortcuts([
            QKeySequence(Qt.CTRL + Qt.SHIFT + Qt.Key_M),
            QKeySequence(Qt.CTRL + Qt.SHIFT + Qt.Key_C)
        ])
        self.view_menu.addSeparator()  # Does nothing on Mac
        self.view_menu.addAction(dock_act)
        dock.close()

    def create_status_bar(self):
        self.statusBar().showMessage("Ready")
        self.statusBar().addPermanentWidget(self.mode_label)

    def read_settings(self):
        settings = QSettings('PMA', 'OneHandTextEdit')
        pos = settings.value('pos', QPoint(200, 200))
        size = settings.value('size', QSize(400, 400))
        md_font = settings.value('md_font',
                                 self.md_text_edit.document().defaultFont())
        self.md_text_edit.document().setDefaultFont(md_font)
        self.move(pos)
        self.resize(size)

    def write_settings(self):
        settings = QSettings('PMA', 'OneHandTextEdit')
        settings.setValue('pos', self.pos())
        settings.setValue('size', self.size())
        settings.setValue('md_font',
                          self.md_text_edit.document().defaultFont())

    def maybe_save(self):
        if self.text_edit.document().isModified():
            ret = QMessageBox.warning(
                self, "OneHandTextEdit",
                "The document has been modified.\nDo you want to save your changes?",
                QMessageBox.Save | QMessageBox.Discard | QMessageBox.Cancel)

            if ret == QMessageBox.Save:
                return self.save()
            elif ret == QMessageBox.Cancel:
                return False

        return True

    def save(self):
        if self.is_untitled:
            return self.save_as()
        else:
            return self.save_file(self.cur_file)

    def save_as(self):
        file_name, _ = QFileDialog.getSaveFileName(self, "Save As",
                                                   self.cur_file)
        if not file_name:
            return False

        return self.save_file(file_name)

    def save_file(self, file_name):
        """

        :param file_name: A canonical file path or whatever QFileDialog.getSaveFileName returns.
        :return: boolean for use in closeEvent method.
        """
        error = None

        QApplication.setOverrideCursor(Qt.WaitCursor)
        file = QSaveFile(file_name)
        if file.open(QFile.WriteOnly | QFile.Text):
            outstr = QTextStream(file)
            outstr << self.text_edit.toPlainText()
            if not file.commit():
                error = "Cannot write file {}:\n{}.".format(
                    file_name, file.errorString())
        else:
            error = "Cannot open file {}:\n{}.".format(file_name,
                                                       file.errorString())
        QApplication.restoreOverrideCursor()

        if error:
            QMessageBox.warning(self, "OneHandTextEdit", error)
            return False

        self.set_current_file(file_name)
        self.statusBar().showMessage("File saved", 2000)
        return True

    def load_file(self, file_name):
        """
        Load file into current instance.

        :param file_name: whatever QFileDialog.getOpenFileName returns (abs or canonical path?), or canonical
        :return:
        """
        file = QFile(file_name)
        if not file.open(QFile.ReadOnly | QFile.Text):
            QMessageBox.warning(
                self, "OneHandTextEdit",
                "Cannot read file {}:\n{}.".format(file_name,
                                                   file.errorString()))
            return

        instr = QTextStream(file)
        QApplication.setOverrideCursor(Qt.WaitCursor)
        self.text_edit.setPlainText(instr.readAll())
        QApplication.restoreOverrideCursor()

        self.set_current_file(file_name)
        self.statusBar().showMessage("File loaded", 2000)

    def set_current_file(self, file_name: str):
        """Sets cur_file to a canonical file path if file exists, otherwise a default placeholder bare file name.
           Updates window title and resets widget to unmodified.
           Updates recent files list.
        """
        self.is_untitled = not file_name
        if self.is_untitled:
            self.cur_file = "document{!s}.txt".format(
                MainWindow.sequence_number)
            MainWindow.sequence_number += 1
        else:
            self.cur_file = QFileInfo(file_name).canonicalFilePath()

        self.text_edit.document().setModified(False)
        self.setWindowModified(False)

        stripped_name = QFileInfo(self.cur_file).fileName()
        self.setWindowTitle("{}[*]".format(stripped_name))

        # Recent files
        if self.is_untitled:
            return

        settings = QSettings('PMA', 'OneHandTextEdit')
        recent_files: List = settings.value('recent_files', [])

        try:
            recent_files.remove(self.cur_file)
        except ValueError:
            pass
        recent_files.insert(0, self.cur_file)
        recent_files = recent_files[:MainWindow.max_recent_files]

        settings.setValue('recent_files', recent_files)

        for widget in QApplication.topLevelWidgets():
            if isinstance(widget, MainWindow):
                widget.update_recent_file_actions()

    def clear_recent_files(self):
        """Clears the recent files setting and updates menus across all main windows."""
        settings = QSettings('PMA', 'OneHandTextEdit')
        settings.setValue('recent_files', [])

        for widget in QApplication.topLevelWidgets():
            if isinstance(widget, MainWindow):
                widget.update_recent_file_actions()

    def update_recent_file_actions(self):
        settings = QSettings('PMA', 'OneHandTextEdit')
        recent_files: List = settings.value('recent_files', [])

        self.clear_recent_files_act.setEnabled(len(recent_files) > 0)

        for i, file in enumerate(recent_files):
            self.recent_file_acts[i].setText(QFileInfo(file).fileName())
            self.recent_file_acts[i].setData(file)
            self.recent_file_acts[i].setVisible(True)

        for j in range(len(recent_files), MainWindow.max_recent_files):
            self.recent_file_acts[j].setVisible(False)

    def find_main_window(self, file_name):
        canonical_file_path = QFileInfo(file_name).canonicalFilePath()

        for widget in QApplication.instance().topLevelWidgets():
            if isinstance(
                    widget,
                    MainWindow) and widget.cur_file == canonical_file_path:
                return widget

        return

    def show_validating_dialog(self, input_label: str,
                               handler: Callable[[str], None]):
        regex = QRegExp(r'[A-Za-z]+([A-Za-z\'-]+[A-Za-z]+|[A-Za-z]*)')
        validator = QRegExpValidator(regex)
        help_dialog = QMessageBox(
            QMessageBox.Information,
            "OneHandTextEdit",
            "A word can only contain letters (upper or lower case) and "
            "contain (but not start or end with) - (dashes) and ' (apostrophes).",
            buttons=QMessageBox.Ok)
        dialog = ValidatingDialog(validator,
                                  help_dialog,
                                  input_label=input_label,
                                  parent=self)
        dialog.submitted.connect(handler)
        dialog.show()
        dialog.raise_()
        dialog.activateWindow()

    def show_find_and_replace_dialog(self):
        find_replace_dialog = PlainTextFindReplaceDialog(self.text_edit,
                                                         parent=self)
        find_replace_dialog.show()

    def show_add_word_dialog(self):
        self.show_validating_dialog("Add word:", self.handle_add_word)

    def show_del_word_dialog(self):
        self.show_validating_dialog("Remove word:", self.handle_delete_word)

    def handle_add_word(self, word: str):
        """
        Adds word to dictionary and marks dictionary as modified.
        :param word: Word to add to dictionary.
        :return:
        """
        added: bool = add_word_to_dict(word, self.regex_map)
        if added:
            MainWindow.dict_modified = True
        else:
            QMessageBox.information(self, "One Hand Text Edit",
                                    "Word already in your dictionary")

    def handle_delete_word(self, word: str):
        """
        Deletes word from dictionary and marks dictionary as modified.
        :param word: Word to remove from dictionary.
        :return:
        """
        deleted: bool = del_word_from_dict(word, self.regex_map)
        if deleted:
            MainWindow.dict_modified = True
        else:
            QMessageBox.information(self, "One Hand Text Edit",
                                    "Word not found in dictionary")

    def handle_entry_default_set(self):
        MainWindow.dict_modified = True
Ejemplo n.º 32
0
class MainWindow(QMainWindow):
    def __init__(self):
        super().__init__()
        self.__activeCount: int = 0  # number of operations in progress
        centralWidget = MainWidget()
        self.setCentralWidget(centralWidget)
        self.notifier = None  # Set by main script
        # Initialise a thread pool
        self.threadPool = QThreadPool.globalInstance()
        logging.info('Multithreading with maximum {} threads'.format(
            self.threadPool.maxThreadCount()))
        self.setWindowTitle('dataMole')

        self.setUpMenus()
        self.__spinnerMutex = QMutex()

        centralWidget.frameInfoPanel.operationRequest.connect(
            self.executeOperation)
        centralWidget.workbenchView.selectedRowChanged[str, str].connect(
            self.changedSelectedFrame)

    def moveEvent(self, event: QtGui.QMoveEvent) -> None:
        self.notifier.mNotifier.updatePosition()
        super().moveEvent(event)

    def resizeEvent(self, event: QtGui.QResizeEvent) -> None:
        self.notifier.mNotifier.updatePosition()
        super().resizeEvent(event)

    @Slot()
    def openComparePanel(self) -> None:
        w = self.centralWidget().workbenchModel
        dv = DataframeSideBySideView(self)
        dv.setWindowFlags(Qt.Window)
        dv.setAttribute(Qt.WA_DeleteOnClose)
        dv.setWindowTitle('Side by side view')
        dv.dataWidgetL.setWorkbench(w)
        dv.dataWidgetR.setWorkbench(w)
        if w.rowCount():
            dv.dataWidgetL.setDataframe(dv.dataWidgetL.inputCB.currentText())
            dv.dataWidgetR.setDataframe(dv.dataWidgetR.inputCB.currentText())
        dv.show()

    # @Slot()
    # def openDiffPanel(self) -> None:
    #     TODO: remove this?
    #     dv = DiffDataframeWidget(self)
    #     dv.setWindowFlags(Qt.Window)
    #     dv.setAttribute(Qt.WA_DeleteOnClose)
    #     dv.setWindowTitle('Diff view')
    #     dv.setWorkbench(self.centralWidget().workbenchModel)
    #     dv.show()

    @Slot(str, str)
    def changedSelectedFrame(self, newName: str, _: str) -> None:
        # Slot called when workbench selection change
        self.aWriteCsv.setOperationArgs(w=self.centralWidget().workbenchModel,
                                        frameName=newName)
        self.aWritePickle.setOperationArgs(
            w=self.centralWidget().workbenchModel, frameName=newName)

    @Slot(int, str)
    def operationStateChanged(self, uid: int, state: str) -> None:
        if state == 'success':
            logging.info('Operation uid={:d} succeeded'.format(uid))
            self.statusBar().showMessage('Operation succeeded', 10000)
        elif state == 'error':
            logging.error('Operation uid={:d} stopped with errors'.format(uid))
            self.statusBar().showMessage('Operation stopped with errors',
                                         10000)
        elif state == 'start':
            self.__spinnerMutex.lock()
            self.__activeCount += 1
            self.__spinnerMutex.unlock()
            self.statusBar().startSpinner()
            logging.info('Operation uid={:d} started'.format(uid))
            self.statusBar().showMessage('Executing...', 10000)
        elif state == 'finish':
            logging.info('Operation uid={:d} finished'.format(uid))
            self.__spinnerMutex.lock()
            self.__activeCount -= 1
            if self.__activeCount == 0:
                self.statusBar().stopSpinner()
            self.__spinnerMutex.unlock()
        # print('Emit', uid, state, 'count={}'.format(self.__activeCount))

    @Slot(type)
    def executeOperation(self, opType: type) -> None:
        action = OperationAction(opType, self, opType.name(),
                                 self.rect().center(),
                                 self.centralWidget().workbenchModel)
        # Set selected frame in the input combo box of the action
        selection = self.centralWidget().workbenchView.selectedIndexes()
        if selection:
            selectedFrame: str = selection[0].data(Qt.DisplayRole)
            action.setSelectedFrame(selectedFrame)
        # Delete action when finished
        action.stateChanged.connect(self.operationStateChanged)
        action.stateChanged.connect(self.deleteAction)
        # Start operation
        action.trigger()

    @Slot(int, str)
    def deleteAction(self, uid: int, state: str):
        if state == 'finish':
            action: QAction = self.sender()
            action.deleteLater()
            logging.info(
                'Action for operation uid={:d} scheduled for deletion'.format(
                    uid))

    def setUpMenus(self) -> None:
        menuBar = QMenuBar()
        fileMenu = menuBar.addMenu('File')
        importMenu = fileMenu.addMenu('Import')
        exportMenu = fileMenu.addMenu('Export')
        flowMenu = menuBar.addMenu('Flow')
        viewMenu = menuBar.addMenu('View')
        helpMenu = menuBar.addMenu('Help')
        aAppendEmpty = QAction('Add frame', fileMenu)
        aAppendEmpty.setStatusTip('Create an empty dataframe in the workbench')
        aQuit = QAction('Quit', fileMenu)
        aLoadCsv = OperationAction(CsvLoader, fileMenu, 'From csv',
                                   self.rect().center(),
                                   self.centralWidget().workbenchModel)
        self.aWriteCsv = OperationAction(CsvWriter,
                                         fileMenu,
                                         'To csv',
                                         self.rect().center(),
                                         w=self.centralWidget().workbenchModel)
        aLoadPickle = OperationAction(PickleLoader, fileMenu, 'From pickle',
                                      self.rect().center(),
                                      self.centralWidget().workbenchModel)
        self.aWritePickle = OperationAction(
            PickleWriter,
            fileMenu,
            'To pickle',
            self.mapToGlobal(self.rect().center()),
            w=self.centralWidget().workbenchModel)
        aCompareFrames = QAction('Compare dataframes', viewMenu)
        aLogDir = QAction('Open log directory', helpMenu)
        aClearLogs = QAction('Delete old logs', helpMenu)
        fileMenu.addActions([aAppendEmpty, aQuit])
        exportMenu.addActions([self.aWriteCsv, self.aWritePickle])
        importMenu.addActions([aLoadCsv, aLoadPickle])

        self._aStartFlow = QAction('Execute', flowMenu)
        self._aResetFlow = QAction('Reset', flowMenu)
        aSaveFlow = QAction('Save', flowMenu)
        aLoadFlow = QAction('Load', flowMenu)
        flowMenu.addActions(
            [self._aStartFlow, self._aResetFlow, aSaveFlow, aLoadFlow])
        viewMenu.addAction(aCompareFrames)
        helpMenu.addActions([aLogDir, aClearLogs])

        self.setMenuBar(menuBar)

        # Tips
        aLoadCsv.setStatusTip('Load a csv file in the workbench')
        aLoadPickle.setStatusTip('Load a Pickle file in the workbench')
        self.aWriteCsv.setStatusTip('Write a dataframe to a csv file')
        self.aWritePickle.setStatusTip(
            'Serializes a dataframe into a pickle file')
        aCompareFrames.setStatusTip('Open two dataframes side by side')
        self._aStartFlow.setStatusTip('Start flow-graph execution')
        self._aResetFlow.setStatusTip('Reset the node status in flow-graph')
        aLogDir.setStatusTip('Open the folder containing all logs')
        aClearLogs.setStatusTip('Delete older logs and keep the last 5')

        # Connect
        aAppendEmpty.triggered.connect(
            self.centralWidget().workbenchModel.appendEmptyRow)
        aQuit.triggered.connect(self.close)
        self._aStartFlow.triggered.connect(
            self.centralWidget().controller.executeFlow)
        self._aResetFlow.triggered.connect(
            self.centralWidget().controller.resetFlowStatus)
        aCompareFrames.triggered.connect(self.openComparePanel)
        aLogDir.triggered.connect(self.openLogDirectory)
        aClearLogs.triggered.connect(self.clearLogDir)
        aSaveFlow.triggered.connect(self.saveFlow)
        aLoadFlow.triggered.connect(self.readFlow)

        aLoadCsv.stateChanged.connect(self.operationStateChanged)
        aLoadPickle.stateChanged.connect(self.operationStateChanged)
        self.aWriteCsv.stateChanged.connect(self.operationStateChanged)
        self.aWritePickle.stateChanged.connect(self.operationStateChanged)

    @Slot()
    def openLogDirectory(self) -> None:
        QDesktopServices.openUrl(
            QUrl(os.path.join(os.getcwd(), flogging.LOG_FOLDER)))

    @Slot()
    def clearLogDir(self) -> None:
        flogging.deleteOldLogs()
        gui.statusBar.showMessage('Logs cleared')

    @Slot()
    def saveFlow(self):
        """ Dump a pipeline in a pickle file """
        path, ext = QFileDialog.getSaveFileName(self, 'Save flow graph')
        if path:
            path = getFileNameWithExtension(path, ext)
            serialization = self.centralWidget().graph.serialize()
            # Add info about scene position to node data
            nodeSerialization: Dict[int, Dict] = serialization['nodes']
            for nodeId, data in nodeSerialization.items():
                data['pos'] = self.centralWidget(
                ).graphScene.nodesDict[nodeId].scenePos().toTuple()
            with open(path, 'wb') as file:
                pickle.dump(serialization, file)
            gui.statusBar.showMessage(
                'Pipeline was successfully exported in {:s}'.format(path), 15)

    @Slot()
    def readFlow(self):
        """ Load a pipeline from a pickle file """
        path, ext = QFileDialog.getOpenFileName(
            self, 'Open flow graph', filter='Pickle (*.pickle);;All files (*)')
        if path:
            try:
                with open(path, 'rb') as file:
                    serialization: Dict = pickle.load(file)
                graph = flow.dag.OperationDag.deserialize(serialization)
            except pickle.PickleError as e:
                gui.notifier.addMessage('Pickle error', str(e),
                                        QMessageBox.Critical)
            except exc.DagException as e:
                gui.notifier.addMessage('Error while creating pipeline',
                                        str(e), QMessageBox.Critical)
            else:
                # Add the workbench
                g = graph.getNxGraph()
                for nodeId in g.nodes:
                    g.nodes[nodeId][
                        'op'].operation._workbench = self.centralWidget(
                        ).workbenchModel
                self.centralWidget().createNewFlow(graph)
                self.centralWidget().controller.showGraphInScene()
                # Set position of every node
                nodeDict = serialization['nodes']
                for nodeId, node in self.centralWidget(
                ).graphScene.nodesDict.items():
                    pos: Tuple[float, float] = nodeDict[nodeId]['pos']
                    node.setPos(*pos)
                    node.refresh()  # Update connected edges
                # Reconnect actions to the new controller
                self._aStartFlow.triggered.connect(
                    self.centralWidget().controller.executeFlow)
                self._aResetFlow.triggered.connect(
                    self.centralWidget().controller.resetFlowStatus)
                gui.statusBar.showMessage('Pipeline was successfully imported',
                                          15)
Ejemplo n.º 33
0
    def create_actions(self):
        # File
        self.new_act = QAction("&New",
                               self,
                               statusTip="Create a new file",
                               triggered=self.new_file)
        self.new_act.setShortcuts(
            [QKeySequence.New,
             QKeySequence(Qt.CTRL + Qt.Key_B)])

        self.open_act = QAction("&Open...",
                                self,
                                statusTip="Open an existing file",
                                triggered=self.open)
        self.open_act.setShortcuts(
            [QKeySequence.Open,
             QKeySequence(Qt.CTRL + Qt.Key_T)])

        self.save_act = QAction("&Save",
                                self,
                                statusTip="Save the document to disk",
                                triggered=self.save)
        self.save_act.setShortcuts(
            [QKeySequence.Save,
             QKeySequence(Qt.CTRL + Qt.Key_L)])

        self.save_as_act = QAction(
            "Save &As...",
            self,
            statusTip="Save the document under a new name",
            triggered=self.save_as)
        self.save_as_act.setShortcuts(
            [QKeySequence.SaveAs,
             QKeySequence(Qt.CTRL + Qt.SHIFT + Qt.Key_L)])

        self.recent_file_acts = []
        for i in range(MainWindow.max_recent_files):
            self.recent_file_acts.append(
                QAction(self, visible=False, triggered=self.open_recent))

        self.clear_recent_files_act = QAction(
            "Clear Menu",
            self,
            enabled=False,
            triggered=self.clear_recent_files)

        self.print_act = QAction("&Print...",
                                 self,
                                 statusTip="Print the document",
                                 triggered=functools.partial(
                                     self.print_with_setup,
                                     text_edit=self.text_edit))
        self.print_act.setShortcuts(
            [QKeySequence.Print,
             QKeySequence(Qt.CTRL + Qt.Key_R)])

        self.print_markdown_act = QAction("Print &Markdown...",
                                          self,
                                          triggered=functools.partial(
                                              self.print_with_setup,
                                              text_edit=self.md_text_edit))
        self.print_markdown_act.setShortcuts([
            QKeySequence(Qt.CTRL + Qt.SHIFT + Qt.Key_P),
            QKeySequence(Qt.CTRL + Qt.SHIFT + Qt.Key_R)
        ])

        self.print_preview_act = QAction("Print Preview...",
                                         self,
                                         triggered=functools.partial(
                                             self.print_preview,
                                             text_edit=self.text_edit))

        self.print_preview_markdown_act = QAction(
            "Print Markdown Preview...",
            self,
            triggered=functools.partial(self.print_preview,
                                        text_edit=self.md_text_edit))

        self.close_act = QAction("&Close",
                                 self,
                                 statusTip="Close this window",
                                 triggered=self.close)
        self.close_act.setShortcuts([
            QKeySequence(Qt.CTRL + Qt.Key_W),
            QKeySequence(Qt.CTRL + Qt.Key_BracketRight)
        ])

        self.exit_act = QAction(
            "E&xit",
            self,
            statusTip="Exit the application",
            triggered=QApplication.instance().closeAllWindows)
        self.exit_act.setShortcuts([
            QKeySequence(Qt.CTRL + Qt.Key_Q),
            QKeySequence(Qt.CTRL + Qt.Key_BracketLeft)
        ])

        # Edit
        self.undo_act = QAction("Undo",
                                self,
                                enabled=False,
                                triggered=self.text_edit.undo)
        self.undo_act.setShortcuts(
            [QKeySequence.Undo,
             QKeySequence(Qt.CTRL + Qt.Key_Slash)])

        self.redo_act = QAction("Redo",
                                self,
                                enabled=False,
                                triggered=self.text_edit.redo)
        self.redo_act.setShortcuts(
            [QKeySequence.Redo,
             QKeySequence(Qt.CTRL + Qt.Key_Y)])

        self.cut_act = QAction(
            "Cu&t",
            self,
            enabled=False,
            statusTip="Cut the current selection's contents to the clipboard",
            triggered=self.text_edit.cut)
        self.cut_act.setShortcuts(
            [QKeySequence.Cut,
             QKeySequence(Qt.CTRL + Qt.Key_Period)])

        self.copy_act = QAction(
            "&Copy",
            self,
            enabled=False,
            statusTip="Copy the current selection's contents to the clipboard",
            triggered=self.text_edit.copy)
        self.copy_act.setShortcuts(
            [QKeySequence.Copy,
             QKeySequence(Qt.CTRL + Qt.Key_Comma)])

        self.paste_act = QAction(
            "&Paste",
            self,
            statusTip=
            "Paste the clipboard's contents into the current selection",
            triggered=self.text_edit.paste)
        self.paste_act.setShortcuts(
            [QKeySequence.Paste,
             QKeySequence(Qt.CTRL + Qt.Key_M)])

        self.select_all_act = QAction("Select All",
                                      self,
                                      triggered=self.text_edit.selectAll)
        self.select_all_act.setShortcuts(
            [QKeySequence.SelectAll,
             QKeySequence(Qt.CTRL + Qt.Key_Semicolon)])

        self.find_and_replace_act = QAction(
            "Find and Replace...",
            self,
            triggered=self.show_find_and_replace_dialog)
        self.find_and_replace_act.setShortcuts(
            [QKeySequence.Find,
             QKeySequence(Qt.CTRL + Qt.SHIFT + Qt.Key_J)])

        # About
        self.about_act = QAction("&About",
                                 self,
                                 statusTip="Show the application's About box",
                                 triggered=self.about)

        self.about_Qt_act = QAction(
            "About &Qt",
            self,
            statusTip="Show the Qt library's About box",
            triggered=QApplication.instance().aboutQt)

        # View
        self.zoom_in_act = QAction("Zoom In",
                                   self,
                                   triggered=self.text_edit.zoomIn,
                                   shortcut=QKeySequence.ZoomIn)

        self.zoom_out_act = QAction("Zoom Out",
                                    self,
                                    triggered=self.text_edit.zoomOut,
                                    shortcut=QKeySequence.ZoomOut)

        # Format
        self.md_font_act = QAction("Markdown Font...",
                                   self,
                                   triggered=self.set_markdown_font)

        # Dictionary
        self.add_word_act = QAction("Add Word...",
                                    self,
                                    statusTip="Add a word to the dictionary",
                                    triggered=self.show_add_word_dialog)
        self.add_word_act.setShortcuts([
            QKeySequence(Qt.CTRL + Qt.Key_J),
            QKeySequence(Qt.CTRL + Qt.Key_G)
        ])

        self.delete_word_act = QAction(
            "Delete Word...",
            self,
            statusTip="Delete a word from the dictionary",
            triggered=self.show_del_word_dialog)
        self.delete_word_act.setShortcuts([
            QKeySequence(Qt.CTRL + Qt.Key_D),
            QKeySequence(Qt.CTRL + Qt.Key_U)
        ])

        self.toggle_mode_act = QAction(
            "Switch Mode", self, triggered=self.text_edit.handle_mode_toggle)
        self.toggle_mode_act.setShortcuts([
            QKeySequence(Qt.CTRL + Qt.Key_I),
            QKeySequence(Qt.CTRL + Qt.Key_E)
        ])

        # Connections
        self.text_edit.copyAvailable.connect(self.cut_act.setEnabled)
        self.text_edit.copyAvailable.connect(self.copy_act.setEnabled)
        self.text_edit.undoAvailable.connect(self.undo_act.setEnabled)
        self.text_edit.redoAvailable.connect(self.redo_act.setEnabled)
Ejemplo n.º 34
0
    central_widget = CentralWidget(window)
    window.setCentralWidget(central_widget)

    status_bar = StatusBar(window)
    window.setStatusBar(status_bar)

    dock = Dock("File Explorer", central_widget, window)
    dock.tree_init()
    window.addDockWidget(Qt.LeftDockWidgetArea, dock)
    toggle_dock_action = dock.toggleViewAction()
    toggle_dock_action.setShortcut("Ctrl+B")
    menubar.view_menu.addAction(toggle_dock_action)

    dock_db = Dock("Connected Databases", central_widget, window)
    dock_db.init_db_tree()
    window.addDockWidget(Qt.LeftDockWidgetArea, dock_db)
    toggle_connected_dbs_action = dock_db.toggleViewAction()
    toggle_connected_dbs_action.setShortcut("Ctrl+D")

    refresh_action = QAction(QIcon("view/images/menubar/refresh.png"), "Refresh Connected DBs", dock_db)
    refresh_action.setShortcut("Ctrl+R")
    refresh_action.setStatusTip("Refreshes list of connected databases in the dock")
    refresh_action.triggered.connect(dock_db.connected_dbs)

    menubar.database_menu.addAction(refresh_action)
    menubar.view_menu.addAction(toggle_connected_dbs_action)

    window.showMaximized()

    sys.exit(app.exec())
Ejemplo n.º 35
0
    def initActions(self):
        self.newGameAction = QAction("&New Game", self)
        self.newGameAction.setIcon(QIcon(CONST.ICONS["New"]))
        self.newGameAction.triggered.connect(self.newGame)
        self.newGameAction.setShortcut('CTRL+N')

        self.openAction = QAction("&Open", self)
        self.openAction.setIcon(QIcon(CONST.ICONS["Open"]))
        self.openAction.triggered.connect(self.openFile)
        self.openAction.setShortcut('CTRL+O')

        self.saveGameAction = QAction("&Save", self)
        self.saveGameAction.setIcon(QIcon(CONST.ICONS["Save"]))
        self.saveGameAction.triggered.connect(self.saveGame)
        self.saveGameAction.setShortcut('CTRL+S')

        self.saveAsAction = QAction("Save &As", self)
        self.saveAsAction.setIcon(QIcon(CONST.ICONS["Save"]))
        self.saveAsAction.triggered.connect(self.saveGameAs)
        self.saveAsAction.setShortcut('CTRL+A')

        self.showAboutDialogAction = QAction("&About DCS Liberation", self)
        self.showAboutDialogAction.setIcon(QIcon.fromTheme("help-about"))
        self.showAboutDialogAction.triggered.connect(self.showAboutDialog)

        self.showLiberationPrefDialogAction = QAction("&Preferences", self)
        self.showLiberationPrefDialogAction.setIcon(
            QIcon.fromTheme("help-about"))
        self.showLiberationPrefDialogAction.triggered.connect(
            self.showLiberationDialog)

        self.openDiscordAction = QAction("&Discord Server", self)
        self.openDiscordAction.setIcon(CONST.ICONS["Discord"])
        self.openDiscordAction.triggered.connect(
            lambda: webbrowser.open_new_tab("https://" + "discord.gg" + "/" +
                                            "bKrt" + "rkJ"))

        self.openGithubAction = QAction("&Github Repo", self)
        self.openGithubAction.setIcon(CONST.ICONS["Github"])
        self.openGithubAction.triggered.connect(
            lambda: webbrowser.open_new_tab(
                "https://github.com/khopa/dcs_liberation"))
Ejemplo n.º 36
0
    def __init__(self, game):
        """
        La fenêtre principale est initialisée avec l'organisation suivante :

        +--------------------------------------------------------------------------+
        |              self.menu = self.menuBar()                                  |
        |                                                                          |
        +--------------------------------------------------------------------------+
        |       toolbar = QToolBar()  (déplacement/sélection des robots,           |
        |                     boutons annuler, indice et solution)                 |
        +------------------------layout0 = QHBoxLayout()---------------------------+
        |    layout2 = QHBoxLayout()                  +      moves_label           |
        | l                    +                      |                            |
        | a  grid_choice       |  nb_robots_choice    |     (affichage des         |
        +-y--------------------+----------------------+  L                         |
        | o                                           |  a  mouvements effectués)  |
        | u                                           |  y                         |
        | t                                           +--o-------------------------+
        | =          label = QLabel()                 |  u                         |
        | Q                                           |  t     tip_label           |
        | V          contient la grille de jeu        |  3                         |
        | B                                           |      (Affichage de l'indice|
        | o                                           |  =                         |
        | x                                           |      si demandé)           |
        | L                                           |  Q                         |
        | a                                           +--V+------------------------+
        | y                                           |  B     solution_label      |
        | o                                           |  o                         |
        | u                                           |  x   (Affichage de la      |
        | t                                           |                            |
        |                                             |      solution si demandée) |
        +---------------------------------------------+----------------------------+

        """

        super().__init__()
        self.game = game
        self.initial_game_state = self.game.get_state()
        self.number_moves = 0
        self.setWindowTitle("Robot Ricochet")
        self.resize(self.DIMENSION + 150, self.DIMENSION + 100)

        # label contient la grille de jeu
        self.label = QLabel()
        canvas = QPixmap(self.DIMENSION, self.DIMENSION)
        canvas.fill(Qt.white)
        self.label.setPixmap(canvas)

        # layout0 contient, à gauche, les barres d'outils et la grille,
        # et à droite, la liste des états et l'indice affiché par le solveur

        layout0 = QHBoxLayout()
        layout0.setContentsMargins(0, 0, 0, 0)
        layout0.setSpacing(0)

        layout = QVBoxLayout()
        layout.setContentsMargins(0, 0, 0, 0)
        layout.setSpacing(0)
        layout2 = QHBoxLayout()

        # Choix de la grille
        self.choice_of_grid_menu()

        # choix du nombre de robots
        self.nb_robots_choice_menu()

        # CheckBox placement aléatoire
        widget3 = QCheckBox("Placement aléatoire des robots et de l'objectif")
        widget3.setCheckState(Qt.Checked)
        widget3.stateChanged.connect(self.placer_aleatoirement)

        # layout2 contient les 3 widgets horizontaux de choix de grille, robots et aléa
        layout2.addWidget(self.grid_choice)
        layout2.addWidget(self.nb_robots_choice)
        #layout2.addWidget(widget3)
        layout2.setContentsMargins(0, 0, 0, 0)
        layout2.setSpacing(0)
        widget2 = QWidget()
        widget2.setLayout(layout2)

        layout.addWidget(widget2)
        layout.addWidget(self.label)

        # liste des mouvement effectués, indice et solution:
        layout3 = QVBoxLayout()
        layout3.setContentsMargins(0, 0, 0, 0)
        layout3.setSpacing(0)

        self.moves_label = QLabel()
        self.print_moves_list()
        self.tip_label = QLabel()
        self.solution_label = QLabel()

        layout3.addWidget(self.moves_label)
        layout3.addWidget(self.tip_label)
        layout3.addWidget(self.solution_label)

        layout0.addLayout(layout)
        layout0.addLayout(layout3)
        widget = QWidget()
        widget.setLayout(layout0)
        self.setCentralWidget(widget)

        # Menu
        self.menu = self.menuBar()
        self.file_menu = self.menu.addMenu("File")
        self.help_menu = self.menu.addMenu("Aide et instructions")  # A faire
        self.size_fenetre = self.geometry()

        # Play QAction
        play_action = QAction("Réinitialiser !", self)
        play_action.triggered.connect(self.replay)
        self.file_menu.addAction(play_action)

        # Open_grid QAction
        open_grid_action = QAction("Ouvrir une grille", self)
        open_grid_action.setShortcut('Ctrl+O')
        open_grid_action.triggered.connect(self.open_grid)
        self.file_menu.addAction(open_grid_action)

        # Open_game QAction
        open_game_action = QAction("Ouvrir un jeu", self)
        open_game_action.triggered.connect(self.open_game)
        self.file_menu.addAction(open_game_action)

        # Save_grid QAction
        save_grid_action = QAction("Enregistrer cette grille", self)
        save_grid_action.triggered.connect(self.save_grid)
        self.file_menu.addAction(save_grid_action)

        # Save_game QAction
        save_game_action = QAction("Enregistrer ce jeu", self)
        save_game_action.triggered.connect(self.save_game)
        self.file_menu.addAction(save_game_action)

        # Exit QAction
        exit_action = QAction("Quitter", self)
        exit_action.setShortcut(QKeySequence.Quit)
        exit_action.triggered.connect(self.close)
        self.file_menu.addAction(exit_action)

        # Help QAction
        help_action = QAction("Aide", self)
        help_action.triggered.connect(self.help)
        self.help_menu.addAction(help_action)
        self.toolbar_menus()

        #Le robot rouge est sélectionné par défaut
        self.selected_robot = 'R'

        self.draw_robots_and_goal()
Ejemplo n.º 37
0
class QLiberationWindow(QMainWindow):
    def __init__(self, game: Optional[Game]) -> None:
        super(QLiberationWindow, self).__init__()

        self.game = game
        self.game_model = GameModel(game)
        Dialog.set_game(self.game_model)
        self.ato_panel = QAirTaskingOrderPanel(self.game_model)
        self.info_panel = QInfoPanel(self.game)
        self.liberation_map = QLiberationMap(self.game_model)

        self.setGeometry(300, 100, 270, 100)
        self.setWindowTitle(f"DCS Liberation - v{VERSION}")
        self.setWindowIcon(QIcon("./resources/icon.png"))
        self.statusBar().showMessage('Ready')

        self.initUi()
        self.initActions()
        self.initToolbar()
        self.initMenuBar()
        self.connectSignals()

        screen = QDesktopWidget().screenGeometry()
        self.setGeometry(0, 0, screen.width(), screen.height())
        self.setWindowState(Qt.WindowMaximized)

        if self.game is None:
            last_save_file = liberation_install.get_last_save_file()
            if last_save_file:
                try:
                    logging.info("Loading last saved game : " +
                                 str(last_save_file))
                    game = persistency.load_game(last_save_file)
                    self.onGameGenerated(game)
                except:
                    logging.info("Error loading latest save game")
            else:
                logging.info("No existing save game")
        else:
            self.onGameGenerated(self.game)

    def initUi(self):
        hbox = QSplitter(Qt.Horizontal)
        vbox = QSplitter(Qt.Vertical)
        hbox.addWidget(self.ato_panel)
        hbox.addWidget(vbox)
        vbox.addWidget(self.liberation_map)
        vbox.addWidget(self.info_panel)

        # Will make the ATO sidebar as small as necessary to fit the content. In
        # practice this means it is sized by the hints in the panel.
        hbox.setSizes([1, 10000000])
        vbox.setSizes([600, 100])

        vbox = QVBoxLayout()
        vbox.setMargin(0)
        vbox.addWidget(QTopPanel(self.game_model))
        vbox.addWidget(hbox)

        central_widget = QWidget()
        central_widget.setLayout(vbox)
        self.setCentralWidget(central_widget)

    def connectSignals(self):
        GameUpdateSignal.get_instance().gameupdated.connect(self.setGame)
        GameUpdateSignal.get_instance().debriefingReceived.connect(
            self.onDebriefing)

    def initActions(self):
        self.newGameAction = QAction("&New Game", self)
        self.newGameAction.setIcon(QIcon(CONST.ICONS["New"]))
        self.newGameAction.triggered.connect(self.newGame)
        self.newGameAction.setShortcut('CTRL+N')

        self.openAction = QAction("&Open", self)
        self.openAction.setIcon(QIcon(CONST.ICONS["Open"]))
        self.openAction.triggered.connect(self.openFile)
        self.openAction.setShortcut('CTRL+O')

        self.saveGameAction = QAction("&Save", self)
        self.saveGameAction.setIcon(QIcon(CONST.ICONS["Save"]))
        self.saveGameAction.triggered.connect(self.saveGame)
        self.saveGameAction.setShortcut('CTRL+S')

        self.saveAsAction = QAction("Save &As", self)
        self.saveAsAction.setIcon(QIcon(CONST.ICONS["Save"]))
        self.saveAsAction.triggered.connect(self.saveGameAs)
        self.saveAsAction.setShortcut('CTRL+A')

        self.showAboutDialogAction = QAction("&About DCS Liberation", self)
        self.showAboutDialogAction.setIcon(QIcon.fromTheme("help-about"))
        self.showAboutDialogAction.triggered.connect(self.showAboutDialog)

        self.showLiberationPrefDialogAction = QAction("&Preferences", self)
        self.showLiberationPrefDialogAction.setIcon(
            QIcon.fromTheme("help-about"))
        self.showLiberationPrefDialogAction.triggered.connect(
            self.showLiberationDialog)

        self.openDiscordAction = QAction("&Discord Server", self)
        self.openDiscordAction.setIcon(CONST.ICONS["Discord"])
        self.openDiscordAction.triggered.connect(
            lambda: webbrowser.open_new_tab("https://" + "discord.gg" + "/" +
                                            "bKrt" + "rkJ"))

        self.openGithubAction = QAction("&Github Repo", self)
        self.openGithubAction.setIcon(CONST.ICONS["Github"])
        self.openGithubAction.triggered.connect(
            lambda: webbrowser.open_new_tab(
                "https://github.com/khopa/dcs_liberation"))

    def initToolbar(self):
        self.tool_bar = self.addToolBar("File")
        self.tool_bar.addAction(self.newGameAction)
        self.tool_bar.addAction(self.openAction)
        self.tool_bar.addAction(self.saveGameAction)

        self.links_bar = self.addToolBar("Links")
        self.links_bar.addAction(self.openDiscordAction)
        self.links_bar.addAction(self.openGithubAction)

        self.display_bar = self.addToolBar("Display")

    def initMenuBar(self):
        self.menu = self.menuBar()

        file_menu = self.menu.addMenu("&File")
        file_menu.addAction(self.newGameAction)
        file_menu.addAction(self.openAction)
        file_menu.addSeparator()
        file_menu.addAction(self.saveGameAction)
        file_menu.addAction(self.saveAsAction)
        file_menu.addSeparator()
        file_menu.addAction(self.showLiberationPrefDialogAction)
        file_menu.addSeparator()
        file_menu.addAction("E&xit", self.close)

        displayMenu = self.menu.addMenu("&Display")

        last_was_group = False
        for item in DisplayOptions.menu_items():
            if isinstance(item, DisplayRule):
                if last_was_group:
                    displayMenu.addSeparator()
                    self.display_bar.addSeparator()
                action = self.make_display_rule_action(item)
                displayMenu.addAction(action)
                if action.icon():
                    self.display_bar.addAction(action)
                last_was_group = False
            elif isinstance(item, DisplayGroup):
                displayMenu.addSeparator()
                self.display_bar.addSeparator()
                group = QActionGroup(displayMenu)
                for display_rule in item:
                    action = self.make_display_rule_action(display_rule, group)
                    displayMenu.addAction(action)
                    if action.icon():
                        self.display_bar.addAction(action)
                last_was_group = True

        help_menu = self.menu.addMenu("&Help")
        help_menu.addAction(self.openDiscordAction)
        help_menu.addAction(self.openGithubAction)
        help_menu.addAction(
            "&Releases", lambda: webbrowser.open_new_tab(
                "https://github.com/Khopa/dcs_liberation/releases"))
        help_menu.addAction("&Online Manual",
                            lambda: webbrowser.open_new_tab(URLS["Manual"]))
        help_menu.addAction(
            "&ED Forum Thread",
            lambda: webbrowser.open_new_tab(URLS["ForumThread"]))
        help_menu.addAction("Report an &issue",
                            lambda: webbrowser.open_new_tab(URLS["Issues"]))

        help_menu.addSeparator()
        help_menu.addAction(self.showAboutDialogAction)

    @staticmethod
    def make_display_rule_action(display_rule,
                                 group: Optional[QActionGroup] = None
                                 ) -> QAction:
        def make_check_closure():
            def closure():
                display_rule.value = action.isChecked()

            return closure

        action = QAction(f"&{display_rule.menu_text}", group)

        if display_rule.menu_text in CONST.ICONS.keys():
            action.setIcon(CONST.ICONS[display_rule.menu_text])

        action.setCheckable(True)
        action.setChecked(display_rule.value)
        action.toggled.connect(make_check_closure())
        return action

    def newGame(self):
        wizard = NewGameWizard(self)
        wizard.show()
        wizard.accepted.connect(
            lambda: self.onGameGenerated(wizard.generatedGame))

    def openFile(self):
        file = QFileDialog.getOpenFileName(
            self,
            "Select game file to open",
            dir=persistency._dcs_saved_game_folder,
            filter="*.liberation")
        if file is not None:
            game = persistency.load_game(file[0])
            GameUpdateSignal.get_instance().updateGame(game)

    def saveGame(self):
        logging.info("Saving game")

        if self.game.savepath:
            persistency.save_game(self.game)
            GameUpdateSignal.get_instance().updateGame(self.game)
            liberation_install.setup_last_save_file(self.game.savepath)
            liberation_install.save_config()
        else:
            self.saveGameAs()

    def saveGameAs(self):
        file = QFileDialog.getSaveFileName(
            self,
            "Save As",
            dir=persistency._dcs_saved_game_folder,
            filter="*.liberation")
        if file is not None:
            self.game.savepath = file[0]
            persistency.save_game(self.game)
            liberation_install.setup_last_save_file(self.game.savepath)
            liberation_install.save_config()

    def onGameGenerated(self, game: Game):
        logging.info("On Game generated")
        self.game = game
        GameUpdateSignal.get_instance().updateGame(self.game)

    def setGame(self, game: Optional[Game]):
        try:
            self.game = game
            if self.info_panel is not None:
                self.info_panel.setGame(game)
            self.game_model.set(self.game)
            if self.liberation_map is not None:
                self.liberation_map.setGame(game)
        except AttributeError:
            logging.exception("Incompatible save game")
            QMessageBox.critical(
                self, "Could not load save game",
                "The save game you have loaded is incompatible with this "
                "version of DCS Liberation.\n"
                "\n"
                f"{traceback.format_exc()}", QMessageBox.Ok)
            GameUpdateSignal.get_instance().updateGame(None)

    def showAboutDialog(self):
        text = "<h3>DCS Liberation " + VERSION + "</h3>" + \
               "<b>Source code :</b> https://github.com/khopa/dcs_liberation" + \
               "<h4>Authors</h4>" + \
               "<p>DCS Liberation was originally developed by <b>shdwp</b>, DCS Liberation 2.0 is a partial rewrite based on this work by <b>Khopa</b>." \
               "<h4>Contributors</h4>" + \
               "shdwp, Khopa, ColonelPanic, Roach, Wrycu, calvinmorrow, JohanAberg, Deus, root0fall, Captain Cody, steveveepee, pedromagueija, parithon, bwRavencl, davidp57, Plob, Hawkmoon" + \
               "<h4>Special Thanks  :</h4>" \
               "<b>rp-</b> <i>for the pydcs framework</i><br/>"\
               "<b>Grimes (mrSkortch)</b> & <b>Speed</b> <i>for the MIST framework</i><br/>"\
               "<b>Ciribob </b> <i>for the JTACAutoLase.lua script</i><br/>"\
               "<b>Walder </b> <i>for the Skynet-IADS script</i><br/>"\
               "<b>Anubis Yinepu </b> <i>for the Hercules Cargo script</i><br/>"
        about = QMessageBox()
        about.setWindowTitle("About DCS Liberation")
        about.setIcon(QMessageBox.Icon.Information)
        about.setText(text)
        logging.info(about.textFormat())
        about.exec_()

    def showLiberationDialog(self):
        self.subwindow = QLiberationPreferencesWindow()
        self.subwindow.show()

    def onDebriefing(self, debrief: Debriefing):
        logging.info("On Debriefing")
        self.debriefing = QDebriefingWindow(debrief)
        self.debriefing.show()

    def closeEvent(self, event: QCloseEvent) -> None:
        result = QMessageBox.question(
            self, "Quit Liberation?",
            "Are you sure you want to quit? All unsaved progress will be lost.",
            QMessageBox.Yes | QMessageBox.No)
        if result == QMessageBox.Yes:
            super().closeEvent(event)
        else:
            event.ignore()
Ejemplo n.º 38
0
def start(_exit: bool = False) -> None:
    app = QApplication(sys.argv)

    first_start = False
    if not os.path.isfile(STATE_FILE):
        first_start = True

    logo = QIcon(LOGO)
    main_window = MainWindow()
    ui = main_window.ui
    main_window.setWindowIcon(logo)
    tray = QSystemTrayIcon(logo, app)
    tray.activated.connect(main_window.systray_clicked)

    menu = QMenu()
    action_show = QAction("Show")
    action_show.triggered.connect(main_window.show)
    action_exit = QAction("Exit")
    action_exit.triggered.connect(app.exit)
    menu.addAction(action_show)
    menu.addAction(action_exit)

    tray.setContextMenu(menu)

    ui.text.textChanged.connect(partial(queue_text_change, ui))
    ui.command.textChanged.connect(partial(update_button_command, ui))
    ui.keys.textChanged.connect(partial(update_button_keys, ui))
    ui.write.textChanged.connect(partial(update_button_write, ui))
    ui.change_brightness.valueChanged.connect(
        partial(update_change_brightness, ui))
    ui.switch_page.valueChanged.connect(partial(update_switch_page, ui))
    ui.imageButton.clicked.connect(partial(select_image, main_window))
    ui.brightness.valueChanged.connect(partial(set_brightness, ui))
    ui.information.currentIndexChanged.connect(partial(set_information, ui))

    items = api.open_decks().items()
    print("wait for device(s)")

    while len(items) == 0:
        time.sleep(3)
        items = api.open_decks().items()

    print("found " + str(len(items)) + ": " +
          ",".join(str(i) for i in list(items)))

    for deck_id, deck in items:
        ui.device_list.addItem(f"{deck['type']} - {deck_id}", userData=deck_id)

    build_device(ui)
    ui.device_list.currentIndexChanged.connect(partial(build_device, ui))

    ui.pages.currentChanged.connect(partial(change_page, ui))

    ui.actionExport.triggered.connect(partial(export_config, main_window))
    ui.actionImport.triggered.connect(partial(import_config, main_window))
    ui.actionExit.triggered.connect(app.exit)

    timer = QTimer()
    timer.timeout.connect(partial(sync, ui))
    timer.start(1000)

    api.render()
    tray.show()
    if first_start:
        main_window.show()

    if _exit:
        return
    else:
        sys.exit(app.exec_())
Ejemplo n.º 39
0
class AppMenuBar(QMenuBar):
    """ This code is for the menu bar at the top of the main window. File, help, etc. """
    def __init__(self, parent, log_handlers: [StreamHandler], lang: LangEnum):
        self._logger = getLogger(__name__)
        for h in log_handlers:
            self._logger.addHandler(h)
        self._logger.debug("Initializing")
        super().__init__(parent)
        self.setGeometry(QRect(0, 0, 840, 22))

        self._file_menu = QMenu(self)
        self.addAction(self._file_menu.menuAction())

        self._open_last_save_dir_action = QAction(self)
        self._file_menu.addAction(self._open_last_save_dir_action)

        # self._cam_list_menu = QMenu(self)
        # self._file_menu.addMenu(self._cam_list_menu)

        # self._use_cams_action = QAction(self)
        # self._use_cams_action.setCheckable(True)
        # self._cam_list_menu.addAction(self._use_cams_action)

        # sep = self._cam_list_menu.addSeparator()

        self._settings_menu = QMenu(self)
        self.addAction(self._settings_menu.menuAction())

        self._debug_actions = []
        self._debug_menu = QMenu(self)
        self._settings_menu.addMenu(self._debug_menu)

        self._debug_action = QAction(self)
        self._debug_action.setCheckable(True)
        self._debug_action.triggered.connect(self._debug_clicked)
        self._debug_actions.append(self._debug_action)
        self._debug_menu.addAction(self._debug_action)

        self._warning_action = QAction(self)
        self._warning_action.setCheckable(True)
        self._warning_action.triggered.connect(self._warning_clicked)
        self._debug_actions.append(self._warning_action)
        self._debug_menu.addAction(self._warning_action)

        self._lang_actions = []
        self._language_menu = QMenu(self)
        self._settings_menu.addMenu(self._language_menu)

        self._english_action = QAction(self)
        self._lang_actions.append(self._english_action)
        self._english_action.setCheckable(True)
        self._english_action.triggered.connect(self._eng_clicked)
        self._language_menu.addAction(self._english_action)

        self._french_action = QAction(self)
        self._lang_actions.append(self._french_action)
        self._french_action.setCheckable(True)
        self._french_action.triggered.connect(self._fre_clicked)
        self._language_menu.addAction(self._french_action)

        self._german_action = QAction(self)
        self._lang_actions.append(self._german_action)
        self._german_action.setCheckable(True)
        self._german_action.triggered.connect(self._ger_clicked)
        self._language_menu.addAction(self._german_action)

        self._spanish_action = QAction(self)
        self._lang_actions.append(self._spanish_action)
        self._spanish_action.setCheckable(True)
        self._spanish_action.triggered.connect(self._spa_clicked)
        self._language_menu.addAction(self._spanish_action)

        # TODO: issue with Chinese characters.
        #       Maybe use traditional instead of simplified.
        # self._chinese_action = QAction(self)
        # self._lang_actions.append(self._chinese_action)
        # self._chinese_action.setCheckable(True)
        # self._chinese_action.triggered.connect(self._chi_clicked)
        # self._language_menu.addAction(self._chinese_action)

        self._help_menu = QMenu(self)
        self.addAction(self._help_menu.menuAction())

        self._about_app_action = QAction(self)
        self._help_menu.addAction(self._about_app_action)

        self._about_company_action = QAction(self)
        self._help_menu.addAction(self._about_company_action)

        self._update_action = QAction(self)
        self._help_menu.addAction(self._update_action)

        self._log_window_action = QAction(self)
        self._help_menu.addAction(self._log_window_action)

        self._cam_actions = {}

        self._debug_callback = None
        self._lang_callback = None
        self._strings = dict()
        self.set_lang(lang)
        self._logger.debug("Initialized")

    def set_lang(self, lang: LangEnum) -> None:
        """
        Set the language of this view item.
        :param lang: The language enum to use.
        :return None:
        """
        self._strings = strings[lang]
        self._set_texts()
        if lang == LangEnum.ENG:
            self._reset_lang_actions(self._english_action)
        elif lang == LangEnum.FRE:
            self._reset_lang_actions(self._french_action)
        elif lang == LangEnum.GER:
            self._reset_lang_actions(self._german_action)
        elif lang == LangEnum.SPA:
            self._reset_lang_actions(self._spanish_action)
        # elif lang == LangEnum.CHI:
        #     self._reset_lang_actions(self._chinese_action)

    def add_lang_select_handler(self, func: classmethod) -> None:
        """
        Add handler for these selectable. Handler must take a LangEnum
        :param func: The handler.
        :return None:
        """
        self._lang_callback = func

    def set_debug_action(self, level) -> None:
        """
        Set which debug action is checked.
        :param level: The debug level.
        :return None:
        """
        if level == DEBUG:
            self._reset_debug_actions(self._debug_action)
        elif level == WARNING:
            self._reset_debug_actions(self._warning_action)

    def add_debug_select_handler(self, func: classmethod) -> None:
        """
        Add handler for these selectables. Handler must take a string.
        :param func: The handler.
        :return None:
        """
        self._debug_callback = func

    def set_cam_action_enabled(self, is_active: bool) -> None:
        """
        Set whether or not the camera actions can be used.
        :param is_active: can be used.
        :return None:
        """

        self._use_cams_action.setEnabled(is_active)
        for action in self._cam_actions.values():
            action.setEnabled(is_active)

    def set_cam_bool_checked(self, is_active: bool) -> None:
        """
        Set whether or not this action is checked.
        :param is_active: whether or not this action should be checked.
        :return None:
        """
        self._use_cams_action.setChecked(is_active)
        self.empty_cam_actions()

    def add_cam_bool_handler(self, func: classmethod) -> None:
        """
        Add handler to this selectable.
        :param func: The handler.
        :return None:
        """
        self._logger.debug("running")
        self._use_cams_action.toggled.connect(func)
        self._logger.debug("done")

    def set_use_cams_action_active(self, is_active: bool) -> None:
        """
        Set whether or not this action is usable.
        :param is_active: whether or not to let this action be usable.
        :return None:
        """

        self._use_cams_action.setEnabled(is_active)

    def add_open_last_save_dir_handler(self, func: classmethod) -> None:
        """
        Add handler to this selectable.
        :param func: The handler.
        :return None:
        """
        self._logger.debug("running")
        self._open_last_save_dir_action.triggered.connect(func)
        self._logger.debug("done")

    def add_about_app_handler(self, func: classmethod) -> None:
        """
        Add handler to this selectable.
        :param func: The handler.
        :return None:
        """
        self._logger.debug("running")
        self._about_app_action.triggered.connect(func)
        self._logger.debug("done")

    def add_about_company_handler(self, func: classmethod) -> None:
        """
        Add handler to this selectable.
        :param func: The handler.
        :return None:
        """
        self._logger.debug("running")
        self._about_company_action.triggered.connect(func)
        self._logger.debug("done")

    def add_update_handler(self, func: classmethod) -> None:
        """
        Add handler to this selectable.
        :param func: The handler.
        :return None:
        """
        self._logger.debug("running")
        self._update_action.triggered.connect(func)
        self._logger.debug("done")

    def add_log_window_handler(self, func: classmethod) -> None:
        """
        Add handler to this selectable.
        :param func: The handler.
        :return None:
        """
        self._logger.debug("running")
        self._log_window_action.triggered.connect(func)
        self._logger.debug("done")

    def add_cam_action(self,
                       name: str,
                       handler: classmethod,
                       is_active: bool = True) -> None:
        """
        Add a new action in the camera menu by name.
        :param name: The name of the camera being added.
        :param handler: The button handler.
        :param is_active: Whether or not this camera is considered active.
        :return None:
        """

        new_cam_action = QAction(self)
        new_cam_action.setText(name)
        new_cam_action.setCheckable(True)
        new_cam_action.setChecked(is_active)
        new_cam_action.toggled.connect(handler)
        self._cam_actions[name] = new_cam_action
        self._cam_list_menu.addAction(new_cam_action)

    def remove_cam_action(self, name: str) -> None:
        """
        Remove a cam action by name.
        :param name: The name of the camera being removed.
        :return None:
        """

        if name in self._cam_actions.keys():
            self._cam_list_menu.removeAction(self._cam_actions[name])
            del self._cam_actions[name]

    def _eng_clicked(self) -> None:
        """
        Private handler for self._english_action
        :return None:
        """
        if self._lang_callback:
            self._lang_callback(LangEnum.ENG)

    def _fre_clicked(self) -> None:
        """
        Private handler for self._french_action
        :return None:
        """
        if self._lang_callback:
            self._lang_callback(LangEnum.FRE)

    def _ger_clicked(self) -> None:
        """
        Private handler for self._german_action
        :return None:
        """
        if self._lang_callback:
            self._lang_callback(LangEnum.GER)

    def _spa_clicked(self) -> None:
        """
        Private handler for self._spanish_action
        :return None:
        """
        if self._lang_callback:
            self._lang_callback(LangEnum.SPA)

    def _chi_clicked(self) -> None:
        """
        Private handler for self._chinese_action
        :return None:
        """
        if self._lang_callback:
            self._lang_callback(LangEnum.CHI)

    def _debug_clicked(self) -> None:
        """
        Private handler for self._french_action
        :return None:
        """
        if self._debug_callback:
            self._debug_callback(DEBUG)
        self._reset_debug_actions(self._debug_action)

    def _warning_clicked(self) -> None:
        """
        Private handler for self._french_action
        :return None:
        """
        if self._debug_callback:
            self._debug_callback(WARNING)
        self._reset_debug_actions(self._warning_action)

    def _reset_debug_actions(self, keep_checked: QAction) -> None:
        """
        Unset all except for keep_checked QAction.
        :param keep_checked: The QAction to keep checked.
        :return None:
        """
        for action in self._debug_actions:
            action.setChecked(False)
        keep_checked.setChecked(True)

    def _reset_lang_actions(self, keep_checked: QAction) -> None:
        """
        Unset all except for keep_checked QAction.
        :param keep_checked: The QAction to keep checked.
        :return None:
        """
        for action in self._lang_actions:
            action.setChecked(False)
        keep_checked.setChecked(True)

    def _set_texts(self) -> None:
        """
        Set the texts of this view object.
        :return None:
        """
        self._logger.debug("running")
        self._file_menu.setTitle(self._strings[StringsEnum.FILE])
        self._open_last_save_dir_action.setText(
            self._strings[StringsEnum.LAST_DIR])
        self._settings_menu.setTitle(self._strings[StringsEnum.SETTINGS])
        self._debug_menu.setTitle(self._strings[StringsEnum.DEBUG_MENU])
        self._debug_action.setText(self._strings[StringsEnum.DEBUG])
        self._warning_action.setText(self._strings[StringsEnum.WARNING])
        # self._cam_list_menu.setTitle(self._strings[StringsEnum.ATTACHED_CAMS])
        # self._use_cams_action.setText(self._strings[StringsEnum.USE_CAMS])
        self._language_menu.setTitle(self._strings[StringsEnum.LANG])
        self._english_action.setText(self._strings[StringsEnum.ENG])
        self._french_action.setText(self._strings[StringsEnum.FRE])
        self._german_action.setText(self._strings[StringsEnum.GER])
        self._spanish_action.setText(self._strings[StringsEnum.SPA])
        # self._chinese_action.setText(self._strings[StringsEnum.CHI])
        self._help_menu.setTitle(self._strings[StringsEnum.HELP])
        self._about_app_action.setText(self._strings[StringsEnum.ABOUT_APP])
        self._about_company_action.setText(
            self._strings[StringsEnum.ABOUT_COMPANY])
        self._update_action.setText(self._strings[StringsEnum.UPDATE_CHECK])
        self._log_window_action.setText(
            self._strings[StringsEnum.SHOW_LOG_WINDOW])
        self._logger.debug("done")

    def empty_cam_actions(self) -> None:
        """
        :return None:
        """
        for name in self._cam_actions.keys():
            self._cam_list_menu.removeAction(self._cam_actions[name])
        self._cam_actions = {}
Ejemplo n.º 40
0
    def create_menu(self):
        mainMenu = self.menuBar()
        fileMenu = mainMenu.addMenu("File")
        viewMenu = mainMenu.addMenu("View")
        editMenu = mainMenu.addMenu("Edit")
        analysisMenu = mainMenu.addMenu("Analysis")
        helpMenu = mainMenu.addMenu("Help")

        openAction = QAction("Open", self)
        openAction.triggered.connect(self.load)
        openAction.setShortcut("Ctrl+O")
        exportAction = QAction("Export", self)
        exportAction.setShortcut("Ctrl+e")
        exportAction.triggered.connect(self.export_img)
        exitAction = QAction("Exit", self)
        exitAction.triggered.connect(self.close)
        exitAction.setShortcut("Ctrl+q")

        membTransAction = QAction('Membrane Translocation', self)
        thresholdAction = QAction('Threshold', self)
        RoIAction = QAction('RoI', self)
        RoIAction.triggered.connect(self.set_roi)
        MeasureAction = QAction('Measure', self)
        MeasureAction.triggered.connect(self.measure)
        int_trackAction = QAction('Intensity Tracking', self)
        int_trackAction.triggered.connect(self.int_track)

        analysisMenu.addAction(membTransAction)
        analysisMenu.addAction(thresholdAction)
        analysisMenu.addAction(RoIAction)
        analysisMenu.addAction(MeasureAction)
        analysisMenu.addAction(int_trackAction)
        fileMenu.addAction(openAction)
        fileMenu.addAction(exportAction)
        fileMenu.addAction(exitAction)
Ejemplo n.º 41
0
    def __init__(self, parent, log_handlers: [StreamHandler], lang: LangEnum):
        self._logger = getLogger(__name__)
        for h in log_handlers:
            self._logger.addHandler(h)
        self._logger.debug("Initializing")
        super().__init__(parent)
        self.setGeometry(QRect(0, 0, 840, 22))

        self._file_menu = QMenu(self)
        self.addAction(self._file_menu.menuAction())

        self._open_last_save_dir_action = QAction(self)
        self._file_menu.addAction(self._open_last_save_dir_action)

        # self._cam_list_menu = QMenu(self)
        # self._file_menu.addMenu(self._cam_list_menu)

        # self._use_cams_action = QAction(self)
        # self._use_cams_action.setCheckable(True)
        # self._cam_list_menu.addAction(self._use_cams_action)

        # sep = self._cam_list_menu.addSeparator()

        self._settings_menu = QMenu(self)
        self.addAction(self._settings_menu.menuAction())

        self._debug_actions = []
        self._debug_menu = QMenu(self)
        self._settings_menu.addMenu(self._debug_menu)

        self._debug_action = QAction(self)
        self._debug_action.setCheckable(True)
        self._debug_action.triggered.connect(self._debug_clicked)
        self._debug_actions.append(self._debug_action)
        self._debug_menu.addAction(self._debug_action)

        self._warning_action = QAction(self)
        self._warning_action.setCheckable(True)
        self._warning_action.triggered.connect(self._warning_clicked)
        self._debug_actions.append(self._warning_action)
        self._debug_menu.addAction(self._warning_action)

        self._lang_actions = []
        self._language_menu = QMenu(self)
        self._settings_menu.addMenu(self._language_menu)

        self._english_action = QAction(self)
        self._lang_actions.append(self._english_action)
        self._english_action.setCheckable(True)
        self._english_action.triggered.connect(self._eng_clicked)
        self._language_menu.addAction(self._english_action)

        self._french_action = QAction(self)
        self._lang_actions.append(self._french_action)
        self._french_action.setCheckable(True)
        self._french_action.triggered.connect(self._fre_clicked)
        self._language_menu.addAction(self._french_action)

        self._german_action = QAction(self)
        self._lang_actions.append(self._german_action)
        self._german_action.setCheckable(True)
        self._german_action.triggered.connect(self._ger_clicked)
        self._language_menu.addAction(self._german_action)

        self._spanish_action = QAction(self)
        self._lang_actions.append(self._spanish_action)
        self._spanish_action.setCheckable(True)
        self._spanish_action.triggered.connect(self._spa_clicked)
        self._language_menu.addAction(self._spanish_action)

        # TODO: issue with Chinese characters.
        #       Maybe use traditional instead of simplified.
        # self._chinese_action = QAction(self)
        # self._lang_actions.append(self._chinese_action)
        # self._chinese_action.setCheckable(True)
        # self._chinese_action.triggered.connect(self._chi_clicked)
        # self._language_menu.addAction(self._chinese_action)

        self._help_menu = QMenu(self)
        self.addAction(self._help_menu.menuAction())

        self._about_app_action = QAction(self)
        self._help_menu.addAction(self._about_app_action)

        self._about_company_action = QAction(self)
        self._help_menu.addAction(self._about_company_action)

        self._update_action = QAction(self)
        self._help_menu.addAction(self._update_action)

        self._log_window_action = QAction(self)
        self._help_menu.addAction(self._log_window_action)

        self._cam_actions = {}

        self._debug_callback = None
        self._lang_callback = None
        self._strings = dict()
        self.set_lang(lang)
        self._logger.debug("Initialized")
Ejemplo n.º 42
0
    def _create_menu(self):
        file_menu = self.menuBar().addMenu("&File")
        exit_action = QAction(QIcon.fromTheme("application-exit"), "E&xit",
                             self, shortcut = "Ctrl+Q", triggered=qApp.quit)
        file_menu.addAction(exit_action)

        navigation_menu = self.menuBar().addMenu("&Navigation")

        style_icons = ':/qt-project.org/styles/commonstyle/images/'
        back_action = QAction(QIcon.fromTheme("go-previous",
                                             QIcon(style_icons + 'left-32.png')),
                             "Back", self,
                             shortcut = QKeySequence(QKeySequence.Back),
                             triggered = self._tab_widget.back)
        self._actions[QWebEnginePage.Back] = back_action
        back_action.setEnabled(False)
        navigation_menu.addAction(back_action)
        forward_action = QAction(QIcon.fromTheme("go-next",
                                                QIcon(style_icons + 'right-32.png')),
                                "Forward", self,
                                shortcut = QKeySequence(QKeySequence.Forward),
                                triggered = self._tab_widget.forward)
        forward_action.setEnabled(False)
        self._actions[QWebEnginePage.Forward] = forward_action

        navigation_menu.addAction(forward_action)
        reload_action = QAction(QIcon(style_icons + 'refresh-32.png'),
                               "Reload", self,
                               shortcut = QKeySequence(QKeySequence.Refresh),
                               triggered = self._tab_widget.reload)
        self._actions[QWebEnginePage.Reload] = reload_action
        reload_action.setEnabled(False)
        navigation_menu.addAction(reload_action)

        navigation_menu.addSeparator()

        new_tab_action = QAction("New Tab", self,
                             shortcut = 'Ctrl+T',
                             triggered = self.add_browser_tab)
        navigation_menu.addAction(new_tab_action)

        close_tab_action = QAction("Close Current Tab", self,
                                 shortcut = "Ctrl+W",
                                 triggered = self._close_current_tab)
        navigation_menu.addAction(close_tab_action)

        edit_menu = self.menuBar().addMenu("&Edit")

        find_action = QAction("Find", self,
                             shortcut = QKeySequence(QKeySequence.Find),
                             triggered = self._show_find)
        edit_menu.addAction(find_action)

        edit_menu.addSeparator()
        undo_action = QAction("Undo", self,
                             shortcut = QKeySequence(QKeySequence.Undo),
                             triggered = self._tab_widget.undo)
        self._actions[QWebEnginePage.Undo] = undo_action
        undo_action.setEnabled(False)
        edit_menu.addAction(undo_action)

        redo_action = QAction("Redo", self,
                             shortcut = QKeySequence(QKeySequence.Redo),
                             triggered = self._tab_widget.redo)
        self._actions[QWebEnginePage.Redo] = redo_action
        redo_action.setEnabled(False)
        edit_menu.addAction(redo_action)

        edit_menu.addSeparator()

        cut_action = QAction("Cut", self,
                            shortcut = QKeySequence(QKeySequence.Cut),
                            triggered = self._tab_widget.cut)
        self._actions[QWebEnginePage.Cut] = cut_action
        cut_action.setEnabled(False)
        edit_menu.addAction(cut_action)

        copy_action = QAction("Copy", self,
                             shortcut = QKeySequence(QKeySequence.Copy),
                             triggered = self._tab_widget.copy)
        self._actions[QWebEnginePage.Copy] = copy_action
        copy_action.setEnabled(False)
        edit_menu.addAction(copy_action)

        paste_action = QAction("Paste", self,
                             shortcut = QKeySequence(QKeySequence.Paste),
                             triggered = self._tab_widget.paste)
        self._actions[QWebEnginePage.Paste] = paste_action
        paste_action.setEnabled(False)
        edit_menu.addAction(paste_action)

        edit_menu.addSeparator()

        select_all_action = QAction("Select All", self,
                                  shortcut = QKeySequence(QKeySequence.SelectAll),
                                  triggered = self._tab_widget.select_all)
        self._actions[QWebEnginePage.SelectAll] = select_all_action
        select_all_action.setEnabled(False)
        edit_menu.addAction(select_all_action)

        self._bookmark_menu = self.menuBar().addMenu("&Bookmarks")
        add_bookmark_action = QAction("&Add Bookmark", self,
                                    triggered = self._add_bookmark)
        self._bookmark_menu.addAction(add_bookmark_action)
        add_tool_bar_bookmark_action = QAction("&Add Bookmark to Tool Bar", self,
                                           triggered = self._add_tool_bar_bookmark)
        self._bookmark_menu.addAction(add_tool_bar_bookmark_action)
        self._bookmark_menu.addSeparator()

        tools_menu = self.menuBar().addMenu("&Tools")
        download_action = QAction("Open Downloads", self,
                                 triggered = DownloadWidget.open_download_directory)
        tools_menu.addAction(download_action)

        window_menu = self.menuBar().addMenu("&Window")

        window_menu.addAction(self._bookmark_dock.toggleViewAction())

        window_menu.addSeparator()

        zoom_in_action = QAction(QIcon.fromTheme("zoom-in"),
                               "Zoom In", self,
                               shortcut = QKeySequence(QKeySequence.ZoomIn),
                               triggered = self._zoom_in)
        window_menu.addAction(zoom_in_action)
        zoom_out_action = QAction(QIcon.fromTheme("zoom-out"),
                                "Zoom Out", self,
                                shortcut = QKeySequence(QKeySequence.ZoomOut),
                                triggered = self._zoom_out)
        window_menu.addAction(zoom_out_action)

        reset_zoom_action = QAction(QIcon.fromTheme("zoom-original"),
                                  "Reset Zoom", self,
                                  shortcut = "Ctrl+0",
                                  triggered = self._reset_zoom)
        window_menu.addAction(reset_zoom_action)

        about_menu = self.menuBar().addMenu("&About")
        about_action = QAction("About Qt", self,
                              shortcut = QKeySequence(QKeySequence.HelpContents),
                              triggered=qApp.aboutQt)
        about_menu.addAction(about_action)
Ejemplo n.º 43
0
class Header(QLabel):
    currPosX = 0
    currPosY = 0
    selectedHeader = None
    def __init__(self,parent = None):
        QLabel.__init__(self, parent)
        self.headers = []
        self.position = 0
        self.viewWidth = 800
        self.viewHeight = 100
        self.hideFlag = False
        self.w = 180
        self.h = 40
        self.t = 10
        self.setMouseTracking(True)

        self.setContextMenuPolicy(QtCore.Qt.CustomContextMenu)
        self.customContextMenuRequested.connect(self.createHeaderMenus)

        self.deleteAct = QAction('Hide', self)
        self.deleteAct.setStatusTip('Hide this life-line')
        self.deleteAct.triggered.connect(self.hideLifeLine)

        self.groupAct = QAction('Make a cluster', self)
        self.groupAct.setStatusTip('Make a cluster of multiple life-lines')
        self.groupAct.triggered.connect(self.showClusterDialog)

        self.scatterAct = QAction('Scatter', self)
        self.scatterAct.setStatusTip('Scatter this cluster')
        self.scatterAct.triggered.connect(self.scatterCluster)

    def connectMainView(self,mainView):
        """
        mainView contains sequence diagram
        """
        self.mainView = mainView

    def reset(self):
        self.headers = []
        self.update() # Clear up all the heads

    def createHeaderMenus(self):
        for headInfo in self.headers:
            x = headInfo['x']
            x = x - self.position
            if self.currPosX > x and self.currPosX < x+self.w and self.currPosY > self.t and self.currPosY < self.h+self.t:
                if 0 == self.headers.index(headInfo):
                    break

                self.selectedHeader = headInfo
                menu = QMenu()
                if headInfo['flagCluster']:
                    menu.addAction(self.scatterAct)
                else:
                    menu.addAction(self.deleteAct)
                    menu.addAction(self.groupAct)
                menu.exec_(QtGui.QCursor.pos())

    def showClusterDialog(self):
        response, cluster_name = ClusterDialog.ClusterDialog.getClusterName(self.mainView.getLifeLines(),self.selectedHeader['name'])

        if response:
            if self.mainView.createCluster(cluster_name):
                pass
            else:
                pass

    def scatterCluster(self):
        self.mainView.removeCluster(self.selectedHeader['name'])
        
    def hideLifeLine(self):
        self.mainView.hideLifeline(self.selectedHeader['name'])
        self.mainView.refreshData()

    def mouseMoveEvent(self,e):
        self.currPosX = e.x()
        self.currPosY = e.y()
        selected_head_name = None
        for headInfo in self.headers:
            x = headInfo['x']
            headx = x - self.position
            if e.x() > headx and e.x() < headx+self.w and e.y() > self.t and e.y() < self.h+self.t:
                msg_list = self.mainView.getMessageList(headInfo['name'])
                formatted = '<< ' + headInfo['name'] + ' >>\n'
                for m in msg_list:
                    formatted += '\n- ' + m
                self.setToolTip(formatted)
                break
            else:
                self.setToolTip('')

    def updateViewSize(self,width,height):
        self.viewWidth = width
        self.setFixedHeight(self.viewHeight)

    def paintEvent(self, event):
        QLabel.paintEvent(self,event)

        self.resize(self.viewWidth,self.viewHeight)

        for headInfo in self.headers:
            name = headInfo['name']
            x = headInfo['x']
            x = x - self.position

            if x+self.w < 0:
                continue

            if x > self.viewWidth:
                continue

            self.headLeftPos = x
            self.headRightPos = x+self.w
            self.headTopPos = self.t
            self.headBottomPos = self.t+self.h

            qp = QtGui.QPainter()
            qp.begin(self)

            qp.setBrush(headInfo['color'])
            qp.drawRect(x,self.t,self.w,self.h)
            qp.setPen(QtGui.QColor(20, 20, 30))
            qp.setFont(QtGui.QFont('Decorative', 10))

            leaf_name = list(reversed(name.split(".")))[0]
            parent_name = ".".join(list(reversed(list(reversed(name.split(".")))[1:])))

            if parent_name == "":
                qp.setFont(QtGui.QFont('Decorative', 11))
                wd = QtGui.QFontMetrics(self.font()).boundingRect(leaf_name).width()
                align_option = QtCore.Qt.AlignRight | QtCore.Qt.AlignVCenter if wd > self.w-20 else QtCore.Qt.AlignCenter | QtCore.Qt.AlignVCenter
                qp.drawText(QtCore.QRect(x+10,self.t,self.w-20,self.h), align_option, leaf_name) 
            else:
                qp.setFont(QtGui.QFont('Decorative', 7))
                wd = QtGui.QFontMetrics(self.font()).boundingRect(parent_name).width()
                align_option = QtCore.Qt.AlignRight | QtCore.Qt.AlignVCenter if wd > self.w-20 else QtCore.Qt.AlignCenter | QtCore.Qt.AlignVCenter
                qp.drawText(QtCore.QRect(x+10,self.t,self.w-20,self.h/2), align_option, parent_name) 
                qp.setFont(QtGui.QFont('Decorative', 11))
                qp.drawText(QtCore.QRect(x+10,self.t+self.h/2,self.w-20,self.h/2), QtCore.Qt.AlignCenter | QtCore.Qt.AlignVCenter, leaf_name) 

            qp.drawLine(x+self.w/2,self.h+self.t,x+self.w/2,90000)

            qp.end()

    def mouseReleaseEvent(self, e):
        self.currPosX = e.x()
        self.currPosY = e.y()
        selected_head_name = None

    def wheelEvent(self, e):
        print("mouse wheel event")

    def drawAtHeaderRegion(self,x,color,name,flagCluster):
        item = {'x':x, 'color':color, 'name':name, 'flagCluster':flagCluster}
        if item not in self.headers:
            self.headers.append(item)

    def resetLifelines(self):
        del self.headers[:]

    def setPosition(self, x):
        self.position = x
        self.update()

    def activateHide(self,flag):
        self.hideFlag = flag

    def resetAllLifelines(self):
        pass

    def activateCapture(self,flag):
        pass

    def searchMessage(self,str):
        pass

    def moveToPrev(self):
        pass
        
    def moveToNext(self):
        pass