1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
|
<!DOCTYPE HTML PUBLIC "-//W3C//DTD HTML 4.0 Transitional//EN">
<!-- /home/espenr/tmp/qt-3.3.8-espenr-2499/qt-x11-free-3.3.8/extensions/motif/doc/walkthrough.doc:921 -->
<html>
<head>
<meta http-equiv="Content-Type" content="text/html; charset=ISO-8859-1">
<title>Refactoring Existing Code</title>
<style type="text/css"><!--
fn { margin-left: 1cm; text-indent: -1cm; }
a:link { color: #004faf; text-decoration: none }
a:visited { color: #672967; text-decoration: none }
body { background: #ffffff; color: black; }
--></style>
</head>
<body>
<table border="0" cellpadding="0" cellspacing="0" width="100%">
<tr bgcolor="#E5E5E5">
<td valign=center>
<a href="index.html">
<font color="#004faf">Home</font></a>
| <a href="classes.html">
<font color="#004faf">All Classes</font></a>
| <a href="mainclasses.html">
<font color="#004faf">Main Classes</font></a>
| <a href="annotated.html">
<font color="#004faf">Annotated</font></a>
| <a href="groups.html">
<font color="#004faf">Grouped Classes</font></a>
| <a href="functions.html">
<font color="#004faf">Functions</font></a>
</td>
<td align="right" valign="center"><img src="logo32.png" align="right" width="64" height="32" border="0"></td></tr></table><h1 align=center>Refactoring Existing Code</h1>
[ <a href="motif-walkthrough-6.html">Previous: Using Qt Main Window Classes</a> ]
[ <a href="motif-walkthrough.html">Home</a> ]
[ <a href="motif-walkthrough-8.html">Next: Replacing the View Widget</a> ]
<p> In the author's view, the existing code is slightly disorganized.
Even though the code <em>does</em> 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.
<p> <h2> Migrating Data Structures to C++
</h2>
<a name="1"></a><p> The <tt>Page</tt> data structure is an opaque data type. The real data
structure is called <tt>PageRec</tt>; <tt>Page</tt> defined to be a pointer to a
<tt>PageRec</tt>. In addition, we have the <tt>AllocPage()</tt> function that
allocates and initializes memory for a <tt>PageRec</tt> struct.
<p> With C++, we can do this in the constructor. We can also write a
destructor which automatically frees all resources in the <tt>PageRec</tt>,
instead of having to do it in several different places.
<p> The <tt>PageRec</tt> struct declaration is removed from <tt>page.h</tt>. We
declare a <tt>Page</tt> struct with the same data members as <tt>PageRec</tt>, a
constructor and a destructor.
<p>
<pre></pre>
<p> The existing <tt>pages</tt>, <tt>currentPage</tt> and <tt>maxpages</tt> global variables
are removed from the source files. We replace them with <tt>extern</tt>
declarations in <tt>page.h</tt>.
<p> <pre></pre>
<p> The global variable instantiations are placed in <tt>todo.cpp</tt>.
<p> Each source file contains function declarations that deal with the
global <tt>Page</tt> related variables. We remove these declarations from
the source files and declare them once in the <tt>page.h</tt> header file.
<p> <pre></pre>
<p> Now that <tt>Page</tt> has a constructor, we remove the <tt>AllocPage()</tt>
function. It is no longer needed. The calls to <tt>AllocPage()</tt> are
replaced with <tt>'new Page()'</tt> in the <tt>NewPage()</tt>, <tt>DeletePage()</tt>
and <tt>ReadDB()</tt> functions. We also replace the code to deallocate
pages with <tt>delete pages[X]</tt>, where <em>X</em> is the appropriate index
value. This is done in the <tt>ReadDB</tt> and <tt>DeletePage()</tt> functions.
<p> Code that accesses the global <tt>pages</tt> variable does not need to be
modified since the data members of the <tt>Page</tt> struct did not change.
The existing code will continue to work.
<p> The <tt>OptionsRec</tt> struct declared in <tt>page.h</tt> is also updated,
following the same pattern as the <tt>Page</tt> struct above.
<p> <pre></pre>
<p> The global variable instantiation is also placed in <tt>todo.cpp</tt>.
<p> Code that accesses the global <tt>options</tt> variable does not need to be
modified since the data members of the <tt>Options</tt> struct did not
change. The existing code will continue to work.
<p> <h2> Using <em>new</em> and <em>delete</em>
</h2>
<a name="2"></a><p> The destructors of the <tt>Page</tt> and <tt>Options</tt> structs use <em>delete</em>
instead of <tt>XtFree()</tt> to deallocate all <tt>char*</tt> members. This is a
necessary change since we are migrating away from Xt/Motif. We need
to fix existing code that modifies the <tt>Page</tt> struct members to use
<em>new</em> and <em>delete</em> ( instead of <tt>XtMalloc()</tt>, <tt>XtNewString()</tt> and
<tt>XtFree()</tt> ).
<p> The <tt>PageChange()</tt> function in <tt>todo.cpp</tt> simply saves the contents
and cursor position of current page before calling <tt>SetPage()</tt>. We
use <em>new</em> and <em>delete</em> when modifying members of the <tt>Page</tt> struct.
<p>
<pre></pre>
<p> When storing the context of the <tt>XmText</tt> widget, we use <a href="qcstring.html#qstrdup">qstrdup</a>()
to make a copy of the string returned by the <tt>XmTextGetString()</tt>
function.
<p> <pre></pre>
<p> The <tt>ReadDB()</tt> function in <tt>io.cpp</tt> needs similar changes. We
replace all use of <tt>XtMalloc()</tt> and <tt>XtNewString()</tt> with <em>new</em> and
<a href="qcstring.html#qstrdup">qstrdup</a>(), respectively.
<p> This needs to be done just after opening the file.
<p>
<pre></pre>
<p> ... when starting a new page ...
<p> <pre>
...
</pre>
<pre></pre>
<p> ... and when reading in the label and tab texts/
<p> <pre>
...
</pre>
<pre></pre><pre>
...
</pre>
<pre></pre><pre>
...
</pre>
<pre></pre>
<p> The <tt>ReadDB()</tt> function uses <tt>XtRealloc()</tt> 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.
<p> <pre></pre>
<p> There is also one occurence in <tt>ReadDB()</tt> where we call <tt>XtMalloc()</tt>
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 <em>new</em>.
<p> <pre></pre>
<p> The <tt>SaveDB()</tt> function in <tt>io.cpp</tt> also needs these changes. We
change one occurence of <tt>XtFree()</tt> to <em>delete</em>.
<p> <pre></pre>
<p> Finally, We need to replace two occurences of <tt>XtNewString()</tt> in the <tt>main()</tt> function in <tt>todo.cpp</tt>.
<p>
<pre></pre>
<p> <h2> Moving Existing Code
</h2>
<a name="3"></a><p> The rest of the refactoring process involves moving existing code into
new places. Currently, each function in the <tt>mainwindow.ui.h</tt> file
simply calls the old callback handlers present in the other files.
Instead of calling the old callback functions, the implementations are
moved accordingly.
<p> <center><table cellpadding="4" cellspacing="2" border="0">
<tr bgcolor="#a2c511"> <th valign="top">Function <th valign="top">Original File <th valign="top">Moved to Function
<tr bgcolor="#f0f0f0"> <td valign="top"><tt>New()</tt> <td valign="top"><tt>todo.cpp</tt> <td valign="top"><tt>MainWindow::fileNew()</tt>
<tr bgcolor="#d0d0d0"> <td valign="top"><tt>Open()</tt> <td valign="top"><tt>todo.cpp</tt> <td valign="top"><tt>MainWindow::fileOpen()</tt>
<tr bgcolor="#f0f0f0"> <td valign="top"><tt>SaveIt()</tt> <td valign="top"><tt>actions.cpp</tt> <td valign="top"><tt>MainWindow::fileSave()</tt>
<tr bgcolor="#d0d0d0"> <td valign="top"><tt>Save()</tt> <td valign="top"><tt>todo.cpp</tt> <td valign="top"><tt>MainWindow::fileSaveAs()</tt>
<tr bgcolor="#f0f0f0"> <td valign="top"><tt>ShowPrintDialog()</tt> <td valign="top"><tt>todo.cpp</tt> <td valign="top"><tt>MainWindow::filePrint()</tt>
<tr bgcolor="#d0d0d0"> <td valign="top"><tt>EditPage()</tt> <td valign="top"><tt>actions.cpp</tt> <td valign="top"><tt>MainWindow::selProperties()</tt>
<tr bgcolor="#f0f0f0"> <td valign="top"><tt>NewPage()</tt> <td valign="top"><tt>actions.cpp</tt> <td valign="top"><tt>MainWindow::selNewPage()</tt>
<tr bgcolor="#d0d0d0"> <td valign="top"><tt>DeletePage()</tt> <td valign="top"><tt>actions.cpp</tt> <td valign="top"><tt>MainWindow::selDeletePage()</tt>
</table></center>
<p> The <tt>Print()</tt> callback function is still used by the <em>Print</em>
dialog, so we move it into <tt>mainwindow.ui.h</tt> and make it <tt>static</tt>.
<p> Previously, the <tt>Open()</tt>, <tt>Save()</tt>, <tt>EditPage()</tt> and <tt>DeletePage()</tt>
functions created dialogs with <em>client_data</em> as the parent argument.
Since we have moved the code directly into the <em>Main Window</em>
implementation, we create these dialogs with <em>this</em> as the parent
argument.
<p> The <tt>PageChange()</tt> callback function is moved from <tt>actions.cpp</tt>
to <tt>todo.cpp</tt> and made <tt>static</tt> since it is not used anywhere else.
<p> Earlier modifications to <tt>actions.cpp</tt> caused the <tt>Trim()</tt> function
to become redundant, so we remove it.
<p> The <tt>MIN()</tt> and <tt>MAX()</tt> macros in <tt>todo.cpp</tt> are redundant. Qt
provides the <tt>QMIN()</tt> and <tt>QMAX()</tt> macros which we will use.
<p> Earlier modifications caused the <tt>fallback_resources</tt> array to become
redundant, so we remove it.
<p> In the near future, our program will not use <a href="motif-extension.html#Motif">Motif</a> any more, and we
will no longer need to use <a href="qmotif.html">QMotif</a>. To prepare for this, we remove the
<tt>resources</tt> and <tt>optionDesc</tt> arrays and create the QMotif instance
with just the <em>APP_CLASS</em> argument.
<p> The <tt>#include</tt> statements in the source files are mostly incorrect
due to the refactoring changes. Many of the <tt>#include</tt> statements
are no longer needed. The <tt>#include</tt> statements from each file are
listed below, instead of describing which includes are removed and
added to each file.
<p> Includes for <tt>actions.cpp</tt>:
<p>
<pre></pre>
<p> Includes for <tt>io.cpp</tt>:
<p>
<pre></pre><pre></pre><pre></pre>
<p> Includes for <tt>todo.cpp</tt>:
<p>
<pre></pre><pre></pre><pre></pre>
<p> Includes for <tt>mainwindow.ui.h</tt>:
<p>
<pre></pre><pre></pre><pre></pre><pre></pre><pre></pre>
<p> [ <a href="motif-walkthrough-6.html">Previous: Using Qt Main Window Classes</a> ]
[ <a href="motif-walkthrough.html">Home</a> ]
[ <a href="motif-walkthrough-8.html">Next: Replacing the View Widget</a> ]
<p>
<!-- eof -->
<p><address><hr><div align=center>
<table width=100% cellspacing=0 border=0><tr>
<td>Copyright © 2007
<a href="troll.html">Trolltech</a><td align=center><a href="trademarks.html">Trademarks</a>
<td align=right><div align=right>Qt 3.3.8</div>
</table></div></address></body>
</html>
|