class FileSystemView(QWidget): def __init__(self, dir_path): super().__init__() # appWidth = 800 # appHeight = 300 self.setWindowTitle('File System Viewer') # self.setGeometry(300, 300, appWidth, appHeight) self.model = QFileSystemModel() self.model.setRootPath(dir_path) self.tree = QTreeView() self.tree.setModel(self.model) self.tree.setRootIndex(self.model.index(dir_path)) self.tree.setColumnWidth(0, 250) self.tree.setAlternatingRowColors(True) layout = QVBoxLayout() layout.addWidget(self.tree) self.setLayout(layout)
class MainWindow(QMainWindow): def __init__(self, app): super(MainWindow, self).__init__() self._app = app self._selectedIndex = None # model nodeFactory = NodeFactory() rootNode = nodeFactory.create(NodeType.General, 'Root') # for i in range(10000): # for testing childNode0 = nodeFactory.create(NodeType.General, 'RightPirateLeg', rootNode) childNode1 = nodeFactory.create(NodeType.General, 'RightPirateLeg_END', childNode0) childNode2 = nodeFactory.create(NodeType.General, 'LeftFemur', rootNode) childNode3 = nodeFactory.create(NodeType.Sphere, 'LeftTibia', childNode2) childNode4 = nodeFactory.create(NodeType.Sphere, 'LeftFoot', childNode3) transform = childNode4.component(ComponentType.Transform) qTransform = transform.component() translation = qTransform.translation() translation.setX(5) qTransform.setTranslation(translation) # childNode5 = nodeFactory.create(NodeType.Box, 'LeftFoot_END', childNode4) self._model = SceneGraphModel(rootNode) self._sceneView = SceneView(rootNode.entity()) self._container = self.createWindowContainer(self._sceneView) # scene graph view self._treeView = QTreeView() self._treeView.setModel(self._model) self._treeView.setHeaderHidden(True) self._treeView.setAlternatingRowColors(True) dockWidget = QDockWidget() dockWidget.setWidget(self._treeView) dockWidget.setWindowTitle('Scene Graph') dockWidget.setObjectName('sceneGraph') sceneGraphToggleAction = dockWidget.toggleViewAction() self.addDockWidget(Qt.LeftDockWidgetArea, dockWidget) # property editor propertyEditor = PropertyEditor(self._model, nodeFactory, FieldFactory()) dockWidget = QDockWidget() dockWidget.setWidget(propertyEditor) dockWidget.setWindowTitle('Property Editor') dockWidget.setObjectName('propertyEditor') propertyEditorToggleAction = dockWidget.toggleViewAction() self.addDockWidget(Qt.RightDockWidgetArea, dockWidget) # menu menuBar = self.menuBar() menu = menuBar.addMenu('&File') exitAction = menu.addAction('E&xit') exitAction.triggered.connect(self.close) menu.addAction(exitAction) menu = menuBar.addMenu('&Windows') menu.addAction(sceneGraphToggleAction) menu.addAction(propertyEditorToggleAction) menuBar.addMenu(menu) # central widget #button = QPushButton() self.setCentralWidget(self._container) # selection change event selectionModel = self._treeView.selectionModel() selectionModel.currentChanged.connect(propertyEditor.changeSelection) # click event #button.clicked.connect(self.buttonClicked) def selectedNode(self): indices = self._treeView.selectedIndexes() result = None if len(indices) == 1: self._selectedIndex = indices[0] result = self._selectedIndex.internalPointer() return result def commitChange(self): self._model.dataChanged.emit(self._selectedIndex, self._selectedIndex) def closeEvent(self, event): self._app.exit() # data change example def buttonClicked(self): node = self.selectedNode() if not node: return general = node.component(ComponentType.General) general.setName('CLICKED') self.commitChange()
class MyWidget(QtWidgets.QWidget): @Slot() def run_report(self): dialog = ReportNameDialog() if dialog.exec_(): metadata_fields = {} item_model = self.list.model() for i in range(item_model.rowCount()): qmodel_index = item_model.index(i, 0) index_name = item_model.item(i, 0).text() if item_model.itemData(qmodel_index).get(10) == 2: metadata_fields[index_name] = "" if hasattr(item_model.item(i, 1), "text"): index_value = item_model.item(i, 1).text() if index_name == DOCUMENT_TYPE: if index_value == TYPE_ASSET: index_value = "IO" if index_value == TYPE_FOLDER: index_value = "SO" if index_value == TYPE_ANY: index_value = "" metadata_fields[index_name] = index_value self.progress = QProgressDialog( "Creating Report\n\nPlease Wait...", None, 0, 100) self.progress.setModal(True) self.progress.setWindowTitle("Report") self.progress.setAutoClose(True) self.progress.setAutoReset(True) self.callback = CallBack() worker = Worker(self.client, self.search_value.text(), dialog.report(), metadata_fields, self.callback, dialog.auto_report()) self.callback.change_value.connect(self.progress.setValue) self.callback.max_value.connect(self.progress.setMaximum) self.callback.reset_dialog.connect(self.progress.reset) self.threadpool.start(worker) self.progress.show() def __init__(self): super().__init__() self.threadpool = QThreadPool() self.threadpool.setMaxThreadCount(1) self.setWindowTitle("Preservica Solr Reporting") self.windowModality() self.progress = None self.callback = None self.search_label = QtWidgets.QLabel( "Main Search Term (% returns everything)") self.search_value = QtWidgets.QLineEdit("%") self.help_label = QtWidgets.QLabel( "Select from the list of indexed fields below to " "add columns to the output spreadsheet\n\n" "Indexes can have an optional filter term. Filters " "are only applied to selected fields") self.list = QTreeView() self.list.setSelectionBehavior(QAbstractItemView.SelectRows) model = QStandardItemModel() model.setHorizontalHeaderLabels(['Index Name', 'Index Filter Term']) self.list.setModel(model) self.list.setUniformRowHeights(True) self.list.setAlternatingRowColors(True) self.list.setColumnWidth(0, 350) self.list.setColumnWidth(1, 250) self.list.setItemDelegateForColumn( 1, ComboDelegate(self.list, DOCUMENT_TYPE, model)) if not os.path.isfile("credentials.properties"): dialog = PasswordDialog() if dialog.exec_(): self.client = ContentAPI(dialog.username(), dialog.password(), dialog.tenant(), dialog.server()) else: raise SystemExit else: self.client = ContentAPI() for index_name in self.client.indexed_fields(): if index_name == "xip.full_text": continue index = QStandardItem(index_name) index.setCheckable(True) index.setEditable(False) model.appendRow([index]) self.run_report_button = QtWidgets.QPushButton("Run Report") self.run_report_button.released.connect(self.run_report) self.list.setModel(model) self.layout = QtWidgets.QVBoxLayout() self.layout.addWidget(self.search_label) self.layout.addWidget(self.search_value) self.layout.addWidget(self.help_label) self.layout.addWidget(self.list) self.layout.addWidget(self.run_report_button) self.setLayout(self.layout)
class Window(QWidget): def __init__(self): super(Window, self).__init__() self.proxyModel = SortFilterProxyModel() self.proxyModel.setDynamicSortFilter(True) self.sourceGroupBox = QGroupBox("Original Model") self.proxyGroupBox = QGroupBox("Sorted/Filtered Model") self.sourceView = QTreeView() self.sourceView.setRootIsDecorated(False) self.sourceView.setAlternatingRowColors(True) self.proxyView = QTreeView() self.proxyView.setRootIsDecorated(False) self.proxyView.setAlternatingRowColors(True) self.proxyView.setModel(self.proxyModel) self.proxyView.setSortingEnabled(True) self.sortCaseSensitivityCheckBox = QCheckBox("Case sensitive sorting") self.filterCaseSensitivityCheckBox = QCheckBox("Case sensitive filter") self.filterPatternLineEdit = QLineEdit() self.filterPatternLabel = QLabel("&Filter pattern:") self.filterPatternLabel.setBuddy(self.filterPatternLineEdit) self.filterSyntaxComboBox = QComboBox() self.filterSyntaxComboBox.addItem("Regular expression", QRegExp.RegExp) self.filterSyntaxComboBox.addItem("Wildcard", QRegExp.Wildcard) self.filterSyntaxComboBox.addItem("Fixed string", QRegExp.FixedString) self.filterSyntaxLabel = QLabel("Filter &syntax:") self.filterSyntaxLabel.setBuddy(self.filterSyntaxComboBox) self.filterColumnComboBox = QComboBox() self.filterColumnComboBox.addItem("Subject") self.filterColumnComboBox.addItem("Sender") self.filterColumnComboBox.addItem("Date") self.filterColumnLabel = QLabel("Filter &column:") self.filterColumnLabel.setBuddy(self.filterColumnComboBox) self.filterPatternLineEdit.textChanged.connect( self.filterRegExpChanged) self.filterSyntaxComboBox.currentIndexChanged.connect( self.filterRegExpChanged) self.filterColumnComboBox.currentIndexChanged.connect( self.filterColumnChanged) self.filterCaseSensitivityCheckBox.toggled.connect( self.filterRegExpChanged) self.sortCaseSensitivityCheckBox.toggled.connect(self.sortChanged) sourceLayout = QHBoxLayout() sourceLayout.addWidget(self.sourceView) self.sourceGroupBox.setLayout(sourceLayout) proxyLayout = QGridLayout() proxyLayout.addWidget(self.proxyView, 0, 0, 1, 3) proxyLayout.addWidget(self.filterPatternLabel, 1, 0) proxyLayout.addWidget(self.filterPatternLineEdit, 1, 1, 1, 2) proxyLayout.addWidget(self.filterSyntaxLabel, 2, 0) proxyLayout.addWidget(self.filterSyntaxComboBox, 2, 1, 1, 2) proxyLayout.addWidget(self.filterColumnLabel, 3, 0) proxyLayout.addWidget(self.filterColumnComboBox, 3, 1, 1, 2) proxyLayout.addWidget(self.filterCaseSensitivityCheckBox, 4, 0, 1, 2) proxyLayout.addWidget(self.sortCaseSensitivityCheckBox, 4, 2) self.proxyGroupBox.setLayout(proxyLayout) mainLayout = QVBoxLayout() mainLayout.addWidget(self.sourceGroupBox) mainLayout.addWidget(self.proxyGroupBox) self.setLayout(mainLayout) self.setWindowTitle("Basic Sort/Filter Model") self.resize(500, 450) self.proxyView.sortByColumn(SENDER, Qt.AscendingOrder) self.filterColumnComboBox.setCurrentIndex(SENDER) self.filterPatternLineEdit.setText("Andy|Grace") self.filterCaseSensitivityCheckBox.setChecked(True) self.sortCaseSensitivityCheckBox.setChecked(True) def setSourceModel(self, model): self.proxyModel.setSourceModel(model) self.sourceView.setModel(model) def filterRegExpChanged(self): syntax_nr = self.filterSyntaxComboBox.itemData( self.filterSyntaxComboBox.currentIndex()) syntax = QRegExp.PatternSyntax(syntax_nr) if self.filterCaseSensitivityCheckBox.isChecked(): caseSensitivity = Qt.CaseSensitive else: caseSensitivity = Qt.CaseInsensitive regExp = QRegExp(self.filterPatternLineEdit.text(), caseSensitivity, syntax) self.proxyModel.setFilterRegExp(regExp) def filterColumnChanged(self): self.proxyModel.setFilterKeyColumn( self.filterColumnComboBox.currentIndex()) def sortChanged(self): if self.sortCaseSensitivityCheckBox.isChecked(): caseSensitivity = Qt.CaseSensitive else: caseSensitivity = Qt.CaseInsensitive self.proxyModel.setSortCaseSensitivity(caseSensitivity)
def create_ui(self): """Setup main UI elements, dock widgets, UI-related elements, etc. """ log.debug('Loading UI') # Undo Stack self.undo_stack = QUndoStack(self) self.undo_stack.setUndoLimit(100) # Object navigation history self.obj_history = deque([], config.MAX_OBJ_HISTORY) app = QApplication.instance() base_font = QFont() base_font.fromString(self.prefs['base_font']) app.setFont(base_font) # Object class table widget # classTable = QTableView(self) classTable = classtable.TableView(self) classTable.setObjectName("classTable") classTable.setAlternatingRowColors(True) classTable.setFrameShape(QFrame.StyledPanel) classTable_font = QFont() classTable_font.fromString(self.prefs['class_table_font']) classTable.setFont(classTable_font) fm = classTable.fontMetrics() classTable.setWordWrap(True) classTable.setEditTriggers(QAbstractItemView.EditKeyPressed | QAbstractItemView.DoubleClicked | QAbstractItemView.AnyKeyPressed | QAbstractItemView.SelectedClicked) # classTable.horizontalHeader().setMovable(True) # classTable.verticalHeader().setMovable(False) classTable.horizontalHeader().setSectionResizeMode(QHeaderView.Interactive) classTable.verticalHeader().setSectionResizeMode(QHeaderView.Interactive) classTable.horizontalHeader().setDefaultSectionSize(self.prefs['default_column_width']) classTable.verticalHeader().setDefaultSectionSize(fm.height() + 0) classTable.setSelectionMode(QAbstractItemView.ExtendedSelection) classTable.setContextMenuPolicy(Qt.CustomContextMenu) classTable.customContextMenuRequested.connect(self.custom_table_context_menu) # Create table model and proxy layers for transposing and filtering self.classTableModel = classtable.IDFObjectTableModel(classTable) self.transposeableModel = classtable.TransposeProxyModel(self.classTableModel) self.transposeableModel.setSourceModel(self.classTableModel) self.sortableModel = classtable.SortFilterProxyModel(self.transposeableModel) self.sortableModel.setSourceModel(self.transposeableModel) # Assign model to table (enable sorting FIRST) # table.setSortingEnabled(True) # Disable for now, CRUD actions won't work! classTable.setModel(self.sortableModel) # Connect some signals selection_model = classTable.selectionModel() selection_model.selectionChanged.connect(self.table_selection_changed) scroll_bar = classTable.verticalScrollBar() scroll_bar.valueChanged.connect(self.scroll_changed) # These are currently broken # classTable.horizontalHeader().sectionMoved.connect(self.moveObject) # classTable.verticalHeader().sectionMoved.connect(self.moveObject) # Object class tree widget classTreeDockWidget = QDockWidget("Object Classes and Counts", self) classTreeDockWidget.setObjectName("classTreeDockWidget") classTreeDockWidget.setAllowedAreas(Qt.AllDockWidgetAreas) classTree = QTreeView(classTreeDockWidget) classTree.setUniformRowHeights(True) classTree.setAllColumnsShowFocus(True) classTree.setRootIsDecorated(False) classTree.setExpandsOnDoubleClick(True) classTree.setIndentation(15) classTree.setAnimated(True) classTree_font = QFont() classTree_font.fromString(self.prefs['class_tree_font']) classTree.setFont(classTree_font) classTree.setAlternatingRowColors(True) classTree.setHorizontalScrollMode(QAbstractItemView.ScrollPerPixel) palette = classTree.palette() palette.setColor(QPalette.Highlight, Qt.darkCyan) classTree.setPalette(palette) class_tree_window = QWidget(classTreeDockWidget) class_tree_dock_layout_v = QVBoxLayout() class_tree_dock_layout_h = QHBoxLayout() class_tree_dock_layout_v.setContentsMargins(0, 8, 0, 0) class_tree_dock_layout_h.setContentsMargins(0, 0, 0, 0) class_tree_filter_edit = QLineEdit(classTreeDockWidget) class_tree_filter_edit.setPlaceholderText("Filter Classes") class_tree_filter_edit.textChanged.connect(self.treeFilterRegExpChanged) class_tree_filter_cancel = QPushButton("Clear", classTreeDockWidget) class_tree_filter_cancel.setMaximumWidth(45) class_tree_filter_cancel.clicked.connect(self.clearTreeFilterClicked) class_tree_dock_layout_h.addWidget(class_tree_filter_edit) class_tree_dock_layout_h.addWidget(class_tree_filter_cancel) class_tree_dock_layout_v.addLayout(class_tree_dock_layout_h) class_tree_dock_layout_v.addWidget(classTree) class_tree_window.setLayout(class_tree_dock_layout_v) classTreeDockWidget.setWidget(class_tree_window) classTreeDockWidget.setContentsMargins(0,0,0,0) # Comments widget commentDockWidget = QDockWidget("Comments", self) commentDockWidget.setObjectName("commentDockWidget") commentDockWidget.setAllowedAreas(Qt.AllDockWidgetAreas) commentView = UndoRedoTextEdit(commentDockWidget, self) commentView.setLineWrapMode(QTextEdit.FixedColumnWidth) commentView.setLineWrapColumnOrWidth(499) commentView.setFrameShape(QFrame.StyledPanel) commentView_font = QFont() commentView_font.fromString(self.prefs['comments_font']) commentView.setFont(commentView_font) commentDockWidget.setWidget(commentView) # Info and help widget infoDockWidget = QDockWidget("Info", self) infoDockWidget.setObjectName("infoDockWidget") infoDockWidget.setAllowedAreas(Qt.AllDockWidgetAreas) infoView = QTextEdit(infoDockWidget) infoView.setFrameShape(QFrame.StyledPanel) infoView.setReadOnly(True) infoDockWidget.setWidget(infoView) # Node list and jump menu widget refDockWidget = QDockWidget("Field References", self) refDockWidget.setObjectName("refDockWidget") refDockWidget.setAllowedAreas(Qt.AllDockWidgetAreas) ref_model = reftree.ReferenceTreeModel(None, refDockWidget) refView = QTreeView(refDockWidget) refView.setModel(ref_model) refView.setUniformRowHeights(True) refView.setRootIsDecorated(False) refView.setIndentation(15) refView.setColumnWidth(0, 160) refView.setFrameShape(QFrame.StyledPanel) refDockWidget.setWidget(refView) refView.doubleClicked.connect(self.ref_tree_double_clicked) # Logging and debugging widget logDockWidget = QDockWidget("Log Viewer", self) logDockWidget.setObjectName("logDockWidget") logDockWidget.setAllowedAreas(Qt.AllDockWidgetAreas) logView = QPlainTextEdit(logDockWidget) logView.setLineWrapMode(QPlainTextEdit.NoWrap) logView.setReadOnly(True) logView_font = QFont() logView_font.fromString(self.prefs['base_font']) logView.setFont(logView_font) logView.ensureCursorVisible() logDockWidget.setWidget(logView) # Undo view widget undoDockWidget = QDockWidget("Undo History", self) undoDockWidget.setObjectName("undoDockWidget") undoDockWidget.setAllowedAreas(Qt.AllDockWidgetAreas) undoView = QUndoView(self.undo_stack) undoDockWidget.setWidget(undoView) # Define corner docking behaviour self.setDockNestingEnabled(True) self.setCorner(Qt.TopLeftCorner, Qt.LeftDockWidgetArea) self.setCorner(Qt.TopRightCorner, Qt.RightDockWidgetArea) self.setCorner(Qt.BottomLeftCorner, Qt.LeftDockWidgetArea) self.setCorner(Qt.BottomRightCorner, Qt.RightDockWidgetArea) # Assign main widget and dock widgets to QMainWindow self.setCentralWidget(classTable) self.addDockWidget(Qt.LeftDockWidgetArea, classTreeDockWidget) self.addDockWidget(Qt.RightDockWidgetArea, commentDockWidget) self.addDockWidget(Qt.RightDockWidgetArea, infoDockWidget) self.addDockWidget(Qt.RightDockWidgetArea, refDockWidget) self.addDockWidget(Qt.RightDockWidgetArea, logDockWidget) self.addDockWidget(Qt.RightDockWidgetArea, undoDockWidget) # Store widgets for access by other objects self.classTable = classTable self.commentView = commentView self.infoView = infoView self.classTree = classTree self.logView = logView self.undoView = undoView self.refView = refView self.filterTreeBox = class_tree_filter_edit # Store docks for access by other objects self.commentDockWidget = commentDockWidget self.infoDockWidget = infoDockWidget self.classTreeDockWidget = classTreeDockWidget self.logDockWidget = logDockWidget self.undoDockWidget = undoDockWidget self.refDockWidget = refDockWidget # Perform other UI-related initialization tasks self.center() self.setUnifiedTitleAndToolBarOnMac(True) self.setWindowIcon(QIcon(':/images/logo.png')) # Status bar setup self.statusBar().showMessage('Status: Ready') self.unitsLabel = QLabel() self.unitsLabel.setAlignment(Qt.AlignCenter) self.unitsLabel.setMinimumSize(self.unitsLabel.sizeHint()) self.unitsLabel.setFrameStyle(QFrame.StyledPanel | QFrame.Sunken) self.statusBar().addPermanentWidget(self.unitsLabel) self.pathLabel = QLabel() self.pathLabel.setAlignment(Qt.AlignCenter) self.pathLabel.setMinimumSize(self.pathLabel.sizeHint()) self.pathLabel.setFrameStyle(QFrame.StyledPanel | QFrame.Sunken) self.statusBar().addPermanentWidget(self.pathLabel) self.versionLabel = QLabel() self.versionLabel.setAlignment(Qt.AlignCenter) self.versionLabel.setMinimumSize(self.versionLabel.sizeHint()) self.versionLabel.setFrameStyle(QFrame.StyledPanel | QFrame.Sunken) self.statusBar().addPermanentWidget(self.versionLabel) self.progressBarIDF = QProgressBar() self.progressBarIDF.setAlignment(Qt.AlignCenter) self.progressBarIDF.setMaximumWidth(200) self.statusBar().addPermanentWidget(self.progressBarIDF) self.clipboard = QApplication.instance().clipboard() self.obj_clipboard = [] self.setStyleSheet(""" QToolTip { background-color: gray; color: white; border: black solid 1px } # QMenu { # background-color: rgbf(0.949020, 0.945098, 0.941176); # color: rgb(255,255,255); # } # QMenu::item::selected { # background-color: rgbf(0.949020, 0.945098, 0.941176); # } """)
class Window(QWidget): def __init__(self): super(Window, self).__init__() self.proxyModel = QSortFilterProxyModel() self.proxyModel.setDynamicSortFilter(True) self.sourceGroupBox = QGroupBox("Original Model") self.proxyGroupBox = QGroupBox("Sorted/Filtered Model") self.sourceView = QTreeView() self.sourceView.setRootIsDecorated(False) self.sourceView.setAlternatingRowColors(True) self.proxyView = QTreeView() self.proxyView.setRootIsDecorated(False) self.proxyView.setAlternatingRowColors(True) self.proxyView.setModel(self.proxyModel) self.proxyView.setSortingEnabled(True) self.sortCaseSensitivityCheckBox = QCheckBox("Case sensitive sorting") self.filterCaseSensitivityCheckBox = QCheckBox("Case sensitive filter") self.filterPatternLineEdit = QLineEdit() self.filterPatternLineEdit.setClearButtonEnabled(True) self.filterPatternLabel = QLabel("&Filter pattern:") self.filterPatternLabel.setBuddy(self.filterPatternLineEdit) self.filterSyntaxComboBox = QComboBox() self.filterSyntaxComboBox.addItem("Regular expression", REGULAR_EXPRESSION) self.filterSyntaxComboBox.addItem("Wildcard", WILDCARD) self.filterSyntaxComboBox.addItem("Fixed string", FIXED_STRING) self.filterSyntaxLabel = QLabel("Filter &syntax:") self.filterSyntaxLabel.setBuddy(self.filterSyntaxComboBox) self.filterColumnComboBox = QComboBox() self.filterColumnComboBox.addItem("Subject") self.filterColumnComboBox.addItem("Sender") self.filterColumnComboBox.addItem("Date") self.filterColumnLabel = QLabel("Filter &column:") self.filterColumnLabel.setBuddy(self.filterColumnComboBox) self.filterPatternLineEdit.textChanged.connect(self.filterRegExpChanged) self.filterSyntaxComboBox.currentIndexChanged.connect(self.filterRegExpChanged) self.filterColumnComboBox.currentIndexChanged.connect(self.filterColumnChanged) self.filterCaseSensitivityCheckBox.toggled.connect(self.filterRegExpChanged) self.sortCaseSensitivityCheckBox.toggled.connect(self.sortChanged) sourceLayout = QHBoxLayout() sourceLayout.addWidget(self.sourceView) self.sourceGroupBox.setLayout(sourceLayout) proxyLayout = QGridLayout() proxyLayout.addWidget(self.proxyView, 0, 0, 1, 3) proxyLayout.addWidget(self.filterPatternLabel, 1, 0) proxyLayout.addWidget(self.filterPatternLineEdit, 1, 1, 1, 2) proxyLayout.addWidget(self.filterSyntaxLabel, 2, 0) proxyLayout.addWidget(self.filterSyntaxComboBox, 2, 1, 1, 2) proxyLayout.addWidget(self.filterColumnLabel, 3, 0) proxyLayout.addWidget(self.filterColumnComboBox, 3, 1, 1, 2) proxyLayout.addWidget(self.filterCaseSensitivityCheckBox, 4, 0, 1, 2) proxyLayout.addWidget(self.sortCaseSensitivityCheckBox, 4, 2) self.proxyGroupBox.setLayout(proxyLayout) mainLayout = QVBoxLayout() mainLayout.addWidget(self.sourceGroupBox) mainLayout.addWidget(self.proxyGroupBox) self.setLayout(mainLayout) self.setWindowTitle("Basic Sort/Filter Model") self.resize(500, 450) self.proxyView.sortByColumn(1, Qt.AscendingOrder) self.filterColumnComboBox.setCurrentIndex(1) self.filterPatternLineEdit.setText("Andy|Grace") self.filterCaseSensitivityCheckBox.setChecked(True) self.sortCaseSensitivityCheckBox.setChecked(True) def setSourceModel(self, model): self.proxyModel.setSourceModel(model) self.sourceView.setModel(model) def filterRegExpChanged(self): syntax_nr = self.filterSyntaxComboBox.currentData() pattern = self.filterPatternLineEdit.text() if syntax_nr == WILDCARD: pattern = QRegularExpression.wildcardToRegularExpression(pattern) elif syntax_nr == FIXED_STRING: pattern = QRegularExpression.escape(pattern) regExp = QRegularExpression(pattern) if not self.filterCaseSensitivityCheckBox.isChecked(): options = regExp.patternOptions() options |= QRegularExpression.CaseInsensitiveOption regExp.setPatternOptions(options) self.proxyModel.setFilterRegularExpression(regExp) def filterColumnChanged(self): self.proxyModel.setFilterKeyColumn(self.filterColumnComboBox.currentIndex()) def sortChanged(self): if self.sortCaseSensitivityCheckBox.isChecked(): caseSensitivity = Qt.CaseSensitive else: caseSensitivity = Qt.CaseInsensitive self.proxyModel.setSortCaseSensitivity(caseSensitivity)
class WTreeEdit(QWidget): """TreeEdit widget is to show and edit all of the pyleecan objects data.""" # Signals dataChanged = Signal() def __init__(self, obj, *args, **kwargs): QWidget.__init__(self, *args, **kwargs) self.class_dict = ClassInfo().get_dict() self.treeDict = None # helper to track changes self.obj = obj # the object self.is_save_needed = False self.model = TreeEditModel(obj) self.setupUi() # === Signals === self.selectionModel.selectionChanged.connect(self.onSelectionChanged) self.treeView.collapsed.connect(self.onItemCollapse) self.treeView.expanded.connect(self.onItemExpand) self.treeView.customContextMenuRequested.connect(self.openContextMenu) self.model.dataChanged.connect(self.onDataChanged) self.dataChanged.connect(self.setSaveNeeded) # === Finalize === # set 'root' the selected item and resize columns self.treeView.setCurrentIndex(self.treeView.model().index(0, 0)) self.treeView.resizeColumnToContents(0) def setupUi(self): """Setup the UI""" # === Widgets === # TreeView self.treeView = QTreeView() # self.treeView.rootNode = model.invisibleRootItem() self.treeView.setModel(self.model) self.treeView.setAlternatingRowColors(False) # self.treeView.setColumnWidth(0, 150) self.treeView.setMinimumWidth(100) self.treeView.setContextMenuPolicy(Qt.CustomContextMenu) self.selectionModel = self.treeView.selectionModel() self.statusBar = QStatusBar() self.statusBar.setSizeGripEnabled(False) self.statusBar.setSizePolicy(QSizePolicy.Expanding, QSizePolicy.Maximum) self.statusBar.setStyleSheet( "QStatusBar {border: 1px solid rgb(200, 200, 200)}") self.saveLabel = QLabel("unsaved") self.saveLabel.setVisible(False) self.statusBar.addPermanentWidget(self.saveLabel) # Splitters self.leftSplitter = QSplitter() self.leftSplitter.setStretchFactor(0, 0) self.leftSplitter.setStretchFactor(1, 1) # === Layout === # Horizontal Div. self.hLayout = QVBoxLayout() self.hLayout.setContentsMargins(0, 0, 0, 0) self.hLayout.setSpacing(0) # add widgets to layout self.hLayout.addWidget(self.leftSplitter) self.hLayout.addWidget(self.statusBar) # add widgets self.leftSplitter.addWidget(self.treeView) self.setLayout(self.hLayout) def update(self, obj): """Check if object has changed and update tree in case.""" if not obj is self.obj: self.obj = obj self.model = TreeEditModel(obj) self.treeView.setModel(self.model) self.model.dataChanged.connect(self.onDataChanged) self.selectionModel = self.treeView.selectionModel() self.selectionModel.selectionChanged.connect( self.onSelectionChanged) self.treeView.setCurrentIndex(self.treeView.model().index(0, 0)) self.setSaveNeeded(True) def setSaveNeeded(self, state=True): self.is_save_needed = state self.saveLabel.setVisible(state) def openContextMenu(self, point): """Generate and open context the menu at the given point position.""" index = self.treeView.indexAt(point) pos = QtGui.QCursor.pos() if not index.isValid(): return # get the data item = self.model.item(index) obj_info = self.model.get_obj_info(item) # init the menu menu = TreeEditContextMenu(obj_dict=obj_info, parent=self) menu.exec_(pos) self.onSelectionChanged(self.selectionModel.selection()) def onItemCollapse(self, index): """Slot for item collapsed""" # dynamic resize for ii in range(3): self.treeView.resizeColumnToContents(ii) def onItemExpand(self, index): """Slot for item expand""" # dynamic resize for ii in range(3): self.treeView.resizeColumnToContents(ii) def onDataChanged(self, first=None, last=None): """Slot for changed data""" self.dataChanged.emit() self.onSelectionChanged(self.selectionModel.selection()) def onSelectionChanged(self, itemSelection): """Slot for changed item selection""" # get the index if itemSelection.indexes(): index = itemSelection.indexes()[0] else: index = self.treeView.model().index(0, 0) self.treeView.setCurrentIndex(index) return # get the data item = self.model.item(index) obj = item.object() typ = type(obj).__name__ obj_info = self.model.get_obj_info(item) ref_typ = obj_info["ref_typ"] if obj_info else None # set statusbar information on class typ msg = f"{typ} (Ref: {ref_typ})" if ref_typ else f"{typ}" self.statusBar.showMessage(msg) # --- choose the respective widget by class type --- # numpy array -> table editor if typ == "ndarray": widget = WTableData(obj, editable=True) widget.dataChanged.connect(self.dataChanged.emit) elif typ == "MeshSolution": widget = WMeshSolution(obj) # only a view (not editable) # list (no pyleecan type, non empty) -> table editor # TODO add another widget for lists of non 'primitive' types (e.g. DataND) elif isinstance(obj, list) and not self.isListType(ref_typ) and obj: widget = WTableData(obj, editable=True) widget.dataChanged.connect(self.dataChanged.emit) # generic editor else: # widget = SimpleInputWidget().generate(obj) widget = WTableParameterEdit(obj) widget.dataChanged.connect(self.dataChanged.emit) # show the widget if self.leftSplitter.widget(1) is None: self.leftSplitter.addWidget(widget) else: self.leftSplitter.replaceWidget(1, widget) widget.setParent( self.leftSplitter) # workaround for PySide2 replace bug widget.show() pass def isListType(self, typ): if not typ: return False return typ[0] == "[" and typ[-1] == "]" and typ[1:-1] in self.class_dict def isDictType(self, typ): if not typ: return False return typ[0] == "{" and typ[-1] == "}" and typ[1:-1] in self.class_dict
class SearchReplaceDialog(QDialog): """Search & Replace window """ def __init__(self, parent, initial_query=None): """Initialize the search window """ super(SearchReplaceDialog, self).__init__(parent) self.parent = parent self.prefs = parent.prefs self.items_checked = 0 self.search_button = QPushButton('Search') self.search_text = MySearchField(self.search_button) self.search_text.setPlaceholderText("Enter search query here") self.search_button.clicked.connect(self.submit_search) input_layout = QHBoxLayout() input_layout.addWidget(self.search_text) input_layout.addWidget(self.search_button) self.results_tree = QTreeView() self.results_tree.setRootIsDecorated(False) self.results_tree.setAlternatingRowColors(True) self.results_tree.setAllColumnsShowFocus(True) self.results_tree.setSelectionBehavior(QAbstractItemView.SelectRows) self.results_tree.setSelectionMode(QAbstractItemView.SingleSelection) self.results_tree.doubleClicked.connect(self.go_to_object) self.whole_field_checkbox = QCheckBox("Whole Field Only", self) self.advanced_search_checkbox = QCheckBox("Advanced Search", self) self.advanced_search_checkbox.stateChanged.connect( self.advanced_search_checked) self.ignore_geometry_checkbox = QCheckBox("Ignore Geometry", self) self.go_button = QPushButton('Go') self.go_button.clicked.connect(self.go_to_object) checks_layout = QHBoxLayout() checks_layout.addWidget(self.whole_field_checkbox) checks_layout.addWidget(self.advanced_search_checkbox) checks_layout.addWidget(self.ignore_geometry_checkbox) checks_layout.addStretch() checks_layout.addWidget(self.go_button) self.query_label = QLabel("Query:") self.query_label.setEnabled(False) self.query_text = QLineEdit() self.query_text.setEnabled(True) self.query_text.setReadOnly(True) self.query_text.setFrame(False) self.query_text.setStyleSheet("""QLineEdit { background-color: LightGray; color: white; } """) query_layout = QHBoxLayout() query_layout.addWidget(self.query_label) query_layout.addWidget(self.query_text) self.select_label = QLabel("Select:") self.select_all_button = QPushButton("All") self.select_none_button = QPushButton("None") self.select_invert_button = QPushButton("Invert") self.delete_button = QPushButton("Delete Objects") self.select_all_button.clicked.connect(self.select_all_clicked) self.select_none_button.clicked.connect(self.select_none_clicked) self.select_invert_button.clicked.connect(self.select_invert_clicked) self.delete_button.clicked.connect(self.delete_button_clicked) self.delete_button.setEnabled(False) selection_layout = QHBoxLayout() selection_layout.addWidget(self.select_label) selection_layout.addWidget(self.select_all_button) selection_layout.addWidget(self.select_none_button) selection_layout.addWidget(self.select_invert_button) selection_layout.addStretch() selection_layout.addWidget(self.delete_button) self.replace_with_text = QLineEdit() self.replace_with_label = QLabel("Replace With:") self.replace_button = QPushButton("Replace") self.replace_button.clicked.connect(self.replace_button_clicked) self.replace_button.setEnabled(False) replace_layout = QHBoxLayout() replace_layout.addWidget(self.replace_with_label) replace_layout.addWidget(self.replace_with_text) replace_layout.addWidget(self.replace_button) layout = QVBoxLayout() layout.addLayout(input_layout) layout.addLayout(checks_layout) layout.addLayout(query_layout) layout.addWidget(self.results_tree) layout.addLayout(selection_layout) layout.addLayout(replace_layout) self.resize(650, 450) self.setLayout(layout) self.setWindowTitle("IDF+ Search & Replace") self.search_text.setFocus() self.setTabOrder(self.search_text, self.search_button) self.setTabOrder(self.search_button, self.whole_field_checkbox) self.setTabOrder(self.whole_field_checkbox, self.advanced_search_checkbox) self.setTabOrder(self.advanced_search_checkbox, self.select_all_button) self.setTabOrder(self.select_all_button, self.select_none_button) self.setTabOrder(self.select_none_button, self.select_invert_button) self.setTabOrder(self.select_invert_button, self.replace_with_text) self.setTabOrder(self.replace_with_text, self.replace_button) self.setTabOrder(self.replace_button, self.search_text) self.results_tree.setModel(self.create_results_model([])) self.results_tree.setColumnHidden(2, True) if initial_query is not None: self.search_text.setText(initial_query) self.search_button.click() def create_results_model(self, results): def add_result_row(row_model, value, obj_class, uuid): row_model.insertRow(0) row_model.setData(model.index(0, 0), value) row_model.setData(model.index(0, 1), obj_class) row_model.setData(model.index(0, 2), uuid) item_0 = model.itemFromIndex(model.index(0, 0)) item_0.setCheckState(Qt.Unchecked) item_0.setFlags(item_0.flags() | Qt.ItemIsUserCheckable) item_0.setEditable(False) item_1 = model.itemFromIndex(model.index(0, 1)) item_1.setEditable(False) model = QStandardItemModel(0, 3, self) model.setHeaderData(0, Qt.Horizontal, "Value") model.setHeaderData(1, Qt.Horizontal, "Class") model.setHeaderData(2, Qt.Horizontal, "UUID") for hit in results: add_result_row(model, hit['value'], hit['obj_class_display'], hit['uuid']) return model def submit_search(self): """Submits a search based on the current query """ user_query = self.search_text.text() idf = self.parent.idf if not user_query or len(user_query) < 2 or not idf: return [], "" results, my_query = idf.search( user_query, self.whole_field_checkbox.isChecked(), self.advanced_search_checkbox.isChecked(), self.ignore_geometry_checkbox.isChecked()) self.query_text.setText(str(my_query)) self.results_tree.setModel(self.create_results_model(results)) self.results_tree.model().itemChanged.connect(self.item_checked) # self.results_tree.setColumnHidden(2, True) self.results_tree.resizeColumnToContents(0) self.results_tree.resizeColumnToContents(1) self.results_tree.setSortingEnabled(True) def item_checked(self, item): if item.checkState() == Qt.Checked: self.items_checked += 1 else: self.items_checked -= 1 if self.items_checked > 0: self.delete_button.setEnabled(True) self.replace_button.setEnabled(True) else: self.delete_button.setEnabled(False) self.replace_button.setEnabled(False) def select_all_clicked(self): model = self.results_tree.model() result_count = model.rowCount() for i in range(result_count): model.itemFromIndex(model.index(i, 0)).setCheckState(Qt.Checked) def select_none_clicked(self): model = self.results_tree.model() result_count = model.rowCount() for i in range(result_count): model.itemFromIndex(model.index(i, 0)).setCheckState(Qt.Unchecked) def select_invert_clicked(self): model = self.results_tree.model() result_count = model.rowCount() for i in range(result_count): item = model.itemFromIndex(model.index(i, 0)) if item.checkState() == Qt.Checked: new_state = Qt.Unchecked else: new_state = Qt.Checked item.setCheckState(new_state) def delete_button_clicked(self): model = self.results_tree.model() result_count = model.rowCount() if result_count <= 0 or self.items_checked <= 0: return question = "Are you sure you want to perform this deletion?\n" \ "Undo is currently NOT supported for this operation." response = self.confirm_action(question) if response is not True: return for i in range(result_count): item_0 = model.itemFromIndex(model.index(i, 0)) item_2 = model.itemFromIndex(model.index(i, 2)) if item_0.checkState() != Qt.Checked: continue field = self.parent.idf.field_by_uuid(item_2.text()) obj = field._outer obj_class = self.parent.idf.idf_objects(obj.obj_class) try: index = obj_class.index(obj) self.parent.idf.remove_objects(obj.obj_class, index, index + 1) except ValueError: pass # already deleted self.parent.set_dirty(True) self.submit_search() self.parent.load_table_view(self.parent.current_obj_class) QMessageBox.information(self, "Delete Action", "Deletion Complete!") def advanced_search_checked(self): if self.advanced_search_checkbox.isChecked(): self.whole_field_checkbox.setEnabled(False) self.whole_field_checkbox.setChecked(True) self.ignore_geometry_checkbox.setEnabled(False) self.ignore_geometry_checkbox.setChecked(False) else: self.whole_field_checkbox.setEnabled(True) self.whole_field_checkbox.setChecked(False) self.ignore_geometry_checkbox.setEnabled(True) self.ignore_geometry_checkbox.setChecked(False) def replace_button_clicked(self): search_text = self.search_text.text() replace_with_text = self.replace_with_text.text() if not search_text: return model = self.results_tree.model() result_count = model.rowCount() if result_count <= 0 or self.items_checked <= 0: return question = "Are you sure you want to perform this replacement?\n" \ "Undo is currently NOT supported for this operation." response = self.confirm_action(question) if response is not True: return for i in range(result_count): item_0 = model.itemFromIndex(model.index(i, 0)) item_2 = model.itemFromIndex(model.index(i, 2)) if item_0.checkState() != Qt.Checked: continue field = self.parent.idf.field_by_uuid(item_2.text()) if self.whole_field_checkbox.isChecked( ) or self.advanced_search_checkbox.isChecked(): field.value = replace_with_text else: regex = re.compile(re.escape(search_text), re.IGNORECASE) field.value = regex.sub(replace_with_text, field.value) self.parent.set_dirty(True) self.submit_search() self.parent.load_table_view(self.parent.current_obj_class) QMessageBox.information(self, "Replacement", "Replacement Complete!") def confirm_action(self, question): """Confirm user wants to perform action """ flags = QMessageBox.StandardButton.Yes flags |= QMessageBox.StandardButton.No response = QMessageBox.question(self, "Are you sure?", question, flags) if response == QMessageBox.Yes: return True elif QMessageBox.No: return False else: return False def go_to_object(self, index=None): if index is None: selected = self.results_tree.selectedIndexes() if not selected: return index = selected[0] model = self.results_tree.model() item = model.itemFromIndex(model.index(index.row(), 2)) field = self.parent.idf.field_by_uuid(item.text()) self.parent.activateWindow() self.parent.jump_to_field(field)
class ClassTreeWidget(QDialog): """ TreeView widget to show pyleecan classes structured by their inheritance together with the selected class description. """ def __init__(self, keys=None, expand=True): super(ClassTreeWidget, self).__init__() self.setupUi() self.expandAll = expand self.setMinimumHeight(600) # === default variables === self.classDict = ClassInfo().get_dict() self.keys = keys or ClassInfo().get_base_classes() # TODO all classes self.selectionModel = self.treeView.selectionModel() # === Signals === self.selectionModel.selectionChanged.connect(self.onSelectionChanged) self.treeView.doubleClicked.connect(self.onClassSelected) self.buttons.accepted.connect(self.accept) self.buttons.rejected.connect(self.reject) # === Generate content === self.generate() def onClassSelected(self, index): """Method to accept the selection if a class was double clicked.""" if index.isValid(): self.accept() def onSelectionChanged(self, itSelection): """ """ index = itSelection.indexes()[0] desc = index.model().itemFromIndex(index).data() self.text.setText(desc) def getSelectedClass(self): """Get the currently selected class by its name.""" index = self.selectionModel.selectedIndexes()[0] return index.model().itemFromIndex(index).text() def setupUi(self): """Init. the UI.""" self.setWindowIcon(QIcon(ICON)) # === Widgets === # TreeView model = QtGui.QStandardItemModel(0, 1) model.setHorizontalHeaderLabels(["Class"]) self.treeView = QTreeView() self.treeView.rootNode = model.invisibleRootItem() self.treeView.setModel(model) self.treeView.setAlternatingRowColors(False) # size options # setting min. width in self.generate to fit content self.treeView.setContextMenuPolicy(Qt.CustomContextMenu) # Hide Debug Columns # self.treeView.hideColumn(1) # text output self.text = QLabel() self.text.setAlignment(Qt.AlignTop) self.text.setWordWrap(True) self.text.setMinimumWidth(300) # Splitters self.splitter = QSplitter(self) self.splitter.setStretchFactor(0, 0) self.splitter.setStretchFactor(1, 1) self.splitter.addWidget(self.treeView) self.splitter.addWidget(self.text) # dialog buttons self.buttons = QDialogButtonBox( QDialogButtonBox.Ok | QDialogButtonBox.Cancel ) # window to create confirmation and cancellation buttons # === Layout === # Horizontal Div. layout = QVBoxLayout() # layout.setContentsMargins(0, 0, 0, 0) # layout.setSpacing(0) layout.addWidget(self.splitter) layout.addWidget(self.buttons) self.setLayout(layout) def generate(self): """Method to (recursively) build the tree (view) of the data object.""" self.treeDict = dict() for key in self.keys: self.genTreeDict(key, self.treeDict) self.genTreeView(self.treeDict) # set first row active & expand all branches index = self.treeView.model().index(0, 0) self.treeView.setCurrentIndex(index) self.treeView.expandAll() wHint = self.treeView.sizeHintForColumn(0) self.treeView.setMinimumWidth(wHint) self.treeView.setColumnWidth(0, wHint) if not self.expandAll: self.treeView.collapseAll() def genTreeDict(self, key, parent): """Generate a dict structure of the classes recursively on the parent dict.""" parent[key] = dict() for typ in self.classDict[key]["daughters"]: if key == self.classDict[typ]["mother"]: self.genTreeDict(typ, parent[key]) def genTreeView(self, tree, parent=None): """Generate the view item structure on the parent item.""" # init if root if parent is None: parent = self.treeView.rootNode self.treeView.rootNode.removeRows( 0, self.treeView.rootNode.rowCount()) for key, item in tree.items(): desc = ( f"Class: {key} \nPackage: {self.classDict[key]['package']}" + f"\nDescription: {self.classDict[key]['desc']}") row = self.addRow(parent, key, desc) if item: self.genTreeView(item, parent=row) def addRow(self, parent, name="", desc=""): """Add a new row to the parent item.""" item = QtGui.QStandardItem(name) item.setEditable(False) item.setData(desc) parent.appendRow([item]) return item