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('添加了')
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.")
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.")
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)
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 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)
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
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")
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)
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)
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()
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())