Viadeo Twitter Google Bookmarks ! Facebook Digg del.icio.us MySpace Yahoo MyWeb Blinklist Netvouz Reddit Simpy StumbleUpon Bookmarks Windows Live Favorites 
Logo Documentation Qt ·  Page d'accueil  ·  Toutes les classes  ·  Classes principales  ·  Annotées  ·  Classes groupées  ·  Fonctions  · 

Refactoring Existing Code

[ Previous: Using Qt Main Window Classes ] [ Home ] [ Next: Replacing the View Widget ]

In the author's view, the existing code is slightly disorganized. Even though the code does work, some cleanups and reorganization can only help with readability and maintainability. The steps described below are not necessary during the migration process but are included for completeness.

Migrating Data Structures to C++

The Page data structure is an opaque data type. The real data structure is called PageRec; Page defined to be a pointer to a PageRec. In addition, we have the AllocPage() function that allocates and initializes memory for a PageRec struct.

With C++, we can do this in the constructor. We can also write a destructor which automatically frees all resources in the PageRec, instead of having to do it in several different places.

The PageRec struct declaration is removed from page.h. We declare a Page struct with the same data members as PageRec, a constructor and a destructor.

    struct Page {
        Page()
            : page( 0 ), majorTab( 0 ), minorTab( 0 ), label( 0 ),
              minorPB( (Widget) 0 ), majorPB( (Widget) 0 ),
              lasttoppos( 0 ), lastcursorpos( 0 )
        {
        }

        ~Page()
        {
            if ( page )     XtFree( page );
            if ( majorTab ) XtFree( majorTab );
            if ( minorTab ) XtFree( minorTab );
            if ( label )    XtFree( label );

            if ( minorPB ) XtDestroyWidget( minorPB );
            if ( majorPB ) XtDestroyWidget( majorPB );
        }

        char *page;
        char *majorTab;
        char *minorTab;
        char *label;
        Widget minorPB;
        Widget majorPB;
        int lasttoppos;
        int lastcursorpos;
    };

The existing pages, currentPage and maxpages global variables are removed from the source files. We replace them with extern declarations in page.h.

    extern Page *pages[];
    extern int currentPage;
    extern int maxpages;

The global variable instantiations are placed in todo.cpp.

Each source file contains function declarations that deal with the global Page related variables. We remove these declarations from the source files and declare them once in the page.h header file.

    void SetPage(int);
    void AdjustPages(int, int);
    void FixPages();

Now that Page has a constructor, we remove the AllocPage() function. It is no longer needed. The calls to AllocPage() are replaced with 'new Page()' in the NewPage(), DeletePage() and ReadDB() functions. We also replace the code to deallocate pages with delete pages[X], where X is the appropriate index value. This is done in the ReadDB and DeletePage() functions.

Code that accesses the global pages variable does not need to be modified since the data members of the Page struct did not change. The existing code will continue to work.

The OptionsRec struct declared in page.h is also updated, following the same pattern as the Page struct above.

    struct Options {
        Options() : todoFile( 0 ) { }
        ~Options()
        {
            if ( todoFile ) XtFree( todoFile );
        }

        String todoFile;
    };

    extern Options options;

The global variable instantiation is also placed in todo.cpp.

Code that accesses the global options variable does not need to be modified since the data members of the Options struct did not change. The existing code will continue to work.

Using new and delete

The destructors of the Page and Options structs use delete instead of XtFree() to deallocate all char* members. This is a necessary change since we are migrating away from Xt/Motif. We need to fix existing code that modifies the Page struct members to use new and delete ( instead of XtMalloc(), XtNewString() and XtFree() ).

The PageChange() function in todo.cpp simply saves the contents and cursor position of current page before calling SetPage(). We use new and delete when modifying members of the Page struct.

    PageChange(Widget, XtPointer, XmNotebookCallbackStruct *cs)
    {
      if (modified && pages[currentPage] != NULL) {
        delete [] pages[currentPage] -> page;

When storing the context of the XmText widget, we use qstrdup() to make a copy of the string returned by the XmTextGetString() function.

        char *p = XmTextGetString(textw);
        pages[currentPage] -> page = qstrdup( p );
        XtFree( p );

        pages[currentPage] -> lasttoppos = XmTextGetTopCharacter(textw);
        pages[currentPage] -> lastcursorpos = XmTextGetInsertionPosition(textw);
      }

      SetPage(cs -> page_number - 1);
    }

