Thursday, January 26, 2012

Qt 4.8 Application Example - Part 5

Finally figured out what was going on with the Window title; the string used in setting the title has to include a parameter [*], also need to use setWindowTitle(), not _setWindowFilePath(). Re-wrote _setCurrentFileName() and_strippedName(); implemented the remaining methods/slots and we're done.



#!/usr/bin/env python3
# -*- coding: utf-8 -*-

'''
    PyQt4 conversion of Qt Application Example
    
        Implement the remaining actions:
            _newFile(), _open(), _about(), _loadFile(), 
            _documentWasModified(), _strippedName()
    
        Re-write _setCurrentFile()
    
    BEHAVIOUR:
    =========
    When the open document is modified an asterisk appears
    by the file name in the Window title.
    
    When a new document is loaded, the Window title is updated
    to reflect the file name.
    
    All the Edit functions work.
    
    NOTES:
    =====
    _setCurrentFile() was re-written to use _setWindowTitle()
    rather than _setWindowFilePath(). 
    
    Used Python os.path rather than QFileInfo to get the file 
    name from the full path.
        
last modified: 2012-01-27 jg
ref: 
    http://developer.qt.nokia.com/doc/qt-4.8/mainwindows-application.html
'''
import sys, os
from PyQt4.QtGui import (QApplication, QMainWindow, QPlainTextEdit, QAction,
                         QIcon, QKeySequence, QFileDialog, QMessageBox)
from PyQt4.QtCore import (pyqtSlot, QSettings, QPoint, QSize)
import qrc_app

