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