#!/usr/bin/env python ############################################################################ # # Copyright (C) 2004-2005 Trolltech AS. All rights reserved. # # This file is part of the example classes of the Qt Toolkit. # # This file may be used under the terms of the GNU General Public # License version 2.0 as published by the Free Software Foundation # and appearing in the file LICENSE.GPL included in the packaging of # self file. Please review the following information to ensure GNU # General Public Licensing requirements will be met: # http://www.trolltech.com/products/qt/opensource.html # # If you are unsure which license is appropriate for your use, please # review the following information: # http://www.trolltech.com/products/qt/licensing.html or contact the # sales department at sales@trolltech.com. # # This file is provided AS IS with NO WARRANTY OF ANY KIND, INCLUDING THE # WARRANTY OF DESIGN, MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE. # ############################################################################ import sys from PyQt4 import QtCore, QtGui import mdi_rc class MdiChild(QtGui.QTextEdit): sequenceNumber = 1 def __init__(self): QtGui.QTextEdit.__init__(self, None) self.setAttribute(QtCore.Qt.WA_DeleteOnClose) self.isUntitled = True self.connect(self.document(), QtCore.SIGNAL("contentsChanged()"), self.documentWasModified) def newFile(self): self.isUntitled = True self.curFile = self.tr("document%1.txt").arg(MdiChild.sequenceNumber) MdiChild.sequenceNumber += 1 self.setWindowTitle(self.curFile+"[*]") def loadFile(self, fileName): file = QtCore.QFile(fileName) if not file.open(QtCore.QFile.ReadOnly | QtCore.QFile.Text): QtGui.QMessageBox.warning(self, self.tr("MDI"), self.tr("Cannot read file %1:\n%2.") .arg(fileName) .arg(file.errorString())) return False instr = QtCore.QTextStream(file) QtGui.QApplication.setOverrideCursor(QtCore.Qt.WaitCursor) self.setPlainText(instr.readAll()) QtGui.QApplication.restoreOverrideCursor() self.setCurrentFile(fileName) return True def save(self): if self.isUntitled: return self.saveAs() else: return self.saveFile(self.curFile) def saveAs(self): fileName = QtGui.QFileDialog.getSaveFileName(self, self.tr("Save As"), self.curFile) if fileName.isEmpty: return False return self.saveFile(fileName) def saveFile(self, fileName): file = QtCore.QFile(fileName) if not file.open(QtCore.QFile.WriteOnly | QtCore.QFile.Text): QtGui.QMessageBox.warning(self, self.tr("MDI"), self.tr("Cannot write file %1:\n%2.") .arg(fileName) .arg(file.errorString())) return False outstr = QtCore.QTextStream(file) QtCore.QApplication.setOverrideCursor(QtCore.Qt.WaitCursor) outstr << self.toPlainText() QtCore.QApplication.restoreOverrideCursor() self.setCurrentFile(fileName) return True def userFriendlyCurrentFile(self): return self.strippedName(self.curFile) def currentFile(self): return self.curFile def closeEvent(self, event): if self.maybeSave(): event.accept() else: event.ignore() def documentWasModified(self): self.setWindowModified(self.document().isModified()) def maybeSave(self): if self.document().isModified(): ret = QtGui.QMessageBox.warning(self, self.tr("MDI"), self.tr("'%1' has been modified.\n"\ "Do you want to save your changes?") .arg(self.userFriendlyCurrentFile()), QtGui.QMessageBox.Yes | QtGui.QMessageBox.Default, QtGui.QMessageBox.No, QtGui.QMessageBox.Cancel | QtGui.QMessageBox.Escape) if ret == QtGui.QMessageBox.Yes: return self.save() elif ret == QtGui.QMessageBox.Cancel: return False return True def setCurrentFile(self, fileName): self.curFile = QtCore.QFileInfo(fileName).canonicalFilePath() self.isUntitled = False self.document().setModified(False) self.setWindowModified(False) self.setWindowTitle(self.userFriendlyCurrentFile() + "[*]") def strippedName(self, fullFileName): return QtCore.QFileInfo(fullFileName).fileName() class MainWindow(QtGui.QMainWindow): def __init__(self, parent=None): QtGui.QMainWindow.__init__(self, parent) self.workspace = QtGui.QWorkspace() self.setCentralWidget(self.workspace) self.connect(self.workspace, QtCore.SIGNAL("windowActivated(QWidget *)"), self.updateMenus) self.windowMapper = QtCore.QSignalMapper(self) self.connect(self.windowMapper, QtCore.SIGNAL("mapped(QWidget *)"), self.workspace, QtCore.SLOT("setActiveWindow(QWidget *)")) self.createActions() self.createMenus() self.createToolBars() self.createStatusBar() self.updateMenus() self.readSettings() self.setWindowTitle(self.tr("MDI")) def closeEvent(self, event): self.workspace.closeAllWindows() if self.activeMdiChild(): event.ignore() else: self.writeSettings() event.accept() def newFile(self): child = self.createMdiChild() child.newFile() child.show() def open(self): fileName = QtGui.QFileDialog.getOpenFileName(self) if not fileName.isEmpty(): existing = self.findMdiChild(fileName) if existing: self.workspace.setActiveWindow(existing) return child = self.createMdiChild() if child.loadFile(fileName): self.statusBar().showMessage(self.tr("File loaded"), 2000) child.show() else: child.close() def save(self): if self.activeMdiChild().save(): self.statusBar().showMessage(self.tr("File saved"), 2000) def saveAs(self): if self.activeMdiChild().saveAs(): self.statusBar().showMessage(self.tr("File saved"), 2000) def cut(self): self.activeMdiChild().cut() def copy(self): self.activeMdiChild().copy() def paste(self): self.activeMdiChild().paste() def about(self): QtGui.QMessageBox.about(self, self.tr("About MDI"), self.tr("The MDI 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.arrangeAct.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.addAction(self.arrangeAct) self.windowMenu.addSeparator() self.windowMenu.addAction(self.nextAct) self.windowMenu.addAction(self.previousAct) self.windowMenu.addAction(self.separatorAct) windows = self.workspace.windowList() self.separatorAct.setVisible(len(windows) != 0) i = 0 for child in windows: if i < 9: text = self.tr("&%1 %2").arg(i + 1).arg(child.userFriendlyCurrentFile()) else: text = self.tr("%1 %2").arg(i + 1).arg(child.userFriendlyFile()) i += 1 action = self.windowMenu.addAction(text) action.setCheckable(True) action.setChecked(child == self.activeMdiChild()) self.connect(action, QtCore.SIGNAL("triggered()"), self.windowMapper, QtCore.SLOT("map()")) self.windowMapper.setMapping(action, child) def createMdiChild(self): child = MdiChild() self.workspace.addWindow(child) self.connect(child, QtCore.SIGNAL("copyAvailable(bool)"), self.cutAct.setEnabled) self.connect(child, QtCore.SIGNAL("copyAvailable(bool)"), self.copyAct.setEnabled) return child def createActions(self): self.newAct = QtGui.QAction(QtGui.QIcon(":/images/new.png"), self.tr("&New"), self) self.newAct.setShortcut(self.tr("Ctrl+N")) self.newAct.setStatusTip(self.tr("Create a new file")) self.connect(self.newAct, QtCore.SIGNAL("triggered()"), self.newFile) self.openAct = QtGui.QAction(QtGui.QIcon(":/images/open.png"), self.tr("&Open..."), self) self.openAct.setShortcut(self.tr("Ctrl+O")) self.openAct.setStatusTip(self.tr("Open an existing file")) self.connect(self.openAct, QtCore.SIGNAL("triggered()"), self.open) self.saveAct = QtGui.QAction(QtGui.QIcon(":/images/save.png"), self.tr("&Save"), self) self.saveAct.setShortcut(self.tr("Ctrl+S")) self.saveAct.setStatusTip(self.tr("Save the document to disk")) self.connect(self.saveAct, QtCore.SIGNAL("triggered()"), self.save) self.saveAsAct = QtGui.QAction(self.tr("Save &As..."), self) self.saveAsAct.setStatusTip(self.tr("Save the document under a new name")) self.connect(self.saveAsAct, QtCore.SIGNAL("triggered()"), self.saveAs) self.exitAct = QtGui.QAction(self.tr("E&xit"), self) self.exitAct.setShortcut(self.tr("Ctrl+Q")) self.exitAct.setStatusTip(self.tr("Exit the application")) self.connect(self.exitAct, QtCore.SIGNAL("triggered()"), self.close) self.cutAct = QtGui.QAction(QtGui.QIcon(":/images/cut.png"), self.tr("Cu&t"), self) self.cutAct.setShortcut(self.tr("Ctrl+X")) self.cutAct.setStatusTip(self.tr("Cut the current selection's " "contents to the clipboard")) self.connect(self.cutAct, QtCore.SIGNAL("triggered()"), self.cut) self.copyAct = QtGui.QAction(QtGui.QIcon(":/images/copy.png"), self.tr("&Copy"), self) self.copyAct.setShortcut(self.tr("Ctrl+C")) self.copyAct.setStatusTip(self.tr("Copy the current selection's " "contents to the clipboard")) self.connect(self.copyAct, QtCore.SIGNAL("triggered()"), self.copy) self.pasteAct = QtGui.QAction(QtGui.QIcon(":/images/paste.png"), self.tr("&Paste"), self) self.pasteAct.setShortcut(self.tr("Ctrl+V")) self.pasteAct.setStatusTip(self.tr("Paste the clipboard's contents " "into the current selection")) self.connect(self.pasteAct, QtCore.SIGNAL("triggered()"), self.paste) self.closeAct = QtGui.QAction(self.tr("Cl&ose"), self) self.closeAct.setShortcut(self.tr("Ctrl+F4")) self.closeAct.setStatusTip(self.tr("Close the active window")) self.connect(self.closeAct, QtCore.SIGNAL("triggered()"), self.workspace.closeActiveWindow) self.closeAllAct = QtGui.QAction(self.tr("Close &All"), self) self.closeAllAct.setStatusTip(self.tr("Close all the windows")) self.connect(self.closeAllAct, QtCore.SIGNAL("triggered()"), self.workspace.closeAllWindows) self.tileAct = QtGui.QAction(self.tr("&Tile"), self) self.tileAct.setStatusTip(self.tr("Tile the windows")) self.connect(self.tileAct, QtCore.SIGNAL("triggered()"), self.workspace.tile) self.cascadeAct = QtGui.QAction(self.tr("&Cascade"), self) self.cascadeAct.setStatusTip(self.tr("Cascade the windows")) self.connect(self.cascadeAct, QtCore.SIGNAL("triggered()"), self.workspace.cascade) self.arrangeAct = QtGui.QAction(self.tr("Arrange &icons"), self) self.arrangeAct.setStatusTip(self.tr("Arrange the icons")) self.connect(self.arrangeAct, QtCore.SIGNAL("triggered()"), self.workspace.arrangeIcons) self.nextAct = QtGui.QAction(self.tr("Ne&xt"), self) self.nextAct.setShortcut(self.tr("Ctrl+F6")) self.nextAct.setStatusTip(self.tr("Move the focus to the next window")) self.connect(self.nextAct, QtCore.SIGNAL("triggered()"), self.workspace.activateNextWindow) self.previousAct = QtGui.QAction(self.tr("Pre&vious"), self) self.previousAct.setShortcut(self.tr("Ctrl+Shift+F6")) self.previousAct.setStatusTip(self.tr("Move the focus to the previous " "window")) self.connect(self.previousAct, QtCore.SIGNAL("triggered()"), self.workspace.activatePreviousWindow) self.separatorAct = QtGui.QAction(self) self.separatorAct.setSeparator(True) self.aboutAct = QtGui.QAction(self.tr("&About"), self) self.aboutAct.setStatusTip(self.tr("Show the application's About box")) self.connect(self.aboutAct, QtCore.SIGNAL("triggered()"), self.about) self.aboutQtAct = QtGui.QAction(self.tr("About &Qt"), self) self.aboutQtAct.setStatusTip(self.tr("Show the Qt library's About box")) self.connect(self.aboutQtAct, QtCore.SIGNAL("triggered()"), QtGui.qApp, QtCore.SLOT("aboutQt()")) def createMenus(self): self.fileMenu = self.menuBar().addMenu(self.tr("&File")) self.fileMenu.addAction(self.newAct) self.fileMenu.addAction(self.openAct) self.fileMenu.addAction(self.saveAct) self.fileMenu.addAction(self.saveAsAct) self.fileMenu.addSeparator() self.fileMenu.addAction(self.exitAct) self.editMenu = self.menuBar().addMenu(self.tr("&Edit")) self.editMenu.addAction(self.cutAct) self.editMenu.addAction(self.copyAct) self.editMenu.addAction(self.pasteAct) self.windowMenu = self.menuBar().addMenu(self.tr("&Window")) self.connect(self.windowMenu, QtCore.SIGNAL("aboutToShow()"), self.updateWindowMenu) self.menuBar().addSeparator() self.helpMenu = self.menuBar().addMenu(self.tr("&Help")) self.helpMenu.addAction(self.aboutAct) self.helpMenu.addAction(self.aboutQtAct) def createToolBars(self): self.fileToolBar = self.addToolBar(self.tr("File")) self.fileToolBar.addAction(self.newAct) self.fileToolBar.addAction(self.openAct) self.fileToolBar.addAction(self.saveAct) self.editToolBar = self.addToolBar(self.tr("Edit")) self.editToolBar.addAction(self.cutAct) self.editToolBar.addAction(self.copyAct) self.editToolBar.addAction(self.pasteAct) def createStatusBar(self): self.statusBar().showMessage(self.tr("Ready")) def readSettings(self): settings = QtCore.QSettings("Trolltech", "MDI Example") pos = settings.value("pos", QtCore.QVariant(QtCore.QPoint(200, 200))).toPoint() size = settings.value("size", QtCore.QVariant(QtCore.QSize(400, 400))).toSize() self.move(pos) self.resize(size) def writeSettings(self): settings = QtCore.QSettings("Trolltech", "MDI Example") settings.setValue("pos", QtCore.QVariant(self.pos())) settings.setValue("size", QtCore.QVariant(self.size())) def activeMdiChild(self): return self.workspace.activeWindow() def findMdiChild(self, fileName): canonicalFilePath = QtCore.QFileInfo(fileName).canonicalFilePath() for window in self.workspace.windowList(): if window.currentFile() == canonicalFilePath: return window return None if __name__ == "__main__": app = QtGui.QApplication(sys.argv) mainwindow = MainWindow() mainwindow.show() sys.exit(app.exec_())