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 deleteThe 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 CodeThe 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.
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 OfActualités les plus luesSemaine
Mois
Année
Le blog Digia au hasardUne nouvelle ère d'IHM 3D pour les automobilesLe 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 utilesContact
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 ! |
Copyright © 2000-2012 - www.developpez.com