Esempio n. 1
0
class DownloadedListWidget(QListWidget):
    def __init__(self):
        super(DownloadedListWidget, self).__init__()
        self.setIconSize(QSize(24, 24))
        self.setViewMode(QListWidget.ListMode)
        self.currentRowChanged.connect(self.savelog)
        self.setObjectName('download')

    def get_Item_Widget(self, title, info, url):
        wight = QWidget()
        self.opendirAct = QAction(QIcon('res/opendir.png'), '打开下载路径')
        self.opendirAct.triggered.connect(self.on_click)
        self.fileurl = url
        self.outer = QHBoxLayout()
        self.layout_main = QVBoxLayout()
        self.title = QLabel()
        self.title.setText(title)
        self.bottomLine = QHBoxLayout()
        self.sizelabel = QLabel()
        self.sizelabel.setText(info)
        self.timelabel = QLabel()
        self.timelabel.setText('完成时间:{}'.format(
            strftime("%Y-%m-%d %H:%M:%S", localtime())))
        self.openbtn = QToolButton()
        self.openbtn.setToolButtonStyle(Qt.ToolButtonIconOnly)
        self.openbtn.setToolTip('选择')
        self.openbtn.setPopupMode(QToolButton.MenuButtonPopup)
        self.openbtn.setIcon(QIcon('res/setting.png'))
        self.openbtn.setFixedSize(QSize(38, 38))
        self.openbtn.setIconSize(QSize(38, 38))
        self.openbtn.addAction(self.opendirAct)
        self.bottomLine.addWidget(self.sizelabel)
        self.bottomLine.addWidget(self.timelabel)
        self.layout_main.addWidget(self.title)
        self.layout_main.addLayout(self.bottomLine)
        self.outer.addLayout(self.layout_main)
        self.outer.addWidget(self.openbtn)
        wight.setLayout(self.outer)
        return wight

    def opendir(self):
        system(("start explorer %s" % self.fileurl).replace('/', '\\'))

    def on_click(self):
        # QDesktopServices.openUrl(QUrl('https://www.alipay.com/'))
        if self.sender() == self.opendirAct:
            self.opendir()

    def savelog(self):
        print('添加了')
Esempio n. 2
0
class Spanners(tool.Tool):
    """Dynamics tool in the quick insert panel toolbox."""
    def __init__(self, panel):
        super(Spanners, self).__init__(panel)
        self.removemenu = QToolButton(self,
                                      autoRaise=True,
                                      popupMode=QToolButton.InstantPopup,
                                      icon=icons.get('edit-clear'))

        mainwindow = panel.parent().mainwindow()
        mainwindow.selectionStateChanged.connect(self.removemenu.setEnabled)
        self.removemenu.setEnabled(mainwindow.hasSelection())

        ac = documentactions.DocumentActions.instance(
            mainwindow).actionCollection
        self.removemenu.addAction(ac.tools_quick_remove_slurs)
        self.removemenu.addAction(ac.tools_quick_remove_beams)
        self.removemenu.addAction(ac.tools_quick_remove_ligatures)

        layout = QHBoxLayout()
        layout.addWidget(self.removemenu)
        layout.addStretch(1)

        self.layout().addLayout(layout)
        self.layout().addWidget(ArpeggioGroup(self))
        self.layout().addWidget(GlissandoGroup(self))
        self.layout().addWidget(SpannerGroup(self))
        self.layout().addWidget(GraceGroup(self))
        self.layout().addStretch(1)

    def icon(self):
        """Should return an icon for our tab."""
        return symbols.icon("spanner_phrasingslur")

    def title(self):
        """Should return a title for our tab."""
        return _("Spanners")

    def tooltip(self):
        """Returns a tooltip"""
        return _("Slurs, spanners, etcetera.")
Esempio n. 3
0
class Spanners(tool.Tool):
    """Dynamics tool in the quick insert panel toolbox."""
    def __init__(self, panel):
        super(Spanners, self).__init__(panel)
        self.removemenu = QToolButton(self,
            autoRaise=True,
            popupMode=QToolButton.InstantPopup,
            icon=icons.get('edit-clear'))

        mainwindow = panel.parent().mainwindow()
        mainwindow.selectionStateChanged.connect(self.removemenu.setEnabled)
        self.removemenu.setEnabled(mainwindow.hasSelection())

        ac = documentactions.DocumentActions.instance(mainwindow).actionCollection
        self.removemenu.addAction(ac.tools_quick_remove_slurs)
        self.removemenu.addAction(ac.tools_quick_remove_beams)
        self.removemenu.addAction(ac.tools_quick_remove_ligatures)

        layout = QHBoxLayout()
        layout.addWidget(self.removemenu)
        layout.addStretch(1)

        self.layout().addLayout(layout)
        self.layout().addWidget(ArpeggioGroup(self))
        self.layout().addWidget(GlissandoGroup(self))
        self.layout().addWidget(SpannerGroup(self))
        self.layout().addWidget(GraceGroup(self))
        self.layout().addStretch(1)

    def icon(self):
        """Should return an icon for our tab."""
        return symbols.icon("spanner_phrasingslur")

    def title(self):
        """Should return a title for our tab."""
        return _("Spanners")

    def tooltip(self):
        """Returns a tooltip"""
        return _("Slurs, spanners, etcetera.")
Esempio n. 4
0
class ToolBars(QWidget):
    def __init__(self):
        super(ToolBars, self).__init__()
        self.tools = QToolBar()
        self.tools.showMaximized()
        self.toolbar = QToolButton()
        self.toolbar.showMaximized()
        self.toolbar.setIcon(QIcon("images/images.png"))
        # self.toolbar.setIconSize(QSize(800,800))
        self.toolbar.setPopupMode(QToolButton.InstantPopup)
        self.toolbar.setAutoRaise(True)
        self.toolbar.setToolButtonStyle(Qt.ToolButtonIconOnly)
        self.toolbar.setCheckable(True)
        self.tools.addWidget(self.toolbar)
        self.toolbar.setFixedSize(100, 100)

        self.inbox = QAction(QIcon("images/sign.png"), "Inbox", self)
        self.sends = QAction(QIcon("images/sign.png"), "Send", self)
        self.create = QAction(QIcon("images/sign.png"), "Create", self)
        self.trash = QAction(QIcon("images/sign.png"), "Trash", self)
        self.draft = QAction(QIcon("images/sign.png"), "Draft", self)
        self.toolbar.addAction(self.inbox)
        self.toolbar.addAction(self.create)
        self.toolbar.addAction(self.sends)
        self.toolbar.addAction(self.trash)
        self.toolbar.addAction(self.draft)
        self.tools.setStyleSheet('''
            color: rgb(0, 0, 255);
            font-size: 100;
            font-weight: 1000;
        ''')
        self.toolbar.setStyleSheet('''
            background-color: rgb(255, 0, 0);
        ''')

        self.combo = QComboBox()
        self.combo.setMaximumWidth(800)
        self.combo.setFixedHeight(200)
        ides = api.listAddresses()
        new_ides = json.loads(ides)
        list_ides = new_ides['addresses']
        list_com = []
        for address in list_ides:
            ids = address['address']
            labels = address['label']
            add_label2 = labels + "<" + ids + ">"
            self.combo.addItem(add_label2)
        self.tools.addWidget(self.combo)
Esempio n. 5
0
class Articulations(tool.Tool):
    """Articulations tool in the quick insert panel toolbox.
    
    """
    def __init__(self, panel):
        super(Articulations, self).__init__(panel)
        self.shorthands = QCheckBox(self)
        self.shorthands.setChecked(True)
        self.removemenu = QToolButton(self,
                                      autoRaise=True,
                                      popupMode=QToolButton.InstantPopup,
                                      icon=icons.get('edit-clear'))

        mainwindow = panel.parent().mainwindow()
        mainwindow.selectionStateChanged.connect(self.removemenu.setEnabled)
        self.removemenu.setEnabled(mainwindow.hasSelection())

        ac = documentactions.DocumentActions.instance(
            mainwindow).actionCollection
        self.removemenu.addAction(ac.tools_quick_remove_articulations)
        self.removemenu.addAction(ac.tools_quick_remove_ornaments)
        self.removemenu.addAction(ac.tools_quick_remove_instrument_scripts)

        layout = QHBoxLayout()
        layout.addWidget(self.shorthands)
        layout.addWidget(self.removemenu)
        layout.addStretch(1)

        self.layout().addLayout(layout)
        for cls in (
                ArticulationsGroup,
                OrnamentsGroup,
                SignsGroup,
                OtherGroup,
        ):
            self.layout().addWidget(cls(self))
        self.layout().addStretch(1)
        app.translateUI(self)

    def translateUI(self):
        self.shorthands.setText(_("Allow shorthands"))
        self.shorthands.setToolTip(
            _("Use short notation for some articulations like staccato."))
        self.removemenu.setToolTip(_("Remove articulations etc."))

    def icon(self):
        """Should return an icon for our tab."""
        return symbols.icon("articulation_prall")

    def title(self):
        """Should return a title for our tab."""
        return _("Articulations")

    def tooltip(self):
        """Returns a tooltip"""
        return _("Different kinds of articulations and other signs.")
Esempio n. 6
0
class Articulations(tool.Tool):
    """Articulations tool in the quick insert panel toolbox.

    """
    def __init__(self, panel):
        super(Articulations, self).__init__(panel)
        self.shorthands = QCheckBox(self)
        self.shorthands.setChecked(True)
        self.removemenu = QToolButton(self,
            autoRaise=True,
            popupMode=QToolButton.InstantPopup,
            icon=icons.get('edit-clear'))

        mainwindow = panel.parent().mainwindow()
        mainwindow.selectionStateChanged.connect(self.removemenu.setEnabled)
        self.removemenu.setEnabled(mainwindow.hasSelection())

        ac = documentactions.DocumentActions.instance(mainwindow).actionCollection
        self.removemenu.addAction(ac.tools_quick_remove_articulations)
        self.removemenu.addAction(ac.tools_quick_remove_ornaments)
        self.removemenu.addAction(ac.tools_quick_remove_instrument_scripts)

        layout = QHBoxLayout()
        layout.addWidget(self.shorthands)
        layout.addWidget(self.removemenu)
        layout.addStretch(1)

        self.layout().addLayout(layout)
        for cls in (
                ArticulationsGroup,
                OrnamentsGroup,
                SignsGroup,
                OtherGroup,
            ):
            self.layout().addWidget(cls(self))
        self.layout().addStretch(1)
        app.translateUI(self)

    def translateUI(self):
        self.shorthands.setText(_("Allow shorthands"))
        self.shorthands.setToolTip(_(
            "Use short notation for some articulations like staccato."))
        self.removemenu.setToolTip(_(
            "Remove articulations etc."))

    def icon(self):
        """Should return an icon for our tab."""
        return symbols.icon("articulation_prall")

    def title(self):
        """Should return a title for our tab."""
        return _("Articulations")

    def tooltip(self):
        """Returns a tooltip"""
        return _("Different kinds of articulations and other signs.")
