The K Desktop Environment

Next Previous Table of Contents

8. Defining the Documents

The first step when creating an application based on the Document-View model should always be to think what kind of data the application has to manage. This decides how the view class will look like but especially how the document class will read and write data to and from files and offer methods to manipulate the data. As KScribble will be a simple drawing application that operates on graphical data, we will use the Qt class QPixmap for storing our paintings while it is edited. QPixmap also offers simple methods to read and write pictures into files, so the serialization of the document data is done in just two lines, one for reading and one for writing. Further, we need to define a pen that draws into a document, set it's width and color and make it available for the view class to retrieve the pen - actually you want the view offering the drawing methods, but the document as the central element for all views has to hold the pen originally, because two views of the same document would otherwise use different pens!

Therefore to define how our document class should work, we will add one instance of QPixmap, one of QPen and edit the methods newDocument(), openDocument() and saveDocument().

8.1 Adding the Instances

Open the file kscribbledoc.h by selecting it in one of the fileviewers or by a click on the classviewer over the class KScribbleDoc. Then add the lines marked with -> from the following code snippet:


->  #include <qpixmap.h>
->  #include <qpen.h>

    class KScribbleDoc
    {

->      protected:

->        QPen currentPen(){ return pen;};      
                
->              int penWidth()
->                      { return pen.width(); }

      public slots:
        void updateAllViews(KScribbleView *sender);
        
        protected:
        
->              QPixmap buffer;
        
      private:
->              QPen pen;
        /** the modified flag of the current document */
        bool modified;

As you see, we added pen and buffer as well as currentPen() and penWidth(). As pen is declared private, we offer a possibility to retrive the pen as well as the pen width. As these are already implemented within the classdeclaration, we don't have to add them to the implementation file, where we're turning to now.

8.2 Initialization of the Document

Select the method newDocument() in the KScribbleDoc class to jump to the method declaration. Here, we're only adding one line, marked with the arrow:


  kscribbledoc.cpp

  bool KScribbleDoc::newDocument()
  {
    /////////////////////////////////////////////////
    // TODO: Add your document initialization code here
->  pen=QPen( Qt::black, 3 );
    /////////////////////////////////////////////////
    modified=false;
    return true;
  }

This initializes the pen with the color black and width of 3 pixels; the QPen class has some more constructors, but this one lasts our needs here.

8.3 Implementing the Serialization

What is left to do is to define how to open and save our pictures. This is done in the according methods:


    bool KScribbleDoc::openDocument(const QString &filename, const char *format /*=0*/)
    {

        QFile f( filename );
->     //if ( !f.open( IO_ReadOnly ) )
->     //       return false;
     /////////////////////////////////////////////////
     // TODO: Add your document opening code here
->     if(!buffer.load( filename, "PNG" ))
->      return false;
     /////////////////////////////////////////////////
->     //f.close();


    bool KScribbleDoc::saveDocument(const QString &filename, const char *format /*=0*/)
    {
      QFile f( filename );
->     // if ( !f.open( IO_WriteOnly ) )
->     //       return false;

      /////////////////////////////////////////////////
      // TODO: Add your document saving code here
->      if(!buffer.save( filename, "PNG" ))
->              return false;
      /////////////////////////////////////////////////

->      //f.close();

Add the lines marked with the arrow again to your code. What we did here is to comment out the passages where the file filename is opened, because that is done automatically by the load and save methods of QPixmap, which we add instead. Other documents may open a file and read in its contents such as text lines or whatever, so the QFile methods are already present in the codeframe. As save() and load() return a boolean value if the operation was successful, we're returning false if not, so the rest of the framework gets a return value and can give out warnings if the operation was not successful. The load() and save() methods now are already provided in QPixmap. They require the filename and the format as argument; the source framework on the other hand does not call the document methods with the format yet. If only one format is used, it lasts to set the format here. other methods could detect the format for example- but we will turn to this later. For now, we're using "PNG" as format; see QImageIO for more details about the image formats that can be opened.

Now we're already finished defining our document structure. The QPixmap buffer serves us as a buffer storing the original picture contents while we're working on it, the pen is a valid pen for all views connected to the document. Note that the initialization of the pen is done in newDocument(). This method is always called after the constructor within the framework internally, so you should add document instances initializations there as we did with the pen.

In the next chapter we will turn to the view class to define how the view shall cooperate with the user as well as how it accesses the document- and then we'll be ready to paint !

Next Previous Table of Contents