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)
Exemple #2
0
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()
Exemple #3
0
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)
Exemple #5
0
    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);
            # }
            """)
Exemple #6
0
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)
Exemple #7
0
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
Exemple #8
0
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