Home | All Classes | Main Classes | Annotated | Grouped Classes | Functions |

# 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.

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

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.

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.

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.

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

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.

... when starting a new page ...

        ...

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

        ...

        ...

        ...

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.

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.

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

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

## 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`:

Includes for `io.cpp`:

Includes for `todo.cpp`:

Includes for `mainwindow.ui.h`:

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