class DockElementPlotter(DockElement):

    selected = None
    registerKeySignal = pyqtSignal(str, str, str)

    __settings = {}

    def __init__(self, mainWindow, title):
        DockElement.__init__(self, mainWindow, 'Plotter')
        self.name = title
        self.setWindowTitle(title)
        self.setupUi()

    def setupUi(self):
        self.resize(500, 300)
        self.settingsWidget = QWidget()
        self.settingsWidget.setMinimumSize(900, 150)
        # Create the main widget as a container widget.
        self.mainWidget = QWidget(self)
        self.setWidget(self.mainWidget)
        mainLayout = QVBoxLayout(self.mainWidget)
        # Create 'Settings' dropdown button.
        self.settingsButton = QToolButton(self)
        self.settingsButton.setText("Settings")
        # Remove the menu indicator by applying a global style.
        self.settingsButton.setObjectName("noIndicator")
        # And replace it with a down arrow icon instead (which looks better).
        self.settingsButton.setArrowType(QtCore.Qt.DownArrow)
        self.settingsButton.setToolButtonStyle(
            QtCore.Qt.ToolButtonTextBesideIcon)
        # Set the popup that opens on button click.
        self.settingsButton.setPopupMode(QToolButton.InstantPopup)
        action = QWidgetAction(self.settingsButton)
        action.setDefaultWidget(self.settingsWidget)
        self.settingsButton.addAction(action)
        # Create a horizontal layout for the settings button.
        buttonLayout = QHBoxLayout()
        buttonLayout.addWidget(self.settingsButton)
        buttonLayout.addStretch()
        mainLayout.addLayout(buttonLayout)
        # Create the plotter widget.
        self.plotter = Qt5Plotter()
        self.plotter.setPlotterGUI(self)
        self.plotter.setMinimumSize(300, 200)
        self.plotter.plotLinear()
        mainLayout.addWidget(self.plotter)
        # Create the settings dialog.
        self.setupSettingsDialogUi()
        # Set keys that are plotted by default
        self.defaultKeys = {"TEST": ["loss"], "TRAIN": ["loss"]}

    def setupSettingsDialogUi(self):
        self.settingsDialogLayout = QGridLayout()
        # DropDown for plotAgainstTime or Iterations
        self.dbTimeIter = QComboBox()
        self.dbTimeIter.addItem("Iterations")
        self.dbTimeIter.addItem("Time")
        self.dbTimeIter.setFixedWidth(130)
        self.dbTimeIter.currentIndexChanged.connect(self.plotAgainstTimeIter)
        self.settingsDialogLayout.addWidget(self.dbTimeIter, 1, 3)
        # DropDown for plotting scale linear or logarithmic
        self.dbLinLoga = QComboBox()
        self.dbLinLoga.addItem("Linear")
        self.dbLinLoga.addItem("Logarithmic")
        self.dbLinLoga.setFixedWidth(130)
        self.dbLinLoga.currentIndexChanged.connect(self.plotLinLoga)
        self.settingsDialogLayout.addWidget(self.dbLinLoga, 3, 3)
        # Dynamic checkboxes
        # Key lists from parser that define the table rows for train and test
        self.test_dict_list = []
        self.train_dict_list = []
        # Lists for checkboxes for train and test
        self.test_cb = []
        self.train_cb = []
        # Text labels for better display
        testLabel = QLabel("Test keys:")
        trainLabel = QLabel("Train keys:")
        timeIterLabel = QLabel("Plot against:")
        LinLogaLabel = QLabel("Plot scale:")
        self.settingsDialogLayout.addWidget(testLabel, 0, 4)
        self.settingsDialogLayout.addWidget(trainLabel, 2, 4)
        self.settingsDialogLayout.addWidget(timeIterLabel, 0, 3)
        self.settingsDialogLayout.addWidget(LinLogaLabel, 2, 3)
        # create default Checkboxes
        self.createCheckboxes(self.test_dict_list, self.train_dict_list)
        # Button select Logfiles
        self.btn1 = QPushButton(
            QtGui.QIcon(QApplication.style().standardIcon(
                QStyle.SP_DialogOpenButton)), "")
        self.btn1.setFixedWidth(40)
        self.btn1.clicked.connect(self.getFiles)
        self.settingsDialogLayout.addWidget(self.btn1, 3, 0)
        # Button remove item
        self.btn2 = QPushButton(
            QtGui.QIcon(QApplication.style().standardIcon(
                QStyle.SP_TrashIcon)), "")
        self.btn2.setFixedWidth(40)
        self.btn2.clicked.connect(self.removeItem)
        self.settingsDialogLayout.addWidget(self.btn2, 3, 1)
        # Button CSV export
        self.btn3 = QPushButton("Export as CSV")
        self.btn3.setFixedWidth(110)
        self.btn3.clicked.connect(self.exportCSV)
        self.settingsDialogLayout.addWidget(self.btn3, 3, 2)
        # Create Logfile list
        self.leftlist = QListWidget()
        self.leftlist.setFixedSize(200, 100)
        self.Stack = QStackedWidget(self)
        self.settingsDialogLayout.addWidget(self.Stack, 0, 0, 3, 3)
        self.settingsDialogLayout.addWidget(self.leftlist, 0, 0, 3, 3)
        self.leftlist.currentRowChanged.connect(self.display)
        self.leftlist.currentItemChanged.connect(self.selectedLogItem)
        self.settingsWidget.setLayout(self.settingsDialogLayout)
        # Signal handling
        self.registerKeySignal.connect(self.registerKey)

    def btnstatetest(self, checkbox):
        """
        Plot the selected checkbox for Test-Data
        """
        if self.selected:
            self.plotter.showMetricTest(self.selected, checkbox.text(),
                                        checkbox.isChecked())
            self.displayPlot()
            self.__settings["checkBoxes"][self.selected]["TEST"][
                checkbox.text()] = checkbox.isChecked()

    def btnstatetrain(self, checkbox):
        """
        Plot the selected checkbox for Train-Data
        """
        if self.selected:
            self.plotter.showMetricTrain(self.selected, checkbox.text(),
                                         checkbox.isChecked())
            self.displayPlot()
            self.__settings["checkBoxes"][self.selected]["TRAIN"][
                checkbox.text()] = checkbox.isChecked()

    def displayPlot(self):
        """
        Update the plotter.
        """
        if self.selected:
            self.plotter.plot()
            self.plotter.show()
            self.createNecessaryDocks()

    def createNecessaryDocks(self):
        """
        Create the necessary docks if they don't exist.
        """
        if self.__settings is None:
            self.__settings = {}
        if "checkBoxes" not in self.__settings:
            self.__settings["checkBoxes"] = {}
        if self.selected not in self.__settings["checkBoxes"] or \
                isinstance(self.__settings["checkBoxes"][self.selected], list):
            self.__settings["checkBoxes"][self.selected] = {
                "TEST": {},
                "TRAIN": {}
            }

    def existsKeySelection(self):
        """
        Returns true if there is a selection by the user of keys to be plotted
        """
        if self.__settings is None:
            self.__settings = {}
        if "checkBoxes" not in self.__settings:
            self.__settings["checkBoxes"] = {}
        if self.selected not in self.__settings["checkBoxes"]:
            return False
        return True

    def createCheckboxes(self, test_list, train_list):
        """
        Dynamically creates checkboxes, which are in the lists: test_list and train_list
        """
        self.test_dict_list = test_list
        self.train_dict_list = train_list
        # As long as there are elements in TEST list: create Checkboxes
        if self.test_dict_list is not None:
            for i in range(len(self.test_dict_list)):
                self.test_cb.append(QCheckBox(self.test_dict_list[i], self))
                self.settingsDialogLayout.addWidget(self.test_cb[i], 1, 4 + i)
                self.test_cb[i].stateChanged.connect(
                    lambda checked, i=i: self.btnstatetest(self.test_cb[i]))
                if self.existsKeySelection() and self.test_cb[i].text() in \
                        self.__settings["checkBoxes"][self.selected]["TEST"]:
                    # Compatibility for older projects
                    try:
                        self.test_cb[i].setChecked(
                            self.__settings["checkBoxes"][self.selected]
                            ["TEST"].get(self.test_cb[i].text(), True))
                    except AttributeError:
                        self.test_cb[i].setChecked(True)
                else:
                    self.test_cb[i].setChecked(
                        self.test_cb[i].text() in self.defaultKeys["TEST"])
                self.btnstatetest(self.test_cb[i])

        # As long as there are elements in TRAIN list: create Checkboxes
        if self.train_dict_list is not None:
            for i in range(len(self.train_dict_list)):
                self.train_cb.append(QCheckBox(self.train_dict_list[i], self))
                self.settingsDialogLayout.addWidget(self.train_cb[i], 3, 4 + i)
                self.train_cb[i].stateChanged.connect(
                    lambda checked, i=i: self.btnstatetrain(self.train_cb[i]))
                if self.existsKeySelection() and self.train_cb[i].text() in \
                        self.__settings["checkBoxes"][self.selected]["TRAIN"]:
                    # Compatibility for older projects
                    try:
                        self.train_cb[i].setChecked(
                            self.__settings["checkBoxes"][self.selected]
                            ["TRAIN"].get(self.train_cb[i].text(), True))
                    except AttributeError:
                        self.train_cb[i].setChecked(True)

                else:
                    self.train_cb[i].setChecked(
                        self.train_cb[i].text() in self.defaultKeys["TRAIN"])
                self.btnstatetrain(self.train_cb[i])
        self.settingsWidget.setLayout(self.settingsDialogLayout)

    def display(self, i):
        self.Stack.setCurrentIndex(i)

    def loadFiles(self, filenames):
        """
        Loads every log file in the list of filenames and adds them to the list of logs.
        """
        for i in range(len(filenames)):
            f = filenames[i]
            if not os.path.exists(f):
                Log.error("External log not found: " + f,
                          Log.getCallerId("plotter"))
            else:
                parser = Parser(open(f, 'r'), OrderedDict(),
                                Log.getCallerId(str(f)))
                head, tail = os.path.split(str(f))
                logId = "external_" + tail
                logName = "[ext] " + tail
                self.putLog(logId, parser, logName=logName)
                parser.parseLog()

                # This is for saving the loaded logs in the project file
                # (create the necessary docks if they don't exist)
                if self.__settings is None:
                    self.__settings = {"logFiles": {logId: f}}
                elif "logFiles" not in self.__settings:
                    self.__settings["logFiles"] = {logId: f}
                else:
                    self.__settings["logFiles"][logId] = f

    def getFiles(self):
        """
        Dialog for adding different data files to list for plotting
        """
        dlg = QFileDialog()
        dlg.setFileMode(QFileDialog.ExistingFiles)
        if dlg.exec_():
            self.loadFiles(dlg.selectedFiles())
        self.selectLast()

    def plotAgainstTimeIter(self):
        if self.dbTimeIter.currentText() == "Time":
            self.plotter.plotAgainstTime()
            self.__settings["againstTime"] = "Time"
            self.plotter.plot()
        else:
            if self.dbTimeIter.currentText() == "Iterations":
                self.plotter.plotAgainstIterations()
                self.__settings["againstTime"] = "Iterations"
                self.plotter.plot()

    def plotLinLoga(self):
        if self.dbLinLoga.currentText() == "Linear":
            self.plotter.plotLinear()
            self.__settings["logarithmic"] = "Linear"
            self.plotter.plot()
        else:
            if self.dbLinLoga.currentText() == "Logarithmic":
                self.plotter.plotLogarithmic()
                self.__settings["logarithmic"] = "Logarithmic"
                self.plotter.plot()

    def putLog(self, logId, parser, plotOnUpdate=False, logName=None):
        """
        Add a log (i.e. parser) to the list of shown logs. If a log with the
        log name already exists primes are added to the name until it is unique.
        """
        for i in range(self.leftlist.count()):
            if logId == self.leftlist.item(i).data(Qt.UserRole):
                return
        if not logName:
            logName = logId
        self.test_dict_list = []
        self.train_dict_list = []
        while self.leftlist.findItems(logName, Qt.MatchExactly):
            logName += "'"
        self.plotter.putLog(logId, logName, parser, plotOnUpdate)
        logItem = QListWidgetItem(logName)
        v = QVariant(logId)
        logItem.setData(Qt.UserRole, v)
        self.leftlist.insertItem(self.leftlist.count(), logItem)
        self.selectLast()

    def removeLog(self, logId, logName):
        try:
            self.__settings["checkBoxes"].pop(logId)
        except KeyError:
            pass
        self.plotter.removeLog(logId)
        item = self.leftlist.findItems(logName, Qt.MatchExactly)
        if item:
            row = self.leftlist.row(item[0])
            self.leftlist.takeItem(row)
            self.test_dict_list = []
            self.train_dict_list = []
            self.selectLast()
            self.plotter.plot()
            self.plotter.show()

    def registerKey(self, logId, phase, key):
        """
        Registers the key given by the signal. This is only of interest if the key belongs
        to the selected log file. A new checkbox is then created for that key.
        """
        if self.leftlist.currentItem():
            if str(self.leftlist.currentItem().data(Qt.UserRole)) == logId:
                if phase == "TEST":
                    self.test_dict_list.append(key)
                if phase == "TRAIN":
                    self.train_dict_list.append(key)
                self.updateCheckboxes(self.test_dict_list,
                                      self.train_dict_list)

    def removeItem(self):
        """
        Removes the selected item from the list and also from plot.
        """
        item = self.leftlist.takeItem(self.leftlist.currentRow())
        if item is not None:
            self.removeLog(item.data(Qt.UserRole), item.text())
            self.displayPlot()
            self.selectLast()
            if (self.__settings is not None and "logFiles" in self.__settings
                    and str(item.data(
                        Qt.UserRole)) in self.__settings["logFiles"]):
                del self.__settings["logFiles"][str(item.data(Qt.UserRole))]

    def selectLast(self):
        if len(self.leftlist) > 0:
            self.leftlist.setCurrentItem(
                self.leftlist.item(len(self.leftlist) - 1))
            self.selectedLogItem(self.leftlist.item(len(self.leftlist) - 1))
        else:
            self.test_dict_list = []
            self.train_dict_list = []
            self.updateCheckboxes(self.test_dict_list, self.train_dict_list)

    def selectedLogItem(self, item, update=True):
        """
        Memorize which logfile is selected, block signals, and asks plotter if the checkbox is
        selected or not.
        """
        if item:
            if update:
                self.updateCheckboxes(
                    list(
                        self.plotter.getParser(str(item.data(
                            Qt.UserRole))).getKeys('TEST')),
                    list(
                        self.plotter.getParser(str(item.data(
                            Qt.UserRole))).getKeys('TRAIN')))
            self.selected = str(str(item.data(Qt.UserRole)))
            self.tickBoxes()
            self.__settings["selectedIndex"] = self.leftlist.row(item)

    def updateCheckboxes(self, test_list, train_list):
        """
        Clear all checkboxes and clear the layer and create new checkboxes and
        add them to the layer again
        """
        for i in range(len(self.test_cb)):
            self.settingsDialogLayout.removeWidget(self.test_cb[i])
            self.test_cb[i].deleteLater()
            self.test_cb[i] = None

        for i in range(len(self.train_cb)):
            self.settingsDialogLayout.removeWidget(self.train_cb[i])
            self.train_cb[i].deleteLater()
            self.train_cb[i] = None

        self.test_cb = []
        self.train_cb = []
        # create new Checkboxes with new Keys
        self.createCheckboxes(test_list, train_list)
        self.tickBoxes()

    def tickBoxes(self):
        """
        Whether a plot is shown is stored in the plotter object. This method
        ticks the checkboxes of the keys whose plot is shown in the plotter.
        """
        for i in range(len(self.test_cb)):
            self.test_cb[i].blockSignals(True)
            self.test_cb[i].setChecked(
                self.plotter.isMetricTestShown(self.selected,
                                               self.test_cb[i].text()))
            self.test_cb[i].blockSignals(False)
        for i in range(len(self.train_cb)):
            self.train_cb[i].blockSignals(True)
            self.train_cb[i].setChecked(
                self.plotter.isMetricTrainShown(self.selected,
                                                self.train_cb[i].text()))
            self.train_cb[i].blockSignals(False)

    def setProject(self, project):
        """
        This sets the project object. The plotter settings have the following structure:

        "plotter": {
                   "checkBoxes": {
                       "logName1": {
                           "TEST": {
                                "accuracy": true,
                                "loss": false
                            },
                            "TRAIN": {
                                "LearningRate": true,
                                "loss": false
                            }
                       },
                       "logName2": {
                           ...
                       },
                       ...
                   },
                   "selectedIndex": 0,
                   "againstTime": "Iterations",
                   "logarithmic": "Logarithmic"
               }

        """

        if "plotter" not in project.getSettings():
            project.getSettings()["plotter"] = self.__settings
        else:
            self.__settings = project.getSettings()["plotter"]
        selectedIndex = -1
        if "selectedIndex" in self.__settings:
            selectedIndex = self.__settings["selectedIndex"]
        if "logFiles" in self.__settings:
            self.loadFiles(list(self.__settings["logFiles"].values()))
        if "checkBoxes" in self.__settings:
            for name in self.__settings["checkBoxes"]:
                for key in self.__settings["checkBoxes"][name]["TEST"]:
                    # Compatibility for older projects
                    try:
                        self.plotter.showMetricTest(
                            name, key, self.__settings["checkBoxes"][name]
                            ["TEST"].get(key))
                    except AttributeError:
                        self.plotter.showMetricTest(name, key, True)
                for key in self.__settings["checkBoxes"][name]["TRAIN"]:
                    # Compatibility for older projects
                    try:
                        self.plotter.showMetricTrain(
                            name, key, self.__settings["checkBoxes"][name]
                            ["TRAIN"].get(key))
                    except AttributeError:
                        self.plotter.showMetricTrain(name, key, True)
        if "againstTime" in self.__settings:
            index = self.dbTimeIter.findText(self.__settings["againstTime"],
                                             Qt.MatchFixedString)
            if index >= 0:
                self.dbTimeIter.setCurrentIndex(index)
        if "logarithmic" in self.__settings:
            index = self.dbLinLoga.findText(self.__settings["logarithmic"],
                                            Qt.MatchFixedString)
            if index >= 0:
                self.dbLinLoga.setCurrentIndex(index)
        #for sid in project.getSessions():
        #    session = project.getSession(sid)
        #    self.putLog(str(session.getLogId()), session.getParser(), True, str(session.getLogFileName(True)))
        self.plotter.plot()
        if selectedIndex >= 0:
            self.leftlist.setCurrentItem(self.leftlist.item(selectedIndex))
            self.selectedLogItem(self.leftlist.item(selectedIndex), False)
        else:
            self.selectLast()
        # Delete plot if session is deleted
        project.deleteSession.connect(lambda sid: self.removeLog(
            str(project.getSession(sid).getLogId()),
            str(project.getSession(sid).getLogFileName(True))))
        project.deleteSession.connect(
            lambda sid: project.deletePlotterSettings(
                str(project.getSession(sid).getLogId())))
        project.resetSession.connect(lambda sid: self.removeLog(
            str(project.getSession(sid).getLogId()),
            str(project.getSession(sid).getLogFileName(True))))
        project.resetSession.connect(lambda sid: project.deletePlotterSettings(
            str(project.getSession(sid).getLogId())))

    def exportCSV(self):
        """
        Opens a file dialog and the plotter saves the shown plots to the selected file.
        The file dialog only appears if there is at least one plot.
        """
        if self.plotter.numGraphs() == 0:
            QMessageBox.question(self, 'PyQt5 message', "Nothing selected!",
                                 QMessageBox.Ok, QMessageBox.Ok)
        else:
            path = str(
                QFileDialog.getSaveFileName(
                    filter="CSV table (*.csv) ;; Text file (*.txt)")[0])
            if path:
                if not (path.endswith(".csv") or path.endswith(".txt")):
                    path = path + ".csv"
                self.plotter.exportCSVToFile(path)
