class Hello(QMainWindow): def __init__(self): super(Hello, self).__init__() self.initUI() self.show() def initUI(self): widget = self.initSubWindow() sub_window = QMdiSubWindow() sub_window.setWidget(widget) sub_window.setWindowTitle("MdiSubWindow") self.mdiArea = QMdiArea() self.setCentralWidget(self.mdiArea) self.mdiArea.addSubWindow(sub_window) self.setWindowTitle("MdiArea") def initSubWindow(self): label: QLabel = QLabel('こんにちは、世界!') font: QFont = QFont() font.setPointSize(24) label.setFont(font) label.setAlignment(QtCore.Qt.AlignCenter) layout: QVBoxLayout = QVBoxLayout() layout.addWidget(label) widget = QWidget() widget.setLayout(layout) return widget
class Window(QMainWindow): def __init__(self): super(Window, self).__init__() self.setWindowTitle("Pyside2 Simple Application") self.setGeometry(300, 300, 300, 300) self.mdi = QMdiArea() self.setCentralWidget(self.mdi) menu_bar = self.menuBar() file = menu_bar.addMenu("File") new = QAction("New", self) new.triggered.connect(self.newSlot) file.addAction(new) cascade = QAction("Cascade", self) cascade.triggered.connect(self.cascadeAction) file.addAction(cascade) tiled = QAction("Tiled", self) tiled.triggered.connect(self.tileAction) file.addAction(tiled) self.count = 0 def newSlot(self): self.count += 1 sub = QMdiSubWindow() sub.setWidget(QTextEdit()) sub.setWindowTitle("Sub Window " + str(self.count)) self.mdi.addSubWindow(sub) sub.show() def cascadeAction(self): self.mdi.cascadeSubWindows() def tileAction(self): self.mdi.tileSubWindows()
def __init__(self, main_controller: "MainController", camera_description: CamDesc, mdi_area: QtWidgets.QMdiArea): self.main_controller = main_controller self.camera_description = camera_description self.address_str = camera_description.host.toString() self.sub_window = sub_window = MdiSubWindowCloser() sub_window.setWindowTitle(self.address_str) sub_window.setAttribute(Qt.WA_DeleteOnClose) sub_window.closed.connect(self.window_closed) camera_control = CameraControl(parent=sub_window) self.status = camera_control.status for cmd in ZOOM_COMMANDS: control = getattr(camera_control, cmd) cmd_name = cmd.replace("_", "-") control.pressed.connect( partial(self.zoom_command_pressed, cmd_name)) control.released.connect(self.zoom_command_released) sub_window.setWidget(camera_control) mdi_area.addSubWindow(sub_window) sub_window.show() self.base_url = QUrl(f"http://{self.address_str}/cam.cgi") self.base_request = QNetworkRequest() self.base_request.setRawHeader(QByteArray(b"Connection"), QByteArray(b"Keep-Alive")) self.base_request.setRawHeader(QByteArray(b"User-Agent"), QByteArray(b"Apache-HttpClient")) self.status_query_request = self.build_request({"mode": "getstate"}) self.stop_zoom_request = self.build_request({ "mode": "camcmd", "value": "zoomstop" }) self.ping_timer = QTimer(self.sub_window) self.ping_timer.timeout.connect(self.request_device_state) self.initial_requests = Queue() self.build_initial_request_list() request = self.get_next_request() self.query(request)
def __init__(self, close_event_callback: Event): super(MainWindow, self).__init__() self.close_event_callback = close_event_callback self.resize(700, 900) # main_wgt main_wgt = QWidget() self.setCentralWidget(main_wgt) self.setWindowTitle("RS Companion") # main_window/main_wgt <- main_grid grid = QGridLayout() main_wgt.setLayout(grid) # mdi self.mdi_win = mdi_win.MDIWidget() mdi = QMdiArea() # slider slider = QSlider() slider.setOrientation(Qt.Horizontal) # main_window/main_wgt-main_grid <- gb_control_bar grid.addWidget(self.set_controls(), 0, 0) grid.addWidget(self.set_key_flag(), 0, 1) grid.addWidget(self.set_notes(), 0, 2) grid.addWidget(self.set_information(), 0, 4) grid.addItem( QSpacerItem(300, 0, QSizePolicy.Minimum, QSizePolicy.Expanding), 0, 3) grid.addWidget(mdi, 1, 0, 1, 5) grid.addWidget(slider, 2, 0, 1, 5) grid.setRowStretch(1, 1) # menu self.set_menu() # QMDI subwindow # sub = QMdiSubWindow() # sub.resize(655, 515) # self.mid_text = QLabel("Nothing yet...") # self.mid_text.setText("what??") # sub.setWidget(self.mid_text) # sub.setWindowTitle("VOG COM32") # sub.setWindowIcon(self.create_icon_by_color(QColor("transparent"))) mdi.addSubWindow(self.mdi_win)
class Window(QMainWindow): count = 0 def __init__(self): super().__init__() self.init_ui() def init_ui(self): self.setWindowTitle("Pyside2 MDI Window") self.setGeometry(100, 100, 900, 500) self.setWindowIcon(QIcon('icon.png')) self.mdi = QMdiArea() self.setCentralWidget(self.mdi) menu_bar = self.menuBar() file = menu_bar.addMenu("File") file.addAction("New") file.addAction("Cascade") file.addAction("Tiled") file.triggered[QAction].connect(self.windowTriggered) def windowTriggered(self, p): if p.text() == "New": Window.count = Window.count + 1 sub = QMdiSubWindow() sub.setWidget(QTextEdit()) sub.setWindowTitle("Sub Window " + str(Window.count)) self.mdi.addSubWindow(sub) sub.show() if p.text() == "Cascade": self.mdi.cascadeSubWindows() if p.text() == "Tiled": self.mdi.tileSubWindows()
class MainWindow(QMainWindow): def __init__(self): super(MainWindow, self).__init__() self.mdiArea = QMdiArea() self.mdiArea.setHorizontalScrollBarPolicy(Qt.ScrollBarAsNeeded) self.mdiArea.setVerticalScrollBarPolicy(Qt.ScrollBarAsNeeded) self.setCentralWidget(self.mdiArea) self.mdiArea.subWindowActivated.connect(self.updateMenus) self.windowMapper = QSignalMapper(self) self.windowMapper.mapped[QWidget].connect(self.setActiveSubWindow) self.createActions() self.createMenus() self.createToolBars() self.createStatusBar() self.updateMenus() self.readSettings() self.setWindowTitle("MDI") def closeEvent(self, event): self.mdiArea.closeAllSubWindows() if self.mdiArea.currentSubWindow(): event.ignore() else: self.writeSettings() event.accept() def newFile(self): child = self.createMdiChild() child.newFile() child.show() def open(self): fileName, _ = QFileDialog.getOpenFileName(self) if fileName: existing = self.findMdiChild(fileName) if existing: self.mdiArea.setActiveSubWindow(existing) return child = self.createMdiChild() if child.loadFile(fileName): self.statusBar().showMessage("File loaded", 2000) child.show() else: child.close() def save(self): if self.activeMdiChild() and self.activeMdiChild().save(): self.statusBar().showMessage("File saved", 2000) def saveAs(self): if self.activeMdiChild() and self.activeMdiChild().saveAs(): self.statusBar().showMessage("File saved", 2000) def cut(self): if self.activeMdiChild(): self.activeMdiChild().cut() def copy(self): if self.activeMdiChild(): self.activeMdiChild().copy() def paste(self): if self.activeMdiChild(): self.activeMdiChild().paste() def about(self): QMessageBox.about( self, "About MDI", "The <b>MDI</b> example demonstrates how to write multiple " "document interface applications using Qt.") def updateMenus(self): hasMdiChild = (self.activeMdiChild() is not None) self.saveAct.setEnabled(hasMdiChild) self.saveAsAct.setEnabled(hasMdiChild) self.pasteAct.setEnabled(hasMdiChild) self.closeAct.setEnabled(hasMdiChild) self.closeAllAct.setEnabled(hasMdiChild) self.tileAct.setEnabled(hasMdiChild) self.cascadeAct.setEnabled(hasMdiChild) self.nextAct.setEnabled(hasMdiChild) self.previousAct.setEnabled(hasMdiChild) self.separatorAct.setVisible(hasMdiChild) hasSelection = (self.activeMdiChild() is not None and self.activeMdiChild().textCursor().hasSelection()) self.cutAct.setEnabled(hasSelection) self.copyAct.setEnabled(hasSelection) def updateWindowMenu(self): self.windowMenu.clear() self.windowMenu.addAction(self.closeAct) self.windowMenu.addAction(self.closeAllAct) self.windowMenu.addSeparator() self.windowMenu.addAction(self.tileAct) self.windowMenu.addAction(self.cascadeAct) self.windowMenu.addSeparator() self.windowMenu.addAction(self.nextAct) self.windowMenu.addAction(self.previousAct) self.windowMenu.addAction(self.separatorAct) windows = self.mdiArea.subWindowList() self.separatorAct.setVisible(len(windows) != 0) for i, window in enumerate(windows): child = window.widget() text = "%d %s" % (i + 1, child.userFriendlyCurrentFile()) if i < 9: text = '&' + text action = self.windowMenu.addAction(text) action.setCheckable(True) action.setChecked(child is self.activeMdiChild()) action.triggered.connect(self.windowMapper.map) self.windowMapper.setMapping(action, window) def createMdiChild(self): child = MdiChild() self.mdiArea.addSubWindow(child) child.copyAvailable.connect(self.cutAct.setEnabled) child.copyAvailable.connect(self.copyAct.setEnabled) return child def createActions(self): self.newAct = QAction(QIcon.fromTheme("document-new", QIcon(':/images/new.png')), "&New", self, shortcut=QKeySequence.New, statusTip="Create a new file", triggered=self.newFile) self.openAct = QAction(QIcon.fromTheme("document-open", QIcon(':/images/open.png')), "&Open...", self, shortcut=QKeySequence.Open, statusTip="Open an existing file", triggered=self.open) self.saveAct = QAction(QIcon.fromTheme("document-save", QIcon(':/images/save.png')), "&Save", self, shortcut=QKeySequence.Save, statusTip="Save the document to disk", triggered=self.save) self.saveAsAct = QAction( "Save &As...", self, shortcut=QKeySequence.SaveAs, statusTip="Save the document under a new name", triggered=self.saveAs) self.exitAct = QAction( "E&xit", self, shortcut=QKeySequence.Quit, statusTip="Exit the application", triggered=QApplication.instance().closeAllWindows) self.cutAct = QAction( QIcon.fromTheme("edit-cut", QIcon(':/images/cut.png')), "Cu&t", self, shortcut=QKeySequence.Cut, statusTip="Cut the current selection's contents to the clipboard", triggered=self.cut) self.copyAct = QAction( QIcon.fromTheme("edit-copy", QIcon(':/images/copy.png')), "&Copy", self, shortcut=QKeySequence.Copy, statusTip="Copy the current selection's contents to the clipboard", triggered=self.copy) self.pasteAct = QAction( QIcon.fromTheme("edit-paste", QIcon(':/images/paste.png')), "&Paste", self, shortcut=QKeySequence.Paste, statusTip= "Paste the clipboard's contents into the current selection", triggered=self.paste) self.closeAct = QAction("Cl&ose", self, statusTip="Close the active window", triggered=self.mdiArea.closeActiveSubWindow) self.closeAllAct = QAction("Close &All", self, statusTip="Close all the windows", triggered=self.mdiArea.closeAllSubWindows) self.tileAct = QAction("&Tile", self, statusTip="Tile the windows", triggered=self.mdiArea.tileSubWindows) self.cascadeAct = QAction("&Cascade", self, statusTip="Cascade the windows", triggered=self.mdiArea.cascadeSubWindows) self.nextAct = QAction("Ne&xt", self, shortcut=QKeySequence.NextChild, statusTip="Move the focus to the next window", triggered=self.mdiArea.activateNextSubWindow) self.previousAct = QAction( "Pre&vious", self, shortcut=QKeySequence.PreviousChild, statusTip="Move the focus to the previous window", triggered=self.mdiArea.activatePreviousSubWindow) self.separatorAct = QAction(self) self.separatorAct.setSeparator(True) self.aboutAct = QAction("&About", self, statusTip="Show the application's About box", triggered=self.about) self.aboutQtAct = QAction("About &Qt", self, statusTip="Show the Qt library's About box", triggered=QApplication.instance().aboutQt) def createMenus(self): self.fileMenu = self.menuBar().addMenu("&File") self.fileMenu.addAction(self.newAct) self.fileMenu.addAction(self.openAct) self.fileMenu.addAction(self.saveAct) self.fileMenu.addAction(self.saveAsAct) self.fileMenu.addSeparator() action = self.fileMenu.addAction("Switch layout direction") action.triggered.connect(self.switchLayoutDirection) self.fileMenu.addAction(self.exitAct) self.editMenu = self.menuBar().addMenu("&Edit") self.editMenu.addAction(self.cutAct) self.editMenu.addAction(self.copyAct) self.editMenu.addAction(self.pasteAct) self.windowMenu = self.menuBar().addMenu("&Window") self.updateWindowMenu() self.windowMenu.aboutToShow.connect(self.updateWindowMenu) self.menuBar().addSeparator() self.helpMenu = self.menuBar().addMenu("&Help") self.helpMenu.addAction(self.aboutAct) self.helpMenu.addAction(self.aboutQtAct) def createToolBars(self): self.fileToolBar = self.addToolBar("File") self.fileToolBar.addAction(self.newAct) self.fileToolBar.addAction(self.openAct) self.fileToolBar.addAction(self.saveAct) self.editToolBar = self.addToolBar("Edit") self.editToolBar.addAction(self.cutAct) self.editToolBar.addAction(self.copyAct) self.editToolBar.addAction(self.pasteAct) def createStatusBar(self): self.statusBar().showMessage("Ready") def readSettings(self): settings = QSettings('Trolltech', 'MDI Example') pos = settings.value('pos', QPoint(200, 200)) size = settings.value('size', QSize(400, 400)) self.move(pos) self.resize(size) def writeSettings(self): settings = QSettings('Trolltech', 'MDI Example') settings.setValue('pos', self.pos()) settings.setValue('size', self.size()) def activeMdiChild(self): activeSubWindow = self.mdiArea.activeSubWindow() if activeSubWindow: return activeSubWindow.widget() return None def findMdiChild(self, fileName): canonicalFilePath = QFileInfo(fileName).canonicalFilePath() for window in self.mdiArea.subWindowList(): if window.widget().currentFile() == canonicalFilePath: return window return None def switchLayoutDirection(self): if self.layoutDirection() == Qt.LeftToRight: QApplication.setLayoutDirection(Qt.RightToLeft) else: QApplication.setLayoutDirection(Qt.LeftToRight) def setActiveSubWindow(self, window): if window: self.mdiArea.setActiveSubWindow(window)
class MainWindow(QMainWindow): max_recent = 5 def __init__(self, parent=None): super(MainWindow, self).__init__(parent) QApplication.setApplicationName('Sherloq') QApplication.setOrganizationName('Guido Bartoli') QApplication.setOrganizationDomain('www.guidobartoli.com') QApplication.setApplicationVersion(ToolTree().version) QApplication.setWindowIcon(QIcon('icons/sherloq_white.png')) self.setWindowTitle('{} {}'.format(QApplication.applicationName(), QApplication.applicationVersion())) self.mdi_area = QMdiArea() self.setCentralWidget(self.mdi_area) self.filename = None self.image = None modify_font(self.statusBar(), bold=True) tree_dock = QDockWidget(self.tr('TOOLS'), self) tree_dock.setObjectName('tree_dock') tree_dock.setAllowedAreas(Qt.LeftDockWidgetArea | Qt.RightDockWidgetArea) self.addDockWidget(Qt.LeftDockWidgetArea, tree_dock) self.tree_widget = ToolTree() self.tree_widget.setObjectName('tree_widget') self.tree_widget.itemDoubleClicked.connect(self.open_tool) tree_dock.setWidget(self.tree_widget) tools_action = tree_dock.toggleViewAction() tools_action.setText(self.tr('Show tools')) tools_action.setToolTip(self.tr('Toggle toolset visibility')) tools_action.setShortcut(QKeySequence(Qt.Key_Tab)) tools_action.setObjectName('tools_action') tools_action.setIcon(QIcon('icons/tools.svg')) help_action = QAction(self.tr('Show help'), self) help_action.setToolTip(self.tr('Toggle online help')) help_action.setShortcut(QKeySequence.HelpContents) help_action.setObjectName('help_action') help_action.setIcon(QIcon('icons/help.svg')) help_action.setCheckable(True) help_action.setEnabled(False) load_action = QAction(self.tr('&Load image...'), self) load_action.setToolTip(self.tr('Load an image to analyze')) load_action.setShortcut(QKeySequence.Open) load_action.triggered.connect(self.load_file) load_action.setObjectName('load_action') load_action.setIcon(QIcon('icons/load.svg')) quit_action = QAction(self.tr('&Quit'), self) quit_action.setToolTip(self.tr('Exit from Sherloq')) quit_action.setShortcut(QKeySequence.Quit) quit_action.triggered.connect(self.close) quit_action.setObjectName('quit_action') quit_action.setIcon(QIcon('icons/quit.svg')) tabbed_action = QAction(self.tr('&Tabbed'), self) tabbed_action.setToolTip(self.tr('Toggle tabbed view for window area')) tabbed_action.setShortcut(QKeySequence(Qt.Key_F10)) tabbed_action.setCheckable(True) tabbed_action.triggered.connect(self.toggle_view) tabbed_action.setObjectName('tabbed_action') tabbed_action.setIcon(QIcon('icons/tabbed.svg')) prev_action = QAction(self.tr('&Previous'), self) prev_action.setToolTip(self.tr('Select the previous tool window')) prev_action.setShortcut(QKeySequence.PreviousChild) prev_action.triggered.connect(self.mdi_area.activatePreviousSubWindow) prev_action.setObjectName('prev_action') prev_action.setIcon(QIcon('icons/previous.svg')) next_action = QAction(self.tr('&Next'), self) next_action.setToolTip(self.tr('Select the next tool window')) next_action.setShortcut(QKeySequence.NextChild) next_action.triggered.connect(self.mdi_area.activateNextSubWindow) next_action.setObjectName('next_action') next_action.setIcon(QIcon('icons/next.svg')) tile_action = QAction(self.tr('&Tile'), self) tile_action.setToolTip( self.tr('Arrange windows into non-overlapping views')) tile_action.setShortcut(QKeySequence(Qt.Key_F11)) tile_action.triggered.connect(self.mdi_area.tileSubWindows) tile_action.setObjectName('tile_action') tile_action.setIcon(QIcon('icons/tile.svg')) cascade_action = QAction(self.tr('&Cascade'), self) cascade_action.setToolTip( self.tr('Arrange windows into overlapping views')) cascade_action.setShortcut(QKeySequence(Qt.Key_F12)) cascade_action.triggered.connect(self.mdi_area.cascadeSubWindows) cascade_action.setObjectName('cascade_action') cascade_action.setIcon(QIcon('icons/cascade.svg')) close_action = QAction(self.tr('Close &All'), self) close_action.setToolTip(self.tr('Close all open tool windows')) close_action.setShortcut(QKeySequence(Qt.CTRL + Qt.SHIFT + Qt.Key_W)) close_action.triggered.connect(self.mdi_area.closeAllSubWindows) close_action.setObjectName('close_action') close_action.setIcon(QIcon('icons/close.svg')) self.full_action = QAction(self.tr('Full screen'), self) self.full_action.setToolTip(self.tr('Switch to full screen mode')) self.full_action.setShortcut(QKeySequence.FullScreen) self.full_action.triggered.connect(self.change_view) self.full_action.setObjectName('full_action') self.full_action.setIcon(QIcon('icons/full.svg')) self.normal_action = QAction(self.tr('Normal view'), self) self.normal_action.setToolTip(self.tr('Back to normal view mode')) self.normal_action.setShortcut(QKeySequence(Qt.CTRL + Qt.Key_F12)) self.normal_action.triggered.connect(self.change_view) self.normal_action.setObjectName('normal_action') self.normal_action.setIcon(QIcon('icons/normal.svg')) about_action = QAction(self.tr('&About...'), self) about_action.setToolTip(self.tr('Information about this program')) about_action.triggered.connect(self.show_about) about_action.setObjectName('about_action') about_action.setIcon(QIcon('icons/sherloq_alpha.png')) about_qt_action = QAction(self.tr('About &Qt'), self) about_qt_action.setToolTip( self.tr('Information about the Qt Framework')) about_qt_action.triggered.connect(QApplication.aboutQt) about_qt_action.setIcon(QIcon('icons/Qt.svg')) file_menu = self.menuBar().addMenu(self.tr('&File')) file_menu.addAction(load_action) file_menu.addSeparator() self.recent_actions = [None] * self.max_recent for i in range(len(self.recent_actions)): self.recent_actions[i] = QAction(self) self.recent_actions[i].setVisible(False) self.recent_actions[i].triggered.connect(self.open_recent) file_menu.addAction(self.recent_actions[i]) file_menu.addSeparator() file_menu.addAction(quit_action) view_menu = self.menuBar().addMenu(self.tr('&View')) view_menu.addAction(tools_action) view_menu.addAction(help_action) view_menu.addSeparator() view_menu.addAction(self.full_action) view_menu.addAction(self.normal_action) window_menu = self.menuBar().addMenu(self.tr('&Window')) window_menu.addAction(prev_action) window_menu.addAction(next_action) window_menu.addSeparator() window_menu.addAction(tile_action) window_menu.addAction(cascade_action) window_menu.addAction(tabbed_action) window_menu.addSeparator() window_menu.addAction(close_action) help_menu = self.menuBar().addMenu(self.tr('&Help')) help_menu.addAction(help_action) help_menu.addSeparator() help_menu.addAction(about_action) help_menu.addAction(about_qt_action) main_toolbar = self.addToolBar(self.tr('&Toolbar')) main_toolbar.setToolButtonStyle(Qt.ToolButtonTextBesideIcon) main_toolbar.addAction(load_action) main_toolbar.addSeparator() main_toolbar.addAction(tools_action) main_toolbar.addAction(help_action) main_toolbar.addSeparator() main_toolbar.addAction(prev_action) main_toolbar.addAction(next_action) main_toolbar.addSeparator() main_toolbar.addAction(tile_action) main_toolbar.addAction(cascade_action) main_toolbar.addAction(tabbed_action) main_toolbar.addAction(close_action) # main_toolbar.addSeparator() # main_toolbar.addAction(self.normal_action) # main_toolbar.addAction(self.full_action) main_toolbar.setAllowedAreas(Qt.TopToolBarArea | Qt.BottomToolBarArea) main_toolbar.setObjectName('main_toolbar') settings = QSettings() settings.beginGroup('main_window') self.restoreGeometry(settings.value('geometry')) self.restoreState(settings.value('state')) self.recent_files = settings.value('recent_files') if self.recent_files is None: self.recent_files = [] elif not isinstance(self.recent_files, list): self.recent_files = [self.recent_files] self.update_recent() settings.endGroup() prev_action.setEnabled(False) next_action.setEnabled(False) tile_action.setEnabled(False) cascade_action.setEnabled(False) close_action.setEnabled(False) tabbed_action.setEnabled(False) self.tree_widget.setEnabled(False) self.showNormal() self.normal_action.setEnabled(False) self.show_message(self.tr('Ready')) def change_view(self): if self.isFullScreen(): self.showNormal() self.showMaximized() self.full_action.setEnabled(True) self.normal_action.setEnabled(False) else: self.showFullScreen() self.full_action.setEnabled(False) self.normal_action.setEnabled(True) def closeEvent(self, event): settings = QSettings() settings.beginGroup('main_window') settings.setValue('geometry', self.saveGeometry()) settings.setValue('state', self.saveState()) settings.setValue('recent_files', self.recent_files) settings.endGroup() super(MainWindow, self).closeEvent(event) def update_recent(self): if not self.recent_files: return self.recent_files = [f for f in self.recent_files if os.path.isfile(f)] for i in range(len(self.recent_actions)): if i < len(self.recent_files): text = '&{} {}'.format(i + 1, os.path.basename(self.recent_files[i])) self.recent_actions[i].setText(text) self.recent_actions[i].setData(self.recent_files[i]) self.recent_actions[i].setVisible(True) else: self.recent_actions[i].setVisible(False) def open_recent(self): action = self.sender() if action: filename, basename, image = load_image(self, action.data()) self.initialize(filename, basename, image) def initialize(self, filename, basename, image): self.filename = filename self.image = image self.findChild(ToolTree, 'tree_widget').setEnabled(True) self.findChild(QAction, 'prev_action').setEnabled(True) self.findChild(QAction, 'next_action').setEnabled(True) self.findChild(QAction, 'tile_action').setEnabled(True) self.findChild(QAction, 'cascade_action').setEnabled(True) self.findChild(QAction, 'close_action').setEnabled(True) self.findChild(QAction, 'tabbed_action').setEnabled(True) self.setWindowTitle('[{}] - {} {}'.format( basename, QApplication.applicationName(), QApplication.applicationVersion())) if filename not in self.recent_files: self.recent_files.insert(0, filename) if len(self.recent_files) > self.max_recent: self.recent_files = self.recent_files[:self.max_recent] self.update_recent() self.show_message( self.tr('Image "{}" successfully loaded'.format(basename))) # FIXME: disable_bold della chiusura viene chiamato DOPO open_tool e nell'albero la voce NON diventa neretto self.mdi_area.closeAllSubWindows() self.open_tool(self.tree_widget.topLevelItem(0).child(0), None) def load_file(self): filename, basename, image = load_image(self) if filename is None: return self.initialize(filename, basename, image) def open_tool(self, item, _): if not item.data(0, Qt.UserRole): return group = item.data(0, Qt.UserRole + 1) tool = item.data(0, Qt.UserRole + 2) for sub_window in self.mdi_area.subWindowList(): if sub_window.windowTitle() == item.text(0): sub_window.setWindowState(Qt.WindowActive) sub_window.setFocus() return if group == 0: if tool == 0: tool_widget = OriginalWidget(self.image) elif tool == 1: tool_widget = DigestWidget(self.filename, self.image) elif tool == 2: tool_widget = EditorWidget() elif tool == 3: tool_widget = ReverseWidget() else: return elif group == 1: if tool == 0: tool_widget = HeaderWidget(self.filename) elif tool == 1: tool_widget = ExifWidget(self.filename) elif tool == 2: tool_widget = ThumbWidget(self.filename, self.image) elif tool == 3: tool_widget = LocationWidget(self.filename) else: return elif group == 2: if tool == 0: tool_widget = MagnifierWidget(self.image) elif tool == 1: tool_widget = HistWidget(self.image) elif tool == 2: tool_widget = AdjustWidget(self.image) elif tool == 3: tool_widget = ComparisonWidget(self.filename, self.image) else: return elif group == 3: if tool == 0: tool_widget = GradientWidget(self.image) elif tool == 1: tool_widget = EchoWidget(self.image) elif tool == 2: tool_widget = WaveletWidget(self.image) else: return elif group == 4: if tool == 0: tool_widget = PlotsWidget(self.image) elif tool == 1: tool_widget = SpaceWidget(self.image) elif tool == 2: tool_widget = PcaWidget(self.image) elif tool == 3: tool_widget = StatsWidget(self.image) else: return elif group == 5: if tool == 0: tool_widget = NoiseWidget(self.image) elif tool == 1: tool_widget = MinMaxWidget(self.image) elif tool == 2: tool_widget = FrequencyWidget(self.image) elif tool == 3: tool_widget = PlanesWidget(self.image) else: return elif group == 6: if tool == 0: tool_widget = ElaWidget(self.image) elif tool == 1: tool_widget = QualityWidget(self.filename) elif tool == 2: tool_widget = MultipleWidget(self.image) else: return elif group == 7: if tool == 0: tool_widget = ContrastWidget(self.image) elif tool == 1: tool_widget = CloningWidget(self.image) elif tool == 2: # tool_widget = ResamplingWidget(self.image) pass else: return elif group == 8: if tool == 3: tool_widget = StereoWidget(self.image) else: return else: return # FIXME: Aggiungere un metodo init e dopo fare il connect, sennò i messaggi inviati nel costruttore non si vedono tool_widget.info_message.connect(self.show_message) sub_window = QMdiSubWindow() sub_window.setWidget(tool_widget) sub_window.setWindowTitle(item.text(0)) sub_window.setObjectName(item.text(0)) sub_window.setAttribute(Qt.WA_DeleteOnClose) sub_window.setWindowIcon(QIcon('icons/{}.svg'.format(group))) self.mdi_area.addSubWindow(sub_window) sub_window.show() sub_window.destroyed.connect(self.disable_bold) self.tree_widget.set_bold(item.text(0), enabled=True) def disable_bold(self, item): self.tree_widget.set_bold(item.windowTitle(), enabled=False) def toggle_view(self, tabbed): if tabbed: self.mdi_area.setViewMode(QMdiArea.TabbedView) self.mdi_area.setTabsClosable(True) self.mdi_area.setTabsMovable(True) else: self.mdi_area.setViewMode(QMdiArea.SubWindowView) self.findChild(QAction, 'tile_action').setEnabled(not tabbed) self.findChild(QAction, 'cascade_action').setEnabled(not tabbed) def show_about(self): message = '<h2>{} {}</h2>'.format(QApplication.applicationName(), QApplication.applicationVersion()) message += '<h3>A digital image forensic toolkit</h3>' message += '<p>author: <a href="{}">{}</a></p>'.format( QApplication.organizationDomain(), QApplication.organizationName()) message += '<p>source: <a href="https://github.com/GuidoBartoli/sherloq">GitHub repository</a></p>' QMessageBox.about(self, self.tr('About'), message) def show_message(self, message): self.statusBar().showMessage(message, 10000)
class MainWindow(QMainWindow): """ Main Window service for the nexxT frameworks. Other services usually create dock windows, filters use the subplot functionality to create grid-layouted views. """ mdiSubWindowCreated = Signal( QMdiSubWindow ) # TODO: remove, is not necessary anymore with subplot feature aboutToClose = Signal(object) def __init__(self, config): super().__init__() self.config = config self.config.appActivated.connect(self._appActivated) self.mdi = QMdiArea(self) self.mdi.setHorizontalScrollBarPolicy(Qt.ScrollBarAsNeeded) self.mdi.setVerticalScrollBarPolicy(Qt.ScrollBarAsNeeded) self.setCentralWidget(self.mdi) self.menu = self.menuBar().addMenu("&Windows") self.aboutMenu = QMenuBar(self) self.menuBar().setCornerWidget(self.aboutMenu) m = self.aboutMenu.addMenu("&About") self.aboutNexxT = QAction("About nexxT ...") self.aboutQt = QAction("About Qt ...") self.aboutPython = QAction("About Python ...") m.addActions([self.aboutNexxT, self.aboutQt, self.aboutPython]) self.aboutNexxT.triggered.connect(lambda: QMessageBox.about( self, "About nexxT", """\ This program uses <b>nexxT</b> %(version)s, a generic hybrid python/c++ framework for developing computer vision algorithms.<br><br> nexxT is available under the <a href='https://github.com/ifm/nexxT/blob/master/LICENSE'>Apache 2.0 License</a> together with the <a href='https://github.com/ifm/nexxT/blob/master/NOTICE'>notice</a>. """ % dict(version=nexxT.__version__))) self.aboutQt.triggered.connect(lambda: QMessageBox.aboutQt(self)) self.aboutPython.triggered.connect(self._aboutPython) self.toolbar = None self.managedMdiWindows = [] self.managedSubplots = {} self.windows = {} self.activeApp = None self._ignoreCloseEvent = False def closeEvent(self, closeEvent): """ Override from QMainWindow, saves the state. :param closeEvent: a QCloseEvent instance :return: """ self._ignoreCloseEvent = False self.aboutToClose.emit(self) if self._ignoreCloseEvent: logger.info("Ignoring event") closeEvent.ignore() return closeEvent.accept() self.saveState() self.saveMdiState() super().closeEvent(closeEvent) def ignoreCloseEvent(self): """ Can be called in slots connected to aboutToClose for requesting to ignore the event. Use case is the "There are unsaved changes" dialog. :return: """ self._ignoreCloseEvent = True def restoreState(self): """ restores the state of the main window including the dock windows of Services :return: """ logger.info("restoring main window's state") settings = QSettings() v = settings.value("MainWindowState") if v is not None: super().restoreState(v) v = settings.value("MainWindowGeometry") if v is not None: self.restoreGeometry(v) if self.toolbar is not None: # TODO: add toolbar to windows menu, so we don't need this self.toolbar.show() def saveState(self): """ saves the state of the main window including the dock windows of Services :return: """ logger.info("saving main window's state") settings = QSettings() settings.setValue("MainWindowState", super().saveState()) settings.setValue("MainWindowGeometry", self.saveGeometry()) def saveMdiState(self): """ saves the state of the individual MDI windows :return: """ for i in self.managedMdiWindows: window = i["window"] propColl = i["propColl"] prefix = i["prefix"] logger.debug("save window geometry %s: %s", prefix, window.geometry()) geom = str(window.saveGeometry().toBase64(), "ascii") visible = self.windows[shiboken2.getCppPointer(window) [0]].isChecked() # pylint: disable=no-member propColl.setProperty(prefix + "_geom", geom) logger.debug("%s is visible: %d", prefix, int(visible)) propColl.setProperty(prefix + "_visible", int(visible)) self.managedMdiWindows = [] def __del__(self): logging.getLogger(__name__).debug("deleting MainWindow") @Slot() def getToolBar(self): """ Get the main toolbar (adds seperators as appropriate). :return: """ if self.toolbar is None: self.toolbar = self.addToolBar("NexxT") self.toolbar.setObjectName("NexxT_main_toolbar") else: self.toolbar.addSeparator() return self.toolbar @Slot(str, QObject, int, int) def newDockWidget(self, name, parent, defaultArea, allowedArea=Qt.LeftDockWidgetArea | Qt.BottomDockWidgetArea, defaultLoc=None): """ This function is supposed to be called by services :param name: the name of the dock window :param parent: the parent (usually None) :param defaultArea: the default dock area :param allowedArea: the allowed dock areas :return: a new QDockWindow instance """ res = NexxTDockWidget(name, parent if parent is not None else self) res.setAllowedAreas(allowedArea) res.setAttribute(Qt.WA_DeleteOnClose, False) self.addDockWidget(defaultArea, res) self._registerWindow(res, res.objectNameChanged) res.setObjectName(name) if defaultLoc is not None: dl = self.findChild(QDockWidget, defaultLoc) if dl is not None: self.tabifyDockWidget(dl, res) return res @staticmethod def parseWindowId(windowId): """ convers a subplot window id into windowTitle, row and column :param windowId: the window id :return: title, row, column """ regexp = re.compile(r"([^\[]+)\[(\d+),\s*(\d+)\]") match = regexp.match(windowId) if not match is None: return match.group(1), int(match.group(2)), int(match.group(3)) return windowId, 0, 0 @Slot(str, QObject, QWidget) def subplot(self, windowId, theFilter, widget): """ Adds widget to the GridLayout specified by windowId. :param windowId: a string with the format "<windowTitle>[<row>,<col>]" where <windowTitle> is the caption of the MDI window (and it is used as identifier for saving/restoring window state) and <row>, <col> are the coordinates of the addressed subplots (starting at 0) :param theFilter: a Filter instance which is requesting the subplot :param widget: a QWidget which shall be placed into the grid layout. Note that this widget is reparented as a result of this operation and the parents can be used to get access to the MDI sub window. Use releaseSubplot to remove the window :return: None """ logger.internal("subplot '%s'", windowId) title, row, col = self.parseWindowId(windowId) if title == "": title = "(view)" if title in self.managedSubplots and ( row, col) in self.managedSubplots[title]["plots"]: logger.warning( "subplot %s[%d,%d] is already registered. Creating a new window for the plot.", title, row, col) i = 2 while "%s(%d)" % (title, i) in self.managedSubplots: i += 1 title = "%s(%d)" % (title, i) row = 0 col = 0 if title not in self.managedSubplots: subWindow = self._newMdiSubWindow(theFilter, title) swwidget = QWidget() subWindow.setWidget(swwidget) layout = QGridLayout(swwidget) swwidget.setLayout(layout) self.managedSubplots[title] = dict(mdiSubWindow=subWindow, layout=layout, swwidget=swwidget, plots={}) self.managedSubplots[title]["layout"].addWidget(widget, row, col) self.managedSubplots[title]["mdiSubWindow"].updateGeometry() widget.setParent(self.managedSubplots[title]["swwidget"]) QTimer.singleShot( 0, lambda: (self.managedSubplots[title]["mdiSubWindow"].adjustSize() if widget.parent().size().height() < widget.minimumSizeHint(). height() or widget.parent().size().height() < widget.minimumSize( ).height() else None)) self.managedSubplots[title]["plots"][row, col] = widget @Slot(QWidget) @Slot(str) def releaseSubplot(self, arg): """ This needs to be called to release the previously allocated subplot called windowId. The managed widget is deleted as a consequence of this function. :param arg: the widget as passed to subplot. Passing the windowId is also supported, but deprecated. :return: """ if isinstance(arg, str): windowId = arg logger.warning( "Using deprecated API to release a subplot. Please pass the widget instead of the windowId." ) logger.internal("releaseSubplot '%s'", windowId) title, row, col = self.parseWindowId(windowId) if title not in self.managedSubplots or ( row, col) not in self.managedSubplots[title]["plots"]: logger.warning("releasSubplot: cannot find %s", windowId) return widget = self.managedSubplots[title]["plots"][row, col] elif isinstance(arg, QWidget): widget = arg found = False for title in self.managedSubplots: for row, col in self.managedSubplots[title]["plots"]: if self.managedSubplots[title]["plots"][row, col] is widget: found = True break if found: break if not found: raise RuntimeError( "cannot find widget given for releaseSubplot.") else: raise RuntimeError( "arg of releaseSubplot must be either a string or a QWidget instance." ) self.managedSubplots[title]["layout"].removeWidget(widget) self.managedSubplots[title]["plots"][row, col].deleteLater() del self.managedSubplots[title]["plots"][row, col] if len(self.managedSubplots[title]["plots"]) == 0: self.managedSubplots[title]["layout"].deleteLater() self.managedSubplots[title]["swwidget"].deleteLater() self.managedSubplots[title]["mdiSubWindow"].deleteLater() del self.managedSubplots[title] @Slot(QObject) @Slot(QObject, str) def newMdiSubWindow(self, filterOrService, windowTitle=None): """ Deprectated (use subplot(...) instead): This function is supposed to be called by filters. :param filterOrService: a Filter instance :param windowTitle: the title of the window (might be None) :return: a new QMdiSubWindow instance """ logger.warning( "This function is deprecated. Use subplot function instead.") return self._newMdiSubWindow(filterOrService, windowTitle) def _newMdiSubWindow(self, filterOrService, windowTitle): res = NexxTMdiSubWindow(None) res.setAttribute(Qt.WA_DeleteOnClose, False) self.mdi.addSubWindow(res) self._registerWindow(res, res.windowTitleChanged) if isinstance(filterOrService, Filter): propColl = filterOrService.guiState() res.setWindowTitle( propColl.objectName() if windowTitle is None else windowTitle) else: app = Application.activeApplication.getApplication() propColl = app.guiState("services/MainWindow") res.setWindowTitle( "<unnamed>" if windowTitle is None else windowTitle) prefix = re.sub(r'[^A-Za-z_0-9]', '_', "MainWindow_MDI_" + res.windowTitle()) i = dict(window=res, propColl=propColl, prefix=prefix) self.managedMdiWindows.append(i) window = i["window"] propColl = i["propColl"] prefix = i["prefix"] propColl.defineProperty(prefix + "_geom", "", "Geometry of MDI window") b = QByteArray.fromBase64( bytes(propColl.getProperty(prefix + "_geom"), "ascii")) window.restoreGeometry(b) logger.debug("restored geometry %s:%s (%s)", prefix, window.geometry(), b) propColl.defineProperty(prefix + "_visible", 1, "Visibility of MDI window") if propColl.getProperty(prefix + "_visible"): window.show() else: window.hide() self.mdiSubWindowCreated.emit(res) return res def _registerWindow(self, window, nameChangedSignal): act = QAction("<unnamed>", self) act.setCheckable(True) act.toggled.connect(window.setVisible) window.visibleChanged.connect(act.setChecked) nameChangedSignal.connect(act.setText) self.windows[shiboken2.getCppPointer(window)[0]] = act # pylint: disable=no-member self.menu.addAction(act) logger.debug("Registering window %s, new len=%d", shiboken2.getCppPointer(window), len(self.windows)) # pylint: disable=no-member window.destroyed.connect(self._windowDestroyed) def _windowDestroyed(self, obj): logger.internal("_windowDestroyed") ptr = shiboken2.getCppPointer(obj) # pylint: disable=no-member try: ptr = ptr[0] except TypeError: pass logger.debug("Deregistering window %s, old len=%d", ptr, len(self.windows)) self.windows[ptr].deleteLater() del self.windows[ptr] logger.debug("Deregistering window %s done", ptr) def _appActivated(self, name, app): if app is not None: self.activeApp = name app.aboutToClose.connect(self.saveMdiState, Qt.UniqueConnection) else: self.activeApp = None def _aboutPython(self): piplic = subprocess.check_output( [sys.executable, "-m", "piplicenses", "--format=plain"], encoding="utf-8").replace("\n", "<br>").replace(" ", " ") QMessageBox.about( self, "About python", """\ This program uses <b>python</b> %(version)s and the following installed python packages.<br><br> <pre> %(table)s </pre> """ % dict(version=sys.version, table=piplic))
class MainWindow(QMainWindow): def __init__(self): super(MainWindow, self).__init__() self.mdiArea = QMdiArea() self.mdiArea.setHorizontalScrollBarPolicy(Qt.ScrollBarAsNeeded) self.mdiArea.setVerticalScrollBarPolicy(Qt.ScrollBarAsNeeded) self.setCentralWidget(self.mdiArea) self.mdiArea.subWindowActivated.connect(self.updateMenus) self.windowMapper = QSignalMapper(self) self.windowMapper.mapped[QWidget].connect(self.setActiveSubWindow) self.createActions() self.createMenus() self.createToolBars() self.createStatusBar() self.updateMenus() self.readSettings() self.setWindowTitle("MDI") def closeEvent(self, event): self.mdiArea.closeAllSubWindows() if self.mdiArea.currentSubWindow(): event.ignore() else: self.writeSettings() event.accept() def newFile(self): child = self.createMdiChild() child.newFile() child.show() def open(self): fileName, _ = QFileDialog.getOpenFileName(self) if fileName: existing = self.findMdiChild(fileName) if existing: self.mdiArea.setActiveSubWindow(existing) return child = self.createMdiChild() if child.loadFile(fileName): self.statusBar().showMessage("File loaded", 2000) child.show() else: child.close() def save(self): if self.activeMdiChild() and self.activeMdiChild().save(): self.statusBar().showMessage("File saved", 2000) def saveAs(self): if self.activeMdiChild() and self.activeMdiChild().saveAs(): self.statusBar().showMessage("File saved", 2000) def cut(self): if self.activeMdiChild(): self.activeMdiChild().cut() def copy(self): if self.activeMdiChild(): self.activeMdiChild().copy() def paste(self): if self.activeMdiChild(): self.activeMdiChild().paste() def about(self): QMessageBox.about(self, "About MDI", "The <b>MDI</b> example demonstrates how to write multiple " "document interface applications using Qt.") def updateMenus(self): hasMdiChild = (self.activeMdiChild() is not None) self.saveAct.setEnabled(hasMdiChild) self.saveAsAct.setEnabled(hasMdiChild) self.pasteAct.setEnabled(hasMdiChild) self.closeAct.setEnabled(hasMdiChild) self.closeAllAct.setEnabled(hasMdiChild) self.tileAct.setEnabled(hasMdiChild) self.cascadeAct.setEnabled(hasMdiChild) self.nextAct.setEnabled(hasMdiChild) self.previousAct.setEnabled(hasMdiChild) self.separatorAct.setVisible(hasMdiChild) hasSelection = (self.activeMdiChild() is not None and self.activeMdiChild().textCursor().hasSelection()) self.cutAct.setEnabled(hasSelection) self.copyAct.setEnabled(hasSelection) def updateWindowMenu(self): self.windowMenu.clear() self.windowMenu.addAction(self.closeAct) self.windowMenu.addAction(self.closeAllAct) self.windowMenu.addSeparator() self.windowMenu.addAction(self.tileAct) self.windowMenu.addAction(self.cascadeAct) self.windowMenu.addSeparator() self.windowMenu.addAction(self.nextAct) self.windowMenu.addAction(self.previousAct) self.windowMenu.addAction(self.separatorAct) windows = self.mdiArea.subWindowList() self.separatorAct.setVisible(len(windows) != 0) for i, window in enumerate(windows): child = window.widget() text = "%d %s" % (i + 1, child.userFriendlyCurrentFile()) if i < 9: text = '&' + text action = self.windowMenu.addAction(text) action.setCheckable(True) action.setChecked(child is self.activeMdiChild()) action.triggered.connect(self.windowMapper.map) self.windowMapper.setMapping(action, window) def createMdiChild(self): child = MdiChild() self.mdiArea.addSubWindow(child) child.copyAvailable.connect(self.cutAct.setEnabled) child.copyAvailable.connect(self.copyAct.setEnabled) return child def createActions(self): self.newAct = QAction(QIcon.fromTheme("document-new", QIcon(':/images/new.png')), "&New", self, shortcut=QKeySequence.New, statusTip="Create a new file", triggered=self.newFile) self.openAct = QAction(QIcon.fromTheme("document-open", QIcon(':/images/open.png')), "&Open...", self, shortcut=QKeySequence.Open, statusTip="Open an existing file", triggered=self.open) self.saveAct = QAction(QIcon.fromTheme("document-save", QIcon(':/images/save.png')), "&Save", self, shortcut=QKeySequence.Save, statusTip="Save the document to disk", triggered=self.save) self.saveAsAct = QAction("Save &As...", self, shortcut=QKeySequence.SaveAs, statusTip="Save the document under a new name", triggered=self.saveAs) self.exitAct = QAction("E&xit", self, shortcut=QKeySequence.Quit, statusTip="Exit the application", triggered=QApplication.instance().closeAllWindows) self.cutAct = QAction(QIcon.fromTheme("edit-cut", QIcon(':/images/cut.png')), "Cu&t", self, shortcut=QKeySequence.Cut, statusTip="Cut the current selection's contents to the clipboard", triggered=self.cut) self.copyAct = QAction(QIcon.fromTheme("edit-copy", QIcon(':/images/copy.png')), "&Copy", self, shortcut=QKeySequence.Copy, statusTip="Copy the current selection's contents to the clipboard", triggered=self.copy) self.pasteAct = QAction(QIcon.fromTheme("edit-paste", QIcon(':/images/paste.png')), "&Paste", self, shortcut=QKeySequence.Paste, statusTip="Paste the clipboard's contents into the current selection", triggered=self.paste) self.closeAct = QAction("Cl&ose", self, statusTip="Close the active window", triggered=self.mdiArea.closeActiveSubWindow) self.closeAllAct = QAction("Close &All", self, statusTip="Close all the windows", triggered=self.mdiArea.closeAllSubWindows) self.tileAct = QAction("&Tile", self, statusTip="Tile the windows", triggered=self.mdiArea.tileSubWindows) self.cascadeAct = QAction("&Cascade", self, statusTip="Cascade the windows", triggered=self.mdiArea.cascadeSubWindows) self.nextAct = QAction("Ne&xt", self, shortcut=QKeySequence.NextChild, statusTip="Move the focus to the next window", triggered=self.mdiArea.activateNextSubWindow) self.previousAct = QAction("Pre&vious", self, shortcut=QKeySequence.PreviousChild, statusTip="Move the focus to the previous window", triggered=self.mdiArea.activatePreviousSubWindow) self.separatorAct = QAction(self) self.separatorAct.setSeparator(True) self.aboutAct = QAction("&About", self, statusTip="Show the application's About box", triggered=self.about) self.aboutQtAct = QAction("About &Qt", self, statusTip="Show the Qt library's About box", triggered=QApplication.instance().aboutQt) def createMenus(self): self.fileMenu = self.menuBar().addMenu("&File") self.fileMenu.addAction(self.newAct) self.fileMenu.addAction(self.openAct) self.fileMenu.addAction(self.saveAct) self.fileMenu.addAction(self.saveAsAct) self.fileMenu.addSeparator() action = self.fileMenu.addAction("Switch layout direction") action.triggered.connect(self.switchLayoutDirection) self.fileMenu.addAction(self.exitAct) self.editMenu = self.menuBar().addMenu("&Edit") self.editMenu.addAction(self.cutAct) self.editMenu.addAction(self.copyAct) self.editMenu.addAction(self.pasteAct) self.windowMenu = self.menuBar().addMenu("&Window") self.updateWindowMenu() self.windowMenu.aboutToShow.connect(self.updateWindowMenu) self.menuBar().addSeparator() self.helpMenu = self.menuBar().addMenu("&Help") self.helpMenu.addAction(self.aboutAct) self.helpMenu.addAction(self.aboutQtAct) def createToolBars(self): self.fileToolBar = self.addToolBar("File") self.fileToolBar.addAction(self.newAct) self.fileToolBar.addAction(self.openAct) self.fileToolBar.addAction(self.saveAct) self.editToolBar = self.addToolBar("Edit") self.editToolBar.addAction(self.cutAct) self.editToolBar.addAction(self.copyAct) self.editToolBar.addAction(self.pasteAct) def createStatusBar(self): self.statusBar().showMessage("Ready") def readSettings(self): settings = QSettings('Trolltech', 'MDI Example') pos = settings.value('pos', QPoint(200, 200)) size = settings.value('size', QSize(400, 400)) self.move(pos) self.resize(size) def writeSettings(self): settings = QSettings('Trolltech', 'MDI Example') settings.setValue('pos', self.pos()) settings.setValue('size', self.size()) def activeMdiChild(self): activeSubWindow = self.mdiArea.activeSubWindow() if activeSubWindow: return activeSubWindow.widget() return None def findMdiChild(self, fileName): canonicalFilePath = QFileInfo(fileName).canonicalFilePath() for window in self.mdiArea.subWindowList(): if window.widget().currentFile() == canonicalFilePath: return window return None def switchLayoutDirection(self): if self.layoutDirection() == Qt.LeftToRight: QApplication.setLayoutDirection(Qt.RightToLeft) else: QApplication.setLayoutDirection(Qt.LeftToRight) def setActiveSubWindow(self, window): if window: self.mdiArea.setActiveSubWindow(window)
class WindowWidget(QMainWindow): def __init__(self): super().__init__() self.init_ui() def init_ui(self): self.formCoin = None self.formCliente = None # title, geoemtry and icon for this window self.setWindowTitle("Pyside2 MDI Window") self.setGeometry(100, 100, 900, 500) self.setWindowIcon(QIcon("pyicon.png")) # creating object of MDI self.mdi = QMdiArea() self.setCentralWidget(self.mdi) # our menu bar menu_bar = self.menuBar() # our menu items file = menu_bar.addMenu("File") file.addAction("Coin") file.addAction("Cliente") file.addAction("Cascade") # file.addAction("Tiled") file.triggered[QAction].connect(self.window_triggered) self.showMaximized() def loadSubWindow(self, widget): window = self.mdi.addSubWindow(widget) window.setFixedSize(window.size()) window.setWindowFlags( QtCore.Qt.Dialog | QtCore.Qt.WindowCloseButtonHint | QtCore.Qt.WindowMinimizeButtonHint | QtCore.Qt.CustomizeWindowHint ) window.move( (self.mdi.width() - window.width() - 10) / 2, (self.mdi.height() - window.height() - 90) / 2, ) window.show() def findMdiChild(self, fileName): for window in self.mdi.subWindowList(): if window.widget().windowTitle() == fileName: return window return None def window_triggered(self, p): if p.text() == "Coin": existing = self.findMdiChild('Coin') if existing is None: self.formCoin = Coin("coin.ui") self.loadSubWindow(self.formCoin) else: self.formCoin.setFocus() if p.text() == "Cliente": existing = self.findMdiChild('Cliente') if existing is None: self.formCliente = Cliente("clienteform.ui") self.loadSubWindow(self.formCliente) else: self.formCliente.setFocus() if p.text() == "Cascade": self.mdi.cascadeSubWindows() if p.text() == "Tiled": self.mdi.tileSubWindows()
class MainWindow(QMainWindow): def __init__(self, parent=None): super().__init__(parent) self.setWindowIcon(QIcon(":/icons/apps/16/tabulator.svg")) self._recentDocuments = [] self._actionRecentDocuments = [] self._keyboardShortcutsDialog = None self._preferences = Preferences() self._preferences.loadSettings() self._createActions() self._createMenus() self._createToolBars() self._loadSettings() self._updateActions() self._updateActionFullScreen() self._updateMenuOpenRecent() # Central widget self._documentArea = QMdiArea() self._documentArea.setViewMode(QMdiArea.TabbedView) self._documentArea.setTabsMovable(True) self._documentArea.setTabsClosable(True) self.setCentralWidget(self._documentArea) self._documentArea.subWindowActivated.connect(self._onDocumentWindowActivated) def closeEvent(self, event): if True: # Store application properties and preferences self._saveSettings() self._preferences.saveSettings() event.accept() else: event.ignore() def _loadSettings(self): settings = QSettings() # Recent documents size = settings.beginReadArray("RecentDocuments") for idx in range(size-1, -1, -1): settings.setArrayIndex(idx) canonicalName = QFileInfo(settings.value("Document")).canonicalFilePath() self._updateRecentDocuments(canonicalName) settings.endArray() # Application properties: Geometry geometry = settings.value("Application/Geometry", QByteArray()) if self._preferences.restoreApplicationGeometry() else QByteArray() if not geometry.isEmpty(): self.restoreGeometry(geometry) else: availableGeometry = self.screen().availableGeometry() self.resize(availableGeometry.width() * 2/3, availableGeometry.height() * 2/3) self.move((availableGeometry.width() - self.width()) / 2, (availableGeometry.height() - self.height()) / 2) # Application properties: State state = settings.value("Application/State", QByteArray()) if self._preferences.restoreApplicationState() else QByteArray() if not state.isEmpty(): self.restoreState(state) else: self._toolbarApplication.setVisible(True) self._toolbarDocument.setVisible(True) self._toolbarEdit.setVisible(True) self._toolbarTools.setVisible(True) self._toolbarView.setVisible(False) self._toolbarHelp.setVisible(False) def _saveSettings(self): settings = QSettings() # Recent documents if not self._preferences.restoreRecentDocuments(): self._recentDocuments.clear() settings.remove("RecentDocuments") settings.beginWriteArray("RecentDocuments") for idx in range(len(self._recentDocuments)): settings.setArrayIndex(idx) settings.setValue("Document", self._recentDocuments[idx]) settings.endArray() # Application properties: Geometry geometry = self.saveGeometry() if self._preferences.restoreApplicationGeometry() else QByteArray() settings.setValue("Application/Geometry", geometry) # Application properties: State state = self.saveState() if self._preferences.restoreApplicationState() else QByteArray() settings.setValue("Application/State", state) def _createActions(self): # # Actions: Application self._actionAbout = QAction(self.tr("About {0}").format(QApplication.applicationName()), self) self._actionAbout.setObjectName("actionAbout") self._actionAbout.setIcon(QIcon(":/icons/apps/16/tabulator.svg")) self._actionAbout.setIconText(self.tr("About")) self._actionAbout.setToolTip(self.tr("Brief description of the application")) self._actionAbout.triggered.connect(self._onActionAboutTriggered) self._actionColophon = QAction(self.tr("Colophon"), self) self._actionColophon.setObjectName("actionColophon") self._actionColophon.setToolTip(self.tr("Lengthy description of the application")) self._actionColophon.triggered.connect(self._onActionColophonTriggered) self._actionPreferences = QAction(self.tr("Preferences…"), self) self._actionPreferences.setObjectName("actionPreferences") self._actionPreferences.setIcon(QIcon.fromTheme("configure", QIcon(":/icons/actions/16/application-configure.svg"))) self._actionPreferences.setToolTip(self.tr("Customize the appearance and behavior of the application")) self._actionPreferences.triggered.connect(self._onActionPreferencesTriggered) self._actionQuit = QAction(self.tr("Quit"), self) self._actionQuit.setObjectName("actionQuit") self._actionQuit.setIcon(QIcon.fromTheme("application-exit", QIcon(":/icons/actions/16/application-exit.svg"))) self._actionQuit.setShortcut(QKeySequence.Quit) self._actionQuit.setToolTip(self.tr("Quit the application")) self._actionQuit.triggered.connect(self.close) # # Actions: Document self._actionNew = QAction(self.tr("New"), self) self._actionNew.setObjectName("actionNew") self._actionNew.setIcon(QIcon.fromTheme("document-new", QIcon(":/icons/actions/16/document-new.svg"))) self._actionNew.setShortcut(QKeySequence.New) self._actionNew.setToolTip(self.tr("Create new document")) self._actionNew.triggered.connect(self._onActionNewTriggered) self._actionOpen = QAction(self.tr("Open…"), self) self._actionOpen.setObjectName("actionOpen") self._actionOpen.setIcon(QIcon.fromTheme("document-open", QIcon(":/icons/actions/16/document-open.svg"))) self._actionOpen.setShortcut(QKeySequence.Open) self._actionOpen.setToolTip(self.tr("Open an existing document")) self._actionOpen.triggered.connect(self._onActionOpenTriggered) self._actionOpenRecentClear = QAction(self.tr("Clear List"), self) self._actionOpenRecentClear.setObjectName("actionOpenRecentClear") self._actionOpenRecentClear.setToolTip(self.tr("Clear document list")) self._actionOpenRecentClear.triggered.connect(self._onActionOpenRecentClearTriggered) self._actionSave = QAction(self.tr("Save"), self) self._actionSave.setObjectName("actionSave") self._actionSave.setIcon(QIcon.fromTheme("document-save", QIcon(":/icons/actions/16/document-save.svg"))) self._actionSave.setShortcut(QKeySequence.Save) self._actionSave.setToolTip(self.tr("Save document")) self._actionSave.triggered.connect(self._onActionSaveTriggered) self._actionSaveAs = QAction(self.tr("Save As…"), self) self._actionSaveAs.setObjectName("actionSaveAs") self._actionSaveAs.setIcon(QIcon.fromTheme("document-save-as", QIcon(":/icons/actions/16/document-save-as.svg"))) self._actionSaveAs.setShortcut(QKeySequence.SaveAs) self._actionSaveAs.setToolTip(self.tr("Save document under a new name")) self._actionSaveAs.triggered.connect(self._onActionSaveAsTriggered) self._actionSaveAsDelimiterColon = QAction(self.tr("Colon"), self) self._actionSaveAsDelimiterColon.setObjectName("actionSaveAsDelimiterColon") self._actionSaveAsDelimiterColon.setCheckable(True) self._actionSaveAsDelimiterColon.setToolTip(self.tr("Save document with colon as delimiter under a new name")) self._actionSaveAsDelimiterColon.setData("colon") self._actionSaveAsDelimiterColon.triggered.connect(lambda: self._onActionSaveAsDelimiterTriggered("colon") ) self._actionSaveAsDelimiterComma = QAction(self.tr("Comma"), self) self._actionSaveAsDelimiterComma.setObjectName("actionSaveAsDelimiterComma") self._actionSaveAsDelimiterComma.setCheckable(True) self._actionSaveAsDelimiterComma.setToolTip(self.tr("Save document with comma as delimiter under a new name")) self._actionSaveAsDelimiterComma.setData("comma") self._actionSaveAsDelimiterComma.triggered.connect(lambda: self._onActionSaveAsDelimiterTriggered("comma") ) self._actionSaveAsDelimiterSemicolon = QAction(self.tr("Semicolon"), self) self._actionSaveAsDelimiterSemicolon.setObjectName("actionSaveAsDelimiterSemicolon") self._actionSaveAsDelimiterSemicolon.setCheckable(True) self._actionSaveAsDelimiterSemicolon.setToolTip(self.tr("Save document with semicolon as delimiter under a new name")) self._actionSaveAsDelimiterSemicolon.setData("semicolon") self._actionSaveAsDelimiterSemicolon.triggered.connect(lambda: self._onActionSaveAsDelimiterTriggered("semicolon") ) self._actionSaveAsDelimiterTab = QAction(self.tr("Tab"), self) self._actionSaveAsDelimiterTab.setObjectName("actionSaveAsDelimiterTab") self._actionSaveAsDelimiterTab.setCheckable(True) self._actionSaveAsDelimiterTab.setToolTip(self.tr("Save document with tab as delimiter under a new name")) self._actionSaveAsDelimiterTab.setData("tab") self._actionSaveAsDelimiterTab.triggered.connect(lambda: self._onActionSaveAsDelimiterTriggered("tab") ) self._actionSaveAsDelimiter = QActionGroup(self) self._actionSaveAsDelimiter.setObjectName("actionSaveAsDelimiter") self._actionSaveAsDelimiter.addAction(self._actionSaveAsDelimiterColon) self._actionSaveAsDelimiter.addAction(self._actionSaveAsDelimiterComma) self._actionSaveAsDelimiter.addAction(self._actionSaveAsDelimiterSemicolon) self._actionSaveAsDelimiter.addAction(self._actionSaveAsDelimiterTab) self._actionSaveCopyAs = QAction(self.tr("Save Copy As…"), self) self._actionSaveCopyAs.setObjectName("actionSaveCopyAs") self._actionSaveCopyAs.setIcon(QIcon.fromTheme("document-save-as", QIcon(":/icons/actions/16/document-save-as.svg"))) self._actionSaveCopyAs.setToolTip(self.tr("Save copy of document under a new name")) self._actionSaveCopyAs.triggered.connect(self._onActionSaveCopyAsTriggered) self._actionSaveAll = QAction(self.tr("Save All"), self) self._actionSaveAll.setObjectName("actionSaveAll") self._actionSaveAll.setIcon(QIcon.fromTheme("document-save-all", QIcon(":/icons/actions/16/document-save-all.svg"))) self._actionSaveAll.setShortcut(QKeySequence(Qt.CTRL + Qt.Key_L)) self._actionSaveAll.setToolTip(self.tr("Save all documents")) self._actionSaveAll.triggered.connect(self._onActionSaveAllTriggered) self._actionClose = QAction(self.tr("Close"), self) self._actionClose.setObjectName("actionClose") self._actionClose.setIcon(QIcon.fromTheme("document-close", QIcon(":/icons/actions/16/document-close.svg"))) self._actionClose.setShortcut(QKeySequence.Close) self._actionClose.setToolTip(self.tr("Close document")) self._actionClose.triggered.connect(self._onActionCloseTriggered) self._actionCloseOther = QAction(self.tr("Close Other"), self) self._actionCloseOther.setObjectName("actionCloseOther") self._actionCloseOther.setToolTip(self.tr("Close all other documents")) self._actionCloseOther.triggered.connect(self._onActionCloseOtherTriggered) self._actionCloseAll = QAction(self.tr("Close All"), self) self._actionCloseAll.setObjectName("actionCloseAll") self._actionCloseAll.setShortcut(QKeySequence(Qt.CTRL + Qt.SHIFT + Qt.Key_W)) self._actionCloseAll.setToolTip(self.tr("Close all documents")) self._actionCloseAll.triggered.connect(self._onActionCloseAllTriggered) # # Actions: View self._actionFullScreen = QAction(self) self._actionFullScreen.setObjectName("actionFullScreen") self._actionFullScreen.setIconText(self.tr("Full Screen")) self._actionFullScreen.setCheckable(True) self._actionFullScreen.setShortcuts([QKeySequence(Qt.Key_F11), QKeySequence.FullScreen]) self._actionFullScreen.triggered.connect(self._onActionFullScreenTriggered) self._actionTitlebarFullPath = QAction(self.tr("Show Path in Titlebar"), self) self._actionTitlebarFullPath.setObjectName("actionTitlebarFullPath") self._actionTitlebarFullPath.setCheckable(True) self._actionTitlebarFullPath.setChecked(True) self._actionTitlebarFullPath.setToolTip(self.tr("Display the full path of the document in the titlebar")) self._actionTitlebarFullPath.triggered.connect(self._onActionTitlebarFullPathTriggered) self._actionToolbarApplication = QAction(self.tr("Show Application Toolbar"), self) self._actionToolbarApplication.setObjectName("actionToolbarApplication") self._actionToolbarApplication.setCheckable(True) self._actionToolbarApplication.setToolTip(self.tr("Display the Application toolbar")) self._actionToolbarApplication.toggled.connect(lambda checked: self._toolbarApplication.setVisible(checked)) self._actionToolbarDocument = QAction(self.tr("Show Document Toolbar"), self) self._actionToolbarDocument.setObjectName("actionToolbarDocument") self._actionToolbarDocument.setCheckable(True) self._actionToolbarDocument.setToolTip(self.tr("Display the Document toolbar")) self._actionToolbarDocument.toggled.connect(lambda checked: self._toolbarDocument.setVisible(checked)) self._actionToolbarEdit = QAction(self.tr("Show Edit Toolbar"), self) self._actionToolbarEdit.setObjectName("actionToolbarEdit") self._actionToolbarEdit.setCheckable(True) self._actionToolbarEdit.setToolTip(self.tr("Display the Edit toolbar")) self._actionToolbarEdit.toggled.connect(lambda checked: self._toolbarEdit.setVisible(checked)) self._actionToolbarTools = QAction(self.tr("Show Tools Toolbar"), self) self._actionToolbarTools.setObjectName("actionToolbarTools") self._actionToolbarTools.setCheckable(True) self._actionToolbarTools.setToolTip(self.tr("Display the Tools toolbar")) self._actionToolbarTools.toggled.connect(lambda checked: self._toolbarTools.setVisible(checked)) self._actionToolbarView = QAction(self.tr("Show View Toolbar"), self) self._actionToolbarView.setObjectName("actionToolbarView") self._actionToolbarView.setCheckable(True) self._actionToolbarView.setToolTip(self.tr("Display the View toolbar")) self._actionToolbarView.toggled.connect(lambda checked: self._toolbarView.setVisible(checked)) self._actionToolbarHelp = QAction(self.tr("Show Help Toolbar"), self) self._actionToolbarHelp.setObjectName("actionToolbarHelp") self._actionToolbarHelp.setCheckable(True) self._actionToolbarHelp.setToolTip(self.tr("Display the Help toolbar")) self._actionToolbarHelp.toggled.connect(lambda checked: self._toolbarHelp.setVisible(checked)) # # Actions: Help self._actionKeyboardShortcuts = QAction(self.tr("Keyboard Shortcuts"), self) self._actionKeyboardShortcuts.setObjectName("actionKeyboardShortcuts") self._actionKeyboardShortcuts.setIcon(QIcon.fromTheme("help-keyboard-shortcuts", QIcon(":/icons/actions/16/help-keyboard-shortcuts.svg"))) self._actionKeyboardShortcuts.setIconText(self.tr("Shortcuts")) self._actionKeyboardShortcuts.setToolTip(self.tr("List of all keyboard shortcuts")) self._actionKeyboardShortcuts.triggered.connect(self._onActionKeyboardShortcutsTriggered) def _createMenus(self): # Menu: Application menuApplication = self.menuBar().addMenu(self.tr("Application")) menuApplication.setObjectName("menuApplication") menuApplication.addAction(self._actionAbout) menuApplication.addAction(self._actionColophon) menuApplication.addSeparator() menuApplication.addAction(self._actionPreferences) menuApplication.addSeparator() menuApplication.addAction(self._actionQuit) # # Menu: Document self._menuOpenRecent = QMenu(self.tr("Open Recent"), self) self._menuOpenRecent.setObjectName("menuOpenRecent") self._menuOpenRecent.setIcon(QIcon.fromTheme("document-open-recent", QIcon(":/icons/actions/16/document-open-recent.svg"))) self._menuOpenRecent.setToolTip(self.tr("Open a document which was recently opened")) self._menuSaveAsDelimiter = QMenu(self.tr("Save As with Delimiter…"), self) self._menuSaveAsDelimiter.setObjectName("menuSaveAsDelimiter") self._menuSaveAsDelimiter.setIcon(QIcon.fromTheme("document-save-as", QIcon(":/icons/actions/16/document-save-as.svg"))) self._menuSaveAsDelimiter.setToolTip(self.tr("Save document with specific delimiter under a new name")) self._menuSaveAsDelimiter.addActions(self._actionSaveAsDelimiter.actions()) menuDocument = self.menuBar().addMenu(self.tr("Document")) menuDocument.setObjectName("menuDocument") menuDocument.addAction(self._actionNew) menuDocument.addSeparator() menuDocument.addAction(self._actionOpen) menuDocument.addMenu(self._menuOpenRecent) menuDocument.addSeparator() menuDocument.addAction(self._actionSave) menuDocument.addAction(self._actionSaveAs) menuDocument.addMenu(self._menuSaveAsDelimiter) menuDocument.addAction(self._actionSaveCopyAs) menuDocument.addAction(self._actionSaveAll) menuDocument.addSeparator() menuDocument.addAction(self._actionClose) menuDocument.addAction(self._actionCloseOther) menuDocument.addAction(self._actionCloseAll) # Menu: Edit menuEdit = self.menuBar().addMenu(self.tr("Edit")) menuEdit.setObjectName("menuEdit") # Menu: Tools menuTools = self.menuBar().addMenu(self.tr("Tools")) menuTools.setObjectName("menuTools") # Menu: View menuView = self.menuBar().addMenu(self.tr("View")) menuView.setObjectName("menuView") menuView.addAction(self._actionFullScreen) menuView.addSeparator() menuView.addAction(self._actionTitlebarFullPath) menuView.addSeparator() menuView.addAction(self._actionToolbarApplication) menuView.addAction(self._actionToolbarDocument) menuView.addAction(self._actionToolbarEdit) menuView.addAction(self._actionToolbarTools) menuView.addAction(self._actionToolbarView) menuView.addAction(self._actionToolbarHelp) # Menu: Help menuHelp = self.menuBar().addMenu(self.tr("Help")) menuHelp.setObjectName("menuHelp") menuHelp.addAction(self._actionKeyboardShortcuts) def _createToolBars(self): # Toolbar: Application self._toolbarApplication = self.addToolBar(self.tr("Application Toolbar")) self._toolbarApplication.setObjectName("toolbarApplication") self._toolbarApplication.addAction(self._actionAbout) self._toolbarApplication.addAction(self._actionPreferences) self._toolbarApplication.addSeparator() self._toolbarApplication.addAction(self._actionQuit) self._toolbarApplication.visibilityChanged.connect(lambda visible: self._actionToolbarApplication.setChecked(visible)) # Toolbar: Document self._toolbarDocument = self.addToolBar(self.tr("Document Toolbar")) self._toolbarDocument.setObjectName("toolbarDocument") self._toolbarDocument.addAction(self._actionNew) self._toolbarDocument.addAction(self._actionOpen) self._toolbarDocument.addSeparator() self._toolbarDocument.addAction(self._actionSave) self._toolbarDocument.addAction(self._actionSaveAs) self._toolbarDocument.addSeparator() self._toolbarDocument.addAction(self._actionClose) self._toolbarDocument.visibilityChanged.connect(lambda visible: self._actionToolbarDocument.setChecked(visible)) # Toolbar: Edit self._toolbarEdit = self.addToolBar(self.tr("Edit Toolbar")) self._toolbarEdit.setObjectName("toolbarEdit") self._toolbarEdit.visibilityChanged.connect(lambda visible: self._actionToolbarEdit.setChecked(visible)) # Toolbar: Tools self._toolbarTools = self.addToolBar(self.tr("Tools Toolbar")) self._toolbarTools.setObjectName("toolbarTools") self._toolbarTools.visibilityChanged.connect(lambda visible: self._actionToolbarTools.setChecked(visible)) # Toolbar: View self._toolbarView = self.addToolBar(self.tr("View Toolbar")) self._toolbarView.setObjectName("toolbarView") self._toolbarView.addAction(self._actionFullScreen) self._toolbarView.visibilityChanged.connect(lambda visible: self._actionToolbarView.setChecked(visible)) # Toolbar: Help self._toolbarHelp = self.addToolBar(self.tr("Help Toolbar")) self._toolbarHelp.setObjectName("toolbarHelp") self._toolbarHelp.addAction(self._actionKeyboardShortcuts) self._toolbarHelp.visibilityChanged.connect(lambda visible: self._actionToolbarHelp.setChecked(visible)) def _updateActions(self, subWindowCount=0): hasDocument = subWindowCount >= 1 hasDocuments = subWindowCount >= 2 # Actions: Document self._actionSave.setEnabled(hasDocument) self._actionSaveAs.setEnabled(hasDocument) self._menuSaveAsDelimiter.setEnabled(hasDocument) self._actionSaveCopyAs.setEnabled(hasDocument) self._actionSaveAll.setEnabled(hasDocument) self._actionClose.setEnabled(hasDocument) self._actionCloseOther.setEnabled(hasDocuments) self._actionCloseAll.setEnabled(hasDocument) def _updateActionFullScreen(self): if not self.isFullScreen(): self._actionFullScreen.setText(self.tr("Full Screen Mode")) self._actionFullScreen.setIcon(QIcon.fromTheme("view-fullscreen", QIcon(":/icons/actions/16/view-fullscreen.svg"))) self._actionFullScreen.setChecked(False) self._actionFullScreen.setToolTip(self.tr("Display the window in full screen")) else: self._actionFullScreen.setText(self.tr("Exit Full Screen Mode")) self._actionFullScreen.setIcon(QIcon.fromTheme("view-restore", QIcon(":/icons/actions/16/view-restore.svg"))) self._actionFullScreen.setChecked(True) self._actionFullScreen.setToolTip(self.tr("Exit the full screen mode")) def _updateActionRecentDocuments(self): # Add items to the list, if necessary for idx in range(len(self._actionRecentDocuments)+1, self._preferences.maximumRecentDocuments()+1): actionRecentDocument = QAction(self) actionRecentDocument.setObjectName(f"actionRecentDocument_{idx}") actionRecentDocument.triggered.connect(lambda data=actionRecentDocument.data(): self._onActionOpenRecentDocumentTriggered(data)) self._actionRecentDocuments.append(actionRecentDocument) # Remove items from the list, if necessary while len(self._actionRecentDocuments) > self._preferences.maximumRecentDocuments(): self._actionRecentDocuments.pop() # Update items for idx in range(len(self._actionRecentDocuments)): text = None data = None show = False if idx < len(self._recentDocuments): text = self.tr("{0} [{1}]").format(QFileInfo(self._recentDocuments[idx]).fileName(), self._recentDocuments[idx]) data = self._recentDocuments[idx] show = True self._actionRecentDocuments[idx].setText(text) self._actionRecentDocuments[idx].setData(data) self._actionRecentDocuments[idx].setVisible(show) def _updateMenuOpenRecent(self): self._menuOpenRecent.clear() if self._preferences.maximumRecentDocuments() > 0: # Document list wanted; show the menu self._menuOpenRecent.menuAction().setVisible(True) if len(self._recentDocuments) > 0: # Document list has items; enable the menu self._menuOpenRecent.setEnabled(True) self._menuOpenRecent.addActions(self._actionRecentDocuments) self._menuOpenRecent.addSeparator() self._menuOpenRecent.addAction(self._actionOpenRecentClear) else: # Document list is empty; disable the menu self._menuOpenRecent.setEnabled(False) else: # No document list wanted; hide the menu self._menuOpenRecent.menuAction().setVisible(False) def _updateTitleBar(self): title = None document = self._activeDocument() if document: title = document.canonicalName() if self._actionTitlebarFullPath.isChecked() and document.canonicalName() else document.documentTitle() self.setWindowTitle(title) def _onActionAboutTriggered(self): dialog = AboutDialog(self) dialog.exec_() def _onActionColophonTriggered(self): dialog = ColophonDialog(self) dialog.exec_() def _onActionPreferencesTriggered(self): dialog = PreferencesDialog(self) dialog.setPreferences(self._preferences) dialog.exec_() self._preferences = dialog.preferences() self._updateRecentDocuments(None) self._updateMenuOpenRecent() def _onActionNewTriggered(self): self._loadDocument("") def _onActionOpenTriggered(self): fileNames = QFileDialog.getOpenFileNames(self, self.tr("Open Document"), QStandardPaths.writableLocation(QStandardPaths.HomeLocation), self.tr("CSV Files (*.csv);;All Files (*.*)"))[0] for fileName in fileNames: self._openDocument(fileName) def _onActionOpenRecentDocumentTriggered(self, canonicalName): pass # self.openDocument(canonicalName) def _onActionOpenRecentClearTriggered(self): self._recentDocuments.clear() self._updateRecentDocuments(None) self._updateMenuOpenRecent() def _onActionSaveTriggered(self): pass def _onActionSaveAsTriggered(self): pass def _onActionSaveAsDelimiterTriggered(self, delimiter): pass def _onActionSaveCopyAsTriggered(self): pass def _onActionSaveAllTriggered(self): pass def _onActionCloseTriggered(self): self._documentArea.closeActiveSubWindow() def _onActionCloseOtherTriggered(self): for subWindow in self._documentArea.subWindowList(): if subWindow != self._documentArea.activeSubWindow(): subWindow.close() def _onActionCloseAllTriggered(self): self._documentArea.closeAllSubWindows() def _onActionFullScreenTriggered(self): if not self.isFullScreen(): self.setWindowState(self.windowState() | Qt.WindowFullScreen) else: self.setWindowState(self.windowState() & ~Qt.WindowFullScreen) self._updateActionFullScreen() def _onActionTitlebarFullPathTriggered(self): self._updateTitleBar() def _onActionKeyboardShortcutsTriggered(self): if not self._keyboardShortcutsDialog: self._keyboardShortcutsDialog = KeyboardShortcutsDialog(self) self._keyboardShortcutsDialog.show() self._keyboardShortcutsDialog.raise_() self._keyboardShortcutsDialog.activateWindow() def _onDocumentWindowActivated(self, subWindow): # Update the application window self._updateActions(len(self._documentArea.subWindowList())) self._updateTitleBar() if not subWindow: return def _onDocumentAboutToClose(self, canonicalName): # Workaround to show subwindows always maximized for subWindow in self._documentArea.subWindowList(): if not subWindow.isMaximized(): subWindow.showMaximized() # Update menu items without the emitter self._updateActions(len(self._documentArea.subWindowList()) - 1) def _createDocument(self): document = Document() document.setPreferences(self._preferences) document.aboutToClose.connect(self._onDocumentAboutToClose) subWindow = self._documentArea.addSubWindow(document) subWindow.setWindowIcon(QIcon()) subWindow.showMaximized() return document def _createDocumentIndex(self, canonicalName): fileName = QFileInfo(canonicalName).fileName() canonicalIndex = 0 for subWindow in self._documentArea.subWindowList(): if QFileInfo(subWindow.widget().canonicalName()).fileName() == fileName: if subWindow.widget().canonicalIndex() > canonicalIndex: canonicalIndex = subWindow.widget().canonicalIndex() return canonicalIndex + 1 def _findDocumentWindow(self, canonicalName): for subWindow in self._documentArea.subWindowList(): if subWindow.widget().canonicalName() == canonicalName: return subWindow return None def _activeDocument(self): subWindow = self._documentArea.activeSubWindow() return subWindow.widget() if subWindow else None def _openDocument(self, fileName): canonicalName = QFileInfo(fileName).canonicalFilePath() subWindow = self._findDocumentWindow(canonicalName) if subWindow: # Given document is already loaded; activate the subwindow self._documentArea.setActiveSubWindow(subWindow) # Update list of recent documents self._updateRecentDocuments(canonicalName) self._updateMenuOpenRecent() return True return self._loadDocument(canonicalName); def _loadDocument(self, canonicalName): document = self._createDocument() succeeded = document.load(canonicalName) if succeeded: document.setCanonicalIndex(self._createDocumentIndex(canonicalName)) document.updateDocumentTitle() document.show() # Update list of recent documents self._updateRecentDocuments(canonicalName) self._updateMenuOpenRecent() # Update the application window self._updateActions(len(self._documentArea.subWindowList())) self._updateTitleBar() else: document.close() return succeeded def _updateRecentDocuments(self, canonicalName): if canonicalName: while canonicalName in self._recentDocuments: self._recentDocuments.remove(canonicalName) self._recentDocuments.insert(0, canonicalName) # Remove items from the list, if necessary while len(self._recentDocuments) > self._preferences.maximumRecentDocuments(): self._recentDocuments.pop() self._updateActionRecentDocuments()