The ReadDB() function in io.cpp needs similar changes. We replace all use of XtMalloc() and XtNewString() with new and qstrdup(), respectively.

This needs to be done just after opening the file.

      if (input != NULL) {
        max = MAXINIT;
        buffer = new char[max];
        buffer[0] = 0; /* Reset page buffer */
        current = 0;
        pages[0] = new Page();

... when starting a new page ...

    ...
                    pages[number] -> page = buffer;
                    current = 0;
                    max = MAXINIT;
                    buffer = new char[max];
                    buffer[0] = 0; /* Reset page buffer */
                    number++;
                    pages[number] = new Page();

... and when reading in the label and tab texts/

    ...
                    pages[number] -> label = qstrdup( &line[2] );
    ...
                    pages[number] -> majorTab = qstrdup( &line[2] );
    ...
                    pages[number] -> minorTab = qstrdup( &line[2] );

The ReadDB() function uses XtRealloc() to expand the data storage buffer. Unfortunately, C++ does not provide a way to reallocate an existing block of data, so we have to do this ourselves.

                // C++ doesn't have 'renew', so we need to create a new
                // buffer, copy the existing data from old to new and then
                // delete the old

                int newmax = 2 * max;
                char *b = new char[newmax];
                memcpy( b, buffer, max );

                delete [] buffer;
                buffer = b;
                max = newmax;

There is also one occurence in ReadDB() where we call XtMalloc() with an argument of 2. This was done when a file could not be read. Creating an empty string is not necessary, so we remove this code instead of using new.

      if (input == NULL) {
        number = 0;
        pages[0] = new Page();
      } else {
        pages[number] -> page = buffer;
      }

The SaveDB() function in io.cpp also needs these changes. We change one occurence of XtFree() to delete.

      /* Make sure to grab current page */
      if (modified) {
        delete [] pages[currentPage] -> page;

Finally, We need to replace two occurences of XtNewString() in the main() function in todo.cpp.

      if (options.todoFile == NULL) {
        strcpy(temppath, user -> pw_dir);
        strcat(temppath, "/.todo");
        options.todoFile = qstrdup( temppath );
      } else {
        /* Copy the string for consistency */
        options.todoFile = qstrdup( options.todoFile );
      }

Moving Existing Code

The rest of the refactoring process involves moving existing code into new places. Currently, each function in the mainwindow.ui.h file simply calls the old callback handlers present in the other files. Instead of calling the old callback functions, the implementations are moved accordingly.

Function Original File Moved to Function
New() todo.cpp MainWindow::fileNew()
Open() todo.cpp MainWindow::fileOpen()
SaveIt() actions.cpp MainWindow::fileSave()
Save() todo.cpp MainWindow::fileSaveAs()
ShowPrintDialog() todo.cpp MainWindow::filePrint()
EditPage() actions.cpp MainWindow::selProperties()
NewPage() actions.cpp MainWindow::selNewPage()
DeletePage() actions.cpp MainWindow::selDeletePage()

The Print() callback function is still used by the Print dialog, so we move it into mainwindow.ui.h and make it static.

Previously, the Open(), Save(), EditPage() and DeletePage() functions created dialogs with client_data as the parent argument. Since we have moved the code directly into the Main Window implementation, we create these dialogs with this as the parent argument.

The PageChange() callback function is moved from actions.cpp to todo.cpp and made static since it is not used anywhere else.

Earlier modifications to actions.cpp caused the Trim() function to become redundant, so we remove it.

The MIN() and MAX() macros in todo.cpp are redundant. Qt provides the QMIN() and QMAX() macros which we will use.

Earlier modifications caused the fallback_resources array to become redundant, so we remove it.

In the near future, our program will not use Motif any more, and we will no longer need to use QMotif. To prepare for this, we remove the resources and optionDesc arrays and create the QMotif instance with just the APP_CLASS argument.

The #include statements in the source files are mostly incorrect due to the refactoring changes. Many of the #include statements are no longer needed. The #include statements from each file are listed below, instead of describing which includes are removed and added to each file.

Includes for actions.cpp:

    #include <Xm/Xm.h>
    #include <Xm/Notebook.h>
    #include <Xm/Text.h>

    #include "page.h"

Includes for io.cpp:

    #include <qmessagebox.h>

    #include <unistd.h>
    #include <Xm/Xm.h>
    #include <Xm/Text.h>

    #include "page.h"
    extern "C" {
    #include <Exm/TabB.h>
    }

Includes for todo.cpp:

    #include "mainwindow.h"
    #include <qapplication.h>
    #include <qmotif.h>
    #include <qmotifwidget.h>

    #include <pwd.h>
    #include <unistd.h>
    #include <stdlib.h>
    #include <Xm/Xm.h>
    #include <Xm/Label.h>
    #include <Xm/Notebook.h>
    #include <Xm/Text.h>

    #include "page.h"

Includes for mainwindow.ui.h:

    #include "pageeditdialog.h"
    #include <qapplication.h>
    #include <qfiledialog.h>
    #include <qlineedit.h>
    #include <qmessagebox.h>
    #include <qstatusbar.h>

    #include <qmotifwidget.h>
    #include <qmotifdialog.h>

    #include <unistd.h>
    #include <X11/Intrinsic.h>
    #include <X11/StringDefs.h>
    #include <X11/Xatom.h>
    #include <Xm/Xm.h>
    #include <Xm/Text.h>
    #include "page-refactor.h"

    extern "C" {
    #include <Exm/TabB.h>
    #include <Xmd/Print.h>
    } // extern "C"

[ Previous: Using Qt Main Window Classes ] [ Home ] [ Next: Replacing the View Widget ]

Publicité

Best Of

Actualités les plus lues

Semaine
Mois
Année
  1. « Quelque chose ne va vraiment pas avec les développeurs "modernes" », un développeur à "l'ancienne" critique la multiplication des bibliothèques 94
  2. Apercevoir la troisième dimension ou l'utilisation multithreadée d'OpenGL dans Qt, un article des Qt Quarterly traduit par Guillaume Belz 0
  3. Pourquoi les programmeurs sont-ils moins payés que les gestionnaires de programmes ? Manquent-ils de pouvoir de négociation ? 43
  4. Les développeurs ignorent-ils trop les failles découvertes dans leur code ? Prenez-vous en compte les remarques des autres ? 17
  5. Quelles nouveautés de C++11 Visual C++ doit-il rapidement intégrer ? Donnez-nous votre avis 10
  6. Qt Commercial : Digia organise un webinar gratuit le 27 mars sur la conception d'interfaces utilisateur et d'applications avec le framework 0
  7. 2017 : un quinquennat pour une nouvelle version du C++ ? Possible, selon Herb Sutter 9
Page suivante

Le blog Digia au hasard

Logo

Une nouvelle ère d'IHM 3D pour les automobiles

Le blog Digia est l'endroit privilégié pour la communication sur l'édition commerciale de Qt, où des réponses publiques sont apportées aux questions les plus posées au support. Lire l'article.

Communauté

Ressources

Liens utiles

Contact

  • Vous souhaitez rejoindre la rédaction ou proposer un tutoriel, une traduction, une question... ? Postez dans le forum Contribuez ou contactez-nous par MP ou par email (voir en bas de page).

Qt dans le magazine

Cette page est une traduction d'une page de la documentation de Qt, écrite par Nokia Corporation and/or its subsidiary(-ies). Les éventuels problèmes résultant d'une mauvaise traduction ne sont pas imputables à Nokia. Qt 3.2
Copyright © 2012 Developpez LLC. Tous droits réservés Developpez LLC. Aucune reproduction, même partielle, ne peut être faite de ce site et de l'ensemble de son contenu : textes, documents et images sans l'autorisation expresse de Developpez LLC. Sinon, vous encourez selon la loi jusqu'à 3 ans de prison et jusqu'à 300 000 E de dommages et intérêts. Cette page est déposée à la SACD.
Vous avez déniché une erreur ? Un bug ? Une redirection cassée ? Ou tout autre problème, quel qu'il soit ? Ou bien vous désirez participer à ce projet de traduction ? N'hésitez pas à nous contacter ou par MP !
 
 
 
 
Partenaires

Hébergement Web