Esempio n. 8
0
class MainWindow(QMainWindow):
  def __init__(self, ctx):
    super(MainWindow, self).__init__()
    self.ctx = ctx
    self.configs = AppConfig(self.ctx)
    self.rec_viewer = None
    self.dt = DicomTree(parent=self)
    self.initVar()
    self.initModel()
    self.initUI()
    self.ctx.axes.imshow(self.ctx.app_logo)
    self.ctx.app_data.emit_img_loaded(False)

  def initVar(self):
    self.ctx.initVar()
    pat_field = ['id', 'name', 'sex', 'age', 'protocol', 'date', 'brand', 'model', 'scanner', 'instn']
    self.patient_info = dict(zip(pat_field, [None]*len(pat_field)))
    self.window_width = self.ctx.windowing_model.record(0).value("windowwidth")
    self.window_level = self.ctx.windowing_model.record(0).value("windowlevel")

  def initModel(self):
    record = self.ctx.windowing_model.record()
    record.setValue('id', 0)
    record.setValue('Name', 'Custom')
    record.setNull('WindowWidth')
    record.setNull('WindowLevel')
    self.ctx.windowing_model.insertRecord(-1, record)
    record.setValue('Name', 'None')
    record.setValue('id', -1)
    self.ctx.windowing_model.insertRecord(-1, record)

  def initUI(self):
    self.title = self.ctx.build_settings["app_name"] + " v" + self.ctx.build_settings["version"].split('.')[0]
    self.icon = None
    self._top = 0
    self._left = 0
    self._width = 1280
    self._height = 700
    self.setUIComponents()

  def setUIComponents(self):
    self.setWindowTitle(self.title)
    self.setGeometry(self._top, self._left, self._width, self._height)
    rect = self.frameGeometry()
    rect.moveCenter(QDesktopWidget().availableGeometry().center())
    self.move(rect.topLeft().x(), rect.topLeft().y()-25)
    self.main_widget = QWidget()

    self.setToolbar()
    self.setTabs()
    self.info_panel = InfoPanel(self.ctx, parent=self)
    self.setLayout()
    self.setCentralWidget(self.main_widget)

    self.statusBar().showMessage('READY')
    self.sigConnect()

  def sigConnect(self):
    self.windowing_cb.activated[int].connect(self._get_windowing_parameters)
    self.window_level_edit.editingFinished.connect(self.on_custom_windowing)
    self.window_width_edit.editingFinished.connect(self.on_custom_windowing)
    self.phantom_cb.activated[int].connect(self.on_phantom_update)
    self.phantom_cb.setCurrentIndex(0)
    self.on_phantom_update(0)
    self.open_btn.triggered.connect(self.on_open_files)
    self.open_folder_btn.triggered.connect(self.on_open_folder)
    self.open_sample_btn.triggered.connect(self.on_open_sample)
    self.dcmtree_btn.triggered.connect(self.on_dcmtree)
    self.settings_btn.triggered.connect(self.on_open_config)
    self.help_btn_en.triggered.connect(lambda a: self.on_help('en'))
    self.help_btn_id.triggered.connect(lambda a: self.on_help('id'))
    self.save_btn.triggered.connect(self.on_save_db)
    self.openrec_btn.triggered.connect(self.on_open_viewer)
    self.next_btn.triggered.connect(self.on_next_img)
    self.prev_btn.triggered.connect(self.on_prev_img)
    self.close_img_btn.triggered.connect(self.on_close_image)
    self.go_to_slice_btn.clicked.connect(self.on_go_to_slice)
    self.go_to_slice_sb.editingFinished.connect(self.on_go_to_slice_edit_finish)
    self.sort_btn.clicked.connect(self.on_sort)
    self.ssde_tab.save_btn.clicked.connect(self.on_save_db)
    self.ctdiv_tab.next_tab_btn.clicked.connect(self.on_next_tab)
    self.ctdiv_tab.prev_tab_btn.clicked.connect(self.on_prev_tab)
    self.diameter_tab.next_tab_btn.clicked.connect(self.on_next_tab)
    self.diameter_tab.prev_tab_btn.clicked.connect(self.on_prev_tab)
    self.ssde_tab.next_tab_btn.clicked.connect(self.on_next_tab)
    self.ssde_tab.prev_tab_btn.clicked.connect(self.on_prev_tab)
    QShortcut(Qt.Key_Right, self, self.on_next5_img)
    QShortcut(Qt.Key_Left, self, self.on_prev5_img)

  def setToolbar(self):
    toolbar = QToolBar('Main Toolbar')
    self.addToolBar(toolbar)

    self.open_btn = QAction(self.ctx.open_icon, 'Open File(s)', self)
    self.open_btn.setShortcut('Ctrl+O')
    self.open_btn.setStatusTip('Open File(s)')

    self.open_folder_btn = QAction(self.ctx.folder_icon, 'Open Folder', self)
    self.open_folder_btn.setStatusTip('Open Folder')

    self.open_sample_btn = QAction(self.ctx.sample_icon, 'Open Sample', self)
    self.open_sample_btn.setStatusTip('Load Sample DICOM Files')

    self.dcmtree_btn = QAction(self.ctx.tree_icon, 'DICOM Info', self)
    self.dcmtree_btn.setStatusTip('DICOM Info')
    self.dcmtree_btn.setEnabled(False)

    self.settings_btn = QAction(self.ctx.setting_icon, 'Settings', self)
    self.settings_btn.setStatusTip('Application Settings')

    self.help_btn_en = QAction(self.ctx.help_icon, 'English', self)
    self.help_btn_id = QAction(self.ctx.help_icon, 'Bahasa Indonesia', self)

    self.help_act = QToolButton(self)
    self.help_act.setIcon(self.ctx.help_icon)
    self.help_act.setShortcut('F1')
    self.help_act.setToolTip('Open User Manual')
    self.help_act.setStatusTip('Open User Manual')
    self.help_act.setPopupMode(QToolButton.InstantPopup)
    self.help_act.addAction(self.help_btn_en)
    self.help_act.addAction(self.help_btn_id)

    toolbar.addAction(self.open_btn)
    toolbar.addAction(self.open_folder_btn)
    toolbar.addAction(self.open_sample_btn)
    toolbar.addAction(self.dcmtree_btn)
    toolbar.addAction(self.settings_btn)
    toolbar.addWidget(self.help_act)

    rec_ctrl = QToolBar('Records Control')
    self.addToolBar(rec_ctrl)

    self.save_btn = QAction(self.ctx.save_icon, 'Save Record', self)
    self.save_btn.setShortcut('Ctrl+S')
    self.save_btn.setStatusTip('Save Record to Database')

    self.openrec_btn = QAction(self.ctx.launch_icon, 'Open Records', self)
    self.openrec_btn.setStatusTip('Open Patients Record')

    rec_ctrl.addAction(self.save_btn)
    rec_ctrl.addAction(self.openrec_btn)

    img_ctrl = QToolBar('Image Control')
    self.addToolBar(Qt.BottomToolBarArea, img_ctrl)

    self.next_btn = QAction(self.ctx.next_icon, 'Next Slice', self)
    self.next_btn.setStatusTip('Next Slice')
    self.next_btn.setShortcut(Qt.Key_Up)
    self.prev_btn = QAction(self.ctx.prev_icon, 'Previous Slice', self)
    self.prev_btn.setStatusTip('Previous Slice')
    self.prev_btn.setShortcut(Qt.Key_Down)
    self.close_img_btn = QAction(self.ctx.close_img_icon, 'Close Images', self)
    self.close_img_btn.setStatusTip('Close all images')
    self.close_img_btn.setEnabled(False)
    self.sort_btn = QPushButton('Sort Images')
    self.sort_btn.setEnabled(False)
    self.current_lbl = QLabel('0')
    self.total_lbl = QLabel('0')
    self.go_to_slice_sb = QSpinBox()
    self.go_to_slice_sb.setButtonSymbols(QAbstractSpinBox.NoButtons)
    self.go_to_slice_sb.setMinimumWidth(30)
    self.go_to_slice_sb.setMinimum(0)
    self.go_to_slice_sb.setMaximum(self.ctx.total_img)
    self.go_to_slice_sb.setWrapping(True)
    self.go_to_slice_sb.setAlignment(Qt.AlignCenter)
    self.go_to_slice_btn = QPushButton('Go to slice')

    img_ctrl.addAction(self.close_img_btn)
    img_ctrl.addWidget(self.sort_btn)
    img_ctrl.addSeparator()
    img_ctrl.addAction(self.prev_btn)
    img_ctrl.addWidget(self.current_lbl)
    img_ctrl.addWidget(QLabel('/'))
    img_ctrl.addWidget(self.total_lbl)
    img_ctrl.addAction(self.next_btn)
    img_ctrl.addWidget(self.go_to_slice_sb)
    img_ctrl.addWidget(self.go_to_slice_btn)

    view = QToolBar('View Options')
    self.addToolBar(view)

    self.windowing_cb = QComboBox()
    self.window_width_edit = QLineEdit(str(self.window_width))
    self.window_level_edit = QLineEdit(str(self.window_level))

    self.window_width_edit.setAlignment(Qt.AlignCenter)
    self.window_width_edit.setMaximumWidth(50)
    self.window_width_edit.setEnabled(False)
    self.window_width_edit.setValidator(QIntValidator())

    self.window_level_edit.setAlignment(Qt.AlignCenter)
    self.window_level_edit.setMaximumWidth(50)
    self.window_level_edit.setEnabled(False)
    self.window_level_edit.setValidator(QIntValidator())

    self.windowing_cb.setEnabled(False)
    self.windowing_cb.setModel(self.ctx.windowing_model)
    self.windowing_cb.setModelColumn(self.ctx.windowing_model.fieldIndex('Name'))
    self.windowing_cb.setPlaceholderText('Windowing')
    self.windowing_cb.setCurrentIndex(0)

    view.addWidget(QLabel('Windowing: '))
    view.addWidget(self.windowing_cb)
    view.addWidget(self.window_width_edit)
    view.addWidget(self.window_level_edit)

    opts = QToolBar('Options')
    self.addToolBar(opts)

    spacer = QWidget(self)
    spacer.setSizePolicy(QSizePolicy.Expanding, QSizePolicy.Preferred)
    spacer.setVisible(True)

    self.phantom_cb = QComboBox()
    self.phantom_cb.tag = 'phantom'
    self.phantom_cb.setModel(self.ctx.phantom_model)
    self.phantom_cb.setModelColumn(self.ctx.phantom_model.fieldIndex('name'))
    self.phantom_cb.setPlaceholderText('Phantom')

    opts.addWidget(spacer)
    opts.addWidget(QLabel('Phantom: '))
    opts.addWidget(self.phantom_cb)
    opts.addSeparator()

  def setLayout(self):
    vbox = QVBoxLayout()
    vbox.addWidget(self.info_panel)
    vbox.addWidget(self.tabs)

    right_panel = QWidget()
    right_panel.setLayout(vbox)
    right_panel.setContentsMargins(0,0,0,0)

    hbox = QHBoxLayout()
    splitter = QSplitter(Qt.Horizontal)
    splitter.addWidget(self.ctx.axes)
    splitter.addWidget(right_panel)
    splitter.setSizes([854,427])
    hbox.addWidget(splitter)

    self.main_widget.setLayout(hbox)

  def setTabs(self):
    self.tabs = QTabWidget()
    self.ctdiv_tab = CTDIVolTab(self.ctx)
    self.diameter_tab = DiameterTab(self.ctx, self)
    self.ssde_tab = SSDETab(self.ctx)
    self.organ_tab = OrganTab(self.ctx)
    self.analyze_tab = AnalyzeTab(self.ctx)

    self.tabs.tabBar().setStyleSheet("QTabBar {font-weight: bold;}")
    self.tabs.addTab(self.ctdiv_tab, 'CTDIvol')
    self.tabs.addTab(self.diameter_tab, 'Diameter')
    self.tabs.addTab(self.ssde_tab, 'SSDE')
    self.tabs.addTab(self.organ_tab, 'Organ')
    self.tabs.addTab(self.analyze_tab, 'Analyze')

  def on_open_folder(self):
    dir = QFileDialog.getExistingDirectory(self,"Open Folder", "")
    if dir:
      filenames = []
      for f in os.listdir(dir):
        fullfile = os.path.join(dir, f)
        _, ext = os.path.splitext(f)
        if os.path.isfile(fullfile) and (ext == '.dcm' or ext == ''):
          filenames.append(fullfile)
      self.fsource = 'dir'
      self._load_files(filenames)

  def on_open_files(self):
    filenames, _ = QFileDialog.getOpenFileNames(self,"Open Files", "", "All Files (*);;DICOM Files (*.dcm)")
    if filenames:
      self.fsource = 'files'
      self._load_files(filenames)

  def on_open_sample(self):
    filenames = [os.path.join(self.ctx.sample_dir, f) for f in os.listdir(self.ctx.sample_dir) if os.path.isfile(os.path.join(self.ctx.sample_dir, f))]
    if filenames:
      self.fsource = 'sample'
      self._load_files(filenames)
    else:
      QMessageBox.information(None, "Info", "No DICOM files in sample directory.")

  def filter_invalid(self, ds):
    discarded_count = 0
    valid = []
    for d in ds:
      try:
        type(d.pixel_array)
        valid.append(d)
      except:
        discarded_count+=1
    return valid, discarded_count

  def _load_files(self, fnames):
    # if self.ctx.isImage:
    self.on_close_image()
    self.statusBar().showMessage('Loading Images')
    n = len(fnames)
    progress = QProgressDialog(f"Loading {n} images...", "Cancel", 0, n, self)
    progress.setWindowModality(Qt.WindowModal)
    progress.setMinimumDuration(1000) # operation shorter than 1 sec will not open progress dialog
    files = []
    for idx, filename in enumerate(fnames):
      dcm = get_dicom(filename)
      files.append(dcm)
      progress.setValue(idx)
      if progress.wasCanceled():
        break
    progress.setValue(n)

    if not files:
      progress.cancel()
      if self.fsource=='dir':
        QMessageBox.information(None, "Info", "No DICOM files in the selected directory.")
      elif self.fsource=='sample':
        QMessageBox.information(None, "Info", "No DICOM files in sample directory.")
      elif self.fsource=='files':
        QMessageBox.warning(None, "Info", "The specified file is not a valid DICOM file.")
      return

    self.ctx.isImage = True
    self.ctx.dicoms, dc = self.filter_invalid(files)
    if dc>0:
      f = 'files' if dc>1 else 'file'
      QMessageBox.warning(None, "Unsupported format", f"Cannot load {dc} {f}.")

    self.ctx.total_img = len(self.ctx.dicoms)
    self.total_lbl.setText(str(self.ctx.total_img))
    self.ctx.current_img = 1
    self.update_image()
    self.ctx.app_data.emit_img_loaded(True)

    self.go_to_slice_sb.setValue(self.ctx.current_img)
    self.go_to_slice_sb.setMinimum(self.ctx.current_img)
    self.go_to_slice_sb.setMaximum(self.ctx.total_img)

    self.get_patient_info()
    phantom_id = int(not self.patient_info['protocol'].upper() in ['HEAD', 'HEADNECK', 'NECK']) if self.patient_info['protocol'] is not None else 1
    self.phantom_cb.setCurrentIndex(phantom_id)
    self.on_phantom_update(phantom_id)
    self.info_panel.setInfo(self.patient_info)
    self.dcmtree_btn.setEnabled(True)
    self.close_img_btn.setEnabled(True)
    self.windowing_cb.setEnabled(True)
    self.sort_btn.setEnabled(True)
    self.adjust_slices()

  def adjust_slices(self):
    slice_sbs = [self.ctdiv_tab.calc_slice1_sb, self.ctdiv_tab.calc_slice2_sb,
                 self.ctdiv_tab.dcm_slice1_sb, self.ctdiv_tab.dcm_slice2_sb,
                 self.diameter_tab.slice1_sb, self.diameter_tab.slice2_sb,
                 self.ssde_tab.slice1_sb, self.ssde_tab.slice2_sb,]
    for slice_sb in slice_sbs:
      slice_sb.setMaximum(self.ctx.total_img)
      slice_sb.setMinimum(1)
      slice_sb.setValue(self.ctx.current_img)
    self.ctx.app_data.slice1 = self.ctx.current_img
    self.ctx.app_data.slice2 = self.ctx.current_img

  def get_patient_info(self):
    ref = self.ctx.dicoms[0]
    brand = str(ref.Manufacturer) if 'Manufacturer' in ref else ''
    model = str(ref.ManufacturerModelName) if 'ManufacturerModelName' in ref else ''
    scanner = brand + '-' + model
    self.patient_info = {
      'id': str(ref.PatientID) if 'PatientID' in ref else None,
      'name': str(ref.PatientName) if 'PatientName' in ref else None,
      'sex': str(ref.PatientSex) if 'PatientSex' in ref else None,
      'age': int(str(ref.PatientAge)[:3]) if 'PatientAge' in ref else None,
      'protocol': str(ref.BodyPartExamined) if 'BodyPartExamined' in ref else None,
      'date': str(ref.AcquisitionDate) if 'AcquisitionDate' in ref else None,
      'brand': brand or None,
      'model': model or None,
      'scanner': scanner if scanner!='-' else None,
      'instn': str(ref.InstitutionName) if 'InstitutionName' in ref else None,
    }

  def next_img(self, step):
    if not self.ctx.total_img:
      return
    if self.ctx.current_img == self.ctx.total_img:
      self.ctx.current_img = 1
    elif self.ctx.current_img + step > self.ctx.total_img:
      self.ctx.current_img = self.ctx.total_img
    else:
      self.ctx.current_img += step
    self.update_image()
    self.ctx.app_data.emit_img_changed()

  def on_next_img(self):
    self.next_img(1)

  def on_next5_img(self):
    self.next_img(5)

  def update_image(self):
    self.current_lbl.setText(str(self.ctx.current_img))
    self.ctx.axes.clearAll()
    self.image_data = self.ctx.get_current_img()
    if self.image_data is None:
      self.on_close_image()
      return
    self.ctx.axes.imshow(self.image_data)
    if isinstance(self.window_width, int) and isinstance(self.window_level, int):
      window_img = windowing(self.image_data, self.window_width, self.window_level)
      self.ctx.axes.add_alt_view(window_img)
    self.ctx.img_dims = (int(self.ctx.dicoms[self.ctx.current_img-1].Rows), int(self.ctx.dicoms[self.ctx.current_img-1].Columns))
    self.ctx.recons_dim = float(self.ctx.dicoms[self.ctx.current_img-1].ReconstructionDiameter)
    self.dt.set_ds(self.ctx.dicoms[self.ctx.current_img-1])

  def prev_img(self, step):
    if not self.ctx.total_img:
      return
    if self.ctx.current_img == 1:
      self.ctx.current_img = self.ctx.total_img
    elif self.ctx.current_img - step < 1:
      self.ctx.current_img = 1
    else:
      self.ctx.current_img -= step
    self.update_image()
    self.ctx.app_data.emit_img_changed()

  def on_prev_img(self):
    self.prev_img(1)

  def on_prev5_img(self):
    self.prev_img(5)

  def on_sort(self):
    self.ctx.dicoms, skipcount = reslice(self.ctx.dicoms)
    if skipcount>0:
      QMessageBox.information(None, "Info", f"Skipped {skipcount} files with no SliceLocation.")
    self.ctx.total_img = len(self.ctx.dicoms)
    self.total_lbl.setText(str(self.ctx.total_img))
    self.ctx.current_img = 1
    self.update_image()

  def on_go_to_slice(self):
    if self.ctx.current_img:
      self.ctx.current_img = self.go_to_slice_sb.value()
      self.update_image()

  def on_go_to_slice_edit_finish(self):
    if self.go_to_slice_sb.hasFocus():
      self.on_go_to_slice()
      self.go_to_slice_sb.clearFocus()

  def on_close_image(self):
    self.initVar()
    self.windowing_cb.setCurrentIndex(0)
    self._get_windowing_parameters(0)
    self.current_lbl.setText(str(self.ctx.current_img))
    self.total_lbl.setText(str(self.ctx.total_img))
    self.go_to_slice_sb.setValue(self.ctx.current_img)
    self.go_to_slice_sb.setMinimum(self.ctx.current_img)
    self.go_to_slice_sb.setMaximum(self.ctx.total_img)
    self.info_panel.initVar()
    self.info_panel.setInfo(self.info_panel.getInfo())
    self.ctx.axes.clearAll()
    self.ctx.axes.imshow(self.ctx.app_logo)
    self.dcmtree_btn.setEnabled(False)
    self.close_img_btn.setEnabled(False)
    self.windowing_cb.setEnabled(False)
    self.sort_btn.setEnabled(False)
    self.adjust_slices()
    self.app_reset()

  def _get_windowing_parameters(self, idx):
    id = self.ctx.windowing_model.record(idx).value("id")
    window_width = self.ctx.windowing_model.record(idx).value("windowwidth")
    window_level = self.ctx.windowing_model.record(idx).value("windowlevel")
    if id == 0:
      window_width = self.window_width
      window_level = self.window_level
      self.window_width_edit.setEnabled(True)
      self.window_level_edit.setEnabled(True)
    else:
      self.window_width_edit.setEnabled(False)
      self.window_level_edit.setEnabled(False)
      if id < 0:
        window_width = 'WW'
        window_level = 'WL'
    self.window_width = window_width
    self.window_level = window_level
    self.window_width_edit.setText(str(self.window_width))
    self.window_level_edit.setText(str(self.window_level))

    if self.ctx.isImage:
      self.update_image()

  def on_custom_windowing(self):
    if self.sender().hasFocus():
      self.window_width = int(self.window_width_edit.text())
      self.window_level = int(self.window_level_edit.text())
      self.update_image()

  def on_dcmtree(self):
    if not self.ctx.isImage:
      QMessageBox.warning(None, "Warning", "Open DICOM files first.")
      return
    self.dt.set_ds(self.ctx.dicoms[self.ctx.current_img-1])
    self.dt.show()

  def on_phantom_update(self, idx):
    self.ctx.phantom = self.ctx.phantom_model.record(idx).value("id")
    self.ctx.phantom_name = self.ctx.phantom_model.record(idx).value("name")
    self.ssde_tab.protocol_model.setFilter(f"Group_ID={self.ctx.phantom}")
    self.organ_tab.protocol_model.setFilter(f"Group_ID={self.ctx.phantom}")

    self.ctdiv_tab.on_volt_changed(self.ctdiv_tab.volt_cb.currentIndex())
    self.ssde_tab.on_protocol_changed(self.ssde_tab.protocol_cb.currentIndex())
    self.organ_tab.on_protocol_changed(self.organ_tab.protocol_cb.currentIndex())
    self.ssde_tab.on_report_changed(self.ssde_tab.report_cb.currentIndex())

  def on_open_viewer(self):
    self.rec_viewer = DBViewer(self.ctx, self)
    self.rec_viewer.show()

  def on_open_config(self):
    accepted = self.configs.exec()
    if accepted:
      self.ctx.database.update_connection('patient', self.ctx.patients_database())
      try:
        self.rec_viewer.on_refresh()
      except:
        pass
      self.ctx.records_count = get_records_num(self.ctx.patients_database(), 'PATIENTS')
      self.analyze_tab.set_filter()

  def on_help(self, lang='en'):
    try:
      os.startfile(self.ctx.help_file(lang))
    except:
      QMessageBox.information(None, "Not yet available", "Sorry, the user manual is not available for now.")

  def on_save_db(self):
    btn_reply = QMessageBox.question(self, 'Save Record', 'Are you sure want to save the record?')
    if btn_reply == QMessageBox.No:
      return
    data = self.ssde_tab.display
    self.patient_info = self.info_panel.getInfo()
    if data['diameter']:
      d_mode = 'Deff' if self.ctx.app_data.mode else 'Dw'
    else:
      d_mode = None
    recs = [
      self.patient_info['id'],    # 'id'
      self.patient_info['name'],    # 'name'
      self.patient_info['age'],   # 'age'
      self.patient_info['sex'],   # 'sex'
      self.patient_info['date'],    # 'date'
      self.patient_info['instn'],   # institution
      self.patient_info['brand'],
      self.patient_info['model'],
      self.patient_info['protocol'],    # 'protocol'
      data['ctdi'],   # 'CTDIVol'
      data['diameter'],    # 'DE_WED'
      d_mode,
      data['ssde'],   # 'SSDE'
      data['dlp'],    # 'DLP'
      data['dlpc'],   # 'DLPc'
      data['effdose']   # 'Effective_Dose'
    ]
    print(recs)
    if None in recs:
      ids = [i+1 for i, x in enumerate(recs) if x == None]
      items = np.array(PAT_RECS_FIELDS)
      emp_f = items[ids]
      btn_reply = QMessageBox.question(self, 'Empty field(s)', f'The following fields are empty: {", ".join(emp_f)}\nDo you want to save it anyway?')
      if btn_reply == QMessageBox.No:
        return
    insert_patient(recs, self.ctx.patients_database())
    self.ctx.records_count += 1
    self.analyze_tab.set_filter()
    self.on_close_image()
    self.tabs.setCurrentIndex(0)

  def on_next_tab(self):
    self.tabs.setCurrentIndex(self.tabs.currentIndex()+1)

  def on_prev_tab(self):
    self.tabs.setCurrentIndex(self.tabs.currentIndex()-1)

  def app_reset(self):
    self.ctx.app_data.init_var()
    self.ctdiv_tab.reset_fields()
    self.diameter_tab.reset_fields()
    self.ssde_tab.reset_fields()
    self.organ_tab.reset_fields()
    self.ctx.app_data.emit_img_loaded(False)
    # self.analyze_tab.reset_fields()

  def closeEvent(self, event):
    self.dt.close() if self.dt.isVisible() else None
    try:
      self.rec_viewer.close() if self.rec_viewer.isVisible() else None
    except:
      pass
    for idx in range(self.tabs.count()):
      try:
        if self.tabs.widget(idx).figure.isVisible(): self.tabs.widget(idx).figure.close()
      except:
        continue
