1#!/usr/bin/env python 2 3 4############################################################################# 5## 6## Copyright (C) 2013 Riverbank Computing Limited. 7## Copyright (C) 2010 Nokia Corporation and/or its subsidiary(-ies). 8## All rights reserved. 9## 10## This file is part of the examples of PyQt. 11## 12## $QT_BEGIN_LICENSE:BSD$ 13## You may use this file under the terms of the BSD license as follows: 14## 15## "Redistribution and use in source and binary forms, with or without 16## modification, are permitted provided that the following conditions are 17## met: 18## * Redistributions of source code must retain the above copyright 19## notice, this list of conditions and the following disclaimer. 20## * Redistributions in binary form must reproduce the above copyright 21## notice, this list of conditions and the following disclaimer in 22## the documentation and/or other materials provided with the 23## distribution. 24## * Neither the name of Nokia Corporation and its Subsidiary(-ies) nor 25## the names of its contributors may be used to endorse or promote 26## products derived from this software without specific prior written 27## permission. 28## 29## THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS 30## "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT 31## LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR 32## A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT 33## OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, 34## SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT 35## LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, 36## DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY 37## THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT 38## (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE 39## OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE." 40## $QT_END_LICENSE$ 41## 42############################################################################# 43 44 45from PyQt5.QtCore import QFile, QFileInfo, QSettings, Qt, QTextStream 46from PyQt5.QtGui import QKeySequence 47from PyQt5.QtWidgets import (QAction, QApplication, QFileDialog, QMainWindow, 48 QMessageBox, QTextEdit) 49 50 51class MainWindow(QMainWindow): 52 MaxRecentFiles = 5 53 windowList = [] 54 55 def __init__(self): 56 super(MainWindow, self).__init__() 57 58 self.recentFileActs = [] 59 60 self.setAttribute(Qt.WA_DeleteOnClose) 61 62 self.textEdit = QTextEdit() 63 self.setCentralWidget(self.textEdit) 64 65 self.createActions() 66 self.createMenus() 67 self.statusBar() 68 69 self.setWindowTitle("Recent Files") 70 self.resize(400, 300) 71 72 def newFile(self): 73 other = MainWindow() 74 MainWindow.windowList.append(other) 75 other.show() 76 77 def open(self): 78 fileName, _ = QFileDialog.getOpenFileName(self) 79 if fileName: 80 self.loadFile(fileName) 81 82 def save(self): 83 if self.curFile: 84 self.saveFile(self.curFile) 85 else: 86 self.saveAs() 87 88 def saveAs(self): 89 fileName, _ = QFileDialog.getSaveFileName(self) 90 if fileName: 91 self.saveFile(fileName) 92 93 def openRecentFile(self): 94 action = self.sender() 95 if action: 96 self.loadFile(action.data()) 97 98 def about(self): 99 QMessageBox.about(self, "About Recent Files", 100 "The <b>Recent Files</b> example demonstrates how to provide " 101 "a recently used file menu in a Qt application.") 102 103 def createActions(self): 104 self.newAct = QAction("&New", self, shortcut=QKeySequence.New, 105 statusTip="Create a new file", triggered=self.newFile) 106 107 self.openAct = QAction("&Open...", self, shortcut=QKeySequence.Open, 108 statusTip="Open an existing file", triggered=self.open) 109 110 self.saveAct = QAction("&Save", self, shortcut=QKeySequence.Save, 111 statusTip="Save the document to disk", triggered=self.save) 112 113 self.saveAsAct = QAction("Save &As...", self, 114 shortcut=QKeySequence.SaveAs, 115 statusTip="Save the document under a new name", 116 triggered=self.saveAs) 117 118 for i in range(MainWindow.MaxRecentFiles): 119 self.recentFileActs.append( 120 QAction(self, visible=False, 121 triggered=self.openRecentFile)) 122 123 self.exitAct = QAction("E&xit", self, shortcut="Ctrl+Q", 124 statusTip="Exit the application", 125 triggered=QApplication.instance().closeAllWindows) 126 127 self.aboutAct = QAction("&About", self, 128 statusTip="Show the application's About box", 129 triggered=self.about) 130 131 self.aboutQtAct = QAction("About &Qt", self, 132 statusTip="Show the Qt library's About box", 133 triggered=QApplication.instance().aboutQt) 134 135 def createMenus(self): 136 self.fileMenu = self.menuBar().addMenu("&File") 137 self.fileMenu.addAction(self.newAct) 138 self.fileMenu.addAction(self.openAct) 139 self.fileMenu.addAction(self.saveAct) 140 self.fileMenu.addAction(self.saveAsAct) 141 self.separatorAct = self.fileMenu.addSeparator() 142 for i in range(MainWindow.MaxRecentFiles): 143 self.fileMenu.addAction(self.recentFileActs[i]) 144 self.fileMenu.addSeparator() 145 self.fileMenu.addAction(self.exitAct) 146 self.updateRecentFileActions() 147 148 self.menuBar().addSeparator() 149 150 self.helpMenu = self.menuBar().addMenu("&Help") 151 self.helpMenu.addAction(self.aboutAct) 152 self.helpMenu.addAction(self.aboutQtAct) 153 154 def loadFile(self, fileName): 155 file = QFile(fileName) 156 if not file.open( QFile.ReadOnly | QFile.Text): 157 QMessageBox.warning(self, "Recent Files", 158 "Cannot read file %s:\n%s." % (fileName, file.errorString())) 159 return 160 161 instr = QTextStream(file) 162 QApplication.setOverrideCursor(Qt.WaitCursor) 163 self.textEdit.setPlainText(instr.readAll()) 164 QApplication.restoreOverrideCursor() 165 166 self.setCurrentFile(fileName) 167 self.statusBar().showMessage("File loaded", 2000) 168 169 def saveFile(self, fileName): 170 file = QFile(fileName) 171 if not file.open( QFile.WriteOnly | QFile.Text): 172 QMessageBox.warning(self, "Recent Files", 173 "Cannot write file %s:\n%s." % (fileName, file.errorString())) 174 return 175 176 outstr = QTextStream(file) 177 QApplication.setOverrideCursor(Qt.WaitCursor) 178 outstr << self.textEdit.toPlainText() 179 QApplication.restoreOverrideCursor() 180 181 self.setCurrentFile(fileName) 182 self.statusBar().showMessage("File saved", 2000) 183 184 def setCurrentFile(self, fileName): 185 self.curFile = fileName 186 if self.curFile: 187 self.setWindowTitle("%s - Recent Files" % self.strippedName(self.curFile)) 188 else: 189 self.setWindowTitle("Recent Files") 190 191 settings = QSettings('Trolltech', 'Recent Files Example') 192 files = settings.value('recentFileList', []) 193 194 try: 195 files.remove(fileName) 196 except ValueError: 197 pass 198 199 files.insert(0, fileName) 200 del files[MainWindow.MaxRecentFiles:] 201 202 settings.setValue('recentFileList', files) 203 204 for widget in QApplication.topLevelWidgets(): 205 if isinstance(widget, MainWindow): 206 widget.updateRecentFileActions() 207 208 def updateRecentFileActions(self): 209 settings = QSettings('Trolltech', 'Recent Files Example') 210 files = settings.value('recentFileList', []) 211 212 numRecentFiles = min(len(files), MainWindow.MaxRecentFiles) 213 214 for i in range(numRecentFiles): 215 text = "&%d %s" % (i + 1, self.strippedName(files[i])) 216 self.recentFileActs[i].setText(text) 217 self.recentFileActs[i].setData(files[i]) 218 self.recentFileActs[i].setVisible(True) 219 220 for j in range(numRecentFiles, MainWindow.MaxRecentFiles): 221 self.recentFileActs[j].setVisible(False) 222 223 self.separatorAct.setVisible((numRecentFiles > 0)) 224 225 def strippedName(self, fullFileName): 226 return QFileInfo(fullFileName).fileName() 227 228 229if __name__ == '__main__': 230 231 import sys 232 233 app = QApplication(sys.argv) 234 mainWin = MainWindow() 235 mainWin.show() 236 sys.exit(app.exec_()) 237