def __createInspectorActionGroup(self, parent): """ Creates an action group with 'set inspector' actions for all installed inspector. """ actionGroup = QtWidgets.QActionGroup(parent) actionGroup.setExclusive(True) sortedItems = sorted(self.argosApplication.inspectorRegistry.items, key=lambda item: item.identifier) shortCutNr = 1 for item in sortedItems: logger.debug("item: {}".format(item.identifier)) setAndDrawFn = partial(self.setAndDrawInspectorById, item.identifier) action = QtWidgets.QAction(item.name, self, triggered=setAndDrawFn, checkable=True) action.setData(item.identifier) if shortCutNr <= 9 and "debug" not in item.identifier: # TODO: make configurable by the user action.setShortcut( QtGui.QKeySequence("Ctrl+{}".format(shortCutNr))) shortCutNr += 1 actionGroup.addAction(action) return actionGroup
def __init__(self, settingsFile=None, setExceptHook=True): """ Constructor :param settingsFile: Config file from which the persistent settings are loaded. :param setExceptHook: Sets the global sys.except hook so that Qt shows a dialog box when an exception is raised. In debugging mode, the program will just quit in case of an exception. This is standard Python behavior but PyQt and PySide swallow exceptions by default (only a log message is displayed). The practice of swallowing exceptions fosters bad programming IHMO as it is easy to miss errors. I strongly recommend that you set the setExceptHook to True. """ super(ArgosApplication, self).__init__() if not settingsFile: settingsFile = ArgosApplication.defaultSettingsFile() logger.debug("No config file specified. Using default: {}".format( settingsFile)) self._settingsFile = ArgosApplication.userConfirmedSettingsFile( settingsFile, createWithoutConfirm=ArgosApplication.defaultSettingsFile()) if setExceptHook: logger.debug("Setting sys.excepthook to Argos exception handling") sys.excepthook = handleException QtCore.qInstallMessageHandler(self.handleQtLogMessages) if DEBUGGING: self.qApplication.focusChanged.connect( self.focusChanged) # for debugging self._repo = RepoTreeModel() self._rtiRegistry = globalRtiRegistry() self._inspectorRegistry = InspectorRegistry() self._mainWindows = [] self._settingsSaved = False # boolean to prevent saving settings twice self._recentFiles = [ ] # list of recently opened files ([timeStampe, fileName] per file). self._maxRecentFiles = 10 # Maximum size of recent file #self.qApplication.lastWindowClosed.connect(self.quit) self.qApplication.aboutToQuit.connect(self.aboutToQuitHandler) # Activate-actions for all windows self.windowActionGroup = QtWidgets.QActionGroup(self) self.windowActionGroup.setExclusive(True) # Call setup when the event loop starts. QtCore.QTimer.singleShot(0, self.setup)
def addHeaderContextMenu(self, checked=None, checkable=None, enabled=None): """ Adds the context menu from using header information checked can be a header_name -> boolean dictionary. If given, headers with the key name will get the checked value from the dictionary. The corresponding column will be hidden if checked is False. checkable can be a header_name -> boolean dictionary. If given, header actions with the key name will get the checkable value from the dictionary. (Default True) enabled can be a header_name -> boolean dictionary. If given, header actions with the key name will get the enabled value from the dictionary. (Default True) """ checked = checked if checked is not None else {} checkable = checkable if checkable is not None else {} enabled = enabled if enabled is not None else {} horizontal_header = self.horizontalHeader() horizontal_header.setContextMenuPolicy(Qt.ActionsContextMenu) self.toggle_column_actions_group = QtWidgets.QActionGroup(self) self.toggle_column_actions_group.setExclusive(False) self.__toggle_functions = [] # for keeping references for col in range(horizontal_header.count()): column_label = self.model().headerData(col, Qt.Horizontal, Qt.DisplayRole) #logger.debug("Adding: col {}: {}".format(col, column_label)) action = QtWidgets.QAction( str(column_label), self.toggle_column_actions_group, checkable=checkable.get(column_label, True), enabled=enabled.get(column_label, True), toolTip="Shows or hides the {} column".format(column_label)) func = self.__makeShowColumnFunction(col) self.__toggle_functions.append(func) # keep reference horizontal_header.addAction(action) is_checked = checked.get( column_label, not horizontal_header.isSectionHidden(col)) horizontal_header.setSectionHidden(col, not is_checked) action.setChecked(is_checked) action.toggled.connect(func)
def __init__(self, setExceptHook=True): """ Constructor :param setExceptHook: Sets the global sys.except hook so that Qt shows a dialog box when an exception is raised. In debugging mode, the program will just quit in case of an exception. This is standard Python behavior but PyQt and PySide swallow exceptions by default (only a log message is displayed). The practice of swallowing exceptions fosters bad programming IHMO as it is easy to miss errors. I strongly recommend that you set the setExceptHook to True. """ super(ArgosApplication, self).__init__() # Call initQtWidgetsApplicationInstance() so that the users can call argos.browse without # having to call it themselves. self._qApplication = initQApplication() if setExceptHook: logger.debug("Setting sys.excepthook to Argos exception handling") sys.excepthook = handleException #self.qApplication.focusChanged.connect(self.focusChanged) # for debugging self._repo = RepoTreeModel() self._rtiRegistry = globalRtiRegistry() self._inspectorRegistry = InspectorRegistry() self._profile = '' self._mainWindows = [] self._settingsSaved = False # boolean to prevent saving settings twice self.qApplication.lastWindowClosed.connect(self.quit) # Activate-actions for all windows self.windowActionGroup = QtWidgets.QActionGroup(self) self.windowActionGroup.setExclusive(True) # Call setup when the event loop starts. QtCore.QTimer.singleShot(0, self.setup)
def __createInspectorActionGroup(self, parent): """ Creates an action group with 'set inspector' actions for all installed inspector. """ actionGroup = QtWidgets.QActionGroup(parent) actionGroup.setExclusive(True) for item in self.argosApplication.inspectorRegistry.items: logger.debug("__createInspectorActionGroup item: {} {}".format(item.identifier, item._data)) setAndDrawFn = partial(self.setAndDrawInspectorById, item.identifier) action = QtWidgets.QAction(item.name, self, triggered=setAndDrawFn, checkable=True) action.setData(item.identifier) if item.shortCut: try: keySeq = QtGui.QKeySequence(item.shortCut.strip()) except Exception as ex: logger.warning("Unable to create short cut from: '{}".format(item.shortCut)) else: action.setShortcut(QtGui.QKeySequence(keySeq)) actionGroup.addAction(action) return actionGroup
def __init__(self, repoTreeModel, collector, parent=None): """ Constructor. Maintains a reference to a collector. The repo tree view updates the collector when the currentIndex changes. """ super(RepoTreeView, self).__init__(treeModel=repoTreeModel, parent=parent) self._collector = collector self._config = self._createConfig() treeHeader = self.header() treeHeader.resizeSection(RepoTreeModel.COL_NODE_NAME, COL_NODE_NAME_WIDTH) treeHeader.resizeSection(RepoTreeModel.COL_SHAPE, COL_SHAPE_WIDTH) treeHeader.resizeSection(RepoTreeModel.COL_ELEM_TYPE, COL_ELEM_TYPE_WIDTH) treeHeader.setStretchLastSection(True) headerNames = self.model().horizontalHeaders enabled = dict((name, True) for name in headerNames) enabled[headerNames[ RepoTreeModel.COL_NODE_NAME]] = False # Cannot be unchecked checked = dict((name, False) for name in headerNames) checked[headerNames[RepoTreeModel.COL_NODE_NAME]] = True checked[headerNames[RepoTreeModel.COL_SHAPE]] = True checked[headerNames[RepoTreeModel.COL_ELEM_TYPE]] = True self.addHeaderContextMenu(checked=checked, enabled=enabled, checkable={}) self.setContextMenuPolicy( Qt.DefaultContextMenu) # will call contextMenuEvent self.setUniformRowHeights(True) #self.setIconSize(QtCore.QSize(16, 16)) # Add actions self.currentItemActionGroup = QtWidgets.QActionGroup(self) self.currentItemActionGroup.setExclusive(False) removeFileAction = QtWidgets.QAction( "Remove from Tree", self.currentItemActionGroup, shortcut=QtGui.QKeySequence.Delete, triggered=self.removeCurrentItem) self.addAction(removeFileAction) reloadFileAction = QtWidgets.QAction( "Reload File", self.currentItemActionGroup, shortcut=QtGui.QKeySequence.Refresh, #"Ctrl+R", triggered=self.reloadFileOfCurrentItem) self.addAction(reloadFileAction) self.openItemAction = QtWidgets.QAction("Open Item", self, triggered=self.openCurrentItem) self.addAction(self.openItemAction) self.closeItemAction = QtWidgets.QAction( "Close Item", self, triggered=self.closeCurrentItem) self.addAction(self.closeItemAction) self.collapseItemAction = QtWidgets.QAction( "Collapse Item", self, triggered=self.collapseCurrentItem) self.addAction(self.collapseItemAction) # Connect signals selectionModel = self.selectionModel( ) # need to store reference to prevent crash in PySide selectionModel.currentChanged.connect(self.currentItemChanged) # Close files on collapse. Note that, self.collapsed does NOT seem to be connected to self.collapse by default, # so there is not conflict here. Also there is no need to connect to expand, this is automatic with the # fetchMore mechanism self.collapsed.connect(self.closeItem) self.model().sigItemChanged.connect(self.repoTreeItemChanged) self.model().sigAllChildrenRemovedAtIndex.connect(self.collapse)
def __init__(self, repoTreeModel, collector, parent=None): """ Constructor. Maintains a reference to a collector. The repo tree view updates the collector when the currentIndex changes. """ super(RepoTreeView, self).__init__(treeModel=repoTreeModel, parent=parent) self._collector = collector self._config = self._createConfig() treeHeader = self.header() treeHeader.resizeSection(RepoTreeModel.COL_NODE_NAME, COL_NODE_NAME_WIDTH) treeHeader.resizeSection(RepoTreeModel.COL_SHAPE, COL_SHAPE_WIDTH) treeHeader.resizeSection(RepoTreeModel.COL_ELEM_TYPE, COL_ELEM_TYPE_WIDTH) treeHeader.setStretchLastSection(True) headerNames = self.model().horizontalHeaders enabled = dict((name, True) for name in headerNames) enabled[headerNames[ RepoTreeModel.COL_NODE_NAME]] = False # Cannot be unchecked checked = dict((name, False) for name in headerNames) checked[headerNames[RepoTreeModel.COL_NODE_NAME]] = True checked[headerNames[RepoTreeModel.COL_SHAPE]] = False checked[headerNames[RepoTreeModel.COL_ELEM_TYPE]] = False self.addHeaderContextMenu(checked=checked, enabled=enabled, checkable={}) self.setContextMenuPolicy( Qt.DefaultContextMenu) # will call contextMenuEvent self.setUniformRowHeights(True) #self.setIconSize(QtCore.QSize(16, 16)) # Add actions self.topLevelItemActionGroup = QtWidgets.QActionGroup( self) # TODO: not used anymore? self.topLevelItemActionGroup.setExclusive(False) self.currentItemActionGroup = QtWidgets.QActionGroup(self) self.currentItemActionGroup.setExclusive(False) removeFileAction = QtWidgets.QAction( "Remove from Tree", self.currentItemActionGroup, shortcut=QtGui.QKeySequence.Delete, triggered=self.removeCurrentItem) self.addAction(removeFileAction) reloadFileAction = QtWidgets.QAction( "Reload File", self.currentItemActionGroup, shortcut=QtGui.QKeySequence.Refresh, #"Ctrl+R", triggered=self.reloadFileOfCurrentItem) self.addAction(reloadFileAction) self.openItemAction = QtWidgets.QAction( "Open Item", self, #shortcut="Ctrl+Shift+C", triggered=self.openCurrentItem) self.addAction(self.openItemAction) self.closeItemAction = QtWidgets.QAction( "Close Item", self, #shortcut="Ctrl+C", # Ctrl+C already taken for Copy triggered=self.closeCurrentItem) self.addAction(self.closeItemAction) # Connect signals selectionModel = self.selectionModel( ) # need to store reference to prevent crash in PySide selectionModel.currentChanged.connect(self.currentItemChanged) self.model().sigItemChanged.connect(self.repoTreeItemChanged)
def __init__(self, configTreeModel, parent=None): """ Constructor. :param parent: """ super(ConfigWidget, self).__init__(parent=parent) # Actions that change the reset mode of the reset button self.modeActionGroup = QtWidgets.QActionGroup(self) self.modeActionGroup.setExclusive(True) self.modeAllAction = QtWidgets.QAction("Reset All", self.modeActionGroup) self.modeAllAction.setToolTip( "Changes button reset mode to reset all settings") self.modeAllAction.setCheckable(True) self.modeAllAction.triggered.connect( lambda: self.setResetMode(ResetMode.All)) self.modeRangeAction = QtWidgets.QAction("Reset Ranges", self.modeActionGroup) self.modeRangeAction.setToolTip( "Changes button reset mode to reset axes") self.modeRangeAction.setCheckable(True) self.modeRangeAction.triggered.connect( lambda: self.setResetMode(ResetMode.Ranges)) # Sanity check that actions have been added to action group assert self.modeActionGroup.actions( ), "Sanity check. resetActionGroup is empty" # Actions that actually reset the settings self.resetAllAction = QtWidgets.QAction("Reset All", self) self.resetAllAction.setToolTip("Resets all settings.") self.resetAllAction.setIcon( QtGui.QIcon(os.path.join(icons_directory(), 'reset-l.svg'))) self.resetAllAction.setShortcut("Ctrl+=") self.resetRangesAction = QtWidgets.QAction("Reset Ranges", self) self.resetRangesAction.setToolTip( "Resets range of all plots, color scales, table column/row sizes etc." ) self.resetRangesAction.setIcon( QtGui.QIcon(os.path.join(icons_directory(), 'reset-l.svg'))) self.resetRangesAction.setShortcut("Ctrl+0") self.resetButtonMenu = QtWidgets.QMenu() self.resetButtonMenu.addAction(self.resetAllAction) self.resetButtonMenu.addAction(self.resetRangesAction) self.resetButtonMenu.addSection("Default") self.resetButtonMenu.addAction(self.modeAllAction) self.resetButtonMenu.addAction(self.modeRangeAction) # Widgets self.mainLayout = QtWidgets.QVBoxLayout(self) self.mainLayout.setSpacing(5) self.mainLayout.setContentsMargins(DOCK_MARGIN, DOCK_MARGIN, DOCK_MARGIN, DOCK_MARGIN) self.configTreeView = ConfigTreeView(configTreeModel, parent=self) self.mainLayout.addWidget(self.configTreeView) self.buttonLayout = QtWidgets.QHBoxLayout() self.mainLayout.addLayout(self.buttonLayout) self.autoCheckBox = QtWidgets.QCheckBox("Auto") self.autoCheckBox.setToolTip( "Auto reset when a new item or axis is selected.") self.autoCheckBox.setChecked(True) self.resetButton = QtWidgets.QToolButton() self.resetButton.setToolButtonStyle(Qt.ToolButtonTextBesideIcon) self.resetButton.setDefaultAction(self.resetButtonMenu.defaultAction()) self.resetButton.setPopupMode(QtWidgets.QToolButton.MenuButtonPopup) self.resetButton.setMenu(self.resetButtonMenu) # Set font size to the same as used for push buttons dummyButton = QtWidgets.QPushButton("dummy") fontSize = dummyButton.font().pointSize() del dummyButton logger.debug( "Setting QToolButtons font size to: {} point".format(fontSize)) font = self.resetButton.font() font.setPointSizeF(fontSize) self.resetButton.setFont(font) self.buttonLayout.addStretch() self.buttonLayout.addWidget(self.autoCheckBox) self.buttonLayout.addWidget(self.resetButton) self.buttonLayout.addStretch() self.autoCheckBox.stateChanged.connect(self.setAutoReset) self.resetRangesAction.triggered.connect( self.configTreeView.resetAllRanges) self.resetAllAction.triggered.connect( self.configTreeView.resetAllSettings) self.setResetMode(self.configTreeView.resetMode)