Esempio n. 9
0
class ImportWindow(QDialog):
    def __init__(self, parent: QWidget = None):
        super().__init__(parent)

        self._size: int = os.cpu_count()
        if self._size is None:
            self._size = 2

        self._processes_pool = []
        self._manager = ImportManager(self._size)
        self._max_progress: int = 0
        self._timer: QTimer = QTimer()
        self._confuser = ConfuseWindow(self)
        self._date_start_cache = None
        self._tesseract_path_cache = None
        self._poppler_path_cache = None

        # window settings
        self.setWindowFlag(Qt.WindowContextHelpButtonHint, False)
        self.setWindowTitle(self.tr("Import window"))

        # list widget with files
        self.list_widget = QListWidget()
        self.list_widget.setSortingEnabled(True)

        self.layout_open_folder = QHBoxLayout()
        self.label_find = QLabel(self.tr("Schedules: ") + "0")
        self.layout_open_folder.addWidget(self.label_find)

        self.layout_open_folder.addStretch(1)

        self.push_button_open_folder = QToolButton()
        self.layout_open_folder.addWidget(self.push_button_open_folder)

        self.push_button_open_folder.setText(self.tr("Open folder"))
        self.push_button_open_folder.setPopupMode(QToolButton.MenuButtonPopup)

        self.action_open_files = QAction(self.tr("Open files"))
        self.push_button_open_folder.addAction(self.action_open_files)

        # main progress
        self.group_box_main_progress = QGroupBox(self.tr("Main progress"))
        self.layout_main_progress = QVBoxLayout(self.group_box_main_progress)

        self.process_bar_main = QProgressBar()
        self.layout_main_progress.addWidget(self.process_bar_main)

        self.layout_start_process = QHBoxLayout()
        self.layout_start_process.addStretch(1)

        self.push_button_import = QPushButton(self.tr("Import"))
        self.layout_start_process.addWidget(self.push_button_import)

        self.push_button_stop = QPushButton(self.tr("Stop"))
        self.layout_start_process.addWidget(self.push_button_stop)

        self.push_button_stop.setEnabled(False)

        self.layout_main_progress.addLayout(self.layout_start_process)

        # threads process
        self.group_box_threads = QGroupBox(self.tr("Threads"))
        self.grid_layout_threads = QGridLayout(self.group_box_threads)

        self._progresses_bars = []
        rows = self._size // 2
        columns = 2
        for i in range(rows):
            for j in range(columns):
                progress_bar = QProgressBar()
                progress_bar.setTextVisible(True)
                self._progresses_bars.append(progress_bar)
                self.grid_layout_threads.addWidget(progress_bar, i, j)

        # options
        self.group_box_options = QGroupBox(self.tr("Options"))
        self.form_layout_options = QFormLayout(self.group_box_options)

        self.check_box_weekly = QCheckBox(self.tr("Create weekly schedule"))
        self.form_layout_options.addRow(self.check_box_weekly)

        self.check_box_full = QCheckBox(self.tr("Create full schedule"))
        self.form_layout_options.addRow(self.check_box_full)

        self.check_box_debug_img = QCheckBox(self.tr("Create debug image"))
        self.form_layout_options.addRow(self.check_box_debug_img)

        self.spin_box_dpi = QSpinBox()
        self.form_layout_options.addRow(self.tr("DPI"), self.spin_box_dpi)

        self.combo_box_tesseract_path = QComboBox()
        self.form_layout_options.addRow(self.tr("Tesseract path"),
                                        self.combo_box_tesseract_path)

        self.combo_box_poppler_path = QComboBox()
        self.form_layout_options.addRow(self.tr("Poppler path"),
                                        self.combo_box_poppler_path)

        self.check_box_debug_img.setChecked(True)
        self.check_box_debug_img.setEnabled(False)

        self.spin_box_dpi.setRange(200, 800)
        self.spin_box_dpi.setValue(500)

        self.combo_box_tesseract_path.addItem(
            self.tr("<select tesseract path>"))
        self.combo_box_tesseract_path.addItem("Default", "tesseract")
        self.combo_box_tesseract_path.setCurrentIndex(1)
        self._tesseract_path_cache = self.combo_box_tesseract_path.currentText(
        )

        self.combo_box_poppler_path.addItem(self.tr("<select poppler path>"))
        self.combo_box_poppler_path.addItem("Default", None)
        self.combo_box_poppler_path.setCurrentIndex(1)
        self._poppler_path_cache = self.combo_box_poppler_path.currentText()

        # font edit
        self.group_box_font = QGroupBox(self.tr("Font settings"))
        self.form_layout_font = QFormLayout(self.group_box_font)

        self.label_font = QLabel(self.tr("Font"))
        self.form_layout_font.setWidget(0, QFormLayout.LabelRole,
                                        self.label_font)
        self.combo_box_font = QComboBox()
        self.form_layout_font.setWidget(0, QFormLayout.FieldRole,
                                        self.combo_box_font)

        self.label_encoding = QLabel(self.tr("Encoding"))
        self.form_layout_font.setWidget(1, QFormLayout.LabelRole,
                                        self.label_encoding)
        self.combo_box_encoding = QComboBox()
        self.form_layout_font.setWidget(1, QFormLayout.FieldRole,
                                        self.combo_box_encoding)

        for font_name, font_path in util.get_fonts():
            self.combo_box_font.addItem(font_name, font_path)

        self.combo_box_font.setCurrentText(qApp.font().family())
        self.combo_box_font.setEditable(True)

        self.combo_box_encoding.addItem("UTF-8")
        self.combo_box_encoding.addItem("Latin-1")
        self.combo_box_encoding.addItem("Windows-1252")

        # date edit
        self.group_box_date = QGroupBox(self.tr("Date settings"))
        self.form_layout_date = QFormLayout(self.group_box_date)

        self.label_date_start = QLabel(self.tr("Start"))
        self.form_layout_date.setWidget(0, QFormLayout.LabelRole,
                                        self.label_date_start)
        self.date_edit_start = QDateEdit()
        self.form_layout_date.setWidget(0, QFormLayout.FieldRole,
                                        self.date_edit_start)

        self.label_date_end = QLabel(self.tr("End"))
        self.form_layout_date.setWidget(1, QFormLayout.LabelRole,
                                        self.label_date_end)
        self.date_edit_end = QDateEdit()
        self.form_layout_date.setWidget(1, QFormLayout.FieldRole,
                                        self.date_edit_end)

        self.date_edit_start.setCalendarPopup(True)
        self.date_edit_end.setCalendarPopup(True)

        if QDate.currentDate().day() < QDate.currentDate().dayOfYear() / 2:
            date = QDate(QDate.currentDate().year(), 2, 1)
        else:
            date = QDate(QDate.currentDate().year(), 9, 1)

        self._date_start_cache = date.addDays(8 - date.dayOfWeek())
        self.date_edit_start.setDate(self._date_start_cache)
        self.date_edit_end.setMinimumDate(self._date_start_cache.addDays(7))
        self.date_edit_end.setDate(self._date_start_cache.addDays(16 * 7))

        # subgroup edit
        self.group_box_subgroup = QGroupBox(self.tr("Subgroup settings"))
        self.form_layout_subgroup = QFormLayout(self.group_box_subgroup)

        self.label_color_a = QLabel(self.tr("Color A"))
        self.form_layout_subgroup.setWidget(0, QFormLayout.LabelRole,
                                            self.label_color_a)
        self.combo_box_color_a = QComboBox()
        self.form_layout_subgroup.setWidget(0, QFormLayout.FieldRole,
                                            self.combo_box_color_a)

        self.label_color_b = QLabel(self.tr("Color B"))
        self.form_layout_subgroup.setWidget(1, QFormLayout.LabelRole,
                                            self.label_color_b)
        self.combo_box_color_b = QComboBox()
        self.form_layout_subgroup.setWidget(1, QFormLayout.FieldRole,
                                            self.combo_box_color_b)

        self.label_pattern_a_b = QLabel(self.tr("Pattern A and B"))
        self.form_layout_subgroup.setWidget(2, QFormLayout.LabelRole,
                                            self.label_pattern_a_b)
        self.combo_box_pattern_a_b = QComboBox()
        self.form_layout_subgroup.setWidget(2, QFormLayout.FieldRole,
                                            self.combo_box_pattern_a_b)

        self.add_standard_colors(self.combo_box_color_a)
        self.add_standard_colors(self.combo_box_color_b)
        self.combo_box_color_a.setCurrentIndex(9)  # lime
        self.combo_box_color_b.setCurrentIndex(15)  # yellow

        self.combo_box_pattern_a_b.addItem(self.tr("Chess order"))
        self.combo_box_pattern_a_b.setEnabled(False)

        # navigate
        self.layout_navigate = QHBoxLayout()

        self.layout_navigate.addStretch(1)

        self.push_button_ok = QPushButton(self.tr("OK"))
        self.layout_navigate.addWidget(self.push_button_ok)

        self.push_button_cancel = QPushButton(self.tr("Cancel"))
        self.layout_navigate.addWidget(self.push_button_cancel)

        # layout setup
        self.layout_left = QVBoxLayout()
        self.layout_left.addWidget(self.list_widget)
        self.layout_left.addLayout(self.layout_open_folder)

        self.layout_right = QVBoxLayout()
        self.layout_right.addWidget(self.group_box_main_progress)
        self.layout_right.addWidget(self.group_box_threads)

        self.layout_down = QGridLayout()
        self.layout_down.addWidget(self.group_box_options, 0, 0)
        self.layout_down.addWidget(self.group_box_font, 1, 0)
        self.layout_down.addWidget(self.group_box_date, 0, 1)
        self.layout_down.addWidget(self.group_box_subgroup, 1, 1)

        self.layout_right.addLayout(self.layout_down)
        self.layout_right.addStretch(1)
        self.layout_right.addLayout(self.layout_navigate)

        self.layout_main = QHBoxLayout()
        self.layout_main.addLayout(self.layout_left, 1)
        self.layout_main.addLayout(self.layout_right, 2)

        self.setLayout(self.layout_main)

        # connections
        self._timer.timeout.connect(self.check_processes)

        self.push_button_open_folder.clicked.connect(self.open_folder_clicked)
        self.action_open_files.triggered.connect(self.open_files_clicked)

        self.push_button_import.clicked.connect(
            self.push_button_import_clicked)
        self.push_button_stop.clicked.connect(self.push_button_stop_clicked)

        self.check_box_weekly.clicked.connect(self.check_box_weekly_clicked)
        self.combo_box_tesseract_path.activated.connect(
            self.combo_box_tesseract_path_clicked)
        self.combo_box_poppler_path.activated.connect(
            self.combo_box_poppler_path_clicked)

        self.date_edit_start.dateChanged.connect(self.date_edit_start_changed)
        self.combo_box_color_a.activated.connect(
            self.combo_box_color_a_clicked)
        self.combo_box_color_b.activated.connect(
            self.combo_box_color_b_clicked)

        self.push_button_ok.clicked.connect(self.close)
        self.push_button_cancel.clicked.connect(self.close)

    def check_processes(self):
        work_processes = 0
        for index in range(self._size):
            if self._processes_pool[index].is_alive():
                work_processes += 1

            text = self._manager.progress_text_list[index]
            if text is not None and text != "":
                self._progresses_bars[index].setFormat(text)
                self._progresses_bars[index].setValue(
                    self._manager.progress_value_list[index])

            if self._manager.confuse_answer_list[
                    index] == ConfuseWindow.NeededSolution:
                if self._confuser.status == ConfuseWindow.Solved:
                    answer_index = self._confuser.index
                    self._manager.confuse_list[
                        answer_index] = self._confuser.answer
                    self._manager.confuse_answer_list[
                        answer_index] = ConfuseWindow.Solved
                    self._confuser.status = ConfuseWindow.Nothing
                elif self._confuser.status == ConfuseWindow.Nothing:
                    self._confuser.status = ConfuseWindow.Work
                    self._confuser.index = index
                    self._confuser.text_edit_confuse.setText(
                        self._manager.confuse_info[index])
                    self._confuser.text_edit_answer.setText(
                        self._manager.confuse_list[index])
                    self._confuser.set_image(
                        self._manager.confuse_file_path[index])
                    self._confuser.show()

        progress = self._max_progress - self._manager.queue.qsize(
        ) - work_processes
        self.process_bar_main.setValue(progress)

        if work_processes == 0:
            self.push_button_stop_clicked()
            return

        if not self._manager.flags["stop"]:
            self._timer.start(1000)

    def open_folder_clicked(self):
        path = QFileDialog.getExistingDirectory(self, self.tr("Select folder"))

        provider = QFileIconProvider()
        self.list_widget.clear()

        for dir_path, dir_names, file_names in os.walk(path):
            for file_name in file_names:
                if file_name.endswith(".pdf"):
                    item = QListWidgetItem()
                    item.setText(file_name[0:-4])
                    item.setData(Qt.UserRole, dir_path + os.sep + file_name)
                    item.setIcon(
                        provider.icon(QFileInfo(dir_path + os.sep +
                                                file_name)))

                    self.list_widget.addItem(item)

        self.label_find.setText(
            self.tr("Schedules: ") + str(self.list_widget.count()))

    def open_files_clicked(self):
        files = QFileDialog.getOpenFileNames(
            self, self.tr("Select files"), "",
            "PDF file (*.pdf) ;; All files (*.*)")[0]
        provider = QFileIconProvider()
        self.list_widget.clear()

        for file_path in files:
            file = QFileInfo(file_path)
            item = QListWidgetItem()
            item.setText(file.baseName())
            item.setData(Qt.UserRole, file_path)
            item.setIcon(provider.icon(file))
            self.list_widget.addItem(item)

        self.label_find.setText(
            self.tr("Schedules: ") + str(self.list_widget.count()))

    def push_button_import_clicked(self):
        self.group_box_options.setEnabled(False)
        self.group_box_font.setEnabled(False)
        self.group_box_date.setEnabled(False)
        self.group_box_subgroup.setEnabled(False)
        self.push_button_import.setEnabled(False)
        self.push_button_stop.setEnabled(True)
        self.push_button_ok.setEnabled(False)
        self.push_button_cancel.setEnabled(False)
        self.push_button_open_folder.setEnabled(False)

        for number in range(self.list_widget.count()):
            path = self.list_widget.item(number).data(Qt.UserRole)
            self._manager.queue.put(path)

        self._max_progress = self.list_widget.count()
        self.process_bar_main.setRange(0, self._max_progress)
        self.process_bar_main.setValue(0)

        self._manager.weekly = self.check_box_weekly.isChecked()
        self._manager.full = self.check_box_full.isChecked()
        self._manager.debug_image = self.check_box_debug_img.isChecked()

        self._manager.dpi = self.spin_box_dpi.value()
        self._manager.tesseract_path = self.combo_box_tesseract_path.currentData(
            Qt.UserRole)
        self._manager.poppler_path = self.combo_box_poppler_path.currentData(
            Qt.UserRole)

        self._manager.font_name = self.combo_box_font.currentText()
        self._manager.font_path = self.combo_box_font.currentData(Qt.UserRole)
        self._manager.encoding = self.combo_box_encoding.currentText()

        self._manager.start = self.date_edit_start.date().toPyDate()
        self._manager.end = self.date_edit_end.date().toPyDate()

        self._manager.color_a = self.combo_box_color_a.currentData(Qt.UserRole)
        self._manager.color_b = self.combo_box_color_b.currentData(Qt.UserRole)

        self._manager.flags["stop"] = False

        self._processes_pool.clear()
        for index in range(self._size):
            process = Process(target=import_from_pdf,
                              args=(index, self._manager),
                              daemon=True)
            process.start()
            self._processes_pool.append(process)

        self._timer.start(500)

    def push_button_stop_clicked(self):
        self.push_button_stop.setEnabled(False)

        self._manager.flags["stop"] = True

        self.group_box_options.setEnabled(True)
        self.group_box_font.setEnabled(True)
        self.group_box_date.setEnabled(True)
        self.group_box_subgroup.setEnabled(True)
        self.push_button_import.setEnabled(True)
        self.push_button_ok.setEnabled(True)
        self.push_button_cancel.setEnabled(True)
        self.push_button_open_folder.setEnabled(True)

    def check_box_weekly_clicked(self):
        if self.check_box_weekly.isChecked():
            self.group_box_date.setEnabled(True)
            self.group_box_subgroup.setEnabled(True)
        else:
            self.group_box_date.setEnabled(False)
            self.group_box_subgroup.setEnabled(False)

    def combo_box_tesseract_path_clicked(self, index):
        if index == 0:
            path = QFileDialog.getOpenFileName(self,
                                               self.tr("Select Tesseract"))[0]

            if path == "":
                self.combo_box_tesseract_path.setCurrentText(
                    self._tesseract_path_cache)
                return

            self.combo_box_tesseract_path.addItem(path, path)
            self.combo_box_tesseract_path.setCurrentText(path)
            self._tesseract_path_cache = path

    def combo_box_poppler_path_clicked(self, index):
        if index == 0:
            path = QFileDialog.getOpenFileName(self,
                                               self.tr("Select Poppler"))[0]

            if path == "":
                self.combo_box_poppler_path.setCurrentText(
                    self._poppler_path_cache)
                return

            self.combo_box_poppler_path.addItem(path, path)
            self.combo_box_poppler_path.setCurrentText(path)
            self._poppler_path_cache = path

    def add_standard_colors(self, combo_box: QComboBox) -> None:
        """
        Adds colors to the color selection menu.

        :param combo_box: Color selection menu
        """
        color_items = [(self.tr("Custom color"), QColor()),
                       (self.tr("Aqua"), QColor(0, 255, 255)),
                       (self.tr("Grey"), QColor(128, 128, 128)),
                       (self.tr("Navy"), QColor(0, 0, 192)),
                       (self.tr("Silver"), QColor(192, 192, 192)),
                       (self.tr("Black"), QColor(0, 0, 0)),
                       (self.tr("Green"), QColor(0, 128, 0)),
                       (self.tr("Olive"), QColor(192, 192, 0)),
                       (self.tr("Blue"), QColor(0, 0, 255)),
                       (self.tr("Lime"), QColor(0, 255, 0)),
                       (self.tr("Purple"), QColor(128, 0, 128)),
                       (self.tr("White"), QColor(255, 255, 255)),
                       (self.tr("Fuchsia"), QColor(255, 0, 255)),
                       (self.tr("Maroon"), QColor(128, 0, 0)),
                       (self.tr("Red"), QColor(255, 0, 0)),
                       (self.tr("Yellow"), QColor(255, 255, 0))]

        for name, data in color_items:
            combo_box.addItem(util.create_color_icon(data), name, data)

    def combo_box_color_a_clicked(self) -> None:
        """
        Slot for color selection of A subgroup.
        """
        if self.combo_box_color_a.currentIndex() == 0:
            self.custom_color_selected(self.combo_box_color_a)

    def combo_box_color_b_clicked(self) -> None:
        """
        Slot for color selection of B subgroup.
        """
        if self.combo_box_color_b.currentIndex() == 0:
            self.custom_color_selected(self.combo_box_color_b)

    def custom_color_selected(self, combo_box: QComboBox) -> None:
        """
        Slot to select the color for the desired menu.

        :param combo_box: Menu
        """
        color = QColorDialog.getColor(combo_box.currentData(), self)
        if color.isValid():
            combo_box.setItemIcon(0, util.create_color_icon(color))
            combo_box.setItemData(0, color)

    def date_edit_start_changed(self, date: QDate):
        """
        Slot for changing the end of a range of dates.

        :param date: Start of the date range
        """
        end_date = self.date_edit_end.date().addDays(
            self._date_start_cache.daysTo(date))
        self.date_edit_end.setMinimumDate(date.addDays(7))
        self.date_edit_end.setDate(end_date)
        self._date_start_cache = QDate(date)

    def closeEvent(self, event: QCloseEvent) -> None:
        for process in self._processes_pool:
            process.terminate()

        print("Processes terminate")
