class RouteTable(QWidget): NO1, FROM, NO2, TO, CLUSTER = range(5) def __init__(self): super().__init__() # Main layout main_layout = QVBoxLayout() # Sub layout self.cluster_combobox = QComboBox() self.table_container = QGroupBox("Result") # Route Table self.table = QTreeView() self.table.setRootIsDecorated(False) self.table.setAlternatingRowColors(True) self.model = QStandardItemModel(0, 5, self) self.model.setHeaderData(self.NO1, Qt.Horizontal, "No") self.model.setHeaderData(self.FROM, Qt.Horizontal, "From") self.model.setHeaderData(self.NO2, Qt.Horizontal, "No") self.model.setHeaderData(self.TO, Qt.Horizontal, "To") self.model.setHeaderData(self.CLUSTER, Qt.Horizontal, "Cluster number") self.table.setModel(self.model) table_header = self.table.header() table_header.resizeSection(0, 25) table_header.resizeSection(1, 190) table_header.resizeSection(2, 25) table_header.resizeSection(3, 190) table_container_layout = QHBoxLayout() table_container_layout.addWidget(self.table) self.table_container.setLayout(table_container_layout) # Add to main layout main_layout.addWidget(self.cluster_combobox) main_layout.addWidget(self.table_container) self.setLayout(main_layout) def addRoute(self, model, from_no, from_route, to_no, to_route, cluster_number): root = self.table.model() n = root.rowCount() model.insertRow(n) model.setData(model.index(n, self.NO1), from_no) model.setData(model.index(n, self.FROM), from_route) model.setData(model.index(n, self.NO2), to_no) model.setData(model.index(n, self.TO), to_route) model.setData(model.index(n, self.CLUSTER), cluster_number) def clearAllRoute(self): root = self.table.model() root.removeRows(0, root.rowCount())
class ParameterWindow(QMainWindow): def __init__(self, dplugin, api, pl_win_name = '',parent = None): QMainWindow.__init__(self, parent) # Build the tree for the parameters self.parameterTree = QTreeView(self) self.parameterTree.setObjectName("parameterTree") # Add it as the central widget self.setCentralWidget(self.parameterTree) # Add the DParameterTreeModel to the parameter tree self.dparameterModel = DParameterTreeModel() self.dparameterModel.setHorizontalHeaderLabels(['Name','']) self.parameterTree.setModel(self.dparameterModel) self.parameterTree.setUniformRowHeights(True) # connect the callback function for value changes self.dparameterModel.dataChanged.connect(self.data_changed_parameter_model) self.dpluign_object = dplugin self.api = api self.setWindowTitle(pl_win_name+' Parameter') def show_paramters(self, para_list): """ Shows the list of parameters and values in the parameter window :param para_list: :return: """ for dparameter_name in sorted(para_list): dparameter = para_list[dparameter_name] dparameter_item = DParameterTreeItem(dparameter) self.dparameterModel.appendRow(dparameter_item) self.parameterTree.resizeColumnToContents(0) self.parameterTree.resizeColumnToContents(1) self.parameterTree.expandAll() fh = self.parameterTree.fontMetrics().height() if len(para_list.keys()) > 8: self.setFixedHeight(fh*9+fh+25) else: self.setFixedHeight(fh*len(para_list.keys())+fh+fh+25) def data_changed_parameter_model(self, index, n): """ This function is called when a dparameter value is changed by editing the 'value'-column. :param index: Index of current changed dparameter :param n: None :return: """ dparameter = self.parameterTree.model().data(index, Qt.UserRole) self.api.do_set_parameter(self.dpluign_object.id, dparameter.name, dparameter.value)
class DirectoryDockWidget(QWidget): def __init__(self, directory: Directory, filtered=False, parent=None): super().__init__(parent) layout = QVBoxLayout(self) layout.setContentsMargins(4, 4, 4, 4) self.setLayout(layout) self.path_label = QLineEdit() self.path_label.setReadOnly(True) layout.addWidget(self.path_label) self.tree_view = QTreeView() layout.addWidget(self.tree_view) self.directory = directory self.filtered = filtered self.tree_view.setModel(QFileSystemModel()) for i in range(1, 4): self.tree_view.hideColumn(i) self.tree_view.setHeaderHidden(True) self.directory.changed.connect(self.handle_directory_path_changed) def handle_directory_path_changed(self, path): if not path: return self.path_label.setText(path) model = self.tree_view.model() model.setRootPath(path) self.tree_view.setRootIndex(model.index(path)) if self.filtered: model.setNameFilters(plugin.pattern for plugin in FilePluginRegistry.plugins)
class App(QWidget): def __init__(self): super().__init__() self.title = 'PyQt5 file system view' self.left = 100 self.top = 100 self.width = 1140 self.height = 480 self.initUI() def initUI(self): self.setWindowTitle(self.title) self.setGeometry(self.left, self.top, self.width, self.height) self.model = QFileSystemModel() self.model.setRootPath(QDir.rootPath()) self.tree = QTreeView() self.tree.setModel(self.model) self.tree.setRootIndex(self.model.index(config['rgb_img_path'])) self.tree.setAnimated(False) self.tree.setIndentation(20) self.tree.setSortingEnabled(True) self.tree.setWindowTitle("Dir View") self.tree.resize(640, 480) self.tree.doubleClicked.connect(self.plot) windowLayout = QVBoxLayout() windowLayout.addWidget(self.tree) self.setLayout(windowLayout) self.m = PlotCanvas(self, width=5, height=4) self.m.move(640, 0) self.show() def plot(self, signal): file_path = self.tree.model().filePath(signal) sample_id = re.search(r'\d+', file_path.split('/')[-1]).group() self.m.plot(str(sample_id))
class QTreeSelection(QToolButton): currentIndexChanged = pyqtSignal(QModelIndex, QModelIndex) currentDataChanged = pyqtSignal(object) def __init__(self, *args, **kwargs): super().__init__(*args, **kwargs) self.setPopupMode(QToolButton.MenuButtonPopup) self.setToolButtonStyle(Qt.ToolButtonTextBesideIcon) self.tree = QTreeView(self) self.tree.setMinimumWidth(640) self.tree.setSelectionMode(QTreeView.SingleSelection) self.tree.setSelectionBehavior(QTreeView.SelectRows) act = QWidgetAction(self) act.setDefaultWidget(self.tree) self.menu = QMenu(self) self.menu.addAction(act) self.setMenu(self.menu) self.clicked.connect(self.showMenu) def _currentIndexChanged(self, newindex, oldindex): self.menu.close() selected = newindex.sibling(newindex.row(), 0) display = selected.data(Qt.DisplayRole) icon = selected.data(Qt.DecorationRole) self.setText(display or "") self.setIcon(icon or QIcon()) self.currentIndexChanged.emit(newindex, oldindex) self.currentDataChanged.emit(newindex.data(Qt.UserRole)) def currentIndex(self): return self.tree.currentIndex() def currentData(self): return self.currentIndex().data(Qt.UserRole) def setCurrentIndex(self, index): return self.tree.setCurrentIndex(index) def model(self): return self.tree.model() def setModel(self, model): self.tree.setModel(model) self.tree.selectionModel().currentChanged.connect( self._currentIndexChanged) def keyPressEvent(self, event): if (event.key() in (Qt.Key_Up, Qt.Key_Down) and not (event.modifiers() & (Qt.ShiftModifier | Qt.AltModifier | Qt.ControlModifier))): self.tree.keyPressEvent(event) return super().keyPressEvent(event)
class FileListWidget(QGroupBox): FILENAME, PATH = range(2) def __init__(self, title="Files"): super(QGroupBox, self).__init__(title) self.layout = QVBoxLayout(self) self.dataView = QTreeView() self.dataView.setRootIsDecorated(False) self.dataView.setAlternatingRowColors(True) self.layout.addWidget(self.dataView) model = self.create_file_list_model(self) self.dataView.setModel(model) self.data_dir = None self.loaded_directory_label = QLabel( "Click 'Open' to select a directory.", self) self.layout.addWidget(self.loaded_directory_label) self.btnOpen = QPushButton("Open", self) self.btnOpen.clicked.connect(self.load_data_directory) self.layout.addWidget(self.btnOpen) self.setLayout(self.layout) def load_data_directory(self): d = QFileDialog.getExistingDirectory(self, "Select Directory") self.data_dir = d self.loaded_directory_label.setText(self.data_dir) # Load all encountered files files = [] allowed_extensions = ["jpg", "jpeg", "png"] for ext in allowed_extensions: files.extend(glob.glob(os.path.join(d, "*." + ext))) # Add them all into the file list. for file in files: self.add_file_entry(self.dataView.model(), file) return d def create_file_list_model(self, parent): model = QStandardItemModel(0, 2, parent) model.setHeaderData(self.FILENAME, Qt.Horizontal, "Filename") model.setHeaderData(self.PATH, Qt.Horizontal, "Path") return model def add_file_entry(self, model, path): filename = os.path.basename(path) model.insertRow(0) model.setData(model.index(0, self.FILENAME), filename) model.setData(model.index(0, self.PATH), path)
def main(args): app = QApplication (args) view = QTreeView() view.setModel(StorageModel(view)) view.resize(640, 480) view.setSelectionBehavior(QAbstractItemView.SelectRows) for column in range(view.model().columnCount()): view.resizeColumnToContents(column) view.show() return app.exec_()
class StandardLibraryPage(QSplitter): """ The GUI for the standard library page of a project. """ # The page's label. label = "Standard Library" @property def project(self): """ The project property getter. """ return self._project @project.setter def project(self, value): """ The project property setter. """ if self._project != value: self._project = value self._update_page() def __init__(self): """ Initialise the page. """ super().__init__() self._project = None # Create the page's GUI. stdlib_pane = QWidget() stdlib_layout = QVBoxLayout() self._stdlib_edit = QTreeWidget( whatsThis="This shows the packages and modules in the target " "Python version's standard library. Check those " "packages and modules that are explicitly imported by " "the application. A module will be partially checked " "(and automatically included) if another module " "requires it.") self._stdlib_edit.setHeaderLabels(["Package"]) self._stdlib_edit.itemChanged.connect(self._module_changed) stdlib_layout.addWidget(self._stdlib_edit) stdlib_pane.setLayout(stdlib_layout) self.addWidget(stdlib_pane) extlib_pane = QWidget() extlib_layout = QVBoxLayout() extlib_sublayout = QFormLayout() self._version_edit = QComboBox( whatsThis="Select the target Python version. This will cause " "the standard library package hierarchy to be " "updated.") self._version_edit.addItems(get_supported_python_versions()) self._version_edit.currentIndexChanged.connect(self._version_changed) extlib_sublayout.addRow("Target Python version", self._version_edit) self._ssl_edit = QCheckBox( whatsThis="Enable SSL for the standard library modules " "that have optional support for it.", stateChanged=self._ssl_changed) extlib_sublayout.addRow("Enable optional SSL support", self._ssl_edit) extlib_layout.addLayout(extlib_sublayout) plat_gb = QGroupBox("Use standard Python shared library") plat_gb_layout = QVBoxLayout() self._platform_buttons = [] for scope, plat, subscopes in PLATFORM_SCOPES: plat_cb = QCheckBox(plat, whatsThis="Enable the use of the standard Python shared " "library on {0} rather than a statically compiled " "library.".format(plat), stateChanged=self._platforms_changed) plat_cb._scope = scope plat_gb_layout.addWidget(plat_cb) self._platform_buttons.append(plat_cb) plat_gb.setLayout(plat_gb_layout) extlib_layout.addWidget(plat_gb) self._extlib_edit = QTreeView( whatsThis="This is the list of external libraries that must " "be linked with the application. A library will only " "be enabled if a module in the standard library uses " "it. Double-click in the <b>DEFINES</b>, " "<b>INCLUDEPATH</b> and <b>LIBS</b> columns to modify " "the corresponding <tt>qmake</tt> variable as " "required. Values may be prefixed by a platform " "specific <tt>qmake</tt> scope.") self._extlib_edit.setRootIsDecorated(False) self._extlib_edit.setEditTriggers( QTreeView.DoubleClicked|QTreeView.SelectedClicked| QTreeView.EditKeyPressed) model = QStandardItemModel(self._extlib_edit) model.setHorizontalHeaderLabels( ("External Library", 'DEFINES', 'INCLUDEPATH', 'LIBS')) model.itemChanged.connect(self._extlib_changed) for extlib in external_libraries_metadata: name_itm = QStandardItem(extlib.user_name) extlib._items = (name_itm, QStandardItem(), QStandardItem(), QStandardItem()) model.appendRow(extlib._items) self._extlib_edit.setModel(model) for col in range(3): self._extlib_edit.resizeColumnToContents(col) extlib_layout.addWidget(self._extlib_edit) self._ignore_extlib_changes = False extlib_pane.setLayout(extlib_layout) self.addWidget(extlib_pane) def _update_page(self): """ Update the page using the current project. """ project = self.project blocked = self._version_edit.blockSignals(True) self._version_edit.setCurrentIndex( get_supported_python_version_index( project.python_target_version)) self._version_edit.blockSignals(blocked) blocked = self._ssl_edit.blockSignals(True) self._ssl_edit.setCheckState( Qt.Checked if project.python_ssl else Qt.Unchecked) self._ssl_edit.blockSignals(blocked) for plat in self._platform_buttons: blocked = plat.blockSignals(True) plat.setCheckState( Qt.Checked if plat._scope in project.python_use_platform else Qt.Unchecked) plat.blockSignals(blocked) self._update_extlib_editor() self._update_stdlib_editor() def _update_stdlib_editor(self): """ Update the standard library module editor. """ project = self.project editor = self._stdlib_edit metadata = get_python_metadata(project.python_target_version) blocked = editor.blockSignals(True) editor.clear() def add_module(name, module, parent): itm = QTreeWidgetItem(parent, name.split('.')[-1:]) itm.setFlags(Qt.ItemIsEnabled|Qt.ItemIsUserCheckable) itm._name = name # Handle any sub-modules. if module.modules is not None: for submodule_name in module.modules: # We assume that a missing sub-module is because it is not # in the current version rather than bad meta-data. submodule = metadata.get(submodule_name) if submodule is not None: add_module(submodule_name, submodule, itm) for name, module in metadata.items(): if not module.internal and '.' not in name: add_module(name, module, editor) editor.sortItems(0, Qt.AscendingOrder) editor.blockSignals(blocked) self._set_dependencies() def _set_dependencies(self): """ Set the dependency information. """ project = self.project editor = self._stdlib_edit required_modules, required_libraries = project.get_stdlib_requirements() blocked = editor.blockSignals(True) it = QTreeWidgetItemIterator(editor) itm = it.value() while itm is not None: external = required_modules.get(itm._name) expanded = False if external is None: state = Qt.Unchecked elif external: state = Qt.Checked expanded = True else: state = Qt.PartiallyChecked itm.setCheckState(0, state) # Make sure every explicitly checked item is visible. if expanded: parent = itm.parent() while parent is not None: parent.setExpanded(True) parent = parent.parent() it += 1 itm = it.value() editor.blockSignals(blocked) model = self._extlib_edit.model() # Note that we can't simply block the model's signals as this would # interfere with the model/view interactions. self._ignore_extlib_changes = True for extlib in external_libraries_metadata: if extlib.name in required_libraries: for idx, itm in enumerate(extlib._items): itm.setFlags( Qt.ItemIsEnabled|Qt.ItemIsEditable if idx != 0 else Qt.ItemIsEnabled) else: for itm in extlib._items: itm.setFlags(Qt.NoItemFlags) self._ignore_extlib_changes = False def _update_extlib_editor(self): """ Update the external library editor. """ project = self.project model = self._extlib_edit.model() blocked = model.blockSignals(True) for extlib in external_libraries_metadata: _, defs, incp, libs = extlib._items for prj_extlib in project.external_libraries: if prj_extlib.name == extlib.name: defs.setText(prj_extlib.defines) incp.setText(prj_extlib.includepath) libs.setText(prj_extlib.libs) break else: defs.setText('') incp.setText('') libs.setText(extlib.libs) model.blockSignals(blocked) def _version_changed(self, idx): """ Invoked when the target Python version changes. """ project = self.project project.python_target_version = get_supported_python_version(idx) self._update_page() project.modified = True def _ssl_changed(self, state): """ Invoked when the SSL support changes. """ project = self.project project.python_ssl = (state == Qt.Checked) self._set_dependencies() project.modified = True def _platforms_changed(self, state): """ Invoked when the platforms change. """ project = self._project project.python_use_platform = [] for plat in self._platform_buttons: if plat.checkState() == Qt.Checked: project.python_use_platform.append(plat._scope) project.modified = True def _module_changed(self, itm, col): """ Invoked when a standard library module has changed. """ project = self._project name = itm._name if name in project.standard_library: project.standard_library.remove(name) else: project.standard_library.append(name) self._set_dependencies() project.modified = True def _extlib_changed(self, itm): """ Invoked when an external library has changed. """ if self._ignore_extlib_changes: return self._ignore_extlib_changes = True project = self.project idx = self._extlib_edit.model().indexFromItem(itm) extlib = external_libraries_metadata[idx.row()] col = idx.column() # Get the project entry, creating it if necessary. for prj_extlib in project.external_libraries: if prj_extlib.name == extlib.name: break else: prj_extlib = ExternalLibrary(extlib.name, '', '', extlib.libs) project.external_libraries.append(prj_extlib) # Update the project. text = itm.text().strip() if col == 1: prj_extlib.defines = text elif col == 2: prj_extlib.includepath = text elif col == 3: if text == '': text = extlib.libs itm.setText(text) prj_extlib.libs = text # If the project entry corresponds to the default then remove it. if prj_extlib.defines == '' and prj_extlib.includepath == '' and prj_extlib.libs == extlib.libs: project.external_libraries.remove(prj_extlib) project.modified = True self._ignore_extlib_changes = False
class Installed(preferences.Group): """Overview of installed extensions. A QTreeView lists the metadata of all installed extensions. If the currently selected extension provides a configuration widget it is displayed in the bottom group of the page. With a checkbox individual extensions can be deactivated. Metadata is listed for all *installed* extensions, regardless of manual deactivation or load failure. """ def __init__(self, page): super(Installed, self).__init__(page) layout = QVBoxLayout() self.setLayout(layout) # This must be called before self.populate() because # the data model relies on the labels app.translateUI(self) self.tree = QTreeView() self.name_items = {} self._selected_extension = '' self.tree.setModel(QStandardItemModel()) self.tree.model().setColumnCount(2) self.tree.setSelectionBehavior(QAbstractItemView.SelectRows) self.tree.setEditTriggers(QAbstractItemView.NoEditTriggers) self.tree.setHeaderHidden(True) self.tree.header().setSectionResizeMode( 0, QHeaderView.ResizeToContents) self.tree.selectionModel().selectionChanged.connect( self.selection_changed) self.populate() layout.addWidget(self.tree) def translateUI(self): self.setTitle(_("Installed Extensions")) self.config_labels = { 'extension-name': _("Name"), 'maintainers': _("Maintainer(s)"), 'version': _("Version"), 'api-version': _("API version"), 'license': _("License"), 'short-description': _("Short Description"), 'description': _("Description"), 'repository': _("Repository"), 'website': _("Website"), 'dependencies': _("Dependencies") } def loadSettings(self): s = QSettings() self.setEnabled(self.page().active()) s.beginGroup("extension-settings/installed") inactive = s.value("inactive", [], list) for ext in self.name_items.keys(): self.name_items[ext].setCheckState( Qt.Checked if ext not in inactive else Qt.Unchecked) self.tree.model().dataChanged.connect(self.page().changed) def saveSettings(self): s = QSettings() s.beginGroup("extension-settings/installed") inactive = [ext for ext in self.name_items.keys() if self.name_items[ext].checkState() == Qt.Unchecked] s.setValue("inactive", inactive) def populate(self): """Populate the tree view with data from the installed extensions. """ # TODO/Question: # Would it make sense to move this to a dedicated model class # complementing the FailedModel? root = self.tree.model().invisibleRootItem() extensions = app.extensions() for ext in extensions.installed_extensions(): ext_infos = extensions.infos(ext) display_name = ext_infos.get(ext, ext) if ext_infos else ext.name() loaded_extension = extensions.get(ext) if loaded_extension: display_name += ' ({})'.format(loaded_extension.load_time()) name_item = QStandardItem(display_name) name_item.extension_name = ext name_item.setCheckable(True) self.name_items[ext] = name_item icon = extensions.icon(ext) if icon: name_item.setIcon(icon) root.appendRow([name_item]) for entry in [ 'extension-name', 'short-description', 'description', 'version', 'api-version', 'dependencies', 'maintainers', 'repository', 'website', 'license' ]: label_item = QStandardItem('{}:'.format( self.config_labels[entry])) label_item.setTextAlignment(Qt.AlignTop) bold = QFont() bold.setWeight(QFont.Bold) label_item.setFont(bold) details = ext_infos.get(entry, "") if ext_infos else "" if type(details) == list: details = '\n'.join(details) details_item = QStandardItem(details) details_item.setTextAlignment(Qt.AlignTop) if entry == 'api-version': # Check for correct(ly formatted) api-version entry # and highlight it in case of mismatch api_version = appinfo.extension_api if not details: details_item.setFont(bold) details_item.setText( _("Misformat: {api}").format(details)) elif not details == api_version: details_item.setFont(bold) details_item.setText('{} ({}: {})'.format( details, appinfo.appname, api_version)) name_item.appendRow([label_item, details_item]) def selected_extension(self): """Return the (directory) name of the extension that is currently selected.""" return self._selected_extension def selection_changed(self, new, old): """Show the configuration widget for the selected extension, if available.""" config = self.siblingGroup(Config) if new.indexes(): ext_item = self.tree.model().itemFromIndex(new.indexes()[0]) # NOTE: This may have to be changed if there should be # more complexity in the tree model than now (a selected # row is either a top-level row or its immediate child) if not hasattr(ext_item, 'extension_name'): ext_item = ext_item.parent() name = ext_item.extension_name if name == self.selected_extension(): return else: # If nothing is selected, show the "empty" widget name = "" config.hide_extension() self._selected_extension = name config.show_extension(name)
class bands_pairing2(QWidget): def __init__(self, dataview): super().__init__() """a tree widget to create a list of datasets and select bands from each dataset""" self.dataview = dataview self.firstband = QTreeView() self.secondband = QTreeView() self.firstband.setModel(self.dataview.model) self.secondband.setModel(self.dataview.model) self.pairs = treewidget() self.pairs.setColumnCount(2) self.pairs.setHeaderLabels(['first band', 'second band']) self.pairbutton = QPushButton('Pair') self.pairbutton.clicked.connect(self.add_pair) mainlayout = QVBoxLayout() sublayout = QHBoxLayout() sublayout.addWidget(self.firstband) sublayout.addWidget(self.secondband) firstsecondgroup = QGroupBox() firstsecondgroup.setLayout(sublayout) mainlayout.addWidget(firstsecondgroup) mainlayout.addWidget(self.pairbutton) mainlayout.addWidget(self.pairs) self.maingroup = QGroupBox() self.maingroup.setLayout(mainlayout) def additems(self): """when the widget is activated, a list of selected bands will be added""" dict = self.dataview.collect_user_input() for i in dict['bandsdict'].keys(): name = os.path.basename(i) for j in dict['bandsdict'][name].keys(): band = QListWidgetItem(j) band2 = QListWidgetItem(j) self.firstband.addItem(band) self.secondband.addItem(band2) def add_pair(self): """when pair button is pressed the paire will be add to the list""" # get selected index firstitem = self.firstband.selectedIndexes() # item text (example:band1) firstitemtext = self.firstband.model().itemData(firstitem[0])[0] # parent text (example: rastername.tif) firstparent = self.firstband.model().itemFromIndex(firstitem[0]).parent().data(0) #text to appear on the pairing widget firstpairtext = os.path.basename(firstparent) + ' - ' + firstitemtext # get selected index seconditem = self.secondband.selectedIndexes() # item text (example:band1) seconditemtext = self.secondband.model().itemData(seconditem[0])[0] # parent text (example: rastername.tif) secondparent = self.firstband.model().itemFromIndex(firstitem[0]).parent().data(0) # text to appear on the pairing widget secondpairtext = os.path.basename(secondparent) + ' - ' + seconditemtext print(firstitemtext) print(os.path.basename(firstparent)) pairitem = QTreeWidgetItem() pairitem.setText(0, firstpairtext) pairitem.setText(1, secondpairtext) self.pairs.addTopLevelItem(pairitem) #self.get_pairs() def get_pairs(self): """returns 1. a dictionary of selected bands created with the datatreeview widget, 2. a list of featurebands, 3. a list of texts from the items in the widgets (dataset and band number) """ bandsdict = self.dataview.collectinput()[0] print (bandsdict) datasets = self.dataview.collectinput()[1] selectedbands = self.dataview.collectinput()[2] print(selectedbands) featurebands = [] feturebandstext = [] for i in range(self.pairs.topLevelItemCount()): item = self.pairs.topLevelItem(i) item1text = item.text(0) item2text = item.text(1) # get the list of the items from the widget feturebandstext += [[item1text, item2text]] band1 = bandsdict[item1text] band2 = bandsdict[item2text] # get the pair of bands by indexes pair = [selectedbands.index(band1), selectedbands.index(band2)] featurebands += [pair] print(selectedbands) print(featurebands) return [selectedbands, featurebands,feturebandstext]
class Widget(QWidget): def __init__(self, panel): super(Widget, self).__init__(panel) layout = QVBoxLayout() self.setLayout(layout) layout.setSpacing(0) self.searchEntry = SearchLineEdit() self.treeView = QTreeView(contextMenuPolicy=Qt.CustomContextMenu) self.textView = QTextBrowser() applyButton = QToolButton(autoRaise=True) editButton = QToolButton(autoRaise=True) addButton = QToolButton(autoRaise=True) self.menuButton = QPushButton(flat=True) menu = QMenu(self.menuButton) self.menuButton.setMenu(menu) splitter = QSplitter(Qt.Vertical) top = QHBoxLayout() layout.addLayout(top) splitter.addWidget(self.treeView) splitter.addWidget(self.textView) layout.addWidget(splitter) splitter.setSizes([200, 100]) splitter.setCollapsible(0, False) top.addWidget(self.searchEntry) top.addWidget(applyButton) top.addSpacing(10) top.addWidget(addButton) top.addWidget(editButton) top.addWidget(self.menuButton) # action generator for actions added to search entry def act(slot, icon=None): a = QAction(self, triggered=slot) self.addAction(a) a.setShortcutContext(Qt.WidgetWithChildrenShortcut) icon and a.setIcon(icons.get(icon)) return a # hide if ESC pressed in lineedit a = act(self.slotEscapePressed) a.setShortcut(QKeySequence(Qt.Key_Escape)) # import action a = self.importAction = act(self.slotImport, 'document-open') menu.addAction(a) # export action a = self.exportAction = act(self.slotExport, 'document-save-as') menu.addAction(a) # apply button a = self.applyAction = act(self.slotApply, 'edit-paste') applyButton.setDefaultAction(a) menu.addSeparator() menu.addAction(a) # add button a = self.addAction_ = act(self.slotAdd, 'list-add') a.setShortcut(QKeySequence(Qt.Key_Insert)) addButton.setDefaultAction(a) menu.addSeparator() menu.addAction(a) # edit button a = self.editAction = act(self.slotEdit, 'document-edit') a.setShortcut(QKeySequence(Qt.Key_F2)) editButton.setDefaultAction(a) menu.addAction(a) # set shortcut action a = self.shortcutAction = act( self.slotShortcut, 'preferences-desktop-keyboard-shortcuts') menu.addAction(a) # delete action a = self.deleteAction = act(self.slotDelete, 'list-remove') a.setShortcut(QKeySequence(Qt.CTRL + Qt.Key_Delete)) menu.addAction(a) # restore action a = self.restoreAction = act(self.slotRestore) menu.addSeparator() menu.addAction(a) # help button a = self.helpAction = act(self.slotHelp, 'help-contents') menu.addSeparator() menu.addAction(a) self.treeView.setSelectionBehavior(QTreeView.SelectRows) self.treeView.setSelectionMode(QTreeView.ExtendedSelection) self.treeView.setRootIsDecorated(False) self.treeView.setAllColumnsShowFocus(True) self.treeView.setModel(model.model()) self.treeView.setCurrentIndex(QModelIndex()) # signals self.searchEntry.returnPressed.connect(self.slotReturnPressed) self.searchEntry.textChanged.connect(self.updateFilter) self.treeView.doubleClicked.connect(self.slotDoubleClicked) self.treeView.customContextMenuRequested.connect(self.showContextMenu) self.treeView.selectionModel().currentChanged.connect(self.updateText) self.treeView.model().dataChanged.connect(self.updateFilter) # highlight text self.highlighter = highlight.Highlighter(self.textView.document()) # complete on snippet variables self.searchEntry.setCompleter( QCompleter([ ':icon', ':indent', ':menu', ':name', ':python', ':selection', ':set', ':symbol', ':template', ':template-run' ], self.searchEntry)) self.readSettings() app.settingsChanged.connect(self.readSettings) app.translateUI(self) self.updateColumnSizes() self.setAcceptDrops(True) def dropEvent(self, ev): if not ev.source() and ev.mimeData().hasUrls(): filename = ev.mimeData().urls()[0].toLocalFile() if filename: ev.accept() from . import import_export import_export.load(filename, self) def dragEnterEvent(self, ev): if not ev.source() and ev.mimeData().hasUrls(): ev.accept() def translateUI(self): try: self.searchEntry.setPlaceholderText(_("Search...")) except AttributeError: pass # not in Qt 4.6 shortcut = lambda a: a.shortcut().toString(QKeySequence.NativeText) self.menuButton.setText(_("&Menu")) self.addAction_.setText(_("&Add...")) self.addAction_.setToolTip( _("Add a new snippet. ({key})").format( key=shortcut(self.addAction_))) self.editAction.setText(_("&Edit...")) self.editAction.setToolTip( _("Edit the current snippet. ({key})").format( key=shortcut(self.editAction))) self.shortcutAction.setText(_("Configure Keyboard &Shortcut...")) self.deleteAction.setText(_("&Remove")) self.deleteAction.setToolTip(_("Remove the selected snippets.")) self.applyAction.setText(_("A&pply")) self.applyAction.setToolTip(_("Apply the current snippet.")) self.importAction.setText(_("&Import...")) self.importAction.setToolTip(_("Import snippets from a file.")) self.exportAction.setText(_("E&xport...")) self.exportAction.setToolTip(_("Export snippets to a file.")) self.restoreAction.setText(_("Restore &Built-in Snippets...")) self.restoreAction.setToolTip( _("Restore deleted or changed built-in snippets.")) self.helpAction.setText(_("&Help")) self.searchEntry.setToolTip( _("Enter text to search in the snippets list.\n" "See \"What's This\" for more information.")) self.searchEntry.setWhatsThis(''.join( map("<p>{0}</p>\n".format, ( _("Enter text to search in the snippets list, and " "press Enter to apply the currently selected snippet."), _("If the search text fully matches the value of the '{name}' variable " "of a snippet, that snippet is selected.").format( name="name"), _("If the search text starts with a colon ':', the rest of the " "search text filters snippets that define the given variable. " "After a space a value can also be entered, snippets will then " "match if the value of the given variable contains the text after " "the space."), _("E.g. entering {menu} will show all snippets that are displayed " "in the insert menu.").format(menu="<code>:menu</code>"), )))) def sizeHint(self): return self.parent().mainwindow().size() / 4 def readSettings(self): data = textformats.formatData('editor') self.textView.setFont(data.font) self.textView.setPalette(data.palette()) def showContextMenu(self, pos): """Called when the user right-clicks the tree view.""" self.menuButton.menu().popup(self.treeView.viewport().mapToGlobal(pos)) def slotReturnPressed(self): """Called when the user presses Return in the search entry. Applies current snippet.""" name = self.currentSnippet() if name: view = self.parent().mainwindow().currentView() insert.insert(name, view) self.parent().hide() # make configurable? view.setFocus() def slotEscapePressed(self): """Called when the user presses ESC in the search entry. Hides the panel.""" self.parent().hide() self.parent().mainwindow().currentView().setFocus() def slotDoubleClicked(self, index): name = self.treeView.model().name(index) view = self.parent().mainwindow().currentView() insert.insert(name, view) def slotAdd(self): """Called when the user wants to add a new snippet.""" edit.Edit(self, None) def slotEdit(self): """Called when the user wants to edit a snippet.""" name = self.currentSnippet() if name: edit.Edit(self, name) def slotShortcut(self): """Called when the user selects the Configure Shortcut action.""" from widgets import shortcuteditdialog name = self.currentSnippet() if name: collection = self.parent().snippetActions action = actions.action(name, None, collection) default = collection.defaults().get(name) mgr = actioncollectionmanager.manager(self.parent().mainwindow()) cb = mgr.findShortcutConflict dlg = shortcuteditdialog.ShortcutEditDialog( self, cb, (collection, name)) if dlg.editAction(action, default): mgr.removeShortcuts(action.shortcuts()) collection.setShortcuts(name, action.shortcuts()) self.treeView.update() def slotDelete(self): """Called when the user wants to delete the selected rows.""" rows = sorted(set(i.row() for i in self.treeView.selectedIndexes()), reverse=True) if rows: for row in rows: name = self.treeView.model().names()[row] self.parent().snippetActions.setShortcuts(name, []) self.treeView.model().removeRow(row) self.updateFilter() def slotApply(self): """Called when the user clicks the apply button. Applies current snippet.""" name = self.currentSnippet() if name: view = self.parent().mainwindow().currentView() insert.insert(name, view) def slotImport(self): """Called when the user activates the import action.""" filetypes = "{0} (*.xml);;{1} (*)".format(_("XML Files"), _("All Files")) caption = app.caption(_("dialog title", "Import Snippets")) filename = None filename = QFileDialog.getOpenFileName(self, caption, filename, filetypes)[0] if filename: from . import import_export import_export.load(filename, self) def slotExport(self): """Called when the user activates the export action.""" allrows = [ row for row in range(model.model().rowCount()) if not self.treeView.isRowHidden(row, QModelIndex()) ] selectedrows = [ i.row() for i in self.treeView.selectedIndexes() if i.column() == 0 and i.row() in allrows ] names = self.treeView.model().names() names = [names[row] for row in selectedrows or allrows] filetypes = "{0} (*.xml);;{1} (*)".format(_("XML Files"), _("All Files")) n = len(names) caption = app.caption( _("dialog title", "Export {num} Snippet", "Export {num} Snippets", n).format(num=n)) filename = QFileDialog.getSaveFileName(self, caption, None, filetypes)[0] if filename: from . import import_export try: import_export.save(names, filename) except (IOError, OSError) as e: QMessageBox.critical( self, _("Error"), _("Can't write to destination:\n\n{url}\n\n{error}"). format(url=filename, error=e.strerror)) def slotRestore(self): """Called when the user activates the Restore action.""" from . import restore dlg = restore.RestoreDialog(self) dlg.setWindowModality(Qt.WindowModal) dlg.populate() dlg.show() dlg.finished.connect(dlg.deleteLater) def slotHelp(self): """Called when the user clicks the small help button.""" userguide.show("snippets") def currentSnippet(self): """Returns the name of the current snippet if it is visible.""" row = self.treeView.currentIndex().row() if row != -1 and not self.treeView.isRowHidden(row, QModelIndex()): return self.treeView.model().names()[row] def updateFilter(self): """Called when the text in the entry changes, updates search results.""" text = self.searchEntry.text() ltext = text.lower() filterVars = text.startswith(':') if filterVars: try: fvar, fval = text[1:].split(None, 1) fhide = lambda v: v.get(fvar) in (True, None ) or fval not in v.get(fvar) except ValueError: fvar = text[1:].strip() fhide = lambda v: not v.get(fvar) for row in range(self.treeView.model().rowCount()): name = self.treeView.model().names()[row] nameid = snippets.get(name).variables.get('name', '') if filterVars: hide = fhide(snippets.get(name).variables) elif nameid == text: i = self.treeView.model().createIndex(row, 0) self.treeView.selectionModel().setCurrentIndex( i, QItemSelectionModel.SelectCurrent | QItemSelectionModel.Rows) hide = False elif nameid.lower().startswith(ltext): hide = False elif ltext in snippets.title(name).lower(): hide = False else: hide = True self.treeView.setRowHidden(row, QModelIndex(), hide) self.updateText() def updateText(self): """Called when the current snippet changes.""" name = self.currentSnippet() self.textView.clear() if name: s = snippets.get(name) self.highlighter.setPython('python' in s.variables) self.textView.setPlainText(s.text) def updateColumnSizes(self): self.treeView.resizeColumnToContents(0) self.treeView.resizeColumnToContents(1)
class MainWindow(QMainWindow): def __init__(self): super().__init__() self.setWindowTitle("Untitled") icon = os.path.join(BASE_DIR, 'ide/Icon.ico') self.setWindowIcon(QIcon(icon)) self.saveLoad = SaveLoad() self.fileName = None self.setupUI() def setupUI(self): centralWidget = QWidget(self) layout = QHBoxLayout(centralWidget) self.fileSysView = QTreeView(centralWidget) self.setupFileSystemViewer() self.editor = QsciScintilla(centralWidget) self.setupEditor() layout.addWidget(self.fileSysView, 1) layout.addWidget(self.editor, 3) self.setCentralWidget(centralWidget) self.setMinimumSize(700, 500) self.defaultMenuBar = QMenuBar(self) self.setupMenus() self.setMenuBar(self.defaultMenuBar) self.show() def setupEditor(self): self.editor.setFont(QFont("Times New Roman", 12)) self.editor.setMargins(2) self.editor.setMarginType(0, QsciScintilla.NumberMargin) self.editor.setMarginType(1, QsciScintilla.SymbolMargin) self.editor.setMarginWidth(0, "000") self.editor.setMarginWidth(1, "00") self.editor.markerDefine(QsciScintilla.RightTriangle, 1) if system() == "Windows": self.editor.setEolMode(QsciScintilla.EolWindows) elif system() == "Linux": self.editor.setEolMode(QsciScintilla.EolUnix) elif system() == "Mac": self.editor.setEolMode(QsciScintilla.EolMac) else: print("Using Windows EOL") self.editor.setEolMode(QsciScintilla.EolWindows) self.editor.setBraceMatching(QsciScintilla.SloppyBraceMatch) self.editor.setIndentationsUseTabs(True) self.editor.setTabWidth(4) self.editor.setIndentationGuides(True) self.editor.setTabIndents(True) self.editor.setAutoIndent(True) self.editor.setCaretForegroundColor(QColor("#ff11214b")) self.editor.setCaretLineVisible(True) self.editor.setCaretLineBackgroundColor(QColor("#1f0000ff")) self.editor.setUtf8(True) self.editor.setMarginSensitivity(1, True) self.editor.marginClicked.connect(self.margin_clicked) self.editor.marginRightClicked.connect(self.margin_right_clicked) self.lexer = QsciLexerPython() self.lexer.setFont(QFont("Times New Roman", 12)) self.editor.setLexer(self.lexer) self.editor.textChanged.connect(self.fileChanged) def setupFileSystemViewer(self): model = QFileSystemModel() model.setRootPath("/") self.fileSysView.setModel(model) self.fileSysView.hideColumn(1) self.fileSysView.hideColumn(2) self.fileSysView.hideColumn(3) self.fileSysView.doubleClicked.connect(self.openFile) def setupMenus(self): fileMenu = QMenu(self.defaultMenuBar) fileMenu.setTitle("File") editMenu = QMenu(self.defaultMenuBar) editMenu.setTitle("Edit") viewMenu = QMenu(self.defaultMenuBar) viewMenu.setTitle("View") runMenu = QMenu(self.defaultMenuBar) runMenu.setTitle("Run") settingsMenu = QMenu(self.defaultMenuBar) settingsMenu.setTitle("Settings") self.actionNew = QAction(self) self.actionNew.setText("New") self.actionNew.setShortcut("Ctrl+N") self.actionOpen = QAction(self) self.actionOpen.setText("Open") self.actionOpen.setShortcut("Ctrl+O") self.actionSave = QAction(self) self.actionSave.setText("Save") self.actionSave.setShortcut("Ctrl+S") self.actionSaveAs = QAction(self) self.actionSaveAs.setText("Save As") self.actionSaveAs.setShortcut("Ctrl+Shift+S") self.actionExit = QAction(self) self.actionExit.setText("Exit") self.actionExit.setShortcut("Alt+X") self.actionUndo = QAction(self) self.actionUndo.setText("Undo") self.actionUndo.setShortcut("Ctrl+Z") self.actionRedo = QAction(self) self.actionRedo.setText("Redo") self.actionRedo.setShortcut("Ctrl+Shift+Z") self.actionSelectAll = QAction(self) self.actionSelectAll.setText("Select all") self.actionSelectAll.setShortcut("Ctrl+A") self.actionCut = QAction(self) self.actionCut.setText("Cut") self.actionCut.setShortcut("Ctrl+X") self.actionCopy = QAction(self) self.actionCopy.setText("Copy") self.actionCopy.setShortcut("Ctrl+C") self.actionPaste = QAction(self) self.actionPaste.setText("Paste") self.actionPaste.setShortcut("Ctrl+V") self.actionFind = QAction(self) self.actionFind.setText("Find") self.actionFind.setShortcut("Ctrl+F") self.actionReplace = QAction(self) self.actionReplace.setText("Replace") self.actionReplace.setShortcut("Ctrl+H") self.actionRun = QAction(self) self.actionRun.setText("Run") self.actionRun.setShortcut("F5") self.actionRunCustom = QAction(self) self.actionRunCustom.setText("Run Customized") self.actionRunCustom.setShortcut("Shift+F5") self.actionShell = QAction(self) self.actionShell.setText("Python shell") self.actionShell.setShortcut("Alt+S") self.actionFont = QAction(self) self.actionFont.setText("Font") self.actionEncoding = QAction(self) self.actionEncoding.setText("Encoding") fileMenu.addAction(self.actionNew) fileMenu.addAction(self.actionOpen) fileMenu.addAction(self.actionSave) fileMenu.addAction(self.actionSaveAs) fileMenu.addSeparator() fileMenu.addAction(self.actionExit) editMenu.addAction(self.actionUndo) editMenu.addAction(self.actionRedo) editMenu.addSeparator() editMenu.addAction(self.actionSelectAll) editMenu.addSeparator() editMenu.addAction(self.actionCut) editMenu.addAction(self.actionCopy) editMenu.addAction(self.actionPaste) viewMenu.addAction(self.actionFind) viewMenu.addAction(self.actionReplace) runMenu.addAction(self.actionRun) runMenu.addAction(self.actionRunCustom) runMenu.addAction(self.actionShell) settingsMenu.addAction(self.actionFont) settingsMenu.addAction(self.actionEncoding) self.defaultMenuBar.addAction(fileMenu.menuAction()) self.defaultMenuBar.addAction(editMenu.menuAction()) self.defaultMenuBar.addAction(viewMenu.menuAction()) self.defaultMenuBar.addAction(runMenu.menuAction()) self.defaultMenuBar.addAction(settingsMenu.menuAction()) self.actionNew.triggered.connect(self.new) self.actionOpen.triggered.connect(self.open) self.actionSave.triggered.connect(self.save) self.actionSaveAs.triggered.connect(self.saveAs) self.actionExit.triggered.connect(self.close) self.actionUndo.triggered.connect(self.editor.undo) self.actionRedo.triggered.connect(self.editor.redo) self.actionSelectAll.triggered.connect( lambda: self.editor.selectAll(True)) self.actionCut.triggered.connect(self.editor.cut) self.actionCopy.triggered.connect(self.editor.copy) self.actionPaste.triggered.connect(self.editor.paste) self.actionFind.triggered.connect(self.find) self.actionReplace.triggered.connect(self.replace) self.actionRun.triggered.connect(self.run) self.actionRunCustom.triggered.connect(self.runCustom) self.actionShell.triggered.connect(self.shell) self.actionFont.triggered.connect(self.Font) def margin_clicked(self, margin_nr, line_nr, state): self.editor.markerAdd(line_nr, margin_nr) def margin_right_clicked(self, margin_nr, line_nr, state): self.editor.markerDelete(line_nr, margin_nr) def new(self): if self.windowTitle().endswith("*"): if (Dialogs().Question( self, "Do you want to save your file?") == "accept"): if self.filename is None: self.saveAs() else: self.save() self.editor.setText("") self.setWindowTitle("Untitled") def open(self): if self.windowTitle().endswith("*"): if (Dialogs().Question( self, "Do you want to save your file?") == "accept"): if self.filename is None: self.saveAs() else: self.save() filename = self.saveLoad.OpenDialog() data = Open(filename) if data is not None: self.editor.setText(data) self.setWindowTitle(filename) self.filename = filename def save(self): if self.filename is None: self.saveAs() else: returnval = Save(self.editor.text(), self.filename) if (returnval): Dialogs().Message(self, "File saved successfully") self.setWindowTitle(self.filename) else: Dialogs().Error(self, "File could not be saved") def saveAs(self): self.filename = self.saveLoad.SaveDialog() returnval = Save(self.editor.text(), self.filename) if (returnval): Dialogs().Message(self, "File saved successfully") self.setWindowTitle(self.filename) else: Dialogs().Error(self, "File could not be saved") def run(self): if self.filename is None: self.saveAs() Runfile(self.filename) def runCustom(self): if self.filename is None: self.saveAs() if self.filename != "": print(len(self.filename)) option, ok = QInputDialog().getText( self, "Customized run", "Enter parameters for sys.argv", QLineEdit.Normal, " ") if ok: Runfile(self.filename, option) def shell(self): Shell() def Font(self): font, ok = QFontDialog.getFont() if ok: self.editor.setFont(font) self.lexer.setFont(font) self.editor.setLexer(self.lexer) def openFile(self, signal): fileName = self.fileSysView.model().filePath(signal) if fileName.endswith("py") or fileName.endswith("pyw"): if self.windowTitle().endswith("*"): if Dialogs().Question( self, "Do you want to save your file?") == "accept": if self.filename is None: self.saveAs() else: self.save() data = Open(fileName) if data is not None: self.editor.setText(data) self.setWindowTitle(fileName) self.filename = fileName def fileChanged(self): title = self.windowTitle() if not (title.endswith("*")): self.setWindowTitle(title + " *") def replace(self): replaceObj = replaceDialog(self, self.editor) def find(self): findObj = findDialog(self, self.editor)
class LogInspectorWindow(QMainWindow): def __init__(self, configFilePath, parent=None): super(LogInspectorWindow, self).__init__(parent) self.initMatPlotLib() self.configFilePath = configFilePath folder = os.path.dirname(self.configFilePath) if not os.path.exists(folder): os.makedirs(folder) if os.path.exists(self.configFilePath): # config.yaml found. Read from file. file = open(self.configFilePath, 'r') self.config = yaml.safe_load(file) file.close() else: # config.yaml not found. Create new file. self.config = {} self.config['logs_directory'] = os.path.join( os.path.expanduser("~"), "Documents", "Inertial_Sense", "Logs") self.config['directory'] = "" self.config['serials'] = ["ALL"] file = open(self.configFilePath, 'w') yaml.dump(self.config, file) file.close() self.currently_selected = 'posNEDMap' self.downsample = 5 self.plotargs = None self.log = None self.plotter = None def initMatPlotLib(self): self.figure = plt.figure() self.canvas = FigureCanvas(self.figure) self.toolbar = NavigationToolbar(self.canvas, self) self.figure.subplots_adjust(left=0.05, right=0.99, bottom=0.05, top=0.91, wspace=0.2, hspace=0.2) def addButton(self, name, function, multithreaded=True, layout=None): setattr(self, name + "button", QPushButton(name)) # if multithreaded: # setattr(self, name+"buttonThread", Thread(target=function)) # getattr(self, name+"button").pressed.connect(self.startLoadingIndicator) # getattr(self, name+"button").released.connect(getattr(self, name+"buttonThread").start) # else: getattr(self, name + "button").clicked.connect(function) # getattr(self, name + "button").setMinimumWidth(220) if layout is None: if self.buttonLayoutRightCol.count( ) < self.buttonLayoutMiddleCol.count(): self.buttonLayoutRightCol.addWidget( getattr(self, name + "button")) elif self.buttonLayoutMiddleCol.count( ) < self.buttonLayoutLeftCol.count(): self.buttonLayoutMiddleCol.addWidget( getattr(self, name + "button")) else: self.buttonLayoutLeftCol.addWidget( getattr(self, name + "button")) else: layout.addWidget(getattr(self, name + "button")) def updatePlot(self): self.plot(self.currently_selected, self.plotargs) def updateWindowTitle(self): if np.shape(self.log.data[0, DID_DEV_INFO])[0] != 0: info = self.log.data[0, DID_DEV_INFO][0] infoStr = 'SN' + str(info[1]) + ', H:' + verArrayToString( info[2]) + ', F:' + verArrayToString( info[3]) + ' build ' + str( info[4]) + ', ' + dateTimeArrayToString( info[8], info[9]) + ', ' + info[10].decode('UTF-8') self.setWindowTitle("LogInspector - " + infoStr) def choose_directory(self): log_dir = config['logs_directory'] directory = QFileDialog.getExistingDirectory( parent=self, caption='Choose Log Directory', directory=log_dir) if directory != '': try: self.load(directory) except Exception as e: msg = QMessageBox() msg.setIcon(QMessageBox.Critical) msg.setText("Unable to load log: " + e.__str__()) msg.setDetailedText(traceback.format_exc()) msg.exec() def load(self, directory): print("loading files from " + directory) # if self.log is None: self.log = Log() self.log.load(directory) print("done loading") self.plotter = logPlot(False, False, 'svg', self.log) self.plotter.setDownSample(self.downsample) # str = '' # if self.log.navMode: # str += 'NAV ' # if self.log.rtk: # str += 'RTK ' # if self.log.compassing: # str += 'Comp ' # self.statusLabel.setText(str) self.updatePlot() self.updateWindowTitle() self.stopLoadingIndicator() def setupUi(self): self.setObjectName("LogInspector") self.setWindowTitle("LogInspector") self.resize(1280, 900) self.setWindowFlags(self.windowFlags() | QtCore.Qt.WindowSystemMenuHint | QtCore.Qt.WindowMinMaxButtonsHint) self.setWindowIcon(QIcon("assets/Magnifying_glass_icon.png")) # MainWindow.showMaximized() self.createFileTree() self.createButtonColumn() self.formatButtonColumn() self.createBottomToolbar() self.figureLayout = QVBoxLayout() self.figureLayout.addWidget(self.canvas) self.figureLayout.addLayout(self.toolLayout) self.figureLayout.setStretchFactor(self.canvas, 1) layout = QHBoxLayout() layout.addLayout(self.controlLayout) layout.addLayout(self.figureLayout) layout.setStretch(1, 1) widget = QWidget() widget.setLayout(layout) self.setCentralWidget(widget) # self.resize(1280, 900) self.resize(1450, 1000) self.setAcceptDrops(True) def createButtonColumn(self): self.controlLayout = QVBoxLayout() self.buttonLayoutLeftCol = QVBoxLayout() self.buttonLayoutMiddleCol = QVBoxLayout() self.buttonLayoutRightCol = QVBoxLayout() self.addButton('Pos NED Map', lambda: self.plot('posNEDMap')) self.addButton('Pos NED', lambda: self.plot('posNED')) self.addButton('Pos LLA', lambda: self.plot('posLLA')) self.addButton('GPS LLA', lambda: self.plot('llaGps')) self.addButton('Vel NED', lambda: self.plot('velNED')) self.addButton('Vel UVW', lambda: self.plot('velUVW')) self.addButton('Attitude', lambda: self.plot('attitude')) self.addButton('Heading', lambda: self.plot('heading')) self.addButton('INS Status', lambda: self.plot('insStatus')) self.addButton('HDW Status', lambda: self.plot('hdwStatus')) self.addButton('GPS 1 Stats', lambda: self.plot('gpsStats')) self.addButton('GPS 2 Stats', lambda: self.plot('gps2Stats')) self.addButton('RTK Pos Stats', lambda: self.plot('rtkPosStats')) self.addButton('RTK Cmp Stats', lambda: self.plot('rtkCmpStats')) self.addButton('Flash Config', lambda: self.showFlashConfig()) self.addButton('Device Info', lambda: self.showDeviceInfo()) self.addButton('IMU PQR', lambda: self.plot('imuPQR')) self.addButton('IMU Accel', lambda: self.plot('imuAcc')) self.addButton('PSD PQR', lambda: self.plot('gyroPSD')) self.addButton('PSD Accel', lambda: self.plot('accelPSD')) self.addButton('Magnetometer', lambda: self.plot('magnetometer')) self.addButton('Temp', lambda: self.plot('temp')) def formatButtonColumn(self): self.buttonLayoutLeftCol.setAlignment(QtCore.Qt.AlignTop) self.buttonLayoutMiddleCol.setAlignment(QtCore.Qt.AlignTop) self.buttonLayoutRightCol.setAlignment(QtCore.Qt.AlignTop) self.buttonColumnLayout = QHBoxLayout() self.buttonColumnLayout.addLayout(self.buttonLayoutLeftCol) self.buttonColumnLayout.addLayout(self.buttonLayoutMiddleCol) self.buttonColumnLayout.addLayout(self.buttonLayoutRightCol) self.controlLayout.addLayout(self.buttonColumnLayout) self.controlDirLayout = QHBoxLayout() self.controlDirLayout.addWidget(self.dirLineEdit) self.controlLayout.addLayout(self.controlDirLayout) self.controlLayout.addWidget(self.fileTree) # self.buttonLayout.addItem(QSpacerItem(20, 40, QSizePolicy.Minimum, QSizePolicy.Expanding)) # self.addButton('load', self.choose_directory, multithreaded=False) def createBottomToolbar(self): self.toolLayout = QHBoxLayout() self.toolLayout.addWidget(self.toolbar) self.loadingIndictator = QLabel() self.loadingMovie = QMovie('assets/loader.gif') self.emptyLoadingPicture = QPicture() self.emptyLoadingPicture.load('assets/empty_loader.png') self.stopLoadingIndicator() self.toolLayout.addWidget(self.loadingIndictator) self.toolLayout.addItem( QSpacerItem(20, 40, QSizePolicy.Minimum, QSizePolicy.Expanding)) # self.toolLayout.addWidget(QSpacerItem(150, 10, QSizePolicy.Expanding)) self.copyImagePushButton = QPushButton() # self.copyImagePushButton.setText("Copy") # self.copyImagePushButton.setMinimumWidth(1) # self.copyImagePushButton.style().standardIcon(QStyle.SP_DialogOpenButton) self.copyImagePushButton.setIcon(self.style().standardIcon( QStyle.SP_DialogSaveButton)) self.toolLayout.addWidget(self.copyImagePushButton) self.copyImagePushButton.clicked.connect(self.copyPlotToClipboard) downsampleLabel = QLabel() downsampleLabel.setText("DS") self.downSampleInput = QSpinBox() self.downSampleInput.setValue(self.downsample) self.toolLayout.addWidget(downsampleLabel) self.toolLayout.addWidget(self.downSampleInput) self.downSampleInput.valueChanged.connect(self.changeDownSample) self.statusLabel = QLabel() self.toolLayout.addWidget(self.statusLabel) def changeDownSample(self, val): self.downsample = val self.plotter.setDownSample(self.downsample) self.updatePlot() def copyPlotToClipboard(self): # pixmap = QPixmap.grabWidget(self.canvas) # QApplication.clipboard().setPixmap(pixmap) # pixmap.save('test.png') # store the image in a buffer using savefig(), this has the # advantage of applying all the default savefig parameters # such as background color; those would be ignored if you simply # grab the canvas using Qt buf = io.BytesIO() self.figure.savefig(buf) QApplication.clipboard().setImage(QImage.fromData(buf.getvalue())) buf.close() def startLoadingIndicator(self): self.loadingIndictator.setMovie(self.loadingMovie) self.loadingMovie.start() def dragEnterEvent(self, e): if (e.mimeData().hasUrls()): e.acceptProposedAction() def dropEvent(self, e): try: directory = e.mimeData().urls()[0].toLocalFile() self.load(directory) except Exception as e: self.showError(e) def showError(self, e): msg = QMessageBox() msg.setIcon(QMessageBox.Critical) msg.setText("Unable to load log: " + e.__str__()) msg.setDetailedText(traceback.format_exc()) msg.exec() def createFileTree(self): self.dirModel = QFileSystemModel() self.dirModel.setRootPath(self.config["logs_directory"]) self.dirModel.setFilter(QtCore.QDir.Dirs | QtCore.QDir.NoDotAndDotDot) self.dirLineEdit = QLineEdit() self.dirLineEdit.setText(self.config["logs_directory"]) self.dirLineEdit.setFixedHeight(25) self.dirLineEdit.returnPressed.connect(self.handleTreeDirChange) self.fileTree = QTreeView() self.fileTree.setModel(self.dirModel) self.fileTree.setRootIndex( self.dirModel.index(self.config['logs_directory'])) self.fileTree.setColumnHidden(1, True) self.fileTree.setColumnHidden(2, True) self.fileTree.setColumnHidden(3, True) self.fileTree.setMinimumWidth(300) self.fileTree.clicked.connect(self.handleTreeViewClick) self.fileTree.setContextMenuPolicy(QtCore.Qt.CustomContextMenu) self.fileTree.setSelectionMode(QAbstractItemView.SingleSelection) self.fileTree.customContextMenuRequested.connect( self.handleTreeViewRightClick) # self.populateRMSCheck(self.config['logs_directory']) def updateFileTree(self): self.dirModel.setRootPath(self.config["logs_directory"]) self.fileTree.setRootIndex( self.dirModel.index(self.config['logs_directory'])) def populateRMSCheck(self, directory): for subdir in os.listdir(directory): path = os.path.join(directory, subdir) if os.path.isdir(path): self.populateRMSCheck(path) elif 'RMS' in subdir: f = open(path) rms_report = f.read() p = re.compile(r'(?<=^PASS/FAIL).*\n', re.M) line = re.search(p, rms_report).group() failed = True if "FAIL" in line else False if failed: pass else: pass def handleTreeDirChange(self): self.config["logs_directory"] = self.dirLineEdit.text() self.updateFileTree() file = open(self.configFilePath, 'w') yaml.dump(self.config, file) file.close() def handleTreeViewClick(self): selected_directory = self.fileTree.model().filePath( self.fileTree.selectedIndexes()[0]) for fname in os.listdir(selected_directory): if fname.endswith('.dat'): try: self.load(selected_directory) except Exception as e: self.showError(e) break def handleTreeViewRightClick(self, event): selected_directory = os.path.normpath(self.fileTree.model().filePath( self.fileTree.selectedIndexes()[0])) menu = QMenu(self) copyAction = menu.addAction("Copy path") nppActionHot = menu.addAction("Run NPP, HOT start") nppActionCold = menu.addAction("Run NPP, COLD start") nppActionFactory = menu.addAction("Run NPP, FACTORY start") setDataInfoDirHotAction = menu.addAction( "Set dataInfo.json directory, HOT start") setDataInfoDirColdAction = menu.addAction( "Set dataInfo.json directory, COLD start") setDataInfoDirFactoryAction = menu.addAction( "Set dataInfo.json directory, FACTORY start") exploreAction = menu.addAction("Explore folder") cleanFolderAction = menu.addAction("Clean folder") deleteFolderAction = menu.addAction("Delete folder") action = menu.exec_(self.fileTree.viewport().mapToGlobal(event)) if action == copyAction: cb = QApplication.clipboard() cb.clear(mode=cb.Clipboard) cb.setText(selected_directory, mode=cb.Clipboard) if action == nppActionHot: cleanFolder(selected_directory) setDataInformationDirectory(selected_directory, startMode=START_MODE_HOT) sys.path.insert(1, '../../../../python/src') from supernpp.supernpp import SuperNPP spp = SuperNPP(selected_directory, self.config['serials']) spp.run() if action == nppActionCold: cleanFolder(selected_directory) setDataInformationDirectory(selected_directory, startMode=START_MODE_COLD) sys.path.insert(1, '../../../../python/src') from supernpp.supernpp import SuperNPP spp = SuperNPP(selected_directory, self.config['serials'], startMode=START_MODE_COLD) spp.run() if action == nppActionFactory: cleanFolder(selected_directory) setDataInformationDirectory(selected_directory, startMode=START_MODE_FACTORY) sys.path.insert(1, '../../../../python/src') from supernpp.supernpp import SuperNPP spp = SuperNPP(selected_directory, self.config['serials'], startMode=START_MODE_FACTORY) spp.run() if action == setDataInfoDirHotAction: setDataInformationDirectory(selected_directory, startMode=START_MODE_HOT) if action == setDataInfoDirColdAction: setDataInformationDirectory(selected_directory, startMode=START_MODE_COLD) if action == setDataInfoDirFactoryAction: setDataInformationDirectory(selected_directory, startMode=START_MODE_FACTORY) if action == exploreAction: openFolderWithFileBrowser(selected_directory) if action == cleanFolderAction: cleanFolder(selected_directory) if action == deleteFolderAction: msg = QMessageBox(self) msg.setIcon(QMessageBox.Question) msg.setText("Are you sure you want to delete this folder?\n\n" + selected_directory) msg.setStandardButtons(QMessageBox.Yes | QMessageBox.No) result = msg.exec() if result == QMessageBox.Yes: removeDirectory(selected_directory) def stopLoadingIndicator(self): self.loadingMovie.stop() self.loadingIndictator.clear() self.loadingIndictator.setPicture(self.emptyLoadingPicture) def showDeviceInfo(self): dlg = DeviceInfoDialog(self.log, self) dlg.show() dlg.exec_() def showFlashConfig(self): dlg = FlashConfigDialog(self.log, self) dlg.show() dlg.exec_() def plot(self, func, args=None): print("plotting " + func) self.currently_selected = func self.plotargs = args self.figure.clear() if hasattr(self, 'plotter'): if args is not None: getattr(self.plotter, func)(*args, self.figure) else: getattr(self.plotter, func)(self.figure) self.canvas.draw() self.stopLoadingIndicator() print("done plotting")
class DriveAnalysisWidget(QWidget): def __init__(self): super().__init__() self.setWindowTitle('Drive Analysis Tool') # self.root_path = os.path.expanduser('~') # BUG 2018-09-18: No permission to access certain files for os.stat self.root_path = os.path.expanduser('~\\Downloads') self.threadpool = QThreadPool() self.resize_mode = 'dynamic' select_btn = QPushButton('Select Folder', self) select_btn.setToolTip('Select <b>root folder</b> to simplify.') select_btn.clicked.connect(self.show_file_dialog) select_btn.resize(select_btn.sizeHint()) test_btn = QPushButton('Test Scripts', self) test_btn.clicked.connect(self.run_tests) test_btn.resize(test_btn.sizeHint()) self.folder_edit = QLabel() self.folder_edit.setText(self.root_path) self.status_label = QLabel() self.status_label.setText('') self.status_label.setStyleSheet("color: red;" "font: bold;") ogtree_label = QLabel() ogtree_label.setAlignment(Qt.AlignCenter) ogtree_label.setText('Original folders data') anontree_label = QLabel() anontree_label.setAlignment(Qt.AlignCenter) anontree_label.setText('Anonymized folders data used for research') self.ogtree = QTreeView(self) self.ogtree.setEditTriggers(QAbstractItemView.NoEditTriggers) self.ogmodel = QStandardItemModel() self.ogmodel.setHorizontalHeaderLabels(['Folder Name', 'Number of Files']) self.ogmodel.itemChanged.connect(self.on_item_change) self.anontree = QTreeView(self) self.anontree.setEditTriggers(QAbstractItemView.NoEditTriggers) self.anonmodel = QStandardItemModel() self.anonmodel.setHorizontalHeaderLabels(['Folder Name', 'Number of Files']) self.dir_dict, self.og_dir_dict = dict(), dict() self.build_tree_structure_threaded(self.root_path) grid = QGridLayout() grid.addWidget(select_btn, 0, 0, 1, 1) grid.addWidget(self.folder_edit, 0, 1, 1, 8) grid.addWidget(self.status_label, 1, 0, 1, 9) grid.addWidget(test_btn, 2, 0, 1, 1) grid.addWidget(ogtree_label, 3, 0, 1, 4) grid.addWidget(anontree_label, 3, 5, 1, 4) grid.addWidget(self.ogtree, 4, 0, 1, 4) grid.addWidget(self.anontree, 4, 5, 1, 4) self.setLayout(grid) self.resize(640, 480) self.show() def refresh_tree_header(self, tree, resize_mode='dynamic'): if resize_mode == 'dynamic': tree.header().setSectionResizeMode(0, QHeaderView.ResizeToContents) tree.header().setSectionResizeMode(1, QHeaderView.ResizeToContents) # tree.header().setSectionResizeMode(2, QHeaderView.ResizeToContents) elif resize_mode == 'static': tree.header().setSectionResizeMode(0, QHeaderView.Interactive) tree.header().setSectionResizeMode(1, QHeaderView.Interactive) # tree.header().setSectionResizeMode(2, QHeaderView.Interactive) def show_file_dialog(self): dirpath = QFileDialog.getExistingDirectory(self, 'Select Folder', self.root_path) if dirpath: self.root_path = os.path.abspath(dirpath) self.folder_edit.setText(self.root_path) self.build_tree_structure_threaded(self.root_path, self.prune_thold) def build_tree_structure_threaded(self, root_path): worker = Worker(self.build_tree_structure, root_path) worker.signals.started.connect(self.build_tree_started) worker.signals.result.connect(self.build_tree_finished) self.threadpool.start(worker) def anonymize_tree_structure_threaded(self, root_path, dir_dict, rename_dict, remove_dict): worker = Worker(self.anonymize_tree_structure, root_path, dir_dict, rename_dict, remove_dict) worker.signals.started.connect(self.anonymize_tree_started) worker.signals.result.connect(self.anonymize_tree_finished) self.threadpool.start(worker) def build_tree_structure(self, root_path): # self.slider.setDisabled(True) dir_dict = record_stat(root_path) og_dir_dict = deepcopy(dir_dict) # dir_dict = simplify_tree(root_path, 1, dir_dict, 0.95, self.scale_pruning(prune_thold), print_=False) # self.slider.setEnabled(True) return og_dir_dict, dir_dict def anonymize_tree_structure(self, dir_dict, rename_dict, remove_dict): # dir_dict = simplify_tree(root_path, 1, dir_dict, 0.95, self.scale_pruning(prune_thold), print_=False) dir_dict = anonymize_stat(dir_dict, rename_dict, remove_dict) return dir_dict def build_tree_started(self): self.status_label.setText('Building tree, please wait...') def build_tree_finished(self, result): self.og_dir_dict, self.dir_dict = result # print(self.og_dir_dict[1],self.og_dir_dict[2], self.og_dir_dict[3]) self.refresh_treeview(self.ogmodel, self.ogtree, self.og_dir_dict) # #BUG 2018-09-18: crashes the interface because i am referring to non-existent dictionary keys # (see append_all_children, e.g., dir_dict[dirkey][0]) # I've updated my dir_dict to use string names instead of integers so append_all_children # needs to be updated as well. # self.refresh_treeview(self.anonmodel, self.anontree, self.dir_dict) self.status_label.setText('') def anonymize_tree_started(self): self.status_label.setText('Anonymizing tree, please wait...') def anonymize_tree_finished(self, dir_dict): self.refresh_treeview(self.anonmodel, self.anontree, dir_dict) self.status_label.setText('') def refresh_treeview(self, model, tree, dir_dict): model.removeRow(0) parent = model.invisibleRootItem() self.append_all_children(1, dir_dict, parent) # dir_dict key starts at 1 since 0==False tree.setModel(model) self.refresh_tree_header(tree, self.resize_mode) tree.expandToDepth(0) def append_all_children(self, dirkey, dir_dict, qitem): qitem.setData(dirkey, Qt.UserRole) # PAUSING HERE FOR NOW 20180918-1254 print(dirkey, dir_dict[dirkey]['dirname']) # print(qitem.data(Qt.UserRole)) dirname = QStandardItem(dir_dict[dirkey]['dirname']) nfiles = QStandardItem(str(dir_dict[dirkey]['nfiles'])) # dirname.setFlags(Qt.ItemIsUserCheckable | Qt.ItemIsEnabled) # dirname.setData(QVariant(Qt.Checked), Qt.CheckStateRole) dirname.setCheckable(True) dirname.setCheckState(Qt.Checked) # Qt.Checked == 2 # dirname.setData(QVariant(str(dirkey)), role=Qt.UserRole+1) # doesn't work # qitem.appendRow([QStandardItem(dir_dict[dirkey]['dirname']), # QStandardItem(str(dir_dict[dirkey]['nfiles']))]) qitem.appendRow([dirname, nfiles, QStandardItem(str(dirkey))]) current_row = qitem.rowCount() - 1 print('Current row: ', current_row) print('dirkey for root: ', self.ogmodel.item(0).data(Qt.UserRole), qitem.data(Qt.UserRole)) children_keys = dir_dict[dirkey]['childkeys'] children_names = [dir_dict[child]['dirname'].lower() for child in children_keys] for child_name, child_key in sorted(zip(children_names, children_keys)): self.append_all_children(child_key, dir_dict, qitem.child(current_row)) def on_item_change(self, qitem): # print(type(qitem)) dirkey = qitem.data(Qt.UserRole) print(dirkey) # print(qitem.row(), qitem.column()) # print(qitem.rowCount(), qitem.columnCount()) # print(qitem.hasChildren()) # print(qitem.parent()) # print(qitem.text()) # if qitem.hasChildren(): # doesn't work # for child_item in qitem.sortChildren(): # self.on_item_change(child_item) # qitem.index(1, 1).setCheckState(check_state) # current_row = qitem.rowCount() - 1 # print(qitem.sortChildren(1)) # print(current_row) # print(qitem.checkState()) def run_tests(self): print(self.ogtree.model().rowCount()) for row in range(self.ogmodel.rowCount()): print(self.ogmodel.item(row).text(), self.ogmodel.item(row).data(Qt.UserRole)) print(self.ogmodel.item(row).hasChildren())
class RegisterViewWidget(WidgetBase): def __init__(self, parent: QWidget): super(RegisterViewWidget, self).__init__(parent) self._registers = [] self._running_task: asyncio.Task = None self._visibility_selector = QComboBox(self) self._visibility_selector.addItem("Show all registers", lambda _: True) self._visibility_selector.addItem("Only configuration parameters", lambda r: r.mutable and r.persistent) # noinspection PyUnresolvedReferences self._visibility_selector.currentIndexChanged.connect( lambda _: self._on_visibility_changed()) self._reset_selected_button = make_button( self, "Reset selected", icon_name="clear-symbol", tool_tip=f"Reset the currently selected registers to their default " f"values. The restored values will be committed " f"immediately. This function is available only if a " f"default value is defined. [{RESET_SELECTED_SHORTCUT}]", on_clicked=self._do_reset_selected, ) self._reset_all_button = make_button( self, "Reset all", icon_name="skull-crossbones", tool_tip=f"Reset the all registers to their default " f"values. The restored values will be committed " f"immediately.", on_clicked=self._do_reset_all, ) self._read_selected_button = make_button( self, "Read selected", icon_name="process", tool_tip=f"Read the currently selected registers only " f"[{READ_SELECTED_SHORTCUT}]", on_clicked=self._do_read_selected, ) self._read_all_button = make_button( self, "Read all", icon_name="process-plus", tool_tip="Read all registers from the device", on_clicked=self._do_read_all, ) self._export_button = make_button( self, "Export", icon_name="export", tool_tip="Export configuration parameters", on_clicked=self._do_export, ) self._import_button = make_button( self, "Import", icon_name="import", tool_tip="Import configuration parameters", on_clicked=self._do_import, ) self._expand_all_button = make_button( self, "", icon_name="expand-arrow", tool_tip="Expand all namespaces", on_clicked=lambda: self._tree.expandAll(), ) self._collapse_all_button = make_button( self, "", icon_name="collapse-arrow", tool_tip="Collapse all namespaces", on_clicked=lambda: self._tree.collapseAll(), ) self._status_display = QLabel(self) self._status_display.setWordWrap(True) self._reset_selected_button.setEnabled(False) self._reset_all_button.setEnabled(False) self._read_selected_button.setEnabled(False) self._read_all_button.setEnabled(False) self._export_button.setEnabled(False) self._import_button.setEnabled(False) self._tree = QTreeView(self) self._tree.setVerticalScrollMode(QTreeView.ScrollPerPixel) self._tree.setHorizontalScrollMode(QTreeView.ScrollPerPixel) self._tree.setAnimated(True) self._tree.setSelectionMode(QAbstractItemView.ExtendedSelection) self._tree.setAlternatingRowColors(True) self._tree.setContextMenuPolicy(Qt.ActionsContextMenu) # Not sure about this one. This hardcoded value may look bad on some platforms. self._tree.setIndentation(20) def add_action( callback: typing.Callable[[], None], icon_name: str, name: str, shortcut: typing.Optional[str] = None, ): action = QAction(get_icon(icon_name), name, self) # noinspection PyUnresolvedReferences action.triggered.connect(callback) if shortcut: action.setShortcut(shortcut) action.setAutoRepeat(False) try: action.setShortcutVisibleInContextMenu(True) except AttributeError: pass # This feature is not available in PyQt before 5.10 self._tree.addAction(action) add_action(self._do_read_all, "process-plus", "Read all registers") add_action( self._do_read_selected, "process", "Read selected registers", READ_SELECTED_SHORTCUT, ) add_action( self._do_reset_selected, "clear-symbol", "Reset selected to default", RESET_SELECTED_SHORTCUT, ) self._tree.setItemDelegateForColumn( int(Model.ColumnIndices.VALUE), EditorDelegate(self._tree, self._display_status), ) # It doesn't seem to be explicitly documented, but it seems to be necessary to select either top or bottom # decoration position in order to be able to use center alignment. Left or right positions do not work here. self._tree.setItemDelegateForColumn( int(Model.ColumnIndices.FLAGS), StyleOptionModifyingDelegate( self._tree, decoration_position=QStyleOptionViewItem.Top, # Important decoration_alignment=Qt.AlignCenter, ), ) header: QHeaderView = self._tree.header() header.setSectionResizeMode(QHeaderView.ResizeToContents) header.setStretchLastSection( False) # Horizontal scroll bar doesn't work if this is enabled buttons_layout = QGridLayout() buttons_layout.addWidget(self._read_selected_button, 0, 0) buttons_layout.addWidget(self._reset_selected_button, 0, 2) buttons_layout.addWidget(self._read_all_button, 1, 0) buttons_layout.addWidget(self._reset_all_button, 1, 2) buttons_layout.addWidget(self._import_button, 2, 0) buttons_layout.addWidget(self._export_button, 2, 2) for col in range(3): buttons_layout.setColumnStretch(col, 1) layout = lay_out_vertically( (self._tree, 1), buttons_layout, lay_out_horizontally( self._visibility_selector, (None, 1), self._expand_all_button, self._collapse_all_button, ), self._status_display, ) self.setLayout(layout) def reset(self): self.setup([]) def setup(self, registers: typing.Iterable[Register]): self._registers = list(registers) self._on_visibility_changed() def _replace_model( self, register_visibility_predicate: typing.Callable[[Register], bool]): # Cancel all operations that might be pending on the old model self._cancel_task() old_model = self._tree.model() # Configure the new model filtered_registers = list( filter(register_visibility_predicate, self._registers)) # It is important to set the Tree widget as the parent in order to let the widget take ownership new_model = Model(self._tree, filtered_registers) _logger.info("New model %r", new_model) self._tree.setModel(new_model) # The selection model is implicitly replaced when we replace the model, so it has to be reconfigured self._tree.selectionModel().selectionChanged.connect( lambda *_: self._on_selection_changed()) # TODO: Something fishy is going on. Something keeps the old model alive when we're replacing it. # We could call deleteLater() on it, but it seems dangerous, because if that something ever decided # to refer to that dead model later for any reason, we'll get a rougue dangling pointer access on # our hands. The horror! if old_model is not None: import gc model_referrers = gc.get_referrers(old_model) if len(model_referrers) > 1: _logger.warning( "Extra references to the old model %r: %r", old_model, model_referrers, ) # Update the widget - all root items are expanded by default for row in itertools.count(): index = self._tree.model().index(row, 0) if not index.isValid(): break self._tree.expand(index) self._reset_selected_button.setEnabled(False) self._read_selected_button.setEnabled(False) self._read_all_button.setEnabled(len(filtered_registers) > 0) self._reset_all_button.setEnabled(len(filtered_registers) > 0) self._export_button.setEnabled(len(filtered_registers) > 0) self._import_button.setEnabled(len(filtered_registers) > 0) self._display_status(f"{len(filtered_registers)} registers loaded") def _on_visibility_changed(self): self._replace_model(self._visibility_selector.currentData()) def _on_selection_changed(self): selected = self._get_selected_registers() self._reset_selected_button.setEnabled( any(map(lambda r: r.has_default_value, selected))) self._read_selected_button.setEnabled(len(selected) > 0) def _do_read_selected(self): selected = self._get_selected_registers() if selected: self._read_specific(selected) else: self._display_status("No registers are selected, nothing to read") def _do_reset_selected(self): rv = {} for r in self._get_selected_registers(): if r.has_default_value: rv[r] = r.default_value self._write_specific(rv) def _do_reset_all(self): rv = {} for r in self._registers: if r.has_default_value: rv[r] = r.default_value self._write_specific(rv) def _do_read_all(self): self._read_specific(self._tree.model().registers) def _do_import(self): import_registers(parent=self, registers=self._registers) def _do_export(self): export_registers(parent=self, registers=self._registers) def _read_specific(self, registers: typing.List[Register]): total_registers_read = None def progress_callback(register: Register, current_register_index: int, total_registers: int): nonlocal total_registers_read total_registers_read = total_registers self._display_status( f"Reading {register.name!r} " f"({current_register_index + 1} of {total_registers})") async def executor(): try: _logger.info("Reading registers: %r", [r.name for r in registers]) mod: Model = self._tree.model() await mod.read(registers=registers, progress_callback=progress_callback) except asyncio.CancelledError: self._display_status(f"Read has been cancelled") raise except Exception as ex: _logger.exception("Register read failed") show_error("Read failed", "Could not read registers", repr(ex), self) self._display_status(f"Could not read registers: {ex!r}") else: self._display_status( f"{total_registers_read} registers have been read") self._cancel_task() self._running_task = asyncio.get_event_loop().create_task(executor()) def _write_specific(self, register_value_mapping: typing.Dict[Register, typing.Any]): total_registers_assigned = None def progress_callback(register: Register, current_register_index: int, total_registers: int): nonlocal total_registers_assigned total_registers_assigned = total_registers self._display_status( f"Writing {register.name!r} " f"({current_register_index + 1} of {total_registers})") async def executor(): try: _logger.info( "Writing registers: %r", [r.name for r in register_value_mapping.keys()], ) mod: Model = self._tree.model() await mod.write( register_value_mapping=register_value_mapping, progress_callback=progress_callback, ) except asyncio.CancelledError: self._display_status(f"Write has been cancelled") raise except Exception as ex: _logger.exception("Register write failed") show_error("Write failed", "Could not read registers", repr(ex), self) self._display_status(f"Could not write registers: {ex!r}") else: self._display_status( f"{total_registers_assigned} registers have been written") self._cancel_task() self._running_task = asyncio.get_event_loop().create_task(executor()) def _get_selected_registers(self) -> typing.List[Register]: selected_indexes: typing.List[ QModelIndex] = self._tree.selectedIndexes() selected_registers = set() for si in selected_indexes: r = Model.get_register_from_index(si) if r is not None: selected_registers.add(r) # Beware that sets are not sorted, this may lead to weird user experience when watching the registers # read in a funny order. return list(sorted(selected_registers, key=lambda x: x.name)) def _cancel_task(self): # noinspection PyBroadException try: self._running_task.cancel() except Exception: pass else: _logger.info("A running task had to be cancelled: %r", self._running_task) finally: self._running_task = None def _display_status(self, text=None): self._status_display.setText(text)
class AddToProject(QDialog): """Dialog to let the user choose one of the folders from the opened proj""" def __init__(self, projects, parent=None): super(AddToProject, self).__init__(parent) # projects must be a list self._projects = projects self.setWindowTitle(translations.TR_ADD_FILE_TO_PROJECT) self.path_selected = '' vbox = QVBoxLayout(self) hbox = QHBoxLayout() self._list = QListWidget() for project in self._projects: self._list.addItem(project.name) self._list.setCurrentRow(0) self._tree = QTreeView() self._tree.setHeaderHidden(True) self._tree.setSelectionMode(QTreeView.SingleSelection) self._tree.setAnimated(True) self.load_tree(self._projects[0]) hbox.addWidget(self._list) hbox.addWidget(self._tree) vbox.addLayout(hbox) hbox2 = QHBoxLayout() btn_add = QPushButton(translations.TR_ADD_HERE) btn_cancel = QPushButton(translations.TR_CANCEL) hbox2.addWidget(btn_cancel) hbox2.addWidget(btn_add) vbox.addLayout(hbox2) btn_add.clicked.connect(self._select_path) btn_cancel.clicked.connect(self.close) self._list.currentItemChanged.connect(self._project_changed) def _project_changed(self, item, previous): # FIXME, this is not being called, at least in osx for each_project in self._projects: if each_project.name == item.text(): self.load_tree(each_project) def load_tree(self, project): """Load the tree view on the right based on the project selected.""" qfsm = QFileSystemModel() qfsm.setRootPath(project.path) load_index = qfsm.index(qfsm.rootPath()) qfsm.setFilter(QDir.AllDirs | QDir.NoDotAndDotDot) qfsm.setNameFilterDisables(False) pext = ["*{0}".format(x) for x in project.extensions] qfsm.setNameFilters(pext) self._tree.setModel(qfsm) self._tree.setRootIndex(load_index) t_header = self._tree.header() t_header.setHorizontalScrollMode(QAbstractItemView.ScrollPerPixel) t_header.setSectionResizeMode(0, QHeaderView.Stretch) t_header.setStretchLastSection(False) t_header.setSectionsClickable(True) self._tree.hideColumn(1) # Size self._tree.hideColumn(2) # Type self._tree.hideColumn(3) # Modification date # FIXME: Changing the name column's title requires some magic # Please look at the project tree def _select_path(self): """Set path_selected to the folder selected in the tree.""" path = self._tree.model().filePath(self._tree.currentIndex()) if path: self.path_selected = path self.close()
class MyWindow(QMainWindow): # QWidget def __init__(self): #super(MyWindow, self).__init__() super().__init__() global mainWindow mainWindow = self self.fileLabels = [] self.model = None self.tree = None self.grpBox = None self.viewWindow = None self._drawIndex = -1 self.thumbs = {} self.thumbFileName = None self.newImgFound = False # if True, new image file non-referenced in .pythumbs file is found, need to update the .pythumbs file self.initUI() def initUI(self): self.resize(600, 800) bar = self.menuBar() makeMenu(bar, FILE_MENU, self) # #self.model = QDirModel([], QDir.Dirs, QDir.NoSort ) # rootPath = 'C:/Users/azemero' # QDir.currentPath() # self.model = QFileSystemModel() # self.model.setRootPath(rootPath) # self.model.setFilter(QDir.AllDirs|QDir.NoDotAndDotDot) # #todo: filter or custom tree # proxyModel = QSortFilterProxyModel() # proxyModel.setSourceModel(self.model) # proxyModel.setFilterRegExp(r"^([^.]+)$") # # self.tree = QTreeView() # self.tree.setModel(proxyModel) # self.tree.setColumnHidden(1, True) # self.tree.setColumnHidden(2, True) # self.tree.setColumnHidden(3, True) # self.tree.doubleClicked.connect(self.onDirDblClick) # self.tree.selectionModel().selectionChanged.connect(self.onDirSelChange) # # self.tree.setSortingEnabled(True) # self.tree.sortByColumn(0, Qt.AscendingOrder) # idx = self.model.index(rootPath) # idx = proxyModel.mapFromSource(idx) # self.tree.setRootIndex(idx) # # self.tree.setAnimated(False) # self.tree.setIndentation(20) # self.tree.setSortingEnabled(True) # # self.tree.setWindowTitle("Dir View") # #self.tree.resize(640, 480) # self.tree.setMinimumWidth(200) self.model = QStandardItemModel() parentItem = self.model.invisibleRootItem() frstIdx = None for i in range(4): item = QStandardItem("Pictures %d" % i) item.setData('C:/Users/azemero/Pictures') #item.setIcon(QIcon(os.path.abspath(os.path.join(os.path.dirname(__file__),'..','icons','base','24.png')))) item.setIcon(QIcon(appctxt.get_resource('folder_png8773.ico'))) parentItem.appendRow(item) if not frstIdx: frstIdx = item.index() #parentItem = item self.model.setHeaderData(0, Qt.Horizontal, "Directories") self.tree = QTreeView(self) self.tree.setModel(self.model) self.tree.clicked[QModelIndex].connect(self.onTreeClick) self.tree.setMinimumWidth(200) windowLayout = QHBoxLayout() windowLayout.setSpacing(0) #windowLayout.setContentsMargins(0,0,0,0) windowLayout.addWidget(self.tree, alignment=Qt.AlignLeft) self.grpBox = QGroupBox('') self.grpBox.setLayout( FlowLayout()) #self.grpBox.setLayout(QGridLayout(self)) self.grpBox.setMinimumWidth(400) windowLayout.addWidget(self.grpBox) #, alignment=Qt.AlignLeft) splitter = QSplitter(Qt.Horizontal) splitter.addWidget(self.tree) splitter.addWidget(self.grpBox) splitter.setSizes([200, 800]) splitter.setStretchFactor(1, 1) windowLayout.addWidget(splitter) #~self.setLayout(windowLayout) center = QWidget() center.setLayout(windowLayout) self.setCentralWidget(center) self.viewWindow = ViewWindow() if frstIdx: self.onTreeClick(frstIdx) def onDirDblClick(self, signal): file_path = self.tree.model().filePath(signal) #print(file_path) if os.path.isdir(file_path): self.drawFiles(file_path) def onTreeClick(self, index): item = self.model.itemFromIndex(index) file_path = item.data() #print(file_path) if os.path.isdir(file_path): self.drawFiles(file_path) # def onDirSelChange(self, newitem, olditem): # _ = olditem # idx = newitem.indexes()[0] # idx = self.tree.model().mapToSource(idx) # file_path=self.model.filePath(idx) # #print(file_path) # if os.path.isdir(file_path): # self.drawFiles(file_path) # def onFileDblClick(self): # self.viewWindow.openImage('') # self.viewWindow.show() # def eventFilter(self, obj, event): # if event.type() == QEvent.MouseButtonPress: # pass #здесь выполняем код # return True def drawFiles(self, dname): row = col = 0 for label in self.fileLabels: label.setParent(None) # remove old image labels del self.fileLabels[:] QApplication.processEvents() self.thumbFileName = os.path.join(dname, '.pythumbs') self.newImgFound = False if os.path.isfile(self.thumbFileName): with open(self.thumbFileName, 'rb') as f: data = pickle.load(f) self.thumbs = deserializeDict(data) else: self.thumbs = {} fnames = imgFiles(dname) for fname in fnames: label = ClickableLabel(dname, fname) self.fileLabels.append(label) self.grpBox.layout().addWidget(label) col += 1 if col % 6 == 0: row += 1 col = 0 #print('drawFiles.3') QApplication.processEvents() self._drawIndex = 0 if fnames else -1 threading.Thread(target=self.drawFile).start() def drawFile(self): if self._drawIndex < len(self.fileLabels): self.fileLabels[self._drawIndex].showImage() QApplication.processEvents() self._drawIndex += 1 if self._drawIndex >= len(self.fileLabels): self._drawIndex = -1 if self.thumbFileName and self.newImgFound: print('update .pythumbs') array = serializeDict(self.thumbs) with open(self.thumbFileName, 'wb') as f: pickle.dump(array, f) else: threading.Thread(target=self.drawFile).start()
class DebugWindow(QMainWindow): """A main window to edit text and examine the generated token structure. Example:: from PyQt5.Qt import * a=QApplication([]) from parceqt.debug import DebugWindow w = DebugWindow() w.resize(1200,900) w.show() w.set_theme("default", True) from parce.lang.css import * w.set_root_lexicon(Css.root) w.set_text(open("path/to/parce/themes/default.css").read()) In the debug window you can edit the text at the left and directly at the right examine the tree structure. Along the top of the window the path to the token at the current cursor position is displayed, from the root lexicon upto the token, from which the action is displayed. Clicking a button selects the associated range of the context or token in the text view. Clicking an item in the tree also selects that range in the text. Moving the cursor in the text updates the current item in the tree, and the displayed ancestor path. """ show_updated_region_enabled = False def __init__(self, parent=None): super().__init__(parent, windowTitle="parceqt debugger") f = self._updated_format = QTextCharFormat() c = QColor("palegreen") c.setAlpha(64) f.setBackground(c) f = self._currentline_format = QTextCharFormat() f.setProperty(QTextCharFormat.FullWidthSelection, True) self._actions = Actions(self) self._actions.add_menus(self.menuBar()) widget = QWidget(self) self.setCentralWidget(widget) layout = QVBoxLayout(margin=4, spacing=2) widget.setLayout(layout) top_layout = QHBoxLayout(margin=0, spacing=0) self.guessButton = QToolButton(self, clicked=self.guess_root_lexicon, toolTip="Guess Language", icon=self.style().standardIcon( QStyle.SP_BrowserReload)) self.lexiconChooser = LexiconChooser(self) self.ancestorView = AncestorView(self) top_layout.addWidget(self.guessButton) top_layout.addWidget(self.lexiconChooser) top_layout.addWidget(self.ancestorView) top_layout.addStretch(10) layout.addLayout(top_layout) self.guessButton.setFixedHeight( self.lexiconChooser.sizeHint().height()) splitter = QSplitter(self, orientation=Qt.Horizontal) layout.addWidget(splitter, 100) self.textEdit = QPlainTextEdit(lineWrapMode=QPlainTextEdit.NoWrap, cursorWidth=2) self.treeView = QTreeView() splitter.addWidget(self.textEdit) splitter.addWidget(self.treeView) splitter.setStretchFactor(0, 3) splitter.setStretchFactor(1, 2) self.extraSelectionManager = ExtraSelectionManager(self.textEdit) self.document = d = self.textEdit.document() self.textEdit.setDocument(self.document) self.worker = w = parceqt.worker(d) self.builder = b = w.builder() w.debugging = True self.setStatusBar(QStatusBar()) self.create_model() # signal connections self.textEdit.viewport().installEventFilter(self) self.textEdit.installEventFilter(self) self.lexiconChooser.lexicon_changed.connect( self.slot_root_lexicon_changed) self.ancestorView.node_clicked.connect(self.slot_node_clicked) w.started.connect(self.slot_build_started) w.tree_updated.connect(self.slot_build_updated) self.textEdit.cursorPositionChanged.connect( self.slot_cursor_position_changed) self.treeView.clicked.connect(self.slot_item_clicked) self.textEdit.setFocus() self.set_theme() # somewhat larger font by default font = self.textEdit.font() font.setPointSizeF(11) self.textEdit.setFont(font) def create_model(self): """Instantiate a tree model for the tree view.""" m = self.treeView.model() if not m: m = parceqt.treemodel.TreeModel(self.builder.root) m.connect_debugging_builder(self.builder) self.treeView.setModel(m) def delete_model(self): """Delete the model and remove it from the tree.""" m = self.treeView.model() if m: m.disconnect_debugging_builder(self.builder) self.treeView.setModel(None) m.deleteLater() def set_text(self, text): """Set the text in the text edit.""" self.document.setPlainText(text) def set_root_lexicon(self, lexicon): """Set the root lexicon to use.""" self.lexiconChooser.set_root_lexicon(lexicon) def guess_root_lexicon(self): """Again choose the root lexicon based on the text.""" text = self.document.toPlainText() if text: self.set_root_lexicon(parce.find(contents=text)) def open_file(self, filename): """Read a file from disk and guess the language.""" text = read_file(filename) root_lexicon = parce.find(filename=filename, contents=text) self.set_text(text) self.set_root_lexicon(root_lexicon) c = self.textEdit.textCursor() c.setPosition(0) self.textEdit.setTextCursor(c) def set_theme(self, theme="default", adjust_widget=True): """Set the theme to use for the text edit.""" if isinstance(theme, str): theme = parce.theme_by_name(theme) formatter = parceqt.formatter.Formatter(theme) if theme else None if adjust_widget: if formatter: font = formatter.font(self) self.textEdit.setPalette(formatter.palette(self)) else: font = QApplication.font(self) self.textEdit.setPalette(QApplication.palette(self)) font.setPointSizeF(self.textEdit.font().pointSizeF()) # keep size self.textEdit.setFont(font) self.highlight_current_line() h = parceqt.highlighter.SyntaxHighlighter.instance(self.worker) h.set_formatter(formatter) def slot_build_started(self): """Called when the tree builder has started a build.""" self.treeView.setCursor(Qt.BusyCursor) def slot_build_updated(self): """Called when the tree builder has finished a build.""" self.treeView.unsetCursor() self.slot_cursor_position_changed() self.statusBar().showMessage(", ".join( lexicon_names(self.builder.lexicons))) tree = self.worker.get_root() self.lexiconChooser.setToolTip( parceqt.treemodel.TreeModel.node_tooltip(tree)) if self.show_updated_region_enabled: self.show_updated_region() def slot_cursor_position_changed(self): """Called when the text cursor moved.""" tree = self.worker.get_root() if tree: pos = self.textEdit.textCursor().position() doc = parceqt.document.Document(self.document) token = doc.token(pos) if token: self.ancestorView.set_token_path(token) model = self.treeView.model() if model: index = model.get_model_index(token) self.treeView.setCurrentIndex(index) elif tree is not None: self.ancestorView.clear() self.highlight_current_line() def slot_item_clicked(self, index): """Called when a node in the tree view is clicked.""" tree = self.worker.get_root() if tree: model = self.treeView.model() if model: node = self.treeView.model().get_node(index) cursor = self.textEdit.textCursor() cursor.setPosition(node.end) cursor.setPosition(node.pos, QTextCursor.KeepAnchor) self.textEdit.setTextCursor(cursor) self.textEdit.setFocus() def slot_node_clicked(self, node): """Called when a button in the ancestor view is clicked.""" tree = self.worker.get_root() if tree and node.root() is tree: cursor = self.textEdit.textCursor() cursor.setPosition(node.end) cursor.setPosition(node.pos, QTextCursor.KeepAnchor) self.textEdit.setTextCursor(cursor) self.textEdit.setFocus() model = self.treeView.model() if model: index = model.get_model_index(node) self.treeView.expand(index) self.treeView.setCurrentIndex(index) def slot_root_lexicon_changed(self, lexicon): """Called when the root lexicon is changed.""" parceqt.set_root_lexicon(self.document, lexicon) def highlight_current_line(self): """Highlight the current line.""" group = QPalette.Active if self.textEdit.hasFocus( ) else QPalette.Inactive p = self.textEdit.palette() color = p.color(group, QPalette.AlternateBase) self._currentline_format.setBackground(color) if color != p.color(group, QPalette.Base): c = self.textEdit.textCursor() c.clearSelection() self.extraSelectionManager.highlight(self._currentline_format, [c]) else: self.extraSelectionManager.clear(self._currentline_format) def show_updated_region(self): """Highlight the updated region for 2 seconds.""" end = self.builder.end if end >= self.document.characterCount() - 1: end = self.document.characterCount() - 1 if self.builder.start == 0: return c = QTextCursor(self.document) c.setPosition(end) c.setPosition(self.builder.start, QTextCursor.KeepAnchor) self.extraSelectionManager.highlight(self._updated_format, [c], msec=2000) def clear_updated_region(self): self.extraSelectionManager.clear(self._updated_format) def eventFilter(self, obj, ev): """Implemented to support Ctrl+wheel zooming and keybfocus handling.""" if obj == self.textEdit: if ev.type() in (QEvent.FocusIn, QEvent.FocusOut): self.highlight_current_line() else: # viewport if ev.type() == QEvent.Wheel and ev.modifiers( ) == Qt.ControlModifier: if ev.angleDelta().y() > 0: self.textEdit.zoomIn() elif ev.angleDelta().y() < 0: self.textEdit.zoomOut() return True return False
class KerningWindow(QWidget): def __init__(self, font, parent=None): super().__init__(parent, Qt.Window) self._font = font self._font.kerning.addObserver( self, "_kerningChanged", "Kerning.Changed") self._font.info.addObserver(self, "_fontInfoChanged", "Info.Changed") self.kerningView = QTreeView(self) self.kerningView.setModel( KerningDictModel(font.kerning, self.kerningView)) self.kerningView.expandAll() metrics = self.kerningView.fontMetrics() self.kerningView.setColumnWidth(1, 8 * metrics.width("0")) hdr = self.kerningView.header() hdr.setStretchLastSection(False) hdr.setSectionResizeMode(0, hdr.Stretch) hdr.hide() layout = QVBoxLayout(self) layout.addWidget(self.kerningView) layout.setContentsMargins(0, 0, 0, 0) self.updateWindowTitle(font=font) self.readSettings() def readSettings(self): geometry = settings.kerningWindowGeometry() if geometry: self.restoreGeometry(geometry) def writeSettings(self): settings.setKerningWindowGeometry(self.saveGeometry()) def updateWindowTitle(self, title=None, font=None): if title is None: title = self.tr("Kerning") if font is not None: title = "%s – %s %s" % ( title, font.info.familyName, font.info.styleName) self.setWindowTitle(title) # ------------- # Notifications # ------------- def _kerningChanged(self, notification): model = self.kerningView.model() model.setupModelData(self._font.kerning) def _fontInfoChanged(self, notification): self.updateWindowTitle(font=self._font) # ---------- # Qt methods # ---------- def sizeHint(self): return QSize(280, 460) def moveEvent(self, event): self.writeSettings() resizeEvent = moveEvent def closeEvent(self, event): super().closeEvent(event) if event.isAccepted(): self._font.kerning.removeObserver(self, "Kerning.Changed") self._font.info.removeObserver(self, "Info.Changed")
class Ui_MainWindow(object): def setupUi(self, MainWindow): MainWindow.resize(800, 600) MainWindow.setMinimumSize(600, 400) icon = QIcon() icon.addPixmap(QPixmap("icon.png"), QIcon.Normal, QIcon.Off) font = QFont() font.setFamily("MS Sans Serif") font.setBold(True) font.setWeight(75) MainWindow.setWindowIcon(icon) self.centralwidget = QWidget(MainWindow) MainWindow.setCentralWidget(self.centralwidget) self.menubar = QMenuBar(MainWindow) self.menuFiles = QMenu(self.menubar) self.menuMark = QMenu(self.menubar) self.menuCommands = QMenu(self.menubar) self.menuNet = QMenu(self.menubar) self.menuShow = QMenu(self.menubar) self.menuConfiguration = QMenu(self.menubar) self.menuStart = QMenu(self.menubar) MainWindow.setMenuBar(self.menubar) self.helpMenuBar = QMenuBar(self.menubar) self.menuHelp = QMenu(self.helpMenuBar) self.helpMenuBar.addMenu(self.menuHelp) self.menubar.setCornerWidget(self.helpMenuBar) self.toolBar = QToolBar(MainWindow) self.toolBar.setMovable(False) MainWindow.addToolBar(QtCore.Qt.TopToolBarArea, self.toolBar) self.toolBar_2 = QToolBar(MainWindow) font2 = QFont() font2.setFamily("MS Sans Serif") font2.setWeight(700) font2.setPixelSize(8) font2.setBold(True) self.model1 = QFileSystemModel() self.model1.setRootPath('C:\\Windows') self.tree1 = QTreeView() self.tree1.setModel(self.model1) self.tree1.setRootIndex(self.model1.index("C:\\Windows\\")) self.tree1.setAnimated(False) self.tree1.setFont(font2) self.tree1.setIndentation(20) self.tree1.setSortingEnabled(True) self.tree1.setItemsExpandable(False) self.tree1.setRootIsDecorated(False) self.tree1.sortByColumn(0, QtCore.Qt.AscendingOrder) self.tree1.resize(350, 480) self.model2 = QFileSystemModel() self.model2.setRootPath('C:\\Windows\\System32') self.tree2 = QTreeView() self.tree2.setModel(self.model2) self.tree2.setRootIndex(self.model2.index("C:\\Windows\\System32\\")) self.tree2.setAnimated(False) self.tree2.setFont(font2) self.tree2.setIndentation(20) self.tree2.setItemsExpandable(False) self.tree2.setRootIsDecorated(False) self.tree2.setSortingEnabled(True) self.tree2.resize(350, 480) for i in range(1, self.tree1.model().columnCount()): self.tree1.header().hideSection(i) for i in range(1, self.tree2.model().columnCount()): self.tree2.header().hideSection(i) self.centralHBox = QHBoxLayout() self.centralHBox.addWidget(self.tree1) self.centralHBox.addWidget(self.tree2) self.centralHBox.setContentsMargins(3, 3, 3, 3) self.centralwidget.setLayout(self.centralHBox) self.toolBar_2.setMovable(False) self.toolBar_3 = QToolBar(MainWindow) self.toolBar_3.setFixedHeight(30) self.toolBar_3.setContentsMargins(1, 1, 1, 1) self.dirLabel = QLabel() self.dirLabel.setText('c:\\Windows>') self.dirBox = QComboBox() self.dirBox.setEditable(True) self.dirBox.addItem('') self.dirBox.setFixedWidth(470) self.spacer = QWidget() self.spacer.setSizePolicy(QSizePolicy.Expanding, QSizePolicy.Preferred) self.toolBar_3.addWidget(self.spacer) self.toolBar_3.addWidget(self.dirLabel) self.toolBar_3.addWidget(self.dirBox) self.toolBar_3.setFont(font) self.toolBar_3.setMovable(False) self.toolBar_3.setStyleSheet("QToolBar{spacing: 5px;}") MainWindow.addToolBar(QtCore.Qt.BottomToolBarArea, self.toolBar_2) MainWindow.addToolBar(QtCore.Qt.BottomToolBarArea, self.toolBar_3) MainWindow.insertToolBarBreak(self.toolBar_3) self.actionIndex = QAction(MainWindow) icon1 = QIcon() icon1.addPixmap(QPixmap("help.png"), QIcon.Normal, QIcon.Off) self.actionIndex.setIcon(icon1) self.actionKeyboard = QAction(MainWindow) self.actionRegistration_Info = QAction(MainWindow) self.actionVisit_Total_CMD_s_website = QAction(MainWindow) self.actionAbout_Total_Commander = QAction(MainWindow) self.actionOption_1 = QAction(MainWindow) self.actionOption_2 = QAction(MainWindow) self.actionOption_3 = QAction(MainWindow) self.actionOption_4 = QAction(MainWindow) self.actionOption_5 = QAction(MainWindow) self.actionOption_6 = QAction(MainWindow) self.actionOption_7 = QAction(MainWindow) self.actionOption_8 = QAction(MainWindow) self.actionOption_9 = QAction(MainWindow) self.actionOption_10 = QAction(MainWindow) self.actionOption_11 = QAction(MainWindow) self.actionOption_12 = QAction(MainWindow) self.actionOption_13 = QAction(MainWindow) self.actionOption_14 = QAction(MainWindow) self.Refresh = QAction(MainWindow) icon2 = QIcon() icon2.addPixmap(QPixmap("refresh.png"), QIcon.Normal, QIcon.Off) self.Refresh.setIcon(icon2) self.action_view1 = QAction(MainWindow) icon3 = QIcon() icon3.addPixmap(QPixmap("folder_structure_1.png"), QIcon.Normal, QIcon.Off) self.view_group = QActionGroup(MainWindow) self.action_view1.setIcon(icon3) self.action_view1.setCheckable(True) self.action_view2 = QAction(MainWindow) self.action_view2.setCheckable(True) self.action_view2.setChecked(True) icon4 = QIcon() icon4.addPixmap(QPixmap("folder_structure_2.png"), QIcon.Normal, QIcon.Off) self.action_view2.setIcon(icon4) self.view_group.addAction(self.action_view1) self.view_group.addAction(self.action_view2) self.view_group.setExclusive(True) self.actionF3_View = QToolButton(MainWindow) self.actionF3_View.setStyleSheet("QToolButton{border: none;}") self.actionF3_View.setFont(font) self.actionF4_Edit = QToolButton(MainWindow) self.actionF4_Edit.setStyleSheet("QToolButton{border: none;}") self.actionF4_Edit.setFont(font) self.actionF5_Copy = QToolButton(MainWindow) self.actionF5_Copy.setStyleSheet("QToolButton{border: none;}") self.actionF5_Copy.setFont(font) self.actionF6_Move = QToolButton(MainWindow) self.actionF6_Move.setStyleSheet("QToolButton{border: none;}") self.actionF6_Move.setFont(font) self.actionF5_NewFolder = QToolButton(MainWindow) self.actionF5_NewFolder.setStyleSheet("QToolButton{border: none;}") self.actionF5_NewFolder.setFont(font) self.actionF8_Delete = QToolButton(MainWindow) self.actionF8_Delete.setStyleSheet("QToolButton{border: none;}") self.actionF8_Delete.setFont(font) self.actionAlt_F4_Exit = QToolButton(MainWindow) self.actionAlt_F4_Exit.setStyleSheet("QToolButton{border: none;}") self.actionAlt_F4_Exit.setFont(font) self.menuFiles.addAction(self.actionOption_1) self.menuFiles.addAction(self.actionOption_2) self.menuMark.addAction(self.actionOption_3) self.menuMark.addAction(self.actionOption_4) self.menuCommands.addAction(self.actionOption_5) self.menuCommands.addAction(self.actionOption_6) self.menuNet.addAction(self.actionOption_7) self.menuNet.addAction(self.actionOption_8) self.menuShow.addAction(self.actionOption_9) self.menuShow.addAction(self.actionOption_10) self.menuConfiguration.addAction(self.actionOption_11) self.menuConfiguration.addAction(self.actionOption_12) self.menuStart.addAction(self.actionOption_13) self.menuStart.addAction(self.actionOption_14) self.menuHelp.addAction(self.actionIndex) self.menuHelp.addAction(self.actionKeyboard) self.menuHelp.addAction(self.actionRegistration_Info) self.menuHelp.addAction(self.actionVisit_Total_CMD_s_website) self.menuHelp.addSeparator() self.menuHelp.addAction(self.actionAbout_Total_Commander) self.menubar.addAction(self.menuFiles.menuAction()) self.menubar.addAction(self.menuMark.menuAction()) self.menubar.addAction(self.menuCommands.menuAction()) self.menubar.addAction(self.menuNet.menuAction()) self.menubar.addAction(self.menuShow.menuAction()) self.menubar.addAction(self.menuConfiguration.menuAction()) self.menubar.addAction(self.menuStart.menuAction()) self.helpMenuBar.addAction(self.menuHelp.menuAction()) self.toolBar.addAction(self.Refresh) self.toolBar.addSeparator() self.toolBar.addAction(self.action_view1) self.toolBar.addSeparator() self.toolBar.addAction(self.action_view2) self.separator1 = QFrame() self.separator1.setFrameShape(QFrame.VLine) self.separator1.setFrameShadow(QFrame.Sunken) self.separator2 = QFrame() self.separator2.setFrameShape(QFrame.VLine) self.separator2.setFrameShadow(QFrame.Sunken) self.separator3 = QFrame() self.separator3.setFrameShape(QFrame.VLine) self.separator3.setFrameShadow(QFrame.Sunken) self.separator4 = QFrame() self.separator4.setFrameShape(QFrame.VLine) self.separator4.setFrameShadow(QFrame.Sunken) self.separator5 = QFrame() self.separator5.setFrameShape(QFrame.VLine) self.separator5.setFrameShadow(QFrame.Sunken) self.separator6 = QFrame() self.separator6.setFrameShape(QFrame.VLine) self.separator6.setFrameShadow(QFrame.Sunken) self.toolbarHBoxWidget = QWidget() self.toolbarHBoxWidget.setSizePolicy(QSizePolicy.Expanding, QSizePolicy.Preferred) self.toolbarHBox = QGridLayout() self.toolbarHBoxWidget.setLayout(self.toolbarHBox) self.toolbarHBox.addWidget(self.actionF3_View, 0, 0) self.toolbarHBox.addWidget(self.separator1, 0, 1) self.toolbarHBox.addWidget(self.actionF4_Edit, 0, 2) self.toolbarHBox.addWidget(self.separator2, 0, 3) self.toolbarHBox.addWidget(self.actionF5_Copy, 0, 4) self.toolbarHBox.addWidget(self.separator3, 0, 5) self.toolbarHBox.addWidget(self.actionF6_Move, 0, 6) self.toolbarHBox.addWidget(self.separator4, 0, 7) self.toolbarHBox.addWidget(self.actionF5_NewFolder, 0, 8) self.toolbarHBox.addWidget(self.separator5, 0, 9) self.toolbarHBox.addWidget(self.actionF8_Delete, 0, 10) self.toolbarHBox.addWidget(self.separator6, 0, 11) self.toolbarHBox.addWidget(self.actionAlt_F4_Exit, 0, 12) self.toolBar_2.addWidget(self.toolbarHBoxWidget) self.toolBar_2.setFixedHeight(40) self.retranslateUi(MainWindow) QMetaObject.connectSlotsByName(MainWindow) def retranslateUi(self, MainWindow): MainWindow.setWindowTitle( "Total Commander 7.50a - Politechnika Lodzka - Wydzial EEIA") self.menuFiles.setTitle("Files") self.menuMark.setTitle("Mark") self.menuCommands.setTitle("Commands") self.menuNet.setTitle("Net") self.menuShow.setTitle("Show") self.menuConfiguration.setTitle("Configuration") self.menuStart.setTitle("Start") self.menuHelp.setTitle("Help") self.toolBar.setWindowTitle("toolBar") self.toolBar_2.setWindowTitle("toolBar_2") self.actionIndex.setText("Index") self.actionIndex.setIconText("Index") self.actionIndex.setShortcut("F1") self.actionKeyboard.setText("Keyboard") self.actionRegistration_Info.setText("Registration Info") self.actionVisit_Total_CMD_s_website.setText( "Visit Totalcmd\'s Web Site") self.actionAbout_Total_Commander.setText("About Total Commander...") self.actionOption_1.setText("Option 1") self.actionOption_2.setText("Option 2") self.actionOption_3.setText("Option 1") self.actionOption_4.setText("Option 2") self.actionOption_5.setText("Option 1") self.actionOption_6.setText("Option 2") self.actionOption_7.setText("Option 1") self.actionOption_8.setText("Option 2") self.actionOption_9.setText("Option 1") self.actionOption_10.setText("Option 2") self.actionOption_11.setText("Option 1") self.actionOption_12.setText("Option 2") self.actionOption_13.setText("Option 1") self.actionOption_14.setText("Option 2") self.Refresh.setText("Refresh") self.action_view1.setText("View 1") self.action_view2.setText("View 2") self.actionF3_View.setText("F3 View") self.actionF3_View.setShortcut("F3") self.actionF4_Edit.setText("F4 Edit") self.actionF4_Edit.setShortcut("F4") self.actionF5_Copy.setText("F5 Copy") self.actionF5_Copy.setShortcut("F5") self.actionF6_Move.setText("F6 Move") self.actionF6_Move.setShortcut("F6") self.actionF5_NewFolder.setText("F7 NewFolder") self.actionF5_NewFolder.setShortcut("F7") self.actionF8_Delete.setText("F8 Delete") self.actionF8_Delete.setShortcut("F8") self.actionAlt_F4_Exit.setText("Alt+F4 Exit") self.actionAlt_F4_Exit.setShortcut("Ctrl+Alt+F4")
class VGExplorer(QWidget): def __init__(self, app, config): super().__init__() self.clipboard = app.clipboard() self.config = config self.setWindowTitle(config.server_name) rootPath = self.get_cwd() self.model = QFileSystemModel() index = self.model.setRootPath(rootPath) self.tree = QTreeView() self.tree.setModel(self.model) self.tree.setRootIndex(index) self.tree.setAnimated(False) self.tree.setIndentation(20) self.tree.hideColumn(1) self.tree.hideColumn(2) self.tree.hideColumn(3) self.tree.setHeaderHidden(True) self.tree.doubleClicked.connect(self.on_double_click) self.tree.setContextMenuPolicy(QtCore.Qt.CustomContextMenu) self.tree.customContextMenuRequested.connect(self.show_menu) windowLayout = QVBoxLayout() windowLayout.addWidget(self.tree) self.setLayout(windowLayout) # Shortcut for hide self.shortcut = QShortcut(QKeySequence(config.toggle_key), self) self.shortcut.activated.connect(self.hide) if not config.hidden: self.show() def toggle_show(self): if self.isHidden(): self.show() else: self.hide() def open_file(self, index): path = self.sender().model().filePath(index) if os.path.isfile(path): subprocess.call([ self.config.vim, "--servername", self.config.server_name, "--remote", path ]) def get_cwd(self): path = subprocess.check_output([ self.config.vim, "--servername", self.config.server_name, "--remote-expr", "getcwd()" ]) return path.decode("utf-8").strip() def on_double_click(self, index): self.open_file(index) def show_menu(self, clickPos): index = self.tree.indexAt(clickPos) selected_path = self.tree.model().filePath(index) enclosing_dir = self.find_enclosing_dir(selected_path) menu = QMenu(self) openAction = menu.addAction("Open") newFolderAction = menu.addAction("New Folder") newFileAction = menu.addAction("New File") copyAction = menu.addAction("Copy") pasteAction = menu.addAction("Paste") renameAction = menu.addAction("Rename") fileInfo = menu.addAction("Properties") menuPos = QPoint(clickPos.x() + 15, clickPos.y() + 15) action = menu.exec_(self.mapToGlobal(menuPos)) if action == openAction: self.open_file(index) elif action == newFolderAction: path = self.get_dialog_str("New Folder", "Enter name for new folder:") if path: self.mkdir(os.path.join(enclosing_dir, path)) elif action == newFileAction: path = self.get_dialog_str("New File", "Enter name for new file:") if path: self.touch(os.path.join(enclosing_dir, path)) elif action == renameAction: path = self.get_dialog_str("Rename File", "Enter new name:") # Naive validation if "/" in path: msg = QMessageBox() msg.setIcon(QMessageBox.Critical) msg.setText("Filename cannot contain '/'") msg.setWindowTitle("Error") msg.exec_() return new_path = os.path.join(enclosing_dir, path) self.move(selected_path, new_path) elif action == copyAction: mime_data = QMimeData() # TODO: support multiple selections mime_data.setUrls([QUrl(Path(selected_path).as_uri())]) self.clipboard.setMimeData(mime_data) elif action == pasteAction: mime_data = self.clipboard.mimeData() if not mime_data: return if mime_data.hasUrls(): for src_url in mime_data.urls(): self.copy(src_url.path(), enclosing_dir) def get_dialog_str(self, title, message): text, confirm = QInputDialog.getText(self, title, message, QLineEdit.Normal, "") if confirm and text != '': return text return None ''' Filesystem and OS Functions ''' def copy(self, src_file, dest_dir): src_basename = os.path.basename(src_file) dest_file = os.path.join(dest_dir, src_basename) # First confirm file doesn't already exist if os.path.exists(dest_file): print(f"Destination path '{dest_file}' already exists, skipping") return print(f"Pasting {src_file} -> {dest_file}") shutil.copy2(src_file, dest_file) def move(self, old_path, new_path): os.rename(old_path, new_path) def mkdir(self, path): if not os.path.exists(path): os.mkdir(path) def touch(self, path): subprocess.run(["touch", path]) def find_enclosing_dir(self, path): ''' If path is file, return dir it is in If path is dir, return itself ''' if os.path.isdir(path): return path if os.path.isfile(path): return str(Path(path).parent)
class EncoderSelector(QComboBox): __PATH_SEPARATOR__ = " → " _PATH_ROLE = 1 _DETAILS_ROLE = 2 class EncoderModel(QStandardItemModel): def __init__(self, json_file, disable_selections=False): super().__init__() self.disable_selections = disable_selections self.json_file = json_file self.json = None self.reload() def reload(self): with open(self.json_file) as config: self.json = json.load(config) self.beginResetModel() self.clear() self._build_descendents(self.invisibleRootItem(), self.json, self.disable_selections) self.endResetModel() def get_item(self, model_index): item = self.itemFromIndex(model_index) if item: return item.text() return None def del_item(self, media_type, encoder_group, name): del self.json[media_type][encoder_group][name] # Clean up ancestors if they dont have any children if len(self.json[media_type][encoder_group].keys()) == 0: del self.json[media_type][encoder_group] if len(self.json[media_type].keys()) == 0: del self.json[media_type] def add_item(self, media_type, group, name, extension, executable, command): if media_type not in self.json: self.json[media_type] = {} if group not in self.json[media_type]: self.json[media_type][group] = {} self.json[media_type][group][name] = { "extension": extension, "executable": executable, "command": command } def backup_and_save(self): # Backup current config backup_config_file() # Save new config with open(self.json_file, "w") as config: json.dump(self.json, config, indent=4) self.reload() @staticmethod def _build_descendents(parent, _json, disable_selections): encoder_keys = {"extension", "executable", "command"} intersection = set(_json.keys()) & encoder_keys if not intersection: # add node and build further for key in _json: section_root = QStandardItem(key) parent.appendRow(section_root) if disable_selections: parent.setSelectable(False) EncoderSelector.EncoderModel._build_descendents( section_root, _json[key], disable_selections) else: if len(intersection) < 3: raise SyntaxError( f"Missing value(s) {encoder_keys - intersection} in node {parent.text()}" ) else: path = "" item = parent while item.parent() is not None: path = f"{EncoderSelector.__PATH_SEPARATOR__}{item.text()}" + path item = item.parent() path = f"{item.text()}" + path parent.setData(path, Qt.UserRole + EncoderSelector._PATH_ROLE) parent.setData(_json, Qt.UserRole + EncoderSelector._DETAILS_ROLE) encoder_changed = pyqtSignal('PyQt_PyObject', 'PyQt_PyObject') def __init__(self): super().__init__() self.tree_view = QTreeView(self) self.tree_view.setEditTriggers(QTreeView.NoEditTriggers) self.tree_view.setSelectionBehavior(QTreeView.SelectRows) self.tree_view.setWordWrap(True) self.tree_view.setHeaderHidden(True) self.setView(self.tree_view) self.encoder_model = EncoderSelector.EncoderModel( get_config_file(), disable_selections=True) self.setModel(self.encoder_model) self.refresh_encoders() self._selected_encoder = "" def paintEvent(self, event): style = QApplication.style() opt = QStyleOptionComboBox() opt.rect = self.rect() self.initStyleOption(opt) painter = QPainter(self) painter.save() style.drawComplexControl(QStyle.CC_ComboBox, opt, painter) opt.currentText = self._encoder_path() style.drawControl(QStyle.CE_ComboBoxLabel, opt, painter) painter.restore() def hidePopup(self): super(EncoderSelector, self).hidePopup() selected_index = self.tree_view.selectionModel().currentIndex() if selected_index: encoder = self.tree_view.model().get_item(selected_index) if encoder: self._selected_encoder = encoder self.encoder_changed.emit(self._encoder_path(), self._encoder_details()) def get_encoder(self): return self._encoder_path(), self._encoder_details() def add_encoder(self, media_type, encoder_group, name, command, executable, extension): self.encoder_model.add_item(media_type, encoder_group, name, extension, executable, command) self.encoder_model.backup_and_save() self.refresh_encoders() def del_encoder(self, media_type, encoder_group, name): self.encoder_model.del_item(media_type, encoder_group, name) self.encoder_model.backup_and_save() self.refresh_encoders() def update_encoder(self, media_type, encoder_group, name, command, executable, extension): self.encoder_model.del_item(media_type, encoder_group, name) self.encoder_model.add_item(media_type, encoder_group, name, extension, executable, command) self.encoder_model.backup_and_save() self.refresh_encoders() def refresh_encoders(self): self.encoder_model.reload() self.tree_view.expandAll() def select_encoder(self, encoder_name): match = self._find_encoder(encoder_name) if match: self._selected_encoder = encoder_name self.encoder_changed.emit(self._encoder_path(), self._encoder_details()) def _encoder_path(self): if self._selected_encoder: match = self._find_encoder(self._selected_encoder) if match: return match[0].data(Qt.UserRole + self._PATH_ROLE) return None def _encoder_details(self): if self._selected_encoder: match = self._find_encoder(self._selected_encoder) if match: return match[0].data(Qt.UserRole + self._DETAILS_ROLE) return None def _find_encoder(self, encoder_name): return self.model().match(self.model().index(0, 0), Qt.UserRole + self._PATH_ROLE, encoder_name, 1, Qt.MatchEndsWith | Qt.MatchRecursive)
class CatalogMainWindow(QMainWindow): def __init__(self, parent=None): QMainWindow.__init__(self, parent) # Структура главного окна # Создаем меню self.menu_bar = self.menuBar() # Создаем блоки меню # Блок меню 'Учет движения товаров' self.gma_menu = self.menu_bar.addMenu('Учет движения товаров') self.gma_menu.setEnabled(False) self.ro_open_btn = QAction(self) self.ro_open_btn.setText('Приходный ордер') self.wo_open_btn = QAction(self) self.wo_open_btn.setText('Расходный ордер') self.gma_menu.addAction(self.ro_open_btn) self.gma_menu.addAction(self.wo_open_btn) # Блок меню 'Отчеты' self.r_menu = self.menu_bar.addMenu('Отчеты') self.r_menu.setEnabled(False) self.tws_report_btn = QAction(self) self.tws_report_btn.setText('Операции с поставщиками') self.gis_report_btn = QAction(self) self.gis_report_btn.setText('Товары в наличии') self.r_menu.addAction(self.tws_report_btn) self.r_menu.addAction(self.gis_report_btn) # Блок меню 'Справочники' self.d_menu = self.menu_bar.addMenu('Справочники') self.d_menu.setEnabled(False) self.u_catalog_btn = QAction(self) self.u_catalog_btn.setText('Пользователи') self.r_catalog_btn = QAction(self) self.r_catalog_btn.setText('Права пользователей') self.c_catalog_btn = QAction(self) self.c_catalog_btn.setText('Категории') self.n_catalog_btn = QAction(self) self.n_catalog_btn.setText('Номенклатура товаров') self.un_catalog_btn = QAction(self) self.un_catalog_btn.setText('Единицы измерения') self.s_catalog_btn = QAction(self) self.s_catalog_btn.setText('Поставщики') self.p_catalog_btn = QAction(self) self.p_catalog_btn.setText('Должности') self.e_catalog_btn = QAction(self) self.e_catalog_btn.setText('Сотрудники') self.d_menu.addAction(self.u_catalog_btn) self.d_menu.addAction(self.r_catalog_btn) self.d_menu.addAction(self.c_catalog_btn) self.d_menu.addAction(self.n_catalog_btn) self.d_menu.addAction(self.un_catalog_btn) self.d_menu.addAction(self.s_catalog_btn) self.d_menu.addAction(self.p_catalog_btn) self.d_menu.addAction(self.e_catalog_btn) # Верхний виджет с полным путем до файла БД self.db_lbl = QLabel() self.db_lbl.setText('Путь до БД:') self.db_lbl.setStyleSheet("border-style: none;" "font-size: 10pt;") self.db_path_lbl = QLineEdit() self.db_path_lbl.setStyleSheet( "background-color: white;" "font-size: 10pt;" "color: green;") self.db_path_lbl.setFixedSize(700, 25) self.db_path_lbl.setEnabled(False) self.db_path_btn = QPushButton('...') self.db_path_btn.setFixedSize(25, 25) self.db_path_btn.setStyleSheet( "border-width: 1px;" "border-style: solid;" "border-color: dimgray;" "border-radius: 5px;" "background-color: gainsboro;") self.db_path_btn.clicked.connect(self.on_db_path_btn_clicked) self.tdw = QDockWidget() self.tdw.setFixedHeight(65) self.tdw.setFeatures(self.tdw.NoDockWidgetFeatures) self.tdw_grid = QGridLayout() self.tdw_grid.setColumnStretch(3, 1) self.tdw_grid.addWidget(self.db_lbl) self.tdw_grid.addWidget(self.db_path_lbl) self.tdw_grid.addWidget(self.db_path_btn) self.tdw_frame = QFrame() self.tdw_frame.setStyleSheet( "background-color: ghostwhite;" "border-width: 0.5px;" "border-style: solid;" "border-color: silver;") self.tdw_frame.setLayout(self.tdw_grid) self.tdw.setWidget(self.tdw_frame) self.addDockWidget(QtCore.Qt.TopDockWidgetArea, self.tdw) # Левый виджет с окном каталога продукции self.ldw = QDockWidget() self.ldw.setFixedSize(500, 570) self.ldw.setFeatures(self.ldw.NoDockWidgetFeatures) self.ldw_tree = QTreeView() self.ldw_tree.setFixedSize(500, 530) self.ldw_tree.setHeaderHidden(True) self.ldw_tree_model = QStandardItemModel() self.ldw_tree.setModel(self.ldw_tree_model) self.ldw_tree.clicked.connect(self.on_ldw_tree_clicked) self.outf_scroll = QScrollArea() self.outf_scroll.setWidget(self.ldw_tree) self.ldw.setWidget(self.outf_scroll) self.ldw.setWindowTitle("Каталог продукции") # Центральный виджет с карточкой товара self.cdw = QDockWidget() self.cdw.setFeatures(self.cdw.NoDockWidgetFeatures) #self.setCentralWidget(self.cdw) # Нижний виджет со служебными сообщениями self.smdw = QDockWidget() self.smdw.setFixedHeight(140) self.smdw.setFeatures(self.smdw.NoDockWidgetFeatures) self.sm_list_widget = QListWidget() self.smdw.setWidget(self.sm_list_widget) self.smdw.setWindowTitle("Служебные сообщения") # Функции главного окна # Функция выбора файла базы данных def on_db_path_btn_clicked(self): global db_path db_path, _filter = QFileDialog.getOpenFileName( None, "Open Data File", '.', "(*.sqlite)") self.db_path_lbl.setText(db_path) self.addDockWidget(QtCore.Qt.LeftDockWidgetArea, self.ldw) self.addDockWidget(QtCore.Qt.BottomDockWidgetArea, self.smdw) # Создаем все таблицы, которые нужны con = QtSql.QSqlDatabase.addDatabase('QSQLITE') con.setDatabaseName(db_path) con.open() if 'rules' not in con.tables(): query = QtSql.QSqlQuery() query.exec( "CREATE TABLE rules(rule STRING UNIQUE, description STRING)") r1 = "admin" d1 = "Доступны все опции" query.exec( "INSERT INTO rules(rule, description) VALUES ('%s','%s')" % (r1, d1)) r2 = "Кладовщик" d2 = "Доступны опции кладовщика" query.exec( "INSERT INTO rules(rule, description) VALUES ('%s','%s')" % (r2, d2)) if 'nomenclature' not in con.tables(): query = QtSql.QSqlQuery() query.exec( "CREATE TABLE nomenclature(item_numb INTEGER UNIQUE PRIMARY KEY NOT NULL, \ item_name STRING NOT NULL, item_unit STRING REFERENCES units (unit) NOT NULL, \ item_cat STRING REFERENCES categories (category) NOT NULL, item_img BLOB)") if 'units' not in con.tables(): query = QtSql.QSqlQuery() query.exec("CREATE TABLE units(unit STRING PRIMARY KEY \ UNIQUE NOT NULL)") if 'categories' not in con.tables(): query = QtSql.QSqlQuery() query.exec( "CREATE TABLE categories(category STRING PRIMARY KEY UNIQUE \ NOT NULL, description STRING NOT NULL)") # Создаем таблицу 'users', если не существует if 'users' not in con.tables(): query = QtSql.QSqlQuery() query.exec( "CREATE TABLE users(id_user INTEGER PRIMARY KEY AUTOINCREMENT \ unique NOT NULL, \ login STRING UNIQUE NOT NULL, password STRING NOT NULL, \ name TEXT NOT NULL, \ rules STRING REFERENCES rules (rule) NOT NULL)") if 'suppliers' not in con.tables(): query = QtSql.QSqlQuery() query.exec("CREATE TABLE suppliers( \ id_supplier INTEGER UNIQUE PRIMARY KEY AUTOINCREMENT NOT NULL, \ supplier STRING UNIQUE NOT NULL, \ ownerchipform STRING NOT NULL, \ address STRING NOT NULL, \ phone STRING NOT NULL, \ email STRING NOT NULL \ )") if 'positions' not in con.tables(): query = QtSql.QSqlQuery() query.exec( "CREATE TABLE positions(position STRING PRIMARY KEY UNIQUE \ NOT NULL)") if 'employee' not in con.tables(): query = QtSql.QSqlQuery() query.exec( "CREATE TABLE employee(employee_id INTEGER UNIQUE PRIMARY KEY AUTOINCREMENT, \ fio STRING NOT NULL, \ position STRING REFERENCES positions (position) NOT NULL)") con.close() con = sqlite3.connect(db_path) cur = con.cursor() sql_cats_select = """\ SELECT DISTINCT item_cat FROM nomenclature """ cur.execute(sql_cats_select) arr = cur.fetchall() #print(arr) for cat in arr: sql_items_select = "SELECT item_name FROM nomenclature \ WHERE item_cat = ?" cur.execute(sql_items_select, [cat[0]]) items = cur.fetchall() #print(items) parent_item = QStandardItem(cat[0]) self.ldw_tree_model.appendRow(parent_item) j = 0 for item in items: child_item = QStandardItem(item[0]) parent_item.setChild(j, 0, child_item) j = j + 1 cur.close() con.close() self.gma_menu.setEnabled(True) self.r_menu.setEnabled(True) self.d_menu.setEnabled(True) self.ro_open_btn.triggered.connect( lambda: documents_class.on_ro_doc_btn( self, db_path)) self.wo_open_btn.triggered.connect( lambda: documents_class.on_wo_doc_btn( self, db_path)) self.gis_report_btn.triggered.connect( lambda: gis_report_class.on_gis_report_btn( self, db_path)) self.tws_report_btn.triggered.connect( lambda: tws_report_class.on_tws_report_btn( self, db_path)) self.u_catalog_btn.triggered.connect( lambda: directories_class.on_u_catalog_btn( self, db_path)) self.r_catalog_btn.triggered.connect( lambda: directories_class.on_r_catalog_btn( self, db_path)) self.c_catalog_btn.triggered.connect( lambda: directories_class.on_c_catalog_btn( self, db_path)) self.n_catalog_btn.triggered.connect( lambda: directories_class.on_n_catalog_btn( self, db_path)) self.un_catalog_btn.triggered.connect( lambda: directories_class.on_un_catalog_btn( self, db_path)) self.s_catalog_btn.triggered.connect( lambda: directories_class.on_s_catalog_btn( self, db_path)) self.p_catalog_btn.triggered.connect( lambda: directories_class.on_p_catalog_btn( self, db_path)) self.e_catalog_btn.triggered.connect( lambda: directories_class.on_e_catalog_btn( self, db_path)) # Функция выбора товара из каталога-дерева def on_ldw_tree_clicked(self): #print('вах') try: current_index = self.ldw_tree.currentIndex() file_name = self.ldw_tree.model().data(current_index) con = sqlite3.connect(db_path) cur = con.cursor() sql_item_select = "SELECT item_name FROM nomenclature \ WHERE item_name = ?" cur.execute(sql_item_select, [file_name]) item = cur.fetchone() if item: self.setCentralWidget(self.cdw) self.cdw.setWindowTitle("Карточка товара") item_card = item_card_class(self, db_path, file_name) self.cdw.setWidget(item_card) cur.close() con.close() except Exception as e: print('Ошибка:\n', traceback.format_exc())
class TestDialog(QDialog): def __init__(self, data): super(TestDialog, self).__init__() self.data = copy.deepcopy(data) # Layout btOk = QPushButton("OK") btCancel = QPushButton("Cancel") self.tree = QTreeView() hbox = QHBoxLayout() hbox.addStretch(1) hbox.addWidget(btOk) hbox.addWidget(btCancel) vbox = QVBoxLayout() vbox.addLayout(hbox) vbox.addWidget(self.tree) self.setLayout(vbox) self.setGeometry(300, 300, 600, 400) # Button signals btCancel.clicked.connect(self.reject) btOk.clicked.connect(self.accept) # Tree view self.tree.setModel(QStandardItemModel()) self.tree.setAlternatingRowColors(True) self.tree.setSortingEnabled(True) self.tree.setHeaderHidden(False) self.tree.setSelectionBehavior(QAbstractItemView.SelectItems) self.tree.model().setHorizontalHeaderLabels(['Parameter', 'Value']) for x in self.data: if not self.data[x]: continue parent = QStandardItem(x) parent.setFlags(QtCore.Qt.NoItemFlags) for y in self.data[x]: value = self.data[x][y] child0 = QStandardItem(y) child0.setFlags(QtCore.Qt.NoItemFlags | QtCore.Qt.ItemIsEnabled) child1 = QStandardItem(repr(value)) child1.setFlags(QtCore.Qt.ItemIsEnabled | QtCore.Qt.ItemIsEditable | ~QtCore.Qt.ItemIsSelectable) parent.appendRow([child0, child1]) self.tree.model().appendRow(parent) self.tree.expandAll() self.tree.model().itemChanged.connect(self.handleItemChanged) def get_data(self): return self.data def handleItemChanged(self, item): parent = self.data[item.parent().text()] key = item.parent().child(item.row(), 0).text() parent[key] = eval(item.text())
class AddToProject(QDialog): """Dialog to let the user choose one of the folders from the opened proj""" def __init__(self, projects, parent=None): super(AddToProject, self).__init__(parent) #pathProjects must be a list self._projects = projects self.setWindowTitle(translations.TR_ADD_FILE_TO_PROJECT) self.pathSelected = '' vbox = QVBoxLayout(self) hbox = QHBoxLayout() self._list = QListWidget() for project in self._projects: self._list.addItem(project.name) self._list.setCurrentRow(0) self._tree = QTreeView() #self._tree.header().setHidden(True) self._tree.setSelectionMode(QTreeView.SingleSelection) self._tree.setAnimated(True) self.load_tree(self._projects[0]) hbox.addWidget(self._list) hbox.addWidget(self._tree) vbox.addLayout(hbox) hbox2 = QHBoxLayout() btnAdd = QPushButton(translations.TR_ADD_HERE) btnCancel = QPushButton(translations.TR_CANCEL) hbox2.addWidget(btnCancel) hbox2.addWidget(btnAdd) vbox.addLayout(hbox2) btnCancel.connect(self.close) btnAdd.connect(self._select_path) self._list.currentItemChanged['QTreeWidgetItem*', 'QTreeWidgetItem*'].connect(self._project_changed) def _project_changed(self, item, previous): #FIXME, this is not being called, at least in osx for each_project in self._projects: if each_project.name == item.text(): self.load_tree(each_project) def load_tree(self, project): """Load the tree view on the right based on the project selected.""" qfsm = QFileSystemModel() qfsm.setRootPath(project.path) load_index = qfsm.index(qfsm.rootPath()) qfsm.setFilter(QDir.AllDirs | QDir.NoDotAndDotDot) qfsm.setNameFilterDisables(False) pext = ["*{0}".format(x) for x in project.extensions] qfsm.setNameFilters(pext) self._tree.setModel(qfsm) self._tree.setRootIndex(load_index) t_header = self._tree.header() t_header.setHorizontalScrollMode(QAbstractItemView.ScrollPerPixel) t_header.setSectionResizeMode(0, QHeaderView.Stretch) t_header.setStretchLastSection(False) t_header.setClickable(True) self._tree.hideColumn(1) # Size self._tree.hideColumn(2) # Type self._tree.hideColumn(3) # Modification date #FIXME: Changing the name column's title requires some magic #Please look at the project tree def _select_path(self): """Set pathSelected to the folder selected in the tree.""" path = self._tree.model().filePath(self._tree.currentIndex()) if path: self.pathSelected = path self.close()
class CSearchWidget(QWidget): def __init__(self, bpID, parent=None): super(CSearchWidget, self).__init__(parent) self.m_BPID = bpID self.m_Status = define.FULL_MATCH self.m_Search = None self.m_CaseSensitively = None self.m_WholeWords = None self.m_Regular = None self.m_Tree = None self._InitUI() self._InitSignal() self.m_BtnMatch.click() def _InitUI(self): self.setWindowTitle("搜索") self.setWindowFlags(Qt.Popup | Qt.Sheet) vBox = QVBoxLayout(self) hBox = QHBoxLayout() self.m_Search = QLineEdit(self) self.m_Search.setFocusPolicy(Qt.ClickFocus) self.m_Search.setClearButtonEnabled(True) self.m_Search.setPlaceholderText("搜索节点或者槽名称") hBox.addWidget(self.m_Search) self.m_BtnMatch = QPushButton("全匹配", self) self.m_BtnMatch.setToolTip("点击切换全匹配/模糊匹配") hBox.addWidget(self.m_BtnMatch) vBox.addLayout(hBox) line = QFrame(self) line.setMinimumSize(QSize(0, 2)) line.setMaximumSize(QSize(1234567, 2)) line.setFrameShape(QFrame.HLine) line.setFrameShadow(QFrame.Sunken) vBox.addWidget(line) self.m_Tree = QTreeView(self) self.m_Tree.setHeaderHidden(True) self.m_Tree.setModel(QStandardItemModel(self)) self.m_Tree.setEditTriggers(QAbstractItemView.NoEditTriggers) vBox.addWidget(self.m_Tree) # self.setLayout(vBox) def _InitSignal(self): self.m_BtnMatch.clicked.connect(self.S_ChangeMatch) self.m_Search.returnPressed.connect(self.S_Search) self.m_Tree.doubleClicked.connect(self.S_FocusItem) GetSignal().UI_SHOW_BP_SEARCH.connect(self.S_ShowBPSearch) def S_ChangeMatch(self): self.m_Status ^= define.FUZZY_MATCH if self.m_Status & define.FUZZY_MATCH: self.m_BtnMatch.setText("模糊匹配") else: self.m_BtnMatch.setText("全匹配") def S_ShowBPSearch(self, bpID): if bpID == self.m_BPID: self.show() def S_Search(self): sText = self.m_Search.text() if not sText: return dInfo = interface.GetSearchInfo(self.m_BPID, sText, self.m_Status & define.FUZZY_MATCH) parentModel = self.m_Tree.model() parentModel.clear() for graphicID, dNode in dInfo.items(): graphicName = interface.GetGraphicAttr( graphicID, eddefine.GraphicAttrName.NAME) tInfo = (define.SearchTreeItemType.GRAPHIC, graphicID) oGItem = CStandardItem(graphicName, tInfo) parentModel.appendRow(oGItem) for nodeID, lstPin in dNode.items(): nodeName = interface.GetNodeAttr( nodeID, bddefine.NodeAttrName.DISPLAYNAME) tInfo = (define.SearchTreeItemType.NODE, nodeID) oNItem = CStandardItem(nodeName, tInfo) oGItem.appendRow(oNItem) for pinID in lstPin: pinName = interface.GetPinAttr( pinID, bddefine.PinAttrName.DISPLAYNAME) tInfo = (define.SearchTreeItemType.PIN, pinID) oPItem = CStandardItem(pinName, tInfo) oNItem.appendRow(oPItem) self.m_Tree.expandAll() def S_FocusItem(self, oModelIndex): """ oModelIndex QModelIndex self.model() QStandardItemModel """ item = self.m_Tree.model().itemFromIndex(oModelIndex) if not item: return iItemType, ID = item.GetInfo() if iItemType == define.SearchTreeItemType.GRAPHIC: GetSignal().UI_FOCUS_GRAPHIC.emit(self.m_BPID, ID) else: if iItemType == define.SearchTreeItemType.PIN: ID = interface.GetNodeIDByPinID(ID) graphicID = interface.GetGraphicIDByNodeID(ID) GetSignal().UI_FOCUS_NODE.emit(graphicID, ID)
class Broswer_Img(QMainWindow): """ 选择图片文件并且预览,自动匹配多图的情况和背景图片 """ Close_Signal = pyqtSignal(list) def __init__(self, *args, **kwargs): QMainWindow.__init__(self, *args, **kwargs) self.Current_Dir = QDir.home().absolutePath() #self.Current_Dir = Wk_Dir self.setWindowTitle("Select Imags") self.setWindowModality(Qt.ApplicationModal) self.Left_Dock_Code() self.Central_Frame_Code() self.Right_Dock_Code() self.connect_Signals() self.wb_nav_left.setEnabled(False) self.wb_nav_right.setEnabled(False) self.bkgd_nav_left.setEnabled(False) self.bkgd_nav_right.setEnabled(False) #self.setGeometry(200, 200, 1000, 600) #self.setMaximumSize(QSize(1000, 600)) def Left_Dock_Code(self): self.Left_Frame = QFrame(self) self.Model = QFileSystemModel() self.Model.setNameFilterDisables(False) self.Model.setRootPath(self.Current_Dir) #self.Model.setSorting(QDir.DirsFirst | QDir.IgnoreCase | QDir.Name) self.Model.setFilter(QDir.NoDotAndDotDot | QDir.AllDirs | QDir.AllEntries) self.Model.setNameFilters(['*.tif']) self.Tree = QTreeView(self.Left_Frame) self.Tree.setModel(self.Model) self.Tree.setRootIndex(self.Model.index(self.Current_Dir)) self.Tree.expandAll() self.Dir_Select = QPushButton("Select a Folder", self.Left_Frame) layout = QVBoxLayout() layout.addWidget(self.Tree) layout.addWidget(self.Dir_Select) self.Left_Frame.setLayout(layout) self.Left_Dock = QDockWidget('Broswer Images', self) self.Left_Dock.setWidget(self.Left_Frame) self.Left_Dock.setFeatures(QDockWidget.NoDockWidgetFeatures) self.Dir_Select.clicked.connect(self.dir_selection) self.addDockWidget(Qt.LeftDockWidgetArea, self.Left_Dock) def Central_Frame_Code(self): self.Central_Frame = QFrame(self) layout = QGridLayout() self.wb_label = QLabel(self.Central_Frame) self.bkgd_label = QLabel(self.Central_Frame) #self.wb_label.setMaximumHeight(30) self.wb_label.setWordWrap(True) self.wb = QLabel(self.Central_Frame) self.wb.setScaledContents(True) self.bkgd = QLabel(self.Central_Frame) self.bkgd.setScaledContents(True) self.wb.setMaximumSize(QSize(300, 300)) self.bkgd.setMaximumSize(QSize(300, 300)) self.wb_navigator = QFrame(self.Central_Frame) self.wb_nav_left = QPushButton('<--', self.wb_navigator) self.wb_nav_right = QPushButton('-->', self.wb_navigator) nav_layout = QHBoxLayout() nav_layout.addWidget(self.wb_nav_left) nav_layout.addWidget(self.wb_nav_right) self.wb_navigator.setLayout(nav_layout) self.wb_navigator.setMaximumHeight(60) self.bkgd_navigator = QFrame(self.Central_Frame) self.bkgd_nav_left = QPushButton('<--', self.bkgd_navigator) self.bkgd_nav_right = QPushButton('-->', self.bkgd_navigator) nav_layout2 = QHBoxLayout() nav_layout2.addWidget(self.bkgd_nav_left) nav_layout2.addWidget(self.bkgd_nav_right) self.bkgd_navigator.setLayout(nav_layout2) self.bkgd_navigator.setMaximumHeight(60) self.btns = QFrame(self.Central_Frame) self.btns.setMaximumHeight(60) self.Btn_Add = QPushButton('Add', self.btns) self.Btn_Close = QPushButton('Close', self.btns) btn_layout = QHBoxLayout() btn_layout.addWidget(self.Btn_Add) btn_layout.addWidget(self.Btn_Close) self.btns.setLayout(btn_layout) # 根据具体的传入参数构建不同的视图 layout.addWidget(self.wb_label, 0, 0) layout.addWidget(self.bkgd_label, 0, 1) layout.addWidget(self.wb, 1, 0) layout.addWidget(self.bkgd, 1, 1) layout.addWidget(self.wb_navigator, 2, 0) layout.addWidget(self.bkgd_navigator, 2, 1) layout.addWidget(self.btns, 3, 0, 2, 0) layouts = QVBoxLayout() layouts.addLayout(layout) self.Central_Frame.setLayout(layouts) self.setCentralWidget(self.Central_Frame) #self.setStyleSheet('border:1px solid red') def Right_Dock_Code(self): self.Added_Img_tree = Img_Tree([], self) self.Right_Dock = QDockWidget('Selected Images', self) self.Right_Dock.setWidget(self.Added_Img_tree) self.Right_Dock.setFeatures(QDockWidget.NoDockWidgetFeatures) self.addDockWidget(Qt.RightDockWidgetArea, self.Right_Dock) def connect_Signals(self): self.Tree.clicked.connect(self.Load_Img_to_Central_Frame) self.wb_nav_left.clicked.connect(self.change_img_index) self.wb_nav_right.clicked.connect(self.change_img_index) self.bkgd_nav_left.clicked.connect(self.change_img_index) self.bkgd_nav_right.clicked.connect(self.change_img_index) self.Btn_Add.clicked.connect(self.Add_Btn_Action) self.Btn_Close.clicked.connect(self.Close_Btn_Action) def Load_Img_to_Central_Frame(self, Index): select_file = self.Tree.model().filePath(Index) _, ext = os.path.splitext(select_file) if ext in ['.tif', '.jpeg', '.png', '.jpg']: self.Related_Imgs = BioRad_Imgs(select_file) self.set_Central_Frame() def set_Central_Frame(self): self.wb_nav_left.setEnabled(False) self.wb_nav_right.setEnabled(False) self.bkgd_nav_left.setEnabled(False) self.bkgd_nav_right.setEnabled(False) self.current_wb = self.Related_Imgs.WB_list[self.Related_Imgs.wb_index] self.current_bkgd = self.Related_Imgs.BKGD_list[ self.Related_Imgs.bkgd_index] self.wb_label.setText( self.current_wb.replace(self.Related_Imgs.Dir, '.')) self.bkgd_label.setText( self.current_bkgd.replace(self.Related_Imgs.Dir, '.')) wb, _ = CV_Img_to_QImage(cv2.imread(self.current_wb)) bkgd, _ = CV_Img_to_QImage(cv2.imread(self.current_bkgd)) self.wb.setPixmap(wb) self.wb.setScaledContents(True) self.bkgd.setPixmap(bkgd) wb_len = len(self.Related_Imgs.WB_list) bkgd_len = len(self.Related_Imgs.BKGD_list) if self.Related_Imgs.wb_index > 0: self.wb_nav_left.setEnabled(True) if wb_len - self.Related_Imgs.wb_index > 1: self.wb_nav_right.setEnabled(True) if self.Related_Imgs.bkgd_index > 0: self.bkgd_nav_left.setEnabled(True) if bkgd_len - self.Related_Imgs.bkgd_index > 1: self.bkgd_nav_right.setEnabled(True) def change_img_index(self): sender = self.sender() if sender == self.wb_nav_left: self.Related_Imgs.wb_index = self.Related_Imgs.wb_index - 1 if sender == self.wb_nav_right: self.Related_Imgs.wb_index = self.Related_Imgs.wb_index + 1 if sender == self.bkgd_nav_left: self.Related_Imgs.bkgd_index = self.Related_Imgs.bkgd_index - 1 if sender == self.bkgd_nav_right: self.Related_Imgs.bkgd_index = self.Related_Imgs.bkgd_index + 1 self.set_Central_Frame() def Add_Btn_Action(self): list = [{'wb': self.current_wb, 'bkgd': self.current_bkgd}] self.Added_Img_tree.Add_top_Level_Item(list) print(self.Added_Img_tree.imgs) def Close_Btn_Action(self): self.close() def closeEvent(self, event): self.Close_Signal.emit(self.Added_Img_tree.imgs) def dir_selection(self): global Wk_Dir dir = QFileDialog.getExistingDirectory(self, "Choose a Directory", Wk_Dir) self.Current_Dir = dir Wk_Dir = dir self.Tree.setRootIndex(self.Model.index(self.Current_Dir)) self.Left_Dock.setWindowTitle(dir)
class _PlatformGui(QWidget): """ The platform-specific GUI. """ def __init__(self, platform_name): """ Initialise the object. """ super().__init__() self._project = None self._platform_name = platform_name self._ignore_extlib_changes = False layout = QVBoxLayout() self._pyshlib_cb = QCheckBox( "Use standard Python shared library", whatsThis="Use the standard Python shared library rather than " "a statically compiled library.", stateChanged=self._pyshlib_changed) layout.addWidget(self._pyshlib_cb) self._extlib_edit = QTreeView( whatsThis="This is the list of external libraries that must " "be linked with the application for this platform. A " "library will only be enabled if a module in the " "standard library uses it. Double-click in the " "<b>DEFINES</b>, <b>INCLUDEPATH</b> and <b>LIBS</b> " "columns to modify the corresponding <tt>qmake</tt> " "variable as required.") self._extlib_edit.setRootIsDecorated(False) self._extlib_edit.setEditTriggers(QTreeView.DoubleClicked | QTreeView.SelectedClicked | QTreeView.EditKeyPressed) model = QStandardItemModel(self._extlib_edit) model.setHorizontalHeaderLabels( ("External Library", 'DEFINES', 'INCLUDEPATH', 'LIBS')) model.itemChanged.connect(self._extlib_changed) model._items = {} for extlib in external_libraries_metadata: name_itm = QStandardItem(extlib.user_name) items = (name_itm, QStandardItem(), QStandardItem(), QStandardItem()) model.appendRow(items) model._items[extlib.name] = items self._extlib_edit.setModel(model) for col in range(3): self._extlib_edit.resizeColumnToContents(col) layout.addWidget(self._extlib_edit) self.setLayout(layout) def update_from_project(self, project): """ Update the GUI to reflect the current state of the project. """ self._project = project platform_name = self._platform_name # Update the shared library state. blocked = self._pyshlib_cb.blockSignals(True) self._pyshlib_cb.setCheckState(Qt.Checked if platform_name in project. python_use_platform else Qt.Unchecked) self._pyshlib_cb.blockSignals(blocked) # Update the external libraries. model = self._extlib_edit.model() blocked = model.blockSignals(True) external_libs = project.external_libraries.get(platform_name, []) for extlib in external_libraries_metadata: _, defs, incp, libs = model._items[extlib.name] for prj_extlib in external_libs: if prj_extlib.name == extlib.name: defs.setText(prj_extlib.defines) incp.setText(prj_extlib.includepath) libs.setText(prj_extlib.libs) break else: defs.setText(extlib.defines) incp.setText(extlib.includepath) libs.setText(extlib.get_libs(platform_name)) model.blockSignals(blocked) def update_from_required_libraries(self, required_libraries): """ Update the GUI as the required external libraries changes. """ items = self._extlib_edit.model()._items # Note that we can't simply block the model's signals as this would # interfere with the model/view interactions. self._ignore_extlib_changes = True for extlib in external_libraries_metadata: if extlib.name in required_libraries: for idx, itm in enumerate(items[extlib.name]): itm.setFlags( Qt.ItemIsEnabled | Qt.ItemIsEditable if idx != 0 else Qt.ItemIsEnabled) else: for itm in items[extlib.name]: itm.setFlags(Qt.NoItemFlags) self._ignore_extlib_changes = False def _pyshlib_changed(self, state): """ Invoked when the shared library state changes. """ project = self._project platform_name = self._platform_name if state == Qt.Checked: project.python_use_platform.append(platform_name) else: project.python_use_platform.remove(platform_name) project.modified = True def _extlib_changed(self, itm): """ Invoked when an external library has changed. """ if self._ignore_extlib_changes: return self._ignore_extlib_changes = True project = self._project platform_name = self._platform_name idx = self._extlib_edit.model().indexFromItem(itm) extlib = external_libraries_metadata[idx.row()] col = idx.column() # Get the project entry, creating it if necessary. external_libs = project.external_libraries.get(platform_name, []) for prj_extlib in external_libs: if prj_extlib.name == extlib.name: break else: prj_extlib = ExternalLibrary(extlib.name, '', '', extlib.get_libs(platform_name)) external_libs.append(prj_extlib) project.external_libraries[platform_name] = external_libs # Update the project. text = itm.text().strip() if col == 1: prj_extlib.defines = text elif col == 2: prj_extlib.includepath = text elif col == 3: prj_extlib.libs = text # If the project entry corresponds to the default then remove it. if prj_extlib.defines == extlib.defines and prj_extlib.includepath == extlib.includepath and prj_extlib.libs == extlib.get_libs( platform_name): external_libs.remove(prj_extlib) if len(external_libs) == 0: del project.external_libraries[platform_name] project.modified = True self._ignore_extlib_changes = False
class Widget(QWidget): def __init__(self, panel): super(Widget, self).__init__(panel) layout = QVBoxLayout() self.setLayout(layout) layout.setSpacing(0) self.searchEntry = SearchLineEdit() self.treeView = QTreeView(contextMenuPolicy=Qt.CustomContextMenu) self.textView = QTextBrowser() applyButton = QToolButton(autoRaise=True) editButton = QToolButton(autoRaise=True) addButton = QToolButton(autoRaise=True) self.menuButton = QPushButton(flat=True) menu = QMenu(self.menuButton) self.menuButton.setMenu(menu) splitter = QSplitter(Qt.Vertical) top = QHBoxLayout() layout.addLayout(top) splitter.addWidget(self.treeView) splitter.addWidget(self.textView) layout.addWidget(splitter) splitter.setSizes([200, 100]) splitter.setCollapsible(0, False) top.addWidget(self.searchEntry) top.addWidget(applyButton) top.addSpacing(10) top.addWidget(addButton) top.addWidget(editButton) top.addWidget(self.menuButton) # action generator for actions added to search entry def act(slot, icon=None): a = QAction(self, triggered=slot) self.addAction(a) a.setShortcutContext(Qt.WidgetWithChildrenShortcut) icon and a.setIcon(icons.get(icon)) return a # hide if ESC pressed in lineedit a = act(self.slotEscapePressed) a.setShortcut(QKeySequence(Qt.Key_Escape)) # import action a = self.importAction = act(self.slotImport, 'document-open') menu.addAction(a) # export action a = self.exportAction = act(self.slotExport, 'document-save-as') menu.addAction(a) # apply button a = self.applyAction = act(self.slotApply, 'edit-paste') applyButton.setDefaultAction(a) menu.addSeparator() menu.addAction(a) # add button a = self.addAction_ = act(self.slotAdd, 'list-add') a.setShortcut(QKeySequence(Qt.Key_Insert)) addButton.setDefaultAction(a) menu.addSeparator() menu.addAction(a) # edit button a = self.editAction = act(self.slotEdit, 'document-edit') a.setShortcut(QKeySequence(Qt.Key_F2)) editButton.setDefaultAction(a) menu.addAction(a) # set shortcut action a = self.shortcutAction = act(self.slotShortcut, 'preferences-desktop-keyboard-shortcuts') menu.addAction(a) # delete action a = self.deleteAction = act(self.slotDelete, 'list-remove') a.setShortcut(QKeySequence(Qt.CTRL + Qt.Key_Delete)) menu.addAction(a) # restore action a = self.restoreAction = act(self.slotRestore) menu.addSeparator() menu.addAction(a) # help button a = self.helpAction = act(self.slotHelp, 'help-contents') menu.addSeparator() menu.addAction(a) self.treeView.setSelectionBehavior(QTreeView.SelectRows) self.treeView.setSelectionMode(QTreeView.ExtendedSelection) self.treeView.setRootIsDecorated(False) self.treeView.setAllColumnsShowFocus(True) self.treeView.setModel(model.model()) self.treeView.setCurrentIndex(QModelIndex()) # signals self.searchEntry.returnPressed.connect(self.slotReturnPressed) self.searchEntry.textChanged.connect(self.updateFilter) self.treeView.doubleClicked.connect(self.slotDoubleClicked) self.treeView.customContextMenuRequested.connect(self.showContextMenu) self.treeView.selectionModel().currentChanged.connect(self.updateText) self.treeView.model().dataChanged.connect(self.updateFilter) # highlight text self.highlighter = highlight.Highlighter(self.textView.document()) # complete on snippet variables self.searchEntry.setCompleter(QCompleter([ ':icon', ':indent', ':menu', ':name', ':python', ':selection', ':set', ':symbol', ':template', ':template-run'], self.searchEntry)) self.readSettings() app.settingsChanged.connect(self.readSettings) app.translateUI(self) self.updateColumnSizes() self.setAcceptDrops(True) def dropEvent(self, ev): if not ev.source() and ev.mimeData().hasUrls(): filename = ev.mimeData().urls()[0].toLocalFile() if filename: ev.accept() from . import import_export import_export.load(filename, self) def dragEnterEvent(self, ev): if not ev.source() and ev.mimeData().hasUrls(): ev.accept() def translateUI(self): try: self.searchEntry.setPlaceholderText(_("Search...")) except AttributeError: pass # not in Qt 4.6 shortcut = lambda a: a.shortcut().toString(QKeySequence.NativeText) self.menuButton.setText(_("&Menu")) self.addAction_.setText(_("&Add...")) self.addAction_.setToolTip( _("Add a new snippet. ({key})").format(key=shortcut(self.addAction_))) self.editAction.setText(_("&Edit...")) self.editAction.setToolTip( _("Edit the current snippet. ({key})").format(key=shortcut(self.editAction))) self.shortcutAction.setText(_("Configure Keyboard &Shortcut...")) self.deleteAction.setText(_("&Remove")) self.deleteAction.setToolTip(_("Remove the selected snippets.")) self.applyAction.setText(_("A&pply")) self.applyAction.setToolTip(_("Apply the current snippet.")) self.importAction.setText(_("&Import...")) self.importAction.setToolTip(_("Import snippets from a file.")) self.exportAction.setText(_("E&xport...")) self.exportAction.setToolTip(_("Export snippets to a file.")) self.restoreAction.setText(_("Restore &Built-in Snippets...")) self.restoreAction.setToolTip( _("Restore deleted or changed built-in snippets.")) self.helpAction.setText(_("&Help")) self.searchEntry.setToolTip(_( "Enter text to search in the snippets list.\n" "See \"What's This\" for more information.")) self.searchEntry.setWhatsThis(''.join(map("<p>{0}</p>\n".format, ( _("Enter text to search in the snippets list, and " "press Enter to apply the currently selected snippet."), _("If the search text fully matches the value of the '{name}' variable " "of a snippet, that snippet is selected.").format(name="name"), _("If the search text starts with a colon ':', the rest of the " "search text filters snippets that define the given variable. " "After a space a value can also be entered, snippets will then " "match if the value of the given variable contains the text after " "the space."), _("E.g. entering {menu} will show all snippets that are displayed " "in the insert menu.").format(menu="<code>:menu</code>"), )))) def sizeHint(self): return self.parent().mainwindow().size() / 4 def readSettings(self): data = textformats.formatData('editor') self.textView.setFont(data.font) self.textView.setPalette(data.palette()) def showContextMenu(self, pos): """Called when the user right-clicks the tree view.""" self.menuButton.menu().popup(self.treeView.viewport().mapToGlobal(pos)) def slotReturnPressed(self): """Called when the user presses Return in the search entry. Applies current snippet.""" name = self.currentSnippet() if name: view = self.parent().mainwindow().currentView() insert.insert(name, view) self.parent().hide() # make configurable? view.setFocus() def slotEscapePressed(self): """Called when the user presses ESC in the search entry. Hides the panel.""" self.parent().hide() self.parent().mainwindow().currentView().setFocus() def slotDoubleClicked(self, index): name = self.treeView.model().name(index) view = self.parent().mainwindow().currentView() insert.insert(name, view) def slotAdd(self): """Called when the user wants to add a new snippet.""" edit.Edit(self, None) def slotEdit(self): """Called when the user wants to edit a snippet.""" name = self.currentSnippet() if name: edit.Edit(self, name) def slotShortcut(self): """Called when the user selects the Configure Shortcut action.""" from widgets import shortcuteditdialog name = self.currentSnippet() if name: collection = self.parent().snippetActions action = actions.action(name, None, collection) default = collection.defaults().get(name) mgr = actioncollectionmanager.manager(self.parent().mainwindow()) cb = mgr.findShortcutConflict dlg = shortcuteditdialog.ShortcutEditDialog(self, cb, (collection, name)) if dlg.editAction(action, default): mgr.removeShortcuts(action.shortcuts()) collection.setShortcuts(name, action.shortcuts()) self.treeView.update() def slotDelete(self): """Called when the user wants to delete the selected rows.""" rows = sorted(set(i.row() for i in self.treeView.selectedIndexes()), reverse=True) if rows: for row in rows: name = self.treeView.model().names()[row] self.parent().snippetActions.setShortcuts(name, []) self.treeView.model().removeRow(row) self.updateFilter() def slotApply(self): """Called when the user clicks the apply button. Applies current snippet.""" name = self.currentSnippet() if name: view = self.parent().mainwindow().currentView() insert.insert(name, view) def slotImport(self): """Called when the user activates the import action.""" filetypes = "{0} (*.xml);;{1} (*)".format(_("XML Files"), _("All Files")) caption = app.caption(_("dialog title", "Import Snippets")) filename = None filename = QFileDialog.getOpenFileName(self, caption, filename, filetypes)[0] if filename: from . import import_export import_export.load(filename, self) def slotExport(self): """Called when the user activates the export action.""" allrows = [row for row in range(model.model().rowCount()) if not self.treeView.isRowHidden(row, QModelIndex())] selectedrows = [i.row() for i in self.treeView.selectedIndexes() if i.column() == 0 and i.row() in allrows] names = self.treeView.model().names() names = [names[row] for row in selectedrows or allrows] filetypes = "{0} (*.xml);;{1} (*)".format(_("XML Files"), _("All Files")) n = len(names) caption = app.caption(_("dialog title", "Export {num} Snippet", "Export {num} Snippets", n).format(num=n)) filename = QFileDialog.getSaveFileName(self, caption, None, filetypes)[0] if filename: from . import import_export try: import_export.save(names, filename) except (IOError, OSError) as e: QMessageBox.critical(self, _("Error"), _( "Can't write to destination:\n\n{url}\n\n{error}").format( url=filename, error=e.strerror)) def slotRestore(self): """Called when the user activates the Restore action.""" from . import restore dlg = restore.RestoreDialog(self) dlg.setWindowModality(Qt.WindowModal) dlg.populate() dlg.show() dlg.finished.connect(dlg.deleteLater) def slotHelp(self): """Called when the user clicks the small help button.""" userguide.show("snippets") def currentSnippet(self): """Returns the name of the current snippet if it is visible.""" row = self.treeView.currentIndex().row() if row != -1 and not self.treeView.isRowHidden(row, QModelIndex()): return self.treeView.model().names()[row] def updateFilter(self): """Called when the text in the entry changes, updates search results.""" text = self.searchEntry.text() ltext = text.lower() filterVars = text.startswith(':') if filterVars: try: fvar, fval = text[1:].split(None, 1) fhide = lambda v: v.get(fvar) in (True, None) or fval not in v.get(fvar) except ValueError: fvar = text[1:].strip() fhide = lambda v: not v.get(fvar) for row in range(self.treeView.model().rowCount()): name = self.treeView.model().names()[row] nameid = snippets.get(name).variables.get('name', '') if filterVars: hide = fhide(snippets.get(name).variables) elif nameid == text: i = self.treeView.model().createIndex(row, 0) self.treeView.selectionModel().setCurrentIndex(i, QItemSelectionModel.SelectCurrent | QItemSelectionModel.Rows) hide = False elif nameid.lower().startswith(ltext): hide = False elif ltext in snippets.title(name).lower(): hide = False else: hide = True self.treeView.setRowHidden(row, QModelIndex(), hide) self.updateText() def updateText(self): """Called when the current snippet changes.""" name = self.currentSnippet() self.textView.clear() if name: s = snippets.get(name) self.highlighter.setPython('python' in s.variables) self.textView.setPlainText(s.text) def updateColumnSizes(self): self.treeView.resizeColumnToContents(0) self.treeView.resizeColumnToContents(1)
class ImageViewer(QWidget): def __init__(self): super(ImageViewer, self).__init__() pal = QPalette() pal.setColor(QPalette.Background, Qt.lightGray) self.factor = 3.0 self.config = Config() self.currentRep = "" self.createActions() self.createToolbarMenus() #self.createMenus() self.browserFile() self.imgqLabel() self.boxSliders() self.verticalLayout = QVBoxLayout(self) self.horizontalLayout = QHBoxLayout(self) self.textInfo = QTextEdit() self.textInfoTop = QTextEdit() self.textInfoTop.setEnabled(True) self.textInfoTop.setSizePolicy(QSizePolicy.Expanding, QSizePolicy.Ignored) self.textInfoTop.setFontPointSize(11) self.textInfoTop.setStyleSheet("background-color: lightgray") #self.textInfoTop.adjustSize() self.textInfoTop.setText('Welcome to IRMaGe') self.tableJson = QTableWidget() self.tableJson.setColumnCount(2) self.tableJson.setColumnWidth(0, 150) self.tableJson.setColumnWidth(1, 400) self.tableJson.setSizeAdjustPolicy( QAbstractScrollArea.AdjustToContents) self.tableJson.setHorizontalHeaderLabels(['Keys', 'Values']) #self.tableJson.setBackgroundRole(QPalette.Light) self.scrollText = QScrollArea() self.scrollText.setBackgroundRole(QPalette.Dark) self.scrollText.setWidget(self.textInfoTop) self.scrollText.setWidgetResizable(True) #======================================================================= # self.adjustScrollBar(self.scrollText.horizontalScrollBar(), 1.0) # self.adjustScrollBar(self.scrollText.verticalScrollBar(), 2.0) #======================================================================= self.scrollTable = QScrollArea() self.scrollTable.setBackgroundRole(QPalette.Dark) self.scrollTable.setWidget(self.tableJson) self.scrollTable.setWidgetResizable(True) #======================================================================= # self.adjustScrollBar(self.scrollTable.horizontalScrollBar(), 2.0) # self.adjustScrollBar(self.scrollTable.verticalScrollBar(), 2.0) #======================================================================= self.headerTabData = [ 'Data', 'PatientName', 'StudyName', 'DateCreation', 'PatientSex', 'PatientWeight', 'ProtocolName', 'SequenceName' ] self.tableData = TableDataBrower(self) self.tableData.setColumnCount(8) self.tableData.setRowCount(10) self.tableData.setColumnWidth(0, 200) self.tableData.setHorizontalHeaderLabels(self.headerTabData) self.tableData.setBackgroundRole(QPalette.Light) self.tableData.setSizeAdjustPolicy( QAbstractScrollArea.AdjustToContents) self.tableData.verticalHeader().hide() self.scrollBrowser = QScrollArea() self.scrollBrowser.setBackgroundRole(QPalette.Dark) self.scrollBrowser.setWidget(self.tableData) self.scrollBrowser.setWidgetResizable(True) self.splitter0 = QSplitter(Qt.Vertical) self.splitter0.addWidget(self.scrollText) self.splitter0.addWidget(self.scrollTable) self.scrollArea = QScrollArea() self.scrollArea.setBackgroundRole(QPalette.Dark) self.scrollArea.setWidget(self.imageLabel) self.scrollArea.setWidgetResizable(False) self.scrollArea.setAlignment(Qt.AlignCenter) self.adjustScrollBar(self.scrollArea.horizontalScrollBar(), 0.8) self.adjustScrollBar(self.scrollArea.verticalScrollBar(), 1.0) self.splitter1 = QSplitter(Qt.Horizontal) self.splitter1.addWidget(self.splitter0) self.splitter1.addWidget(self.scrollArea) self.splitter1.addWidget(self.layoutSlide) self.splitter3 = QSplitter(Qt.Horizontal) self.splitter3.addWidget(self.browser) self.splitter3.addWidget(self.scrollBrowser) self.splitter2 = QSplitter(Qt.Vertical) self.splitter2.addWidget(self.splitter1) self.splitter2.addWidget(self.splitter3) self.splitter2.setHandleWidth(15) #======================================================================= # self.splitter2. #======================================================================= self.verticalLayout.addWidget(self.menuToolBar) self.verticalLayout.addWidget(self.splitter2) self.setWindowTitle("MRImage Viewer (IRMaGe)") self.resize(800, 600) self.setAutoFillBackground(True) self.setPalette(pal) def changeSel(self): print('Tab changed') def adjustScrollBar(self, scrollBar, factor): scrollBar.setValue( int(factor * scrollBar.value() + ((factor - 1) * scrollBar.pageStep() / 2))) def imgqLabel(self): QLabel.__init__(self) image = QImage('sources_images/LogoIRMaGe.png') self.scaleFactor = 1.0 self.imageLabel = QLabel() self.imageLabel.setBackgroundRole(QPalette.Base) self.imageLabel.setSizePolicy(QSizePolicy.Ignored, QSizePolicy.Ignored) self.imageLabel.setScaledContents(True) self.imageLabel.setPixmap(QPixmap.fromImage(image)) self.scaleFactor *= self.factor self.imageLabel.adjustSize() self.imageLabel.resize(self.scaleFactor * self.imageLabel.pixmap().size()) def open(self, filePath): self.img = nib.load(filePath) self.textInfoTop.setText('File : ' + filePath + '\n') self.textInfoTop.append('Dim : ' + str(self.img.shape) + '\n') self.enableSliders() self.a1.setValue(0) self.a2.setValue(0) self.a3.setValue(0) self.c2.setMaximum(self.img.shape[0]) self.c2.setMinimum(-self.img.shape[0]) self.c3.setMaximum(self.img.shape[1]) self.c3.setMinimum(-self.img.shape[1]) self.navigImage() self.fitToWindowAct.setEnabled(True) self.fitToWindow() def openJson(self, pathJson, fileName): with open(pathJson, 'r') as stream: try: json_object = json.load(stream) data = json.dumps(json_object, indent=0, sort_keys=True) data = json.loads(data) rowPosition = 0 self.tableJson.setRowCount(0) i = 0 for keyd in self.headerTabData: try: val = str(data[keyd]) val = val.replace('[', '') val = val.replace(']', '') except: val = '' #=========================================================== # self.tableData.insertRow(i) # self.tableData.setItem(0,i,QTableWidgetItem(val)) # i+=1 #=========================================================== #=============================================================== # self.tableData.setItem(0,0,QTableWidgetItem(fileName)) # self.tableData.selectRow(0) #=============================================================== for keys in data: stringValue = str(data[keys]) stringValue = stringValue.replace('[', '') stringValue = stringValue.replace(']', '') self.tableJson.insertRow(rowPosition) self.tableJson.setItem(rowPosition, 0, QTableWidgetItem(keys)) self.tableJson.setItem(rowPosition, 1, QTableWidgetItem(stringValue)) rowPosition += 1 self.tableJson.resizeColumnsToContents() except json.JSONDecodeError as exc: itemError = 'Error Json format' self.tableJson.setRowCount(0) self.tableJson.insertRow(0) self.tableJson.setItem(0, 0, QTableWidgetItem(itemError)) print(exc) def jsonParser(self, pathJson): with open(pathJson, 'r') as stream: try: json_object = json.load(stream) listTag = json.dumps(json_object, indent=0, sort_keys=True) listTag = json.loads(listTag) except json.JSONDecodeError as exc: itemError = 'Error Json format' return listTag def tableDataFill(self, pathRepertory): files = [f for f in fnmatch.filter(os.listdir(pathRepertory), '*.nii')] self.tableData.setRowCount(0) j = 0 for f in files: base = os.path.splitext(f)[0] g = os.path.join(pathRepertory, base + ".json") self.tableData.insertRow(j) if os.path.isfile(g): data = self.jsonParser(g) i = 0 for keyw in self.headerTabData: try: val = str(data[keyw]) val = val.replace('[', '') val = val.replace(']', '') except: val = '' self.tableData.setItem(j, i, QTableWidgetItem(val)) i += 1 else: self.tableData.setItem(j, 1, QTableWidgetItem('No json file found')) self.tableData.setItem(j, 0, QTableWidgetItem(f)) self.tableData.resizeColumnsToContents() j += 1 def indexImage(self): sl1 = self.a1.value() sl2 = self.a2.value() sl3 = self.a3.value() if len(self.img.shape) == 3: x = self.img.get_data()[:, :, sl1].copy() self.a1.setMaximum(self.img.shape[2] - 1) self.a2.setMaximum(0) self.a3.setMaximum(0) if len(self.img.shape) == 4: x = self.img.get_data()[:, :, sl1, sl2].copy() self.a1.setMaximum(self.img.shape[2] - 1) self.a2.setMaximum(self.img.shape[3] - 1) self.a3.setMaximum(0) if len(self.img.shape) == 5: x = self.img.get_data()[:, :, sl1, sl2, sl3].copy() self.a1.setMaximum(self.img.shape[2] - 1) self.a2.setMaximum(self.img.shape[3] - 1) self.a3.setMaximum(self.img.shape[4] - 1) x = rotate(x, -90, reshape=False) x = np.uint8((x - x.min()) / x.ptp() * 255.0) self.x = x ############################ Slice controls ######################################### def boxSliders(self): self.k1 = QLabel('Slider 1 ') self.k2 = QLabel('Slider 2') self.k3 = QLabel('Slider 3') self.a1 = self.createSlider(0, 0, 0) self.a2 = self.createSlider(0, 0, 0) self.a3 = self.createSlider(0, 0, 0) self.a1.valueChanged.connect(self.changePosValue) self.a2.valueChanged.connect(self.changePosValue) self.a3.valueChanged.connect(self.changePosValue) self.txta1 = self.createFieldValue() self.txta2 = self.createFieldValue() self.txta3 = self.createFieldValue() self.controlsGroup = QGroupBox('Slice Controls') gridCtrl = QGridLayout() gridCtrl.addWidget(self.k1, 0, 0) gridCtrl.addWidget(self.a1, 0, 1) gridCtrl.addWidget(self.txta1, 0, 2) gridCtrl.addWidget(self.k2, 1, 0) gridCtrl.addWidget(self.a2, 1, 1) gridCtrl.addWidget(self.txta2, 1, 2) gridCtrl.addWidget(self.k3, 2, 0) gridCtrl.addWidget(self.a3, 2, 1) gridCtrl.addWidget(self.txta3, 2, 2) self.controlsGroup.setLayout(gridCtrl) ############################ brightness and contrast ################################ self.txtb1 = self.createFieldValue() self.txtb2 = self.createFieldValue() self.txtb3 = self.createFieldValue() self.txtb4 = self.createFieldValue() self.l1 = QLabel('Brightness ') self.b1 = self.createSlider(101, 0, 50) self.l2 = QLabel('Contrast') self.b2 = self.createSlider(101, 0, 50) self.l3 = QLabel('Sharpness') self.b3 = self.createSlider(101, 0, 50) self.l4 = QLabel('Color') self.b4 = self.createSlider(101, 0, 50) self.b1.valueChanged.connect(self.changeContValue) self.b2.valueChanged.connect(self.changeContValue) self.b3.valueChanged.connect(self.changeContValue) self.b4.valueChanged.connect(self.changeContValue) self.txtb1.setText(str(0)) self.txtb2.setText(str(0)) self.txtb3.setText(str(0)) self.txtb4.setText(str(0)) self.buttonResetContrast = QPushButton('reset', self) self.buttonResetContrast.setToolTip('Reset all values') self.buttonResetContrast.setEnabled(False) self.buttonResetContrast.clicked.connect(self.resetValuesContrast) self.contrastGroup = QGroupBox('Brightness and Contrast') gridCont = QGridLayout() gridCont.addWidget(self.l1, 0, 0) gridCont.addWidget(self.b1, 0, 1) gridCont.addWidget(self.txtb1, 0, 2) gridCont.addWidget(self.l2, 1, 0) gridCont.addWidget(self.b2, 1, 1) gridCont.addWidget(self.txtb2, 1, 2) gridCont.addWidget(self.l3, 2, 0) gridCont.addWidget(self.b3, 2, 1) gridCont.addWidget(self.txtb3, 2, 2) gridCont.addWidget(self.l4, 3, 0) gridCont.addWidget(self.b4, 3, 1) gridCont.addWidget(self.txtb4, 3, 2) gridCont.addWidget(self.buttonResetContrast, 4, 2) self.contrastGroup.setLayout(gridCont) ############################ Transformation ######################################### self.txtc1 = self.createFieldValue() self.txtc2 = self.createFieldValue() self.txtc3 = self.createFieldValue() self.txtc4 = self.createFieldValue() self.m1 = QLabel('Rotation') self.c1 = self.createSlider(180, -180, 0) self.m2 = QLabel('Translate X ') self.c2 = self.createSlider(1, -1, 0) self.m3 = QLabel('Translate Y ') self.c3 = self.createSlider(1, -1, 0) self.m4 = QLabel('Resize') self.c4 = self.createSlider(10, 0, 0) self.c1.valueChanged.connect(self.changeTransValue) self.c2.valueChanged.connect(self.changeTransValue) self.c3.valueChanged.connect(self.changeTransValue) self.c4.valueChanged.connect(self.changeTransValue) self.txtc1.setText(str(0)) self.txtc2.setText(str(0)) self.txtc3.setText(str(0)) self.txtc4.setText(str(0)) self.buttonResetTransform = QPushButton('reset', self) self.buttonResetTransform.setToolTip('Reset all values') self.buttonResetTransform.setEnabled(False) self.buttonResetTransform.clicked.connect(self.resetValuesTransform) self.transformationGroup = QGroupBox('Transformations') gridTransf = QGridLayout() gridTransf.addWidget(self.m1, 0, 0) gridTransf.addWidget(self.c1, 0, 1) gridTransf.addWidget(self.txtc1, 0, 2) gridTransf.addWidget(self.m2, 1, 0) gridTransf.addWidget(self.c2, 1, 1) gridTransf.addWidget(self.txtc2, 1, 2) gridTransf.addWidget(self.m3, 2, 0) gridTransf.addWidget(self.c3, 2, 1) gridTransf.addWidget(self.txtc3, 2, 2) gridTransf.addWidget(self.m4, 3, 0) gridTransf.addWidget(self.c4, 3, 1) gridTransf.addWidget(self.txtc4, 3, 2) gridTransf.addWidget(self.buttonResetTransform, 4, 2) self.transformationGroup.setLayout(gridTransf) #################################################################################### self.layoutSliders = QVBoxLayout() self.layoutSliders.addWidget(self.controlsGroup) self.layoutSliders.addWidget(self.contrastGroup) self.layoutSliders.addWidget(self.transformationGroup) self.layoutSlide = QWidget() self.layoutSlide.setLayout(self.layoutSliders) def createSlider(self, maxm=0, minm=0, pos=0): slider = QSlider(Qt.Horizontal) slider.setFocusPolicy(Qt.StrongFocus) #slider.setTickPosition(QSlider.TicksBothSides) slider.setTickInterval(1) #slider.setSingleStep(1) slider.setMaximum(maxm) slider.setMinimum(minm) slider.setValue(pos) slider.setEnabled(False) return slider def createFieldValue(self): fieldValue = QLineEdit() fieldValue.setEnabled(False) fieldValue.setSizePolicy(QSizePolicy.Fixed, QSizePolicy.Fixed) return fieldValue def displayPosValue(self): self.txta1.setText( str(self.a1.value() + 1) + ' / ' + str(self.a1.maximum() + 1)) self.txta2.setText( str(self.a2.value() + 1) + ' / ' + str(self.a2.maximum() + 1)) self.txta3.setText( str(self.a3.value() + 1) + ' / ' + str(self.a3.maximum() + 1)) def changePosValue(self): self.navigImage() def navigImage(self): self.indexImage() self.displayPosValue() w, h = self.x.shape image = QImage(self.x.data, w, h, QImage.Format_Indexed8) self.pixm = QPixmap.fromImage(image) self.imageLabel.setPixmap(self.pixm) self.imageLabel.adjustSize() self.imageLabel.resize(self.scaleFactor * self.imageLabel.pixmap().size()) self.filter() def changeContValue(self): self.txtb1.setText(str(self.b1.value() - 50)) self.txtb2.setText(str(self.b2.value() - 50)) self.txtb3.setText(str(self.b3.value() - 50)) self.txtb4.setText(str(self.b4.value() - 50)) self.filter() def changeTransValue(self): self.txtc1.setText(str(self.c1.value())) self.txtc2.setText(str(self.c2.value())) self.txtc3.setText(str(self.c3.value())) self.txtc4.setText(str(self.c4.value())) self.filter() def filter(self): img = Image.fromarray(self.x, 'L') brightness = ImageEnhance.Brightness(img) newImg = brightness.enhance(1.2 * (self.b1.value() + 1) / 50.0) contrast = ImageEnhance.Contrast(newImg) newImg = contrast.enhance((self.b2.value() + 1) / 50.0) sharpness = ImageEnhance.Sharpness(newImg) newImg = sharpness.enhance(2.0 * (self.b3.value() + 1) / 50.0) color = ImageEnhance.Color(newImg) newImg = color.enhance((self.b4.value() + 1) / 50.0) newImg = newImg.rotate(self.c1.value()) newImg = newImg.transform( img.size, Image.AFFINE, (1, 0, self.c2.value(), 0, 1, self.c3.value())) size1 = int(img.size[0] * (self.c4.value() + 1)) size2 = int(img.size[1] * (self.c4.value() + 1)) newImg = newImg.resize((size1, size2), Image.ANTIALIAS) self.pixm = QPixmap.fromImage(newImg.toqimage()) self.imageLabel.setPixmap(self.pixm) self.imageLabel.adjustSize() self.imageLabel.resize(self.scaleFactor * self.imageLabel.pixmap().size()) def resetValuesContrast(self): self.b1.setSliderPosition(50) self.b2.setSliderPosition(50) self.b3.setSliderPosition(50) self.b4.setSliderPosition(50) self.changeContValue() def resetValuesTransform(self): self.c1.setSliderPosition(0) self.c2.setSliderPosition(0) self.c3.setSliderPosition(0) self.c4.setSliderPosition(0) self.changeTransValue() def enableSliders(self): self.a1.setEnabled(True) self.a2.setEnabled(True) self.a3.setEnabled(True) self.b1.setEnabled(True) self.b2.setEnabled(True) self.b3.setEnabled(True) self.b4.setEnabled(True) self.c1.setEnabled(True) self.c2.setEnabled(True) self.c3.setEnabled(True) self.c4.setEnabled(True) self.buttonResetContrast.setEnabled(True) self.buttonResetTransform.setEnabled(True) #################################################################################### def browserFile(self): global Browser, Model self.browser = QTreeView() model = QFileSystemModel() model.setNameFilters(['*.nii']) model.setNameFilterDisables(False) model.setReadOnly(True) self.browser.setModel(model) self.browser.expandAll() self.browser.setColumnWidth(0, 400) self.browser.selectionModel().selectionChanged.connect(self.select) Browser = self.browser Model = model #======================================================================= # self.browser.doubleClicked.connect(self.selection) #self.browser.clicked.connect(self.selection) #======================================================================= def select(self, signal): file_path = self.browser.model().filePath(signal.indexes()[0]) shortName, fileExt = os.path.splitext(file_path) filePath, fileName = os.path.split(file_path) self.textInfo.setText(filePath) blackColor = QColor(0, 0, 0) if os.path.isfile(file_path): if fileExt == ".nii": if self.currentRep != filePath: self.tableDataFill(filePath) self.currentRep = filePath self.open(file_path) self.tableData.selectRow( self.tableData.findItems(fileName, Qt.MatchExactly)[0].row()) if os.path.isfile(shortName + '.json'): greenColor = QColor(50, 150, 100) self.textInfoTop.setTextColor(greenColor) self.textInfoTop.append('Json file exists ' + '\n') self.openJson(shortName + '.json', fileName) else: redColor = QColor(255, 0, 0) self.textInfoTop.setTextColor(redColor) self.textInfoTop.append('Json file doesn\'t exist' + '\n') self.tableJson.setRowCount(0) else: self.tableData.setRowCount(0) self.currentRep = filePath self.textInfoTop.setTextColor(blackColor) self.scrollText.setWidgetResizable(True) #################################################################################### def createMenus(self): self.fileMenu = QMenu("&File", self) self.fileMenu.addAction(self.exitAct) self.viewMenu = QMenu("&View", self) self.viewMenu.addAction(self.zoomInAct) self.viewMenu.addAction(self.zoomOutAct) self.viewMenu.addAction(self.normalSizeAct) self.viewMenu.addSeparator() self.viewMenu.addAction(self.fitToWindowAct) self.viewMenu.addSeparator() self.helpMenu = QMenu("&Help", self) self.helpMenu.addAction(self.aboutAct) self.menuBar = QMenuBar() self.menuBar.addMenu(self.fileMenu) self.menuBar.addMenu(self.viewMenu) self.menuBar.addMenu(self.helpMenu) def createToolbarMenus(self): self.menuToolBar = QToolBar() viewMenu = QToolButton() viewMenu.setText('View') viewMenu.setPopupMode(QToolButton.MenuButtonPopup) aMenu = QMenu() aMenu.addAction(self.zoomInAct) aMenu.addAction(self.zoomOutAct) aMenu.addAction(self.normalSizeAct) aMenu.addSeparator() aMenu.addAction(self.fitToWindowAct) viewMenu.setMenu(aMenu) helpMenu = QToolButton() helpMenu.setText('Help') helpMenu.setPopupMode(QToolButton.MenuButtonPopup) bMenu = QMenu() helpMenu.setMenu(bMenu) self.menuToolBar.addWidget(viewMenu) self.menuToolBar.addWidget(helpMenu) def createActions(self): self.exitAct = QAction("Exit", self, shortcut="Ctrl+Q", triggered=self.close) self.zoomInAct = QAction("Zoom In (25%)", self, shortcut="Ctrl++", enabled=False, triggered=self.zoomIn) self.zoomOutAct = QAction("Zoom Out (25%)", self, shortcut="Ctrl+-", enabled=False, triggered=self.zoomOut) self.normalSizeAct = QAction("Normal Size", self, shortcut="Ctrl+S", enabled=False, triggered=self.normalSize) self.fitToWindowAct = QAction("Fit to Window", self, enabled=False, checkable=True, shortcut="Ctrl+F", triggered=self.fitToWindow) def zoomIn(self): self.factor = 1.25 self.scaleImage(self.factor) def zoomOut(self): self.factor = 0.8 self.scaleImage(self.factor) def normalSize(self): self.imageLabel.adjustSize() self.scaleFactor = 1.0 def fitToWindow(self): fitToWindow = self.fitToWindowAct.isChecked() self.scrollArea.setWidgetResizable(fitToWindow) self.scrollText.setWidgetResizable(fitToWindow) if not fitToWindow: self.normalSize() self.updateActions() def updateActions(self): self.zoomInAct.setEnabled(not self.fitToWindowAct.isChecked()) self.zoomOutAct.setEnabled(not self.fitToWindowAct.isChecked()) self.normalSizeAct.setEnabled(not self.fitToWindowAct.isChecked()) def scaleImage(self, factor): self.scaleFactor *= factor self.imageLabel.resize(self.scaleFactor * self.imageLabel.pixmap().size()) self.adjustScrollBar(self.scrollArea.horizontalScrollBar(), factor) self.adjustScrollBar(self.scrollArea.verticalScrollBar(), factor) self.zoomInAct.setEnabled(self.scaleFactor < 5.0) self.zoomOutAct.setEnabled(self.scaleFactor > 0.333) def close(self): self.close()
class OperacaoLogistica(QDialog): #TODO: Acertar formatação na listagem de items por SIMAFIC def __init__(self, parent=None): super().__init__(parent) self.setWindowFlags(Qt.WindowMinMaxButtonsHint | Qt.WindowCloseButtonHint) self.setWindowTitle('Operação Logística') self.setMinimumSize(QSize(h_size, v_size)) self.setWindowIcon(QIcon(main_icon)) verticalSpacer = QSpacerItem(40, 20, QSizePolicy.Minimum, QSizePolicy.Expanding) #Pedido Input Field self.proxy_list_result_id = QSortFilterProxyModel() self.numero_pedido = QLineEdit(self) self.numero_pedido.setPlaceholderText("Insira o Número do Pedido") self.numero_pedido.textChanged.connect( lambda wildcard: self.proxy_list_result_id.setFilterWildcard( wildcard)) #Voltar Btn self.voltar_btn = QPushButton(self) #self.voltar_btn.setStyleSheet('background-color: rgb(0,0,255); color: #fff') self.voltar_btn.setText('Voltar') self.voltar_btn.clicked.connect(self.goMainWindow) self.close() #Adicionar Cores no StyleSheet colors = ['##393318', ' ##fff'] self.pedidos = services.get_all_pedidos() self.item_result = None self.item_escolhido = None self.id_pedido_list = QListView() self.simafics_do_id = QListWidget() #self.simafics_do_id.setHidden(True) self.createPedidoIdList() self.id_pedido_list.clicked.connect( lambda id_pedido: self.createListaSimafics(id_pedido)) self.simafics_do_id.itemDoubleClicked.connect( lambda pedido: self.simaficSelecionado(pedido)) self.pedidos_label = QLabel() self.pedidos_label.setBuddy(self.id_pedido_list) self.simafic_label = QLabel() self.simafic_label.setBuddy(self.simafics_do_id) self.itensTree = PedidoItensTree() self.treeItensTV = QTreeView() self.treeItensTV.setEditTriggers(QAbstractItemView.NoEditTriggers) self.treeItensTV.setAlternatingRowColors(True) self.treeItensTV.setRootIsDecorated(True) self.treeItensTV.doubleClicked.connect(self.simaficSelecionado) self.treeItensTV.setColumnHidden(8, True) if len(self.pedidos) <= 0: self.pedidos_label.setText( "É necessário adicionar um pedido na tela de cadastro.") self.pedidos_label.setStyleSheet("QLabel { color: red; }") else: self.pedidos_label.setText("Listagem de Pedidos:") self.pedidos_label.setStyleSheet("QLabel { color: black; }") self.simafic_label.setText( "Selecione um pedido para ver a listagem de Itens por SIMAFIC:" ) self.simafic_label.setStyleSheet("QLabel { color: red; }") layout = QGridLayout() layout.setColumnStretch(0, 1) layout.setColumnStretch(1, 4) layout.addWidget(self.numero_pedido, 0, 0) layout.addWidget(self.voltar_btn, 0, 1) layout.addWidget(self.pedidos_label, 1, 0) layout.addWidget(self.simafic_label, 1, 1) layout.addWidget(self.id_pedido_list, 2, 0) layout.addWidget(self.treeItensTV, 2, 1) #layout.addWidget(self.simafics_do_id, 2,1) self.setLayout(layout) def createPedidoIdList(self): print('def createPedidoIdList(self):') onlyids = set() pedidosbyid = [] pedidosCompletos = [] self.proxy_list_result_id = QSortFilterProxyModel() for obj in self.pedidos: if obj.id_pedido not in onlyids: pedidosbyid.append(obj) onlyids.add(obj.id_pedido) self.pedidoId_model = QStringListModel(onlyids, self) self.proxy_list_result_id.setSourceModel(self.pedidoId_model) self.id_pedido_list.setModel(self.proxy_list_result_id) self.id_pedido_list.setAlternatingRowColors(True) self.id_pedido_list.setEditTriggers(QAbstractItemView.NoEditTriggers) def createListaSimafics(self, id_pedido): pedido = id_pedido.data() self.pedidosModel = self.itensTree.createPedidosModel(self.itensTree) self.treeItensTV.setModel(self.pedidosModel) print('def listaSimafics(self, id_pedido): {id_pedido}'.format( id_pedido=pedido)) self.item_result = None self.item_result = [x for x in self.pedidos if x.id_pedido == pedido] self.simafics_do_id.clear() self.pedidosModel.beginResetModel self.pedidosModel.modelReset self.pedidosModel.endResetModel for idx, item in enumerate(self.item_result): print(item) self.itensTree.addItens( self.pedidosModel, item.cod_simafic, item.desc, item.qty_scanneada, item.qty_total, item.nome_responsavel, item.id_caixa, item.time_updated.strftime("%d/%m/%y %H:%M:%S"), item.id_pedido, item) self.simafic_label.setText( "Listagem de Itens do pedido {} por SIMAFIC:".format(pedido)) self.simafic_label.setStyleSheet("QLabel { color: black; }") #self.simafics_do_id.setHidden(False) def simaficSelecionado(self, item): print(item.column(), item.row()) simafic_escolhido = self.treeItensTV.model().index(item.row(), 0).data() id_pedido = self.treeItensTV.model().index(item.row(), 7).data() self.item_escolhido = [ x for x in self.item_result if x.cod_simafic == simafic_escolhido and x.id_pedido == id_pedido ] self.cams = ItemScanner(self.item_escolhido[0]) self.cams.show() self.close() def goMainWindow(self): self.cams = mainView self.cams.show() self.close() def goScan(self): self.cams = ItemScanner("Eu sou o Pedido", "Eu sou o Simafic", "Eu sou a Descrição", "300") self.cams.show() self.close()
class LeftSideBar(QWidget): treeViewSelectionChanged = pyqtSignal(QModelIndex, QModelIndex) treeViewDoubleClicked = pyqtSignal(QModelIndex) addPlaylistRequested = pyqtSignal() removePlaylistRequested = pyqtSignal(UUID) addToPlaylistRequested = pyqtSignal(UUID) playlistAdded = pyqtSignal(UUID) playlistRenamed = pyqtSignal(UUID, str) def __init__(self, tree_items, parent=None): super(LeftSideBar, self).__init__(parent) self._tree_items = tree_items self._restoreSettings() self._setTreeView() self._setAlbumCoverBox() self._renderUI() self.setMinimumWidth(FRONT_COVER_MIN_WIDTH) self.setMaximumWidth(FRONT_COVER_MAX_WIDTH) def _restoreSettings(self): pass def _setTreeView(self): self.treeModel = TreeModel() self.treeModel.addTopLevelItems(self._tree_items.keys()) self.leftBarView = QTreeView() self.leftBarView.setModel(self.treeModel) self.leftBarView.setHeaderHidden(True) self.leftBarView.setRootIsDecorated(False) self.leftBarView.setItemsExpandable(False) self.leftBarView.setMouseTracking(True) self.leftBarView.expandAll() self.leftBarView.setFocusPolicy(Qt.NoFocus) self.leftBarView.setSelectionBehavior(QAbstractItemView.SelectRows) self.leftBarView.setSelectionMode(QAbstractItemView.SingleSelection) self.leftBarView.setEditTriggers(QAbstractItemView.SelectedClicked) self.leftBarView.selectionModel().currentRowChanged.connect( lambda c, p: self.treeViewSelectionChanged.emit(c, p)) self.leftBarView.selectionModel().setCurrentIndex( self.leftBarView.model().index( 0, 0, self.leftBarView.model().index(0, 0)), QItemSelectionModel.Select) self.leftBarView.doubleClicked.connect( lambda i: self.treeViewDoubleClicked.emit(i)) delegate = LeftSideBarDelegate(self.leftBarView) self.leftBarView.setItemDelegate(delegate) delegate.addPlaylistRequested.connect( lambda: self.addPlaylistRequested.emit()) delegate.removePlaylistRequested.connect( lambda i: self.removePlaylistRequested.emit( self.__getUuidFromIndex(i))) delegate.addToPlaylistRequested.connect( lambda i: self.addToPlaylistRequested.emit(self.__getUuidFromIndex(i))) delegate.editingFinished.connect(self._onRenamed) def _onRenamed(self, index, text): self.playlistRenamed.emit( self.__getUuidFromIndex(index), text) @property def model(self): return self.treeModel def _setAlbumCoverBox(self): self.albumCoverBox = CoverArtBox() def _renderUI(self): self.layout = QVBoxLayout() self.layout.setContentsMargins(0, 0, 0, 0) self.layout.setSpacing(0) self.layout.addWidget(self.leftBarView) self.layout.addWidget(self.albumCoverBox) self.setLayout(self.layout) @QtCore.pyqtSlot(str, str, bytes) def changeCoverArtBoxInformation(self, title, artist, cover): self.albumCoverBox.setCoverArtBox(title, artist, cover) @QtCore.pyqtSlot(UUID, str, int, int) def addPlaylistEntry(self, uuid, name, row=0, column=0): model = self.model parent = model.getTopLevelIndex('PLAYLISTS') if model.insertPlaylistEntry(row, name, uuid, parent): self.playlistAdded.emit(uuid) child = model.index(row, column, parent) self.leftBarView.selectionModel().setCurrentIndex( child, QItemSelectionModel.SelectCurrent) self.leftBarView.edit(child) @QtCore.pyqtSlot(UUID, int, int) def createDefaults(self, uuid, row=0, column=0): model = self.model parent = model.getTopLevelIndex('LIBRARY') model.insertPlaylistEntry(row, 'Songs', uuid, parent) def __getUuidFromIndex(self, index): model = self.model uuid = model.getItemUuid(index) return uuid def __getIndexFromUuid(self, uuid): model = self.model row = model.getIndexFromUuid(uuid) return row @QtCore.pyqtSlot(UUID) def removePlaylistEntry(self, uuid): model = self.model row = self.__getIndexFromUuid(uuid) parent = model.getTopLevelIndex('PLAYLISTS') if not model.removeRow(row, parent): return None
class PropertyWidget(QWidget): def __init__(self, itemView, parent=None): super(PropertyWidget, self).__init__(parent) self.itemView = itemView self.currentRow = None # labels nameLabel = QLabel("Title") fileLabel = QLabel("Source path") groupLabel = QLabel("Group") # line edit self.nameEdit = QLineEdit() self.pathEdit = QLineEdit() self.groupEdit = QLineEdit() self.noteEdit = QTextEdit() # buttons self.browseButton = QToolButton(self) self.browseButton.setToolButtonStyle(Qt.ToolButtonTextOnly) self.browseButton.setArrowType(Qt.DownArrow) self.browseButton.setPopupMode(QToolButton.MenuButtonPopup) self.browseButton.setText('Browse...') self.browseButton.setAutoRaise(True) menu = QMenu(self) menu.addAction('Browse Path', lambda: self.slot_browse(0)) menu.addAction('Browse file', lambda: self.slot_browse(1)) self.browseButton.setMenu(menu) # dir tree self.tree = QTreeView() self.tree.setAnimated(False) self.tree.setIndentation(20) self.tree.setSortingEnabled(True) model = QFileSystemModel() self.tree.setModel(model) self.tree.header().setSectionResizeMode(QHeaderView.ResizeToContents) # tree and comments tabs self.tabWidget = QTabWidget() self.tabWidget.addTab(self.tree, "Navigation") self.tabWidget.addTab(self.noteEdit, "Comments") # set layout mainLayout = QGridLayout() mainLayout.addWidget(nameLabel, 0, 0) # title mainLayout.addWidget(self.nameEdit, 0, 1, 1, 2) mainLayout.addWidget(fileLabel, 1, 0) # path mainLayout.addWidget(self.pathEdit, 1, 1) mainLayout.addWidget(self.browseButton, 1, 2) mainLayout.addWidget(groupLabel, 2, 0) # group mainLayout.addWidget(self.groupEdit, 2, 1, 1, 2) mainLayout.addWidget(self.tabWidget, 3, 0, 1, 3) self.setLayout(mainLayout) # initial status self.tabWidget.setTabEnabled(0, False) self.pathEdit.setEnabled(False) self.groupEdit.setEnabled(False) # signals self.nameEdit.textChanged.connect(self.slot_saveItem) self.pathEdit.textChanged.connect(self.slot_saveItem) self.noteEdit.textChanged.connect(self.slot_saveItem) self.tree.doubleClicked.connect(self.slot_openSource) @staticmethod def setTextSafely(textEdit, value): textEdit.blockSignals(True) textEdit.setText(value) textEdit.blockSignals(False) def setEditorsEnbaled(self, enabled=True): self.nameEdit.setEnabled(enabled) self.noteEdit.setEnabled(enabled) self.browseButton.setEnabled(enabled) def setup(self, index, data): '''set data :param index: index of source model, so the following process should also apply on source model, rather than proxy model by default ''' self.setEditorsEnbaled(True) self.currentRow = index.row() if index else None name, group, path, comments = data self.setTextSafely(self.nameEdit, name) self.setTextSafely(self.pathEdit, path) self.setTextSafely(self.groupEdit, group) self.setTextSafely(self.noteEdit, comments) self.updateTree(path) # set dir tree status def slot_saveItem(self): '''save when changed''' editor = self.sender() if editor == self.nameEdit: value = self.nameEdit.text() col = ItemModel.NAME elif editor == self.pathEdit: value = self.pathEdit.text() col = ItemModel.PATH elif editor == self.noteEdit: value = self.noteEdit.toPlainText() col = ItemModel.NOTES else: return # update values model = self.itemView.model().sourceModel() index = model.index(self.currentRow, col) if index.isValid(): model.setData(index, value) # update unreferenced status if path is updated: # move item to UNGROUPED if current group is UNREFERENCED if editor == self.pathEdit: group_index = model.index(self.currentRow, ItemModel.GROUP) if group_index.data() == GroupModel.UNREFERENCED: model.setData(group_index, GroupModel.UNGROUPED) def slot_openSource(self, index): '''open source file/folder from navigation tree''' path = self.tree.model().filePath(index) QDesktopServices.openUrl(QUrl.fromLocalFile(path)) def slot_browse(self, path_type): if path_type == 0: path = QFileDialog.getExistingDirectory(self, "Select directory...") else: path, _ = QFileDialog.getOpenFileName(self, "Select file...") if path: self.pathEdit.setText(path) if not self.nameEdit.text(): self.nameEdit.setText(os.path.basename(path)) # update dir tree self.updateTree(path) def updateTree(self, path): '''show dir tree if directory else set disabled''' if os.path.isdir(path): # set root path model = self.tree.model() model.setRootPath(path) self.tree.setRootIndex(model.index(path)) # activate tree tab self.tabWidget.setTabEnabled(0, True) self.tabWidget.setCurrentIndex(0) else: self.tabWidget.setTabEnabled(0, False)