7.3. Session Management

We touched on session management in Chapter 2 "A Simple KDE Application." You created KSimpleApp and endowed it with the capability to be restarted and maintain its position and size across sessions. (Session refers to the time between logging in and logging out.) Actually, this functionality was provided by KTMainWindow from which the class KSimpleApp was derived.

In general, you'll want to save more information across sessions than just the window position and size. KTMainWindow offers the virtual methods saveProperties() and readProperties() for this purpose. Also, you will want to save the user's data (or at least offer this option) before a session exits. You reimplement the virtual method queryClose() to do this. Listings 7.11–7.13 show the source code for KSaveAcross, an application that demonstrates these features.


Example 7.11. ksaveacross.h: Class Declaration for KSaveAcross, a Widget That Demonstrates Session Management Features of KTMainWindow

   1 
   2  1: #ifndef __KSAVEACROSS_H__
   3  2: #define __KSAVEACROSS_H__
   4  3:
   5  4: #include <ktmainwindow.h>
   6  5:
   7  6: /**
   8  7:  * KSaveAcross
   9  8:  * This application saves its data across sessions. Its data is
  10  9:  *  the contents of a QLineEdit.
  11 10:  **/ 
  12 11: class KSaveAcross : public KTMainWindow
  13 12: {
  14 13:  Q_OBJECT
  15 14:  public:
  16 15:   KSaveAcross (const char *name=0);
  17 16:
  18 17:  public slots:
  19 18:    /**
  20 19:     * Change the font used by qlineedit.
  21 20:     **/
  22 21:   void slotChangeFont();
  23 22:
  24 23:  protected:
  25 24:   QLineEdit *qlineedit;
  26 25:
  27 26:   /**
  28 27:    * Ask the user if he/she wants to save the document.
  29 28:    **/
  30 29:   bool queryClose();
  31 30:
  32 31:   /**
  33 32:    * Save the chosen font.
  34 33:    **/
  35 34:   void saveProperties (KConfig *kconfig);
  36 35:   /**
  37 36:    * Read the chosen font.
  38 37:    **/
  39 38:   void readProperties (KConfig *kconfig);
  40 39:
  41 40: };
  42 41:
  43 42: #endif

The content area of the KSaveAcross widget is a QLineEdit widget. The menubar offers two choices: change the font used by the QLineEdit widget or quit the application. The font chosen by the user is saved across sessions.


Example 7.12. ksaveacross.cpp: Class Definition for KSaveAcross

   1 
   2  1: #include <kapp.h>
   3  2: #include <kfontdialog.h>
   4  3: #include <kstdaction.h>
   5  4: #include <kaction.h>
   6  5: #include <kmessagebox.h>
   7  6: #include <kconfig.h>
   8  7:
   9  8: #include "ksaveacross.moc"
  10  9:
  11 10:
  12 11: KSaveAcross::KSaveAcross (const char *name)
  13 12: {
  14 13:   KStdAction::quit (kapp, SLOT (closeAllWindows()),
  15 14:                actionCollection());
  16 15:
  17 16:   new KAction ("Change Font…", 0, this, SLOT(slotChangeFont()),
  18 17:           actionCollection(), "change_font");
  19 18:   createGUI();
  20 19:
  21 20:   qlineedit = new QLineEdit (this);
  22 21:
  23 22:   setView (qlineedit);
  24 23: }
  25 24:
  26 25: void
  27 26: KSaveAcross::slotChangeFont()
  28 27: {
  29 28:   QFont qfont = qlineedit->font();
  30 29:
  31 30:   if (KFontDialog::getFont (qfont))
  32 31:     qlineedit->setFont(qfont);
  33 32: }
  34 33:
  35 34: bool
  36 35: KSaveAcross::queryClose()
  37 36: {
  38 37:  
  39 38:
  40 39:   const int yes=0, no=1, cancel=2;
  41 40:   int yesnocancel;
  42 41:
  43 42:   yesnocancel =
  44 43:     KMessageBox::
  45 44:     questionYesNo (this, "Save changes to document?", "ksaveacross");
  46 45:
  47 46:   switch (yesnocancel)
  48 47:     {
  49 48:     case (yes):
  50 49:       //You would save the document here and let the application exit.
  51 50:       return true;
  52 51:     case (no):
  53 52:       //Let the application exit without saving the document.
  54 53:       return true;
  55 54:     case (cancel):
  56 55:       //Don't save, but don't let the application exit.
  57 56:       return false;
  58 57:     }
  59 58: }
  60 59:
  61 60:
  62 61: void
  63 62: KSaveAcross::saveProperties (KConfig *kconfig)
  64 63: {
  65 64:   kconfig->writeEntry ("LineEditorFont", qlineedit->font());
  66 65:   kconfig->sync();
  67 66: }
  68 67:
  69 68: void
  70 69: KSaveAcross::readProperties (KConfig *kconfig)
  71 70: {
  72 71:   qlineedit->setFont (kconfig->readFontEntry ("LineEditorFont"));
  73 72: }