Esempio n. 10
0
    def __init__(self, main_window: 'ElectrumWindow') -> None:
        super().__init__(None)

        balance_widget = QToolButton()
        balance_widget.setAutoRaise(True)
        balance_widget.setPopupMode(QToolButton.MenuButtonPopup)
        balance_icon_label = QLabel("")
        balance_icon_label.setPixmap(QPixmap(icon_path("sb_balance.png")))
        hbox = QHBoxLayout()
        hbox.setSpacing(2)
        hbox.setSizeConstraint(hbox.SetFixedSize)
        hbox.addWidget(balance_icon_label)
        self._balance_bsv_label = QLabel("")
        hbox.addWidget(self._balance_bsv_label)
        self._balance_equals_label = QLabel("")
        self._balance_equals_label.setPixmap(QPixmap(icon_path("sb_approximate")))
        hbox.addWidget(self._balance_equals_label)
        self._balance_fiat_label = QLabel("")
        hbox.addWidget(self._balance_fiat_label)
        # This is to pad out the text on the RHS so that the menu indicator does not overlay it.
        hbox.addWidget(QLabel(" "))
        balance_widget.setLayout(hbox)
        balance_widget.addAction(BalancePopupAction(main_window, self, balance_widget))
        self._balance_widget = balance_widget
        self.addPermanentWidget(balance_widget)

        self._fiat_widget = QWidget()
        self._fiat_widget.setVisible(False)
        estimate_icon_label = QLabel("")
        estimate_icon_label.setPixmap(QPixmap(icon_path("sb_fiat.png")))
        hbox = QHBoxLayout()
        hbox.setSpacing(2)
        hbox.setSizeConstraint(hbox.SetFixedSize)
        hbox.addWidget(estimate_icon_label)
        self._fiat_bsv_label = QLabel("")
        hbox.addWidget(self._fiat_bsv_label)
        approximate_icon_label = QLabel("")
        approximate_icon_label.setPixmap(QPixmap(icon_path("sb_approximate")))
        hbox.addWidget(approximate_icon_label)
        self._fiat_value_label = QLabel("")
        fm = self._fiat_bsv_label.fontMetrics()
        width = fm.width("1,000.00 CUR")
        self._fiat_value_label.setMinimumWidth(width)
        hbox.addWidget(self._fiat_value_label)
        self._fiat_widget.setLayout(hbox)
        self.addPermanentWidget(self._fiat_widget)

        network_widget = QWidget()
        network_icon_label = QLabel("")
        network_icon_label.setPixmap(QPixmap(icon_path("sb_network.png")))
        hbox = QHBoxLayout()
        hbox.setSpacing(2)
        hbox.addWidget(network_icon_label)
        self._network_label = QLabel("")
        sp = QSizePolicy(QSizePolicy.Preferred, QSizePolicy.Preferred)
        sp.setHorizontalStretch(1)
        self._network_label.setSizePolicy(sp)
        hbox.addWidget(self._network_label)
        network_widget.setLayout(hbox)
        network_widget.setMinimumWidth(150)
        self.addPermanentWidget(network_widget)

        self.search_box = QLineEdit()
        # self.search_box.textChanged.connect(self.do_search)
        self.search_box.hide()
        self.addPermanentWidget(self.search_box)