class MainWindow(QMainWindow):      # subclass QMainWindow

    def __init__(self, parent=None):    # initialise base class
        super(MainWindow, self).__init__(parent)

        # create central widget        
        self._textEdit = QPlainTextEdit()
        self.setCentralWidget(self._textEdit)

        # create GUI
        self._createActions()
        self._createMenus()
        self._createToolBars()
        self._createStatusBar()

        # connect signals/slots for event handling
        self._textEdit.document().contentsChanged.connect(self._documentWasModified)

        # create application settings object
        QSettings.setDefaultFormat(QSettings.IniFormat)
        self._settings = QSettings()

        # establish initial conditions
        self._readSettings()
        self._setCurrentFile('')
        self.setUnifiedTitleAndToolBarOnMac(True)
        self._newFile()                 # force the window title

    # overridden methods ------------------------------------------------------
    def closeEvent(self, evt):
        if self._maybeSave():
            self._writeSettings()
            evt.accept()
        else:
            evt.ignore()

    # private slots -----------------------------------------------------------
    @pyqtSlot()
    def _newFile(self):
        if self._maybeSave():
            self._textEdit.clear()
            self._setCurrentFile('untitled.txt')

    @pyqtSlot()
    def _open(self):
        if self._maybeSave():
            fname = QFileDialog.getOpenFileName(self)
            if fname:
                self._loadFile(fname)

    @pyqtSlot()
    def _save(self):
        if not self._curFile:
            return self._saveAs()
        else:
            return self._saveFile(self._curFile)

    @pyqtSlot()
    def _saveAs(self):
        fname = QFileDialog.getSaveFileName(self)
        if not fname:
            return False

        return self._saveFile(fname)

    @pyqtSlot()
    def _about(self):
        QMessageBox.about(self,
            self.tr("About Application"),
            self.tr("The Application example demonstrates\n"
                    "how to write modern GUI applications using Qt\n"
                    "with a menubar, toolbars, and a status bar."))

    @pyqtSlot()
    def _documentWasModified(self):
        self.setWindowModified(self._textEdit.document().isModified())

    # private methods ---------------------------------------------------------
    def _createActions(self):
        self._newAct = QAction(QIcon(":/images/new.png"), self.tr("&New"), self)
        self._newAct.setShortcuts(QKeySequence.New)
        self._newAct.setStatusTip((self.tr("Create a new file.")))
        self._newAct.triggered.connect(self._newFile)

        self._openAct = QAction(QIcon(":/images/open.png"), self.tr("&Open"), self)
        self._openAct.setShortcuts(QKeySequence.Open)
        self._openAct.setStatusTip((self.tr("Open a file.")))
        self._openAct.triggered.connect(self._open)

        self._saveAct = QAction(QIcon(":/images/save.png"), self.tr("&Save"), self)
        self._saveAct.setShortcuts(QKeySequence.Save)
        self._saveAct.setStatusTip((self.tr("Save the document to disk.")))
        self._saveAct.triggered.connect(self._save)

        self._saveAsAct = QAction(self.tr("Save &As..."), self)
        self._saveAsAct.setShortcuts(QKeySequence.SaveAs)
        self._saveAsAct.setStatusTip((self.tr("Save the document under a new name.")))
        self._saveAsAct.triggered.connect(self._saveAs)

        self._exitAct = QAction(self.tr("E&xit"), self)
        self._exitAct.setShortcuts(QKeySequence.Quit)
        self._exitAct.setStatusTip((self.tr("Exit the application.")))
        self._exitAct.triggered.connect(self.close)

        self._aboutAct = QAction(self.tr("&About"), self)
        self._aboutAct.setStatusTip((self.tr("Show the application's About box.")))
        self._aboutAct.triggered.connect(self._about)

        self._aboutQtAct = QAction(self.tr("About &Qt"), self)
        self._aboutQtAct.setStatusTip((self.tr("Show the Qt library's About box.")))
        self._aboutQtAct.triggered.connect(QApplication.instance().aboutQt)

        # actions that connect to the 'textEdit' widget
        self._cutAct = QAction(QIcon(":/images/cut.png"), self.tr("Cu&t"), self)
        self._cutAct.setShortcuts(QKeySequence.Cut)
        self._cutAct.setStatusTip((self.tr("Cut the current selection's content to the clipboard.")))
        self._cutAct.triggered.connect(self._textEdit.cut)

        self._copyAct = QAction(QIcon(":/images/copy.png"), self.tr("&Copy"), self)
        self._copyAct.setShortcuts(QKeySequence.Copy)
        self._copyAct.setStatusTip((self.tr("Copy the current selection's content to the clipboard.")))
        self._copyAct.triggered.connect(self._textEdit.copy)

        self._pasteAct = QAction(QIcon(":/images/paste.png"), self.tr("&Paste"), self)
        self._pasteAct.setShortcuts(QKeySequence.Paste)
        self._pasteAct.setStatusTip((self.tr("Paste the clipboard contents into the current selection.")))
        self._pasteAct.triggered.connect(self._textEdit.paste)

        # set action visibility
        self._cutAct.setEnabled(False)
        self._copyAct.setEnabled((False))
        self._textEdit.copyAvailable.connect(self._cutAct.setEnabled)
        self._textEdit.copyAvailable.connect(self._copyAct.setEnabled)

    def _createMenus(self):
        fileMenu = self.menuBar().addMenu(self.tr("&File"))
        fileMenu.addAction(self._newAct)
        fileMenu.addAction(self._openAct)
        fileMenu.addAction(self._saveAct)
        fileMenu.addAction(self._saveAsAct)
        fileMenu.addSeparator()
        fileMenu.addAction(self._exitAct)

        editMenu = self.menuBar().addMenu(self.tr("&Edit"))
        editMenu.addAction(self._cutAct)
        editMenu.addAction(self._copyAct)
        editMenu.addAction(self._pasteAct)

        self.menuBar().addSeparator()

        helpMenu = self.menuBar().addMenu(self.tr("&Help"))
        helpMenu.addAction(self._aboutAct)
        helpMenu.addAction(self._aboutQtAct)


    def _createToolBars(self):
        fileToolBar = self.addToolBar(self.tr("File"))
        fileToolBar.addAction(self._newAct)
        fileToolBar.addAction(self._openAct)
        fileToolBar.addAction(self._saveAct)

        editToolBar = self.addToolBar(self.tr("Edit"))
        editToolBar.addAction(self._cutAct)
        editToolBar.addAction(self._copyAct)
        editToolBar.addAction(self._pasteAct)

    def _createStatusBar(self):
        self.statusBar().showMessage(self.tr("Ready"))

    def _readSettings(self):
        pos = self._settings.value("pos", QPoint(200, 200))
        size = self._settings.value("size", QSize(400, 400))
        self.resize(size)
        self.move(pos)

    def _writeSettings(self):
        self._settings.setValue("pos", self.pos())
        self._settings.setValue("size", self.size())

    def _maybeSave(self):
        if self._textEdit.document().isModified():
            ret = QMessageBox.warning(
                        self,
                        self.tr("Application"),
                        self.tr("The document has been modified.\n"
                                "Do you want to save your changes?"),
                        QMessageBox.Save | QMessageBox.Discard |
                        QMessageBox.Cancel)
            if ret == QMessageBox.Save:
                return self._save()
            elif ret == QMessageBox.Cancel:
                return False

        return True

    def _loadFile(self, fname):
        with open(fname, 'r') as f:
            txt = f.read()
            self._textEdit.setPlainText(txt)

        self._setCurrentFile(fname)
        self.statusBar().showMessage(self.tr("File loaded."))

    def _saveFile(self, fname):

        with open(fname, 'w') as f:
            f.write(self._textEdit.toPlainText())

        self._setCurrentFile(fname)
        self.statusBar().showMessage(self.tr("File saved."))
        return True

    def _setCurrentFile(self, fname):

        self._curFile = fname
        self._textEdit.document().setModified(False)
        self.setWindowModified(False)

        self.setWindowTitle(self.tr("{0} [*] - Application Example".format(
                                self._strippedName(self._curFile))))

    def _strippedName(self, fullFname):
        return os.path.basename(fullFname)

# main ========================================================================
def main():
    app = QApplication(sys.argv)
    app.setOrganizationName("My Business")
    app.setApplicationName("Application Example")
    app.setApplicationVersion("1.0")

    mw = MainWindow()
    mw.show()

    sys.exit(app.exec_())


if __name__ == '__main__':
    main()