The method saveProperties() (lines 61–66) is called just before the application is terminated by the session manager. If the user quits the application normally, the method is not called. When the session manager restarts the application at the beginning of the next session, the method readProperties() is called. In these methods, you should save and read in properties that describe the current state of the application but that may not be saved in or specified in the configuration file. A Web browser, for example, might save the URL of the current page in the method saveProperties(), although it wouldn't want to store this in the configuration file.

saveProperties() and readProperties() work with KConfig objects. These KConfig objects do not operate on the default application configuration file. Instead, they operate on instance-specific configuration files created solely for the purpose of saving this session. The reading and writing methods were described in the previous section. Don't forget to call kconfig->sync() (line 65) at the end of saveProperties() to write the information to disk.

Before the application exits, it should ask the user whether he or she wishes to save the current document. If the application does this in the method queryClose() (a virtual method of the class KTMainWindow), the question is asked whether the application is closed by the user or by the session manager.

If queryClose() returns 3false, the application does not exit. The reimplementation of queryClose() in KSaveAcross (line 34–58) presents the user with the choices Yes, No, and Cancel as answers to the question, "Save changes to document?" If the user answers Yes or No, queryClose() returns true, letting the application exit. If the user chooses Cancel, queryClose() returns false and the user can continue working.

Note

You'll need to create a file called ksaveacrossui.rc and place it in the directory $KDEDIR/share/apps/ksaveacross as explained in Chapter 5, "KDE User Interface Compliance". A usable version of ksaveacrossui.rc is included with the code on this book's Web site.

Listing 7.13 provides the main() function needed to create and start this application. Notice that I have included the session management code (lines 9–15), which was discussed in Chapter 2. Figure 7.4 shows running KSaveAcross.

To create an executable, you'll need the code in Listing 7.13, and you'll need to place the GUI file, ksaveacrossui.rc (found on this book's web site), in the directory $KDEDIR/share/ kstatusbardemo.


Example 7.13. main.cpp: A main() Function Suitable for Testing KSaveAcross

   1 
   2  1: #include <kapp.h>
   3  2:
   4  3: #include "ksaveacross.h"
   5  4:
   6  5: int
   7  6: main (int argc, char *argv[])/
   8  7: {
   9  8:   KApplication kapplication (argc, argv, "ksaveacross");
  10  9:
  11 10:   if (kapplication.isRestored())
  12 11:       RESTORE(KSaveAcross)
  13 12:   else
  14 13:   {
  15 14:     KSaveAcross *ksaveacross = new KSaveAcross;
  16 15:     ksaveacross->show();
  17 16:   }
  18 17:
  19 18:   return kapplication.exec();
  20 19: }


Figure 7.4. KSaveAcross saves its options across sessions and offers to save the user's data before it is closed.