Saving and loading documents

What's the use of an editor if it can't load and save texts? It would be of no use at all— and thus it is high time that we implemented this essential functionality. Loading and saving are part of the KalamDocument class. First, we need to decide if we will make use of the special PyQt file classes, or of the generic Python file classes. Let's do both for now, and you can choose which style you prefer.

Loading

Loading first:

    def open(self, fileName, format=None):
        self.setPathName(fileName)
        f = QFile(fileName)
        if f.exists():
            f.open(IO_ReadOnly)
            self.setText(QTextStream(f).read())
        else:
            raise IOError("No such file or directory: '%s'" % fileName)
        self._modified=FALSE
      

This is the Qt way of doing things: first, a QFile object is created. If a file with the name fileName already exists, a QTextStream is used to read the text from the file. This text is read into a QString object, which is passed on to setText, which we saw above. If the file doesn't exist, an exception is raised, which is caught in the application class, KalamApp.

The Pythonic method is a lot shorter:

    def open(self, fileName, format=None):
        self.setPathName(fileName)
        self.setText(QString(open(str(fileName)).read()))
        self._modified=FALSE
      

The net result is the same: the document receives a text in QString format, and all views are updated. There is no appreciable difference in performance between these two methods, but if you plan to translate the Python application to C++ at some time, it might be preferable to work with as many Qt classes as possible.

Saving

Saving text is slightly more critical than loading: what you can't load, you can't mangle and lose, but if the application refuses to save a text, a user can lose a lot of work. Still, there is little you can do when the disk is full, beyond preventing the application from crashing. As long as Kalam is running, users can still select, copy and paste text - a lesson I learned with early versions of Word. Note that saving using QTextStream is not currently possible. QTextStream uses C++ operator overloading (i.e. <<) to write to a stream, which is not yet available in Python.

    def save(self, fileName = None, format = None):
        if fileName is not None and fileName <> "":
            self.setPathName(fileName)

        if self.pathName() == None:
            raise IOError("Could not save document: no filename.")

        if isinstance(self.pathName(), QString):
            self.setPathName(str(self.pathName()))

        s=str(self.text())

        f = open(self.pathName(), "w")
        f.write(s)

        if s[-1:] != "\n":
            f.write("\n")
        f.flush()

        self._modified = FALSE
      

There are a few necessary checks to perform. The first is to make sure that the document actually possesses a filename; then we check whether the filename is an instance of QString, instead of a Python string. Python's file object cannot use QStrings — it needs to have a genuine Python string. So, if the pathname is an instance of QString, it is converted to a Python string.

The document text is then converted to a Python string. A Python file object is created by using the open function, and we write the string to it. If the last character is not a newline, we write a last newline and flush the file. It is a good idea to end all files with a newline, though you may wish to make this is a user-option in the application.