Esempio n. 11
0
class MultiLayerSelect:
    """QGIS Plugin Implementation."""
    def __init__(self, iface):
        """Constructor.

        :param iface: An interface instance that will be passed to this class
            which provides the hook by which you can manipulate the QGIS
            application at run time.
        :type iface: QgsInterface
        """
        # Save reference to the QGIS interface
        self.iface = iface
        # initialize plugin directory
        self.plugin_dir = os.path.dirname(__file__)
        # initialize locale
        locale = QSettings().value("locale/userLocale")[0:2]
        locale_path = os.path.join(self.plugin_dir, "i18n",
                                   "MultiLayerSelect_{}.qm".format(locale))

        if os.path.exists(locale_path):
            self.translator = QTranslator()
            self.translator.load(locale_path)
            QCoreApplication.installTranslator(self.translator)

        # Init settings
        self.settings = QSettings()
        self.settings.beginGroup("plugins/multilayerselect")

    def tr(self, message):
        """Get the translation for a string using Qt translation API.

        We implement this ourselves since we do not inherit QObject.

        :param message: String for translation.
        :type message: str, QString

        :returns: Translated version of message.
        :rtype: QString
        """
        # pylint: disable=invalid-name

        return QCoreApplication.translate("MultiLayerSelect", message)

    def initGui(self):
        """Create the menu entries and toolbar icons inside the QGIS GUI."""
        # pylint: disable=invalid-name

        # Create settings dialog
        self.settings_dialog = SettingsDialog(self.settings,
                                              self.iface.mainWindow())
        self.expression_dialog = None

        try:
            QgsProject.instance().selectionColorChanged.connect(
                self.on_color_changed)
            QgsProject.instance().selectionColorChanged.connect(
                self.settings_dialog.on_project_color_changed)
        except AttributeError:  # QGIS < 3.10
            self.settings_dialog.colorChanged.connect(self.on_color_changed)
            QgsProject.instance().readProject.connect(
                self.settings_dialog.on_project_color_changed)

        self.settings_dialog.settingsChanged.connect(self.on_settings_changed)

        self.toolbar = QToolBar("Multilayer Select", self.iface.mainWindow())
        self.toolbar.setObjectName("MultiSelectToolbar")

        self.about_action = QAction(
            QIcon(":/plugins/multilayerselect/icons/about.svg"),
            self.tr("About"),
            parent=self.iface.mainWindow(),
        )
        self.about_action.triggered.connect(self.show_about)

        self.settings_action = QAction(
            QIcon(":/images/themes/default/console/iconSettingsConsole.svg"),
            self.tr("Settings"),
            parent=self.iface.mainWindow(),
        )
        self.settings_action.setObjectName("actionMultiLayerSelectSettings")
        self.settings_action.setToolTip(
            self.tr("<b>Multilayer Select Settings</b>"))

        self.settings_action.triggered.connect(self.show_settings)

        self.plugin_menu = self.iface.pluginMenu().addMenu(
            QIcon(":/plugins/multilayerselect/icons/icon.svg"),
            "Multilayer Select")
        self.plugin_menu.addAction(self.about_action)
        self.plugin_menu.addAction(self.settings_action)

        self.selection_tool_button = QToolButton(self.toolbar)
        self.selection_tool_button.setPopupMode(QToolButton.MenuButtonPopup)
        self.selection_tool_button.setObjectName("selectionToolButton")

        self.advanced_selection_tool_button = QToolButton(self.toolbar)
        self.advanced_selection_tool_button.setPopupMode(
            QToolButton.MenuButtonPopup)
        self.advanced_selection_tool_button.setObjectName(
            "advancedSelectionToolButton")

        self.select_rect_tool = MultiSelectionAreaTool(self.iface.mapCanvas())
        self.select_polygon_tool = MultiSelectionPolygonTool(
            self.iface.mapCanvas())
        self.select_freehand_tool = MultiSelectionFreehandTool(
            self.iface.mapCanvas())
        self.select_radius_tool = MultiSelectionRadiusTool(
            self.iface.mapCanvas())

        self.actions_settings = [
            SelectAction(
                text=self.tr("Select Features"),
                tooltip=self.tr(
                    "<b>Select Features by area or single click</b>"),
                icon=":/plugins/multilayerselect/icons/selectRectangle.svg",
                objectname="actionMultiSelectByRectangle",
                tool=self.select_rect_tool,
            ),
            SelectAction(
                text=self.tr("Select Features by Polygon"),
                icon=":/plugins/multilayerselect/icons/selectPolygon.svg",
                objectname="actionMultiSelectByPolygon",
                tool=self.select_polygon_tool,
            ),
            SelectAction(
                text=self.tr("Select Features by Freehand"),
                icon=":/plugins/multilayerselect/icons/selectFreehand.svg",
                objectname="actionMultiSelectByFreehand",
                tool=self.select_freehand_tool,
            ),
            SelectAction(
                text=self.tr("Select Features by Radius"),
                icon=":/plugins/multilayerselect/icons/selectRadius.svg",
                objectname="actionMultiSelectByRadius",
                tool=self.select_radius_tool,
            ),
        ]

        def on_select_tool(tool, action):
            self.selection_tool_button.setDefaultAction(action)
            if self.embedded_selection_tool_button:
                self.embedded_selection_tool_button.setDefaultAction(action)
            self.iface.mapCanvas().setMapTool(tool)

        self.select_actions = []

        for select_action in self.actions_settings:
            action = QAction(select_action.text)
            action.setToolTip(select_action.tooltip)
            action.setObjectName(select_action.objectname)
            action.setCheckable(True)
            select_action.tool.setAction(action)

            action.triggered.connect(
                partial(on_select_tool, select_action.tool, action))
            self.selection_tool_button.addAction(action)
            if not self.selection_tool_button.defaultAction():
                self.selection_tool_button.setDefaultAction(action)
            self.select_actions.append(action)

        self.toolbar.addWidget(self.selection_tool_button)

        self.select_all_action = QAction(
            self.tr("Select all features from all layers"), )
        self.select_all_action.setToolTip("<b>{}</b>".format(
            self.select_all_action.text()))
        self.select_all_action.setObjectName("actionMultiSelectAll")
        self.select_all_action.triggered.connect(self.select_all)
        self.advanced_selection_tool_button.addAction(self.select_all_action)
        self.advanced_selection_tool_button.setDefaultAction(
            self.select_all_action)

        self.invert_all_action = QAction(
            self.tr("Invert selection for all layers"), )
        self.invert_all_action.setToolTip("<b>{}</b>".format(
            self.invert_all_action.text()))
        self.invert_all_action.setObjectName("actionMultiSelectInvert")
        self.invert_all_action.triggered.connect(self.invert_all)
        self.advanced_selection_tool_button.addAction(self.invert_all_action)

        self.select_by_expr_action = QAction(
            QIcon(":/images/themes/default/mIconExpressionSelect.svg"),
            self.tr("Select Features by Expression..."),
        )
        self.select_by_expr_action.setToolTip("<b>{}</b>".format(
            self.select_by_expr_action.text()))
        self.select_by_expr_action.setObjectName("actionMultiSelectExpr")
        self.select_by_expr_action.triggered.connect(self.select_by_expression)
        self.advanced_selection_tool_button.addAction(
            self.select_by_expr_action)

        self.toolbar.addWidget(self.advanced_selection_tool_button)

        self.deselect_all_action = QAction(
            self.tr("Deselect features from all layers"))
        self.deselect_all_action.setToolTip("<b>{}</b>".format(
            self.deselect_all_action.text()))
        self.deselect_all_action.setObjectName("actionDeselectAll")
        self.deselect_all_action.triggered.connect(self.deselect_all)
        self.toolbar.addAction(self.deselect_all_action)

        self.toolbar.addAction(self.settings_action)

        self.iface.mainWindow().addToolBar(self.toolbar)

        # Embedded actions
        self.embedded_selection_tool_button_action = None
        self.embedded_selection_tool_button = None
        self.embedded_advanced_tool_button_action = None
        self.embedded_advanced_tool_button = None

        self.on_color_changed()
        self.on_settings_changed()

    def unload(self):
        """Removes the plugin menu item and icon from QGIS GUI."""

        # Delete Settings dialog
        self.settings_dialog.deleteLater()

        # Remove menu from plugins menu
        self.iface.pluginMenu().removeAction(self.plugin_menu.menuAction())

        self.select_freehand_tool.deleteLater()
        self.select_polygon_tool.deleteLater()
        self.select_radius_tool.deleteLater()
        self.select_rect_tool.deleteLater()

        self.iface.mainWindow().removeToolBar(self.toolbar)
        self.toolbar.deleteLater()

        self.replace_default_action(False)

        try:
            QgsProject.instance().selectionColorChanged.disconnect(
                self.on_color_changed)
            QgsProject.instance().selectionColorChanged.disconnect(
                self.settings_dialog.on_project_color_changed)

        except AttributeError:  # QGIS < 3.10
            pass

    def show_about(self):
        """ Show the about dialog """

        # Used to display plugin icon in the about message box
        bogus = QWidget(self.iface.mainWindow())
        bogus.setWindowIcon(QIcon(":/plugins/multilayerselect/icons/icon.svg"))

        cfg = configparser.ConfigParser()
        cfg.read(os.path.join(os.path.dirname(__file__), "metadata.txt"))
        version = cfg.get("general", "version")
        homepage = cfg.get("general", "homepage")
        tracker = cfg.get("general", "tracker")
        repository = cfg.get("general", "repository")

        QMessageBox.about(
            bogus,
            self.tr("About Multilayer Select"),
            "<b>Version</b> {3}<br><br>"
            "<b>{4}</b> : <a href={0}>GitHub</a><br>"
            "<b>{5}</b> : <a href={1}>GitHub</a><br>"
            "<b>{6}</b> : <a href={2}>GitHub Pages</a>".format(
                repository,
                tracker,
                homepage,
                version,
                self.tr("Source code"),
                self.tr("Report issues"),
                self.tr("Documentation"),
            ),
        )

        bogus.deleteLater()

    def show_settings(self):
        """ Show the settings dialog """

        geometry = self.settings_dialog.geometry()

        # The first time the dialog is shown (y=0), explicitely set its geometry
        # which allow to restore the geometry on subsequent calls
        if geometry.y() == 0:
            self.settings_dialog.show()
            self.settings_dialog.raise_()
            self.settings_dialog.setGeometry(self.settings_dialog.geometry())
            return

        self.settings_dialog.show()
        self.settings_dialog.raise_()

    def on_color_changed(self):
        """ Called when the selection color has changed. Replace every icon """
        color = self.iface.mapCanvas().selectionColor()
        color = QColor.fromHsv(color.hue(),
                               color.saturation() * 0.9,
                               color.value() * 0.95, color.alpha())
        for i in range(len(self.select_actions)):
            path = self.actions_settings[i].icon
            icon = create_icon(path, color)
            self.select_actions[i].setIcon(icon)

        icon = create_icon(":/plugins/multilayerselect/icons/deselectAll.svg",
                           color)
        self.deselect_all_action.setIcon(icon)

        icon = select_all_icon(color)
        self.select_all_action.setIcon(icon)

        icon = invert_selection_icon(color)
        self.invert_all_action.setIcon(icon)

        icon = expression_select_icon(color)
        self.select_by_expr_action.setIcon(icon)

    def on_settings_changed(self):
        """ Called when any setting has changed """
        if self.settings.value("show_settings", True, bool):
            self.toolbar.addAction(self.settings_action)
        else:
            self.toolbar.removeAction(self.settings_action)

        self.replace_default_action(
            self.settings.value("replace_actions", False, bool))

    def deselect_all(self):
        """ Deselect every feature """
        for layer in QgsProject.instance().mapLayers().values():
            if isinstance(layer, QgsVectorLayer):
                layer.removeSelection()
        update_status_message()

    def select_all(self):
        """ Select all the features from every vector layer """
        for layer in vector_layers():
            layer.selectAll()
        self.advanced_selection_tool_button.setDefaultAction(
            self.select_all_action)

        if self.embedded_advanced_tool_button:
            self.embedded_advanced_tool_button.setDefaultAction(
                self.select_all_action)

        update_status_message()

    def invert_all(self):
        """ Invert the selection of every vector layer """
        for layer in vector_layers():
            layer.invertSelection()
        self.advanced_selection_tool_button.setDefaultAction(
            self.invert_all_action)

        if self.embedded_advanced_tool_button:
            self.embedded_advanced_tool_button.setDefaultAction(
                self.invert_all_action)
        update_status_message()

    def select_by_expression(self):
        """ Create and open the Expression builder dialog"""

        if self.expression_dialog:
            self.expression_dialog.deleteLater()
        self.expression_dialog = MultiLayerSelectionExpressionBuilder()
        self.expression_dialog.show()

        self.advanced_selection_tool_button.setDefaultAction(
            self.select_by_expr_action)

        if self.embedded_advanced_tool_button:
            self.embedded_advanced_tool_button.setDefaultAction(
                self.select_by_expr_action)
        update_status_message()

    def replace_default_action(self, value):
        """Replace the default QGIS selection action with the multilayer ones

        Args:
            value (bool): If true, replace the actions, else put the multi actions
                inside their own toolbar
        """

        toolbar = self.iface.attributesToolBar()
        main_window = self.iface.mainWindow()
        main_window.findChild(QAction, "ActionSelect").setVisible(not value)
        main_window.findChild(QAction, "ActionSelection").setVisible(not value)
        main_window.findChild(QAction,
                              "mActionDeselectAll").setVisible(not value)

        actiontable = main_window.findChild(QAction, "mActionOpenTable")
        actionform = main_window.findChild(QAction, "mActionSelectByForm")

        # Remove the multi layer tool buttons from the QGIS attribute toolbar
        toolbar.removeAction(self.embedded_selection_tool_button_action)
        toolbar.removeAction(self.embedded_advanced_tool_button_action)

        if value:

            # Create the QToolButtons that will be added to the default toolbar
            self.embedded_selection_tool_button = QToolButton()
            self.embedded_selection_tool_button.setPopupMode(
                QToolButton.MenuButtonPopup)

            # Add selection tools action to the button (Rect, Polygon, Radius, Freehand)
            self.embedded_selection_tool_button.addActions(self.select_actions)
            self.embedded_selection_tool_button.setDefaultAction(
                self.select_actions[0])

            self.embedded_advanced_tool_button = QToolButton()
            self.embedded_advanced_tool_button.setPopupMode(
                QToolButton.MenuButtonPopup)

            # Add Invert, Select All, Select from value and Select from expressions
            self.embedded_advanced_tool_button.addAction(
                self.select_all_action)
            self.embedded_advanced_tool_button.setDefaultAction(
                self.select_all_action)
            self.embedded_advanced_tool_button.addAction(
                self.invert_all_action)
            self.embedded_advanced_tool_button.addAction(
                self.select_by_expr_action)
            self.embedded_advanced_tool_button.addAction(actionform)

            self.embedded_selection_tool_button_action = toolbar.insertWidget(
                actiontable, self.embedded_selection_tool_button)
            self.embedded_advanced_tool_button_action = toolbar.insertWidget(
                actiontable, self.embedded_advanced_tool_button)

            # Add the deselect all action
            toolbar.insertAction(actiontable, self.deselect_all_action)

            # If the settigns is enabled add the show settings action
            if self.settings.value("show_settings", True, bool):
                toolbar.insertAction(actiontable, self.settings_action)
            else:
                toolbar.removeAction(self.settings_action)
            self.toolbar.hide()

        else:

            # Remove the multi actions from the default toolbar, and show
            # the custom toolbar
            self.embedded_selection_tool_button = None
            self.embedded_advanced_tool_button = None
            toolbar.removeAction(self.deselect_all_action)
            toolbar.removeAction(self.settings_action)
            self.toolbar.show()
class ExportWindow(QDialog):
    """
    Class describing a dialog for exports of schedules.
    """
    def __init__(self, schedule: Schedule, parent: QWidget = None):
        super().__init__(parent)
        self._schedule_ref = schedule
        self._date_start_cache = None

        # window settings
        self.setWindowFlag(Qt.WindowContextHelpButtonHint, False)
        self.setWindowTitle(self.tr("Export window"))
        self.setMinimumWidth(800)

        # title, add_date, work mode
        self.layout_title_date_mode = QHBoxLayout()

        self.label_title = QLabel(self.tr("Title"))
        self.layout_title_date_mode.addWidget(self.label_title)

        self.line_edit_title = QLineEdit()
        self.layout_title_date_mode.addWidget(self.line_edit_title)

        self.check_box_add_date = QCheckBox(self.tr("Add date"))
        self.layout_title_date_mode.addWidget(self.check_box_add_date)

        self.combo_box_work_mode = QComboBox()
        self.layout_title_date_mode.addWidget(self.combo_box_work_mode)

        self.line_edit_title.setPlaceholderText(
            self.tr("My Group. A subgroup - green color, "
                    "B subgroup - yellow color. "))
        self.check_box_add_date.setChecked(True)

        self.combo_box_work_mode.addItem(self.tr("Weekly"))
        self.combo_box_work_mode.addItem(self.tr("Full"))

        # list widget with files
        self.layout_list_widget = QVBoxLayout()

        self.check_box_use_current = QCheckBox(self.tr("Use current schedule"))
        self.layout_list_widget.addWidget(self.check_box_use_current)
        self.check_box_use_current.setChecked(True)

        self.list_widget = QListWidget()
        self.layout_list_widget.addWidget(self.list_widget)
        self.list_widget.setSortingEnabled(True)
        self.list_widget.setEnabled(False)

        self.layout_open_folder = QHBoxLayout()
        self.layout_list_widget.addLayout(self.layout_open_folder)

        self.label_find = QLabel(self.tr("Schedules: ") + "0")
        self.layout_open_folder.addWidget(self.label_find)

        self.layout_open_folder.addStretch(1)

        self.push_button_open_folder = QToolButton()
        self.layout_open_folder.addWidget(self.push_button_open_folder)
        self.push_button_open_folder.setEnabled(False)

        self.push_button_open_folder.setText(self.tr("Open folder"))
        self.push_button_open_folder.setPopupMode(QToolButton.MenuButtonPopup)

        self.action_open_files = QAction(self.tr("Open files"))
        self.push_button_open_folder.addAction(self.action_open_files)

        # font edit
        self.group_box_font = QGroupBox(self.tr("Font settings"))
        self.form_layout_font = QFormLayout(self.group_box_font)

        self.label_font = QLabel(self.tr("Font"))
        self.form_layout_font.setWidget(0, QFormLayout.LabelRole,
                                        self.label_font)
        self.combo_box_font = QComboBox()
        self.form_layout_font.setWidget(0, QFormLayout.FieldRole,
                                        self.combo_box_font)

        self.label_encoding = QLabel(self.tr("Encoding"))
        self.form_layout_font.setWidget(1, QFormLayout.LabelRole,
                                        self.label_encoding)
        self.combo_box_encoding = QComboBox()
        self.form_layout_font.setWidget(1, QFormLayout.FieldRole,
                                        self.combo_box_encoding)

        for font_name, font_path in util.get_fonts():
            self.combo_box_font.addItem(font_name, font_path)

        self.combo_box_font.setCurrentText(qApp.font().family())
        self.combo_box_font.setEditable(True)

        self.combo_box_encoding.addItem("UTF-8")
        self.combo_box_encoding.addItem("Latin-1")
        self.combo_box_encoding.addItem("Windows-1252")

        # date edit
        self.group_box_date = QGroupBox(self.tr("Date settings"))
        self.form_layout_date = QFormLayout(self.group_box_date)

        self.label_date_start = QLabel(self.tr("Start"))
        self.form_layout_date.setWidget(0, QFormLayout.LabelRole,
                                        self.label_date_start)
        self.date_edit_start = QDateEdit()
        self.form_layout_date.setWidget(0, QFormLayout.FieldRole,
                                        self.date_edit_start)

        self.label_date_end = QLabel(self.tr("End"))
        self.form_layout_date.setWidget(1, QFormLayout.LabelRole,
                                        self.label_date_end)
        self.date_edit_end = QDateEdit()
        self.form_layout_date.setWidget(1, QFormLayout.FieldRole,
                                        self.date_edit_end)

        self.date_edit_start.setCalendarPopup(True)
        self.date_edit_end.setCalendarPopup(True)

        if QDate.currentDate().day() < (QDate.currentDate().dayOfYear() / 2):
            date = QDate(QDate.currentDate().year(), 2, 1)
        else:
            date = QDate(QDate.currentDate().year(), 9, 1)

        self._date_start_cache = date.addDays(8 - date.dayOfWeek())
        self.date_edit_start.setDate(self._date_start_cache)
        self.date_edit_end.setMinimumDate(self._date_start_cache.addDays(7))
        self.date_edit_end.setDate(self._date_start_cache.addDays(16 * 7))

        # subgroup edit
        self.group_box_subgroup = QGroupBox(self.tr("Subgroup settings"))
        self.form_layout_subgroup = QFormLayout(self.group_box_subgroup)

        self.label_color_a = QLabel(self.tr("Color A"))
        self.form_layout_subgroup.setWidget(0, QFormLayout.LabelRole,
                                            self.label_color_a)
        self.combo_box_color_a = QComboBox()
        self.form_layout_subgroup.setWidget(0, QFormLayout.FieldRole,
                                            self.combo_box_color_a)

        self.label_color_b = QLabel(self.tr("Color B"))
        self.form_layout_subgroup.setWidget(1, QFormLayout.LabelRole,
                                            self.label_color_b)
        self.combo_box_color_b = QComboBox()
        self.form_layout_subgroup.setWidget(1, QFormLayout.FieldRole,
                                            self.combo_box_color_b)

        self.label_pattern_a_b = QLabel(self.tr("Pattern A and B"))
        self.form_layout_subgroup.setWidget(2, QFormLayout.LabelRole,
                                            self.label_pattern_a_b)
        self.combo_box_pattern_a_b = QComboBox()
        self.form_layout_subgroup.setWidget(2, QFormLayout.FieldRole,
                                            self.combo_box_pattern_a_b)

        self.add_standard_colors(self.combo_box_color_a)
        self.add_standard_colors(self.combo_box_color_b)
        self.combo_box_color_a.setCurrentIndex(9)  # lime
        self.combo_box_color_b.setCurrentIndex(15)  # yellow

        self.combo_box_pattern_a_b.addItem(self.tr("Chess order"))
        self.combo_box_pattern_a_b.setEnabled(False)

        # navigate buttons
        self.layout_navigate = QHBoxLayout()

        self.layout_navigate.addStretch(1)

        self.push_button_export = QPushButton(self.tr("Export"))
        self.layout_navigate.addWidget(self.push_button_export)

        self.push_button_cancel = QPushButton(self.tr("Cancel"))
        self.layout_navigate.addWidget(self.push_button_cancel)

        # layout setup
        self.layout_right_setting = QVBoxLayout()
        self.layout_right_setting.addWidget(self.group_box_font)
        self.layout_right_setting.addWidget(self.group_box_date)
        self.layout_right_setting.addWidget(self.group_box_subgroup)
        self.layout_right_setting.addStretch(1)

        self.layout_center = QHBoxLayout()
        self.layout_center.addLayout(self.layout_list_widget)
        self.layout_center.addLayout(self.layout_right_setting)

        self.layout_main = QVBoxLayout()
        self.layout_main.addLayout(self.layout_title_date_mode)
        self.layout_main.addLayout(self.layout_center)
        self.layout_main.addLayout(self.layout_navigate)

        self.setLayout(self.layout_main)

        # connection
        self.check_box_use_current.clicked.connect(
            self.check_box_use_current_clicked)
        self.push_button_open_folder.clicked.connect(self.open_folder_clicked)
        self.action_open_files.triggered.connect(self.open_files_clicked)

        self.date_edit_start.dateChanged.connect(self.date_edit_start_changed)
        self.combo_box_color_a.activated.connect(
            self.combo_box_color_a_clicked)
        self.combo_box_color_b.activated.connect(
            self.combo_box_color_b_clicked)
        self.push_button_export.clicked.connect(self.export_to_pdf)
        self.push_button_cancel.clicked.connect(self.close)

    def add_standard_colors(self, combo_box: QComboBox) -> None:
        """
        Adds colors to the color selection menu.

        :param combo_box: Color selection menu
        """
        color_items = [(self.tr("Custom color"), QColor()),
                       (self.tr("Aqua"), QColor(0, 255, 255)),
                       (self.tr("Grey"), QColor(128, 128, 128)),
                       (self.tr("Navy"), QColor(0, 0, 192)),
                       (self.tr("Silver"), QColor(192, 192, 192)),
                       (self.tr("Black"), QColor(0, 0, 0)),
                       (self.tr("Green"), QColor(0, 128, 0)),
                       (self.tr("Olive"), QColor(192, 192, 0)),
                       (self.tr("Blue"), QColor(0, 0, 255)),
                       (self.tr("Lime"), QColor(0, 255, 0)),
                       (self.tr("Purple"), QColor(128, 0, 128)),
                       (self.tr("White"), QColor(255, 255, 255)),
                       (self.tr("Fuchsia"), QColor(255, 0, 255)),
                       (self.tr("Maroon"), QColor(128, 0, 0)),
                       (self.tr("Red"), QColor(255, 0, 0)),
                       (self.tr("Yellow"), QColor(255, 255, 0))]

        for name, data in color_items:
            combo_box.addItem(util.create_color_icon(data), name, data)

    def export_to_pdf(self) -> None:
        # select path

        paths = []

        if self.check_box_use_current.isChecked():
            path = QFileDialog.getSaveFileName(self, self.tr("Export to pdf"),
                                               ".", "PDF file (*.pdf)")[0]
            if path == "":
                return

            if not path.endswith(".pdf"):
                path += ".pdf"

            paths.append(path)
        else:
            for index in range(self.list_widget.count()):
                path = self.list_widget.item(index).data(Qt.UserRole)
                paths.append(path)

        # progress dialog
        progress = QProgressDialog(self.tr("Export to pdf"),
                                   self.tr("Abort exports"), 0, 100, self)
        progress.setWindowModality(Qt.WindowModal)
        progress.setMinimumDuration(2000)

        try:
            for index, path in enumerate(paths):

                if self.check_box_use_current.isChecked():
                    title_text = self.line_edit_title.text()
                    schedule = self._schedule_ref
                else:
                    title_text = QFileInfo(path).baseName()
                    schedule = Schedule()
                    schedule.load(path)
                    path = path[0:-5] + ".pdf"

                print(path)
                mode = self.combo_box_work_mode.currentIndex()
                if mode == 0:
                    export_weeks_to_pdf(
                        schedule, title_text,
                        self.check_box_add_date.isChecked(), path,
                        self.combo_box_font.currentText(),
                        self.combo_box_font.currentData(Qt.UserRole),
                        self.combo_box_encoding.currentText(),
                        self.date_edit_start.date().toPyDate(),
                        self.date_edit_end.date().toPyDate(),
                        self.combo_box_color_a.currentData(Qt.UserRole),
                        self.combo_box_color_b.currentData(Qt.UserRole),
                        progress
                        if self.check_box_use_current.isChecked() else None)
                else:
                    export_full_to_pdf(
                        schedule, title_text, path,
                        self.combo_box_font.currentText(),
                        self.combo_box_font.currentData(Qt.UserRole),
                        self.combo_box_encoding.currentText(), progress
                        if self.check_box_use_current.isChecked() else None)

                progress.setValue(int(index * 100 / len(paths)))

            # finish dialog
            progress.setValue(100)
            finish_msg_box = QMessageBox(QMessageBox.Information,
                                         self.tr("Export to pdf"),
                                         self.tr("Gone!"))
            open_folder_button = finish_msg_box.addButton(
                self.tr("Open folder"), QMessageBox.ActionRole)
            finish_msg_box.addButton(QMessageBox.Ok)
            finish_msg_box.exec_()

            if finish_msg_box.clickedButton() == open_folder_button:
                QDesktopServices.openUrl(
                    QUrl(
                        QFileInfo(paths[0] if len(paths) != 0 else ".").
                        absolutePath()))

        except UnicodeEncodeError as ex:
            QMessageBox.critical(self, self.tr("Encoding error"), str(ex))
        except Exception as ex:
            QMessageBox.critical(self, self.tr("Unknown error"), str(ex))
        progress.setValue(100)

    def check_box_use_current_clicked(self, checked: bool):
        if checked:
            self.list_widget.setEnabled(False)
            self.push_button_open_folder.setEnabled(False)
            self.line_edit_title.setEnabled(False)
        else:
            self.list_widget.setEnabled(True)
            self.push_button_open_folder.setEnabled(True)
            self.line_edit_title.setEnabled(True)

    def open_folder_clicked(self):
        path = QFileDialog.getExistingDirectory(self, self.tr("Select folder"))

        provider = QFileIconProvider()
        self.list_widget.clear()

        for dir_path, dir_names, file_names in os.walk(path):
            for file_name in file_names:
                if file_name.endswith(".json"):
                    item = QListWidgetItem()
                    item.setText(file_name[0:-5])
                    item.setData(Qt.UserRole, dir_path + os.sep + file_name)
                    item.setIcon(
                        provider.icon(QFileInfo(dir_path + os.sep +
                                                file_name)))

                    self.list_widget.addItem(item)

        self.label_find.setText(
            self.tr("Schedules: ") + str(self.list_widget.count()))

    def open_files_clicked(self):
        files = QFileDialog.getOpenFileNames(
            self, self.tr("Select files"), "",
            "JSON file (*.json) ;; All files (*.*)")[0]
        provider = QFileIconProvider()
        self.list_widget.clear()

        for file_path in files:
            file = QFileInfo(file_path)
            item = QListWidgetItem()
            item.setText(file.baseName())
            item.setData(Qt.UserRole, file_path)
            item.setIcon(provider.icon(file))
            self.list_widget.addItem(item)

        self.label_find.setText(
            self.tr("Schedules: ") + str(self.list_widget.count()))

    def combo_box_color_a_clicked(self) -> None:
        """
        Slot for color selection of A subgroup.
        """
        if self.combo_box_color_a.currentIndex() == 0:
            self.custom_color_selected(self.combo_box_color_a)

    def combo_box_color_b_clicked(self) -> None:
        """
        Slot for color selection of B subgroup.
        """
        if self.combo_box_color_b.currentIndex() == 0:
            self.custom_color_selected(self.combo_box_color_b)

    def custom_color_selected(self, combo_box: QComboBox) -> None:
        """
        Slot to select the color for the desired menu.

        :param combo_box: Menu
        """
        color = QColorDialog.getColor(combo_box.currentData(), self)
        if color.isValid():
            combo_box.setItemIcon(0, util.create_color_icon(color))
            combo_box.setItemData(0, color)

    def date_edit_start_changed(self, date: QDate):
        """
        Slot for changing the end of a range of dates.

        :param date: Start of the date range
        """
        end_date = self.date_edit_end.date().addDays(
            self._date_start_cache.daysTo(date))
        self.date_edit_end.setMinimumDate(date.addDays(7))
        self.date_edit_end.setDate(end_date)
        self._date_start_cache = QDate(date)
Esempio n. 13
0
    def _add_button(self, parent, index, button_info):
        if hasattr(parent, '_title'):
            self._adjust_title(parent)

        # split title into two lines if long
        orig_title = button_info.title
        title = orig_title
        if '\n' not in title and len(title) > 6:
            title = split_title(title)

        if button_info.highlight_icon is None:
            icon = button_info.icon
        else:
            icon = button_info.highlight_icon

        if not button_info.group:
            group_first = group_follow = False
        else:
            buttons = self._groups.setdefault(parent, {})
            group_first = button_info.group not in buttons  # first button in drop down
            group_follow = not group_first  # subsequent buttons
        if not group_follow:
            b = QToolButton(parent)
            if button_info.vr_mode is not None:
                b.vr_mode = button_info.vr_mode
            b.setAutoRaise(True)
            if icon is None:
                style = Qt.ToolButtonTextOnly
            else:
                if not self.show_button_titles:
                    style = Qt.ToolButtonIconOnly
                elif self.compact:
                    style = Qt.ToolButtonTextBesideIcon
                else:
                    style = Qt.ToolButtonTextUnderIcon
            b.setToolButtonStyle(style)
        if icon is None:
            action = QAction(title)
        else:
            action = QAction(icon, title)
        if button_info.description:
            action.setToolTip(button_info.description)
        if button_info.callback is not None:
            action.triggered.connect(button_info.callback)
        actions = self._actions.setdefault(orig_title, [])
        actions.append(action)
        if group_follow:
            button = self._groups[parent][button_info.group]
            button.addAction(action)
        else:
            if not group_first:
                b.setDefaultAction(action)
            else:
                b.setPopupMode(b.MenuButtonPopup)
                b.triggered.connect(
                    lambda action, b=b: self._update_button_action(b, action))
                self._groups[parent][button_info.group] = b
                b.addAction(action)
                self._update_button_action(b, action)

        # print('Font height:', b.fontMetrics().height())  # DEBUG
        # print('Font size:', b.fontInfo().pixelSize())  # DEBUG
        # print('Icon size:', b.iconSize())  # DEBUG
        if not group_follow:
            if self.compact:
                row = index % self.compact_height
                if row < self.compact_height:
                    parent._layout.setRowStretch(row, 1)
                column = index // self.compact_height
                parent._layout.addWidget(b, row, column,
                                         Qt.AlignLeft | Qt.AlignVCenter)
            else:
                if not self.show_button_titles or button_info.icon is None:
                    align = Qt.AlignCenter
                else:
                    align = Qt.AlignTop
                b.setIconSize(2 * b.iconSize())
                parent._layout.addWidget(b, 0, index, align)
        global _debug
        if _debug:
            _debug = False
            policy = b.sizePolicy()
            print('expanding:', int(policy.expandingDirections()))
            print('horizontal policy:', policy.horizontalPolicy())
            print('horizontal stretch:', policy.horizontalStretch())
            print('vertical policy:', policy.verticalPolicy())
            print('vertical stretch:', policy.verticalStretch())
    def __init__(self, parent=None):
        super().__init__(parent)

        self.settings = QSettings()
        self.settings.beginGroup("plugins/layertreeicons")

        self.setWindowTitle(self.tr("Default layer tree properties"))
        self.setMinimumSize(QSize(250, 0))
        layout = QVBoxLayout(self)

        form_layout = QFormLayout()

        hlayout = QHBoxLayout()
        self.group_font_label = QLabel("")
        group_font_button = QToolButton(self)
        group_font_button.setText("...")
        hlayout.addWidget(self.group_font_label)
        hlayout.addWidget(group_font_button)
        form_layout.addRow(self.tr("Group node font"), hlayout)
        group_font_button.setToolTip("Select font")
        group_font_button.clicked.connect(self.select_group_font)

        hlayout = QHBoxLayout()
        self.layer_font_label = QLabel("")
        layer_font_button = QToolButton(self)
        layer_font_button.setText("...")
        hlayout.addWidget(self.layer_font_label)
        hlayout.addWidget(layer_font_button)
        form_layout.addRow(self.tr("Layer node font"), hlayout)
        layer_font_button.setToolTip("Select font")
        layer_font_button.clicked.connect(self.select_layer_font)

        self.icon_size_combo = QComboBox(self)
        self.icon_size_combo.addItem(self.tr("default"), -1)
        for val in (16, 24, 32, 48, 64):
            self.icon_size_combo.addItem(f"{val} px", val)

        idx = self.icon_size_combo.findData(self.settings.value("iconsize", -1, int))
        self.icon_size_combo.setCurrentIndex(idx)
        self.icon_size_combo.currentIndexChanged.connect(self.on_icon_size_changed)

        form_layout.addRow(self.tr("Icon Size"), self.icon_size_combo)

        layout.addLayout(form_layout)
        group_box = QGroupBox(self)
        group_box.setTitle("Default Icons")
        self.form_layout = QFormLayout(group_box)
        layout.addWidget(group_box)
        self.reset_button = QPushButton(self.tr("Reset default properties"))
        layout.addWidget(self.reset_button)

        self.reset_button.clicked.connect(self.reset_all)

        self.resource_browser = ResourceBrowser(parent)

        self.source_data = {
            "group": (self.tr("Group"), ":/images/themes/default/mActionFolder.svg",),
            "raster": (self.tr("Raster"), ":/images/themes/default/mIconRaster.svg",),
            "point": (self.tr("Point"), ":/images/themes/default/mIconPointLayer.svg",),
            "line": (self.tr("Line"), ":/images/themes/default/mIconLineLayer.svg",),
            "polygon": (
                self.tr("Polygon"),
                ":/images/themes/default/mIconPolygonLayer.svg",
            ),
            "nogeometry": (
                self.tr("No Geometry"),
                ":/images/themes/default/mIconTableLayer.svg",
            ),
        }

        if Qgis.QGIS_VERSION_INT > 30200:

            self.source_data["mesh"] = (
                self.tr("Mesh Layer"),
                ":/images/themes/default/mIconMeshLayer.svg",
            )

        for settings_key, (text, default_icon) in self.source_data.items():

            button = QToolButton(self)
            button.setObjectName(settings_key)
            button.setPopupMode(QToolButton.MenuButtonPopup)
            button.setIconSize(QSize(24, 24))
            button.setIcon(QIcon(default_icon))
            label = QLabel(text, self)
            label.setMinimumSize(QSize(label.minimumSize().width(), 38))
            self.form_layout.addRow(label, button)

            action_from_qgis = QAction("Set from QGIS ressources", button)
            action_from_qgis.triggered.connect(
                partial(self.set_icon_from_ressources, settings_key)
            )
            button.addAction(action_from_qgis)
            button.clicked.connect(action_from_qgis.trigger)

            action_from_file = QAction("Set from file", button)
            action_from_file.triggered.connect(
                partial(self.set_icon_from_file, settings_key)
            )
            button.addAction(action_from_file)

            action_reset = QAction("Reset", button)
            action_reset.triggered.connect(partial(self.reset, settings_key))
            button.addAction(action_reset)

        f = QFont()
        if f.fromString(self.settings.value("group_font")) and f.family():
            iface.layerTreeView().layerTreeModel().setLayerTreeNodeFont(
                QgsLayerTree.NodeGroup, f
            )
        else:
            iface.layerTreeView().layerTreeModel().setLayerTreeNodeFont(
                QgsLayerTree.NodeGroup, iface.layerTreeView().font()
            )
            self.settings.setValue(
                "group_font", iface.layerTreeView().font().toString()
            )

        f = QFont()
        if f.fromString(self.settings.value("layer_font")) and f.family():
            iface.layerTreeView().layerTreeModel().setLayerTreeNodeFont(
                QgsLayerTree.NodeLayer, f
            )
        else:
            f = iface.layerTreeView().font()
            f.setBold(True)
            iface.layerTreeView().layerTreeModel().setLayerTreeNodeFont(
                QgsLayerTree.NodeLayer, f
            )
            self.settings.setValue("layer_font", f.toString())
        self.update_font_labels()
Esempio n. 15
0
class QPlainMdTextEdit(QMainWindow):

    textedit = None

    completer = None
    toolBar = None

    emtab = None
    texttab = None

    md_menu = None

    save_md_act = None
    load_md_act = None

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

        self.textedit = QPlainTextEdit()

        self.setLayout(QHBoxLayout())
        self.layout().addWidget(self.textedit)

        self.setCentralWidget(self.textedit)

        self.emtab = helper.EmojiTable()

        self.emtab.emojiChanged.connect(self.insert)
        self.emtab.setMinimumWidth(40)
        self.texttab = helper.TextTable()
        self.texttab.setMinimumWidth(70)

        self.texttab.insert.connect(self.insert)

        self.toolBar = QToolBar()

        self.addToolBar(self.toolBar)

        self.toolBar.addWidget(self.emtab)
        self.toolBar.addWidget(self.texttab)

        self.md_menu = QToolButton()
        self.md_menu.setText("md")
        self.md_menu.setStyleSheet('''
        * {
            font-size: 24px;
        }
        ''')
        self.md_menu.setPopupMode(2)

        self.save_md_act = QAction("save")
        self.load_md_act = QAction("load")

        self.md_menu.addAction(self.save_md_act)
        self.md_menu.addAction(self.load_md_act)

        self.toolBar.addWidget(self.md_menu)

        self.load_md_act.triggered.connect(self.load_md)

        self.save_md_act.triggered.connect(self.save_md)

        self.textedit.setStyleSheet('''
            * {
                padding-top: 25px;
                padding-left: 25px;
            }
        
        ''')

    def insert(self, text):
        self.textedit.insertPlainText(text)
        self.setFocus()

    def save_md(self):
        filename, t = QFileDialog.getSaveFileName(None, "Save to Markdown",
                                                  ".md", "Markdown (*.md)")

        if filename == "":
            return

        if t == "Markdown (*.md)":
            with open(filename, "w") as file:
                file.write(self.textedit.toPlainText())

    def load_md(self):
        filename, t = QFileDialog.getOpenFileName(None, "Load Markdown", ".md",
                                                  "Markdown (*.md)")

        if filename == "":
            return

        with open(filename, "r") as file:
            self.textedit.setPlainText(file.read())