1############################################################################ 2## 3## Copyright (C) 2016 The Qt Company Ltd. 4## Contact: https://www.qt.io/licensing/ 5## 6## This file is part of the examples of Qt for Python. 7## 8## $QT_BEGIN_LICENSE:BSD$ 9## Commercial License Usage 10## Licensees holding valid commercial Qt licenses may use this file in 11## accordance with the commercial license agreement provided with the 12## Software or, alternatively, in accordance with the terms contained in 13## a written agreement between you and The Qt Company. For licensing terms 14## and conditions see https://www.qt.io/terms-conditions. For further 15## information use the contact form at https://www.qt.io/contact-us. 16## 17## BSD License Usage 18## Alternatively, you may use this file under the terms of the BSD license 19## as follows: 20## 21## "Redistribution and use in source and binary forms, with or without 22## modification, are permitted provided that the following conditions are 23## met: 24## * Redistributions of source code must retain the above copyright 25## notice, this list of conditions and the following disclaimer. 26## * Redistributions in binary form must reproduce the above copyright 27## notice, this list of conditions and the following disclaimer in 28## the documentation and/or other materials provided with the 29## distribution. 30## * Neither the name of The Qt Company Ltd nor the names of its 31## contributors may be used to endorse or promote products derived 32## from this software without specific prior written permission. 33## 34## 35## THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS 36## "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT 37## LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR 38## A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT 39## OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, 40## SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT 41## LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, 42## DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY 43## THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT 44## (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE 45## OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE." 46## 47## $QT_END_LICENSE$ 48## 49############################################################################ 50 51//! [0] 52from PySide2.QtCore import Qt, QFile, QFileInfo, QSettings, QTextStream 53from PySide2.QtGui import QIcon 54from PySide2.Widgets import (QAction, QApplication, QFileDialog, QMainWindow, 55 QPlainTextEdit, QFileDialog, QMessageBox, ) 56//! [0] 57 58//! [1] 59def __init__(self, parent=None): 60 QMainWindow.__init__(self) 61//! [1] //! [2] 62 self.textEdit = QPlainTextEdit() 63 self.setCentralWidget(textEdit) 64 65 self.createActions() 66 self.createMenus() 67 self.createToolBars() 68 self.createStatusBar() 69 70 self.readSettings() 71 72 self.textEdit.document().contentsChanged.connect(self.documentWasModified) 73 74 self.setCurrentFile("") 75 self.setUnifiedTitleAndToolBarOnMac(True) 76 77//! [2] 78 79//! [3] 80def closeEvent(self, event): 81//! [3] //! [4] 82 if maybeSave(): 83 writeSettings() 84 event.accept() 85 else: 86 event.ignore() 87//! [4] 88 89//! [5] 90def File(self): 91//! [5] //! [6] 92 if maybeSave(): 93 textEdit.clear() 94 setCurrentFile("") 95//! [6] 96 97//! [7] 98def open(self): 99//! [7] //! [8] 100 if maybeSave(): 101 fileName = QFileDialog.getOpenFileName(self) 102 if not fileName.isEmpty(): 103 loadFile(fileName) 104//! [8] 105 106//! [9] 107def save(self): 108//! [9] //! [10] 109 if curFile.isEmpty(): 110 return saveAs() 111 else: 112 return saveFile(curFile) 113//! [10] 114 115//! [11] 116def saveAs(self): 117//! [11] //! [12] 118 fileName = QFileDialog.getSaveFileName(self) 119 if fileName.isEmpty(): 120 return False 121 122 return saveFile(fileName) 123//! [12] 124 125//! [13] 126def about(self): 127//! [13] //! [14] 128 QMessageBox.about(self, tr("About Application"), 129 tr("The <b>Application</b> example demonstrates how to " 130 "write modern GUI applications using Qt, with a menu bar, " 131 "toolbars, and a status bar.")) 132 133//! [14] 134 135//! [15] 136def documentWasModified(self): 137//! [15] //! [16] 138 setWindowModified(textEdit.document().isModified()) 139//! [16] 140 141//! [17] 142def MainWindow.createActions(self): 143//! [17] //! [18] 144 Act = QAction(QIcon(":/images/new.png"), tr("&New"), self) 145 Act.setShortcuts(QKeySequence.New) 146 Act.setStatusTip(tr("Create a new file")) 147 Act.triggered.connect(newFile) 148 149//! [19] 150 openAct = QAction(QIcon(":/images/open.png"), tr("&Open..."), self) 151 openAct.setShortcuts(QKeySequence.Open) 152 openAct.setStatusTip(tr("Open an existing file")) 153 openAct.triggered.connect(open) 154//! [18] //! [19] 155 156 saveAct = QAction(QIcon(":/images/save.png"), tr("&Save"), self) 157 saveAct.setShortcuts(QKeySequence.Save) 158 saveAct.setStatusTip(tr("Save the document to disk")) 159 saveAct.triggered.connect(save) 160 161 saveAsAct = QAction(tr("Save &As..."), self) 162 saveAsAct.setShortcuts(QKeySequence.SaveAs) 163 saveAsAct.setStatusTip(tr("Save the document under a name")) 164 saveAsAct.triggered.connect(saveAs) 165 166//! [20] 167 exitAct = QAction(tr("E&xit"), self) 168 exitAct.setShortcut(tr("Ctrl+Q")) 169//! [20] 170 exitAct.setStatusTip(tr("Exit the application")) 171 exitAct.triggered.connect(close) 172 173//! [21] 174 cutAct = QAction(QIcon(":/images/cut.png"), tr("Cu&t"), self) 175//! [21] 176 cutAct.setShortcuts(QKeySequence.Cut) 177 cutAct.setStatusTip(tr("Cut the current selection's contents to the " 178 "clipboard")) 179 cutAct.triggered.connect(cut) 180 181 copyAct = QAction(QIcon(":/images/copy.png"), tr("&Copy"), self) 182 copyAct.setShortcuts(QKeySequence.Copy) 183 copyAct.setStatusTip(tr("Copy the current selection's contents to the " 184 "clipboard")) 185 copyAct.triggered.connect(copy) 186 187 pasteAct = QAction(QIcon(":/images/paste.png"), tr("&Paste"), self) 188 pasteAct.setShortcuts(QKeySequence.Paste) 189 pasteAct.setStatusTip(tr("Paste the clipboard's contents into the current " 190 "selection")) 191 pasteAct.triggered.connect(textEdit.paste) 192 193 aboutAct = QAction(tr("&About"), self) 194 aboutAct.setStatusTip(tr("Show the application's About box")) 195 aboutAct.triggered.connect(about) 196 197//! [22] 198 aboutQtAct = QAction(tr("About &Qt"), self) 199 aboutQtAct.setStatusTip(tr("Show the Qt library's About box")) 200 aboutQtAct.triggered.connect(qApp.aboutQt) 201//! [22] 202 203//! [23] 204 cutAct.setEnabled(False) 205//! [23] //! [24] 206 copyAct.setEnabled(False) 207 textEdit.copyAvailable[bool].connect(cutAct.setEnabled) 208 textEdit.copyAvailable[bool].connect(copyAct.setEnabled) 209} 210//! [24] 211 212//! [25] //! [26] 213def createMenus(self): 214//! [25] //! [27] 215 fileMenu = menuBar().addMenu(tr("&File")) 216 fileMenu.addAction(Act) 217//! [28] 218 fileMenu.addAction(openAct) 219//! [28] 220 fileMenu.addAction(saveAct) 221//! [26] 222 fileMenu.addAction(saveAsAct) 223 fileMenu.addSeparator() 224 fileMenu.addAction(exitAct) 225 226 editMenu = menuBar().addMenu(tr("&Edit")) 227 editMenu.addAction(cutAct) 228 editMenu.addAction(copyAct) 229 editMenu.addAction(pasteAct) 230 231 menuBar().addSeparator() 232 233 helpMenu = menuBar().addMenu(tr("&Help")) 234 helpMenu.addAction(aboutAct) 235 helpMenu.addAction(aboutQtAct) 236 237//! [27] 238 239//! [29] //! [30] 240def createToolBars(self): 241 fileToolBar = addToolBar(tr("File")) 242 fileToolBar.addAction(Act) 243//! [29] //! [31] 244 fileToolBar.addAction(openAct) 245//! [31] 246 fileToolBar.addAction(saveAct) 247 248 editToolBar = addToolBar(tr("Edit")) 249 editToolBar.addAction(cutAct) 250 editToolBar.addAction(copyAct) 251 editToolBar.addAction(pasteAct) 252//! [30] 253 254//! [32] 255def createStatusBar(self): 256//! [32] //! [33] 257 statusBar().showMessage(tr("Ready")) 258 259//! [33] 260 261//! [34] //! [35] 262def readSettings(self): 263//! [34] //! [36] 264 settings("Trolltech", "Application Example") 265 pos = settings.value("pos", QPoint(200, 200)).toPoint() 266 size = settings.value("size", QSize(400, 400)).toSize() 267 resize(size) 268 move(pos) 269 270//! [35] //! [36] 271 272//! [37] //! [38] 273def writeSettings(self): 274//! [37] //! [39] 275 settings = QSettings("Trolltech", "Application Example") 276 settings.setValue("pos", pos()) 277 settings.setValue("size", size()) 278 279//! [38] //! [39] 280 281//! [40] 282def maybeSave(self): 283//! [40] //! [41] 284 if textEdit.document()->isModified(): 285 ret = QMessageBox.warning(self, tr("Application"), 286 tr("The document has been modified.\n" 287 "Do you want to save your changes?"), 288 QMessageBox.Save | QMessageBox.Discard | QMessageBox.Cancel) 289 if ret == QMessageBox.Save: 290 return save() 291 elif ret == QMessageBox.Cancel: 292 return False 293 return True 294//! [41] 295 296//! [42] 297def loadFile(self, fileName): 298//! [42] //! [43] 299 file = QFile(fileName) 300 if !file.open(QFile.ReadOnly | QFile.Text): 301 QMessageBox.warning(self, tr("Application"), tr("Cannot read file " 302 "{}:\n{}.".format(fileName, file.errorString()))) 303 return 304 305 in = QTextStream(file) 306 QApplication.setOverrideCursor(Qt::WaitCursor) 307 textEdit.setPlainText(in.readAll()) 308 QApplication.restoreOverrideCursor() 309 310 self.setCurrentFile(fileName) 311 self.statusBar().showMessage(tr("File loaded"), 2000) 312 313//! [43] 314 315//! [44] 316def saveFile(self, fileName): 317//! [44] //! [45] 318 file = QFile(fileName) 319 if !file.open(QFile.WriteOnly | QFile::Text): 320 QMessageBox.warning(self, tr("Application"), 321 tr("Cannot write file %1:\n%2.") 322 .arg(fileName) 323 .arg(file.errorString())) 324 return False 325 326 out = QTextStream(file) 327 QApplication.setOverrideCursor(Qt.WaitCursor) 328 out << textEdit.toPlainText() 329 QApplication.restoreOverrideCursor() 330 331 setCurrentFile(fileName) 332 statusBar().showMessage(tr("File saved"), 2000) 333 return True 334 335//! [45] 336 337//! [46] 338def setCurrentFile(fileName): 339//! [46] //! [47] 340 curFile = fileName 341 textEdit.document().setModified(False) 342 setWindowModified(False) 343 344 if curFile.isEmpty(): 345 shownName = "untitled.txt" 346 else: 347 shownName = strippedName(curFile) 348 349 setWindowTitle(tr("%1[*] - %2").arg(shownName).arg(tr("Application"))) 350 351//! [47] 352 353//! [48] 354def strippedName(self, fullFileName): 355//! [48] //! [49] 356 return QFileInfo(fullFileName).fileName() 357//! [49] 358