]> vaikene.ee Git - evaf/blob - www/pswgen06.html
Warning fixes and copyright update.
[evaf] / www / pswgen06.html
1 <!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Transitional//EN" "http://www.w3.org/TR/xhtml1/DTD/xhtml1-transitional.dtd">
2 <html lang="et" xmlns="http://www.w3.org/1999/xhtml" xml:lang="et">
3
4 <head>
5 <meta http-equiv="CONTENT-TYPE" content="text/html; charset=utf-8" />
6 <title>eVaf Tutorial - 06 - Storage Module</title>
7 <meta name="Author" content="Enar Väikene" />
8 <meta name="description" content="eVaf Tutorial" />
9 <meta name="keywords" content="evaf c++ application development framework tutorial password generator" />
10 <link rel="StyleSheet" href="evaf.css" type="text/css" media="all" />
11 <link rel="StyleSheet" href="highlight.css" type="text/css" media="all" />
12 </head>
13
14 <body>
15
16 <p>Next: <a href="pswgen07.html">07 - Storage Module</a>, Previous: <a href="pswgen05.html">05 - Building Generator Module</a></p>
17
18 <h1>eVaf Tutorial</h1>
19
20 <h2>06 - Storage Module</h2>
21
22 <p>In this section we start implementing the Storage module. The storage module stores non-sensitive data required to re-generate
23 passwords. We use a simple SQLITE database in this module, but nothing prevents us replacing it with a more complex storage
24 module in the future.</p>
25
26 <h3>iStorage interface</h3>
27
28 <p>Once again, we start by defining the interface for the module and create the file <tt>istorage.h</tt> in the
29 <tt>src/apps/PswGen/Storage</tt> directory:</p>
30
31 <pre class="hl"><span class="hl com">/**</span>
32 <span class="hl com"> * &#64;file PswGen/Storage/istorage.h</span>
33 <span class="hl com"> */</span>
34
35 <span class="hl ppc">#ifndef __PSWGEN_STORAGE_ISTORAGE_H</span>
36 <span class="hl ppc"># define __PSWGEN_STORAGE_ISTORAGE_H</span>
37 <span class="hl ppc">#endif</span> <span class="hl slc">// istorage.h</span></pre>
38
39 <p>Include Qt header files for <tt>QObject</tt> and <tt>QString</tt> as they are almost always needed. In additon, we are going to
40 include headers for <tt>QSharedData</tt> and <tt>QExplicitlySharedDataPointer</tt>. We need a container for the data that
41 we store and making it shared data object with the benefit of automatic reference counting and memory management makes sense.</p>
42
43 <pre class="hl"><span class="hl ppc">#include &lt;QObject&gt;</span>
44 <span class="hl ppc">#include &lt;QString&gt;</span>
45 <span class="hl ppc">#include &lt;QSharedData&gt;</span>
46 <span class="hl ppc">#include &lt;QExplicitlySharedDataPointer&gt;</span></pre>
47
48 <p>Use the <tt>eVaf::PswGen</tt> namespace:</p>
49
50 <pre class="hl"><span class="hl kwa">namespace</span> eVaf <span class="hl opt">{</span>
51 <span class="hl kwa">namespace</span> PswGen <span class="hl opt">{</span>
52
53 <span class="hl opt">}</span> <span class="hl slc">// namespace eVaf::PswGen</span>
54 <span class="hl opt">}</span> <span class="hl slc">// namespace eVaf</span></pre>
55
56 <p>The container class for stored data has the following attributes:</p>
57 <ul>
58 <li>Name -- Name of the generated password</li>
59 <li>Length -- Length of the password</li>
60 <li>Options -- Additional parameters for the password generator</li>
61 </ul>
62
63 <p>The container class belongs to the Storage module and we use the <tt>eVaf::PswGen::Storage</tt> namespace for it:</p>
64
65 <pre class="hl"><span class="hl kwa">namespace</span> Storage <span class="hl opt">{</span>
66
67 <span class="hl kwc">class</span> Data <span class="hl opt">:</span> <span class="hl kwc">public</span> QSharedData
68 <span class="hl opt">{</span>
69 <span class="hl kwc">private</span><span class="hl opt">:</span>
70
71 <span class="hl kwb">bool</span> mModified<span class="hl opt">;</span>
72 QString mName<span class="hl opt">;</span>
73 <span class="hl kwb">int</span> mLength<span class="hl opt">;</span>
74 uint mFlags<span class="hl opt">;</span>
75
76 <span class="hl opt">};</span>
77
78 <span class="hl opt">}</span> <span class="hl slc">// eVaf::PswGen::Storage</span></pre>
79
80 <p>The extra attribute - <tt>mModified</tt> - is used to detect unsaved modifications in the data object.</p>
81
82 <p>Add constructors for the shared data class. Creating a data object without name makes no sense and we include the
83 name attribute in all our constructors:</p>
84
85 <pre class="hl"><span class="hl kwc">public</span><span class="hl opt">:</span>
86
87 <span class="hl kwd">Data</span><span class="hl opt">(</span>QString <span class="hl kwb">const</span> <span class="hl opt">&amp;</span> name<span class="hl opt">)</span>
88 <span class="hl opt">:</span> <span class="hl kwd">QSharedData</span><span class="hl opt">()</span>
89 <span class="hl opt">,</span> <span class="hl kwd">mModified</span><span class="hl opt">(</span><span class="hl kwa">false</span><span class="hl opt">)</span>
90 <span class="hl opt">,</span> <span class="hl kwd">mName</span><span class="hl opt">(</span>name<span class="hl opt">)</span>
91 <span class="hl opt">,</span> <span class="hl kwd">mLength</span><span class="hl opt">(</span><span class="hl num">0</span><span class="hl opt">)</span>
92 <span class="hl opt">,</span> <span class="hl kwd">mFlags</span><span class="hl opt">(</span><span class="hl num">0</span><span class="hl opt">)</span>
93 <span class="hl opt">{}</span>
94
95 <span class="hl kwd">Data</span><span class="hl opt">(</span>QString <span class="hl kwb">const</span> <span class="hl opt">&amp;</span> name<span class="hl opt">,</span> <span class="hl kwb">int</span> l<span class="hl opt">,</span> uint f <span class="hl opt">=</span> <span class="hl num">0</span><span class="hl opt">)</span>
96 <span class="hl opt">:</span> <span class="hl kwd">QSharedData</span><span class="hl opt">()</span>
97 <span class="hl opt">,</span> <span class="hl kwd">mModified</span><span class="hl opt">(</span><span class="hl kwa">false</span><span class="hl opt">)</span>
98 <span class="hl opt">,</span> <span class="hl kwd">mName</span><span class="hl opt">(</span>name<span class="hl opt">)</span>
99 <span class="hl opt">,</span> <span class="hl kwd">mLength</span><span class="hl opt">(</span>l<span class="hl opt">)</span>
100 <span class="hl opt">,</span> <span class="hl kwd">mFlags</span><span class="hl opt">(</span>f<span class="hl opt">)</span>
101 <span class="hl opt">{}</span></pre>
102
103 <p>Fianlly, we add getter and setter methods:</p>
104
105 <pre class="hl">
106 QString <span class="hl kwb">const</span> <span class="hl opt">&amp;</span> <span class="hl kwd">name</span><span class="hl opt">()</span> <span class="hl kwb">const</span> <span class="hl opt">{</span> <span class="hl kwa">return</span> mName<span class="hl opt">; }</span>
107
108 <span class="hl kwb">int</span> <span class="hl kwd">length</span><span class="hl opt">()</span> <span class="hl kwb">const</span> <span class="hl opt">{</span> <span class="hl kwa">return</span> mLength<span class="hl opt">; }</span>
109 <span class="hl kwb">void</span> <span class="hl kwd">setLength</span><span class="hl opt">(</span><span class="hl kwb">int</span> value<span class="hl opt">)</span>
110 <span class="hl opt">{</span>
111 <span class="hl kwa">if</span> <span class="hl opt">(</span>mLength <span class="hl opt">!=</span> value<span class="hl opt">) {</span>
112 mLength <span class="hl opt">=</span> value<span class="hl opt">;</span>
113 mModified <span class="hl opt">=</span> <span class="hl kwa">true</span><span class="hl opt">;</span>
114 <span class="hl opt">}</span>
115 <span class="hl opt">}</span>
116
117 uint <span class="hl kwd">flags</span><span class="hl opt">()</span> <span class="hl kwb">const</span> <span class="hl opt">{</span> <span class="hl kwa">return</span> mFlags<span class="hl opt">; }</span>
118 <span class="hl kwb">void</span> <span class="hl kwd">setFlags</span><span class="hl opt">(</span>uint value<span class="hl opt">)</span>
119 <span class="hl opt">{</span>
120 <span class="hl kwa">if</span> <span class="hl opt">(</span>mFlags <span class="hl opt">!=</span> value<span class="hl opt">) {</span>
121 mFlags <span class="hl opt">=</span> value<span class="hl opt">;</span>
122 mModified <span class="hl opt">=</span> <span class="hl kwa">true</span><span class="hl opt">;</span>
123 <span class="hl opt">}</span>
124 <span class="hl opt">}</span>
125
126 <span class="hl kwb">bool</span> <span class="hl kwd">modified</span><span class="hl opt">()</span> <span class="hl kwb">const</span> <span class="hl opt">{</span> <span class="hl kwa">return</span> mModified<span class="hl opt">; }</span>
127
128 <span class="hl kwb">void</span> <span class="hl kwd">reset</span><span class="hl opt">() {</span> mModified <span class="hl opt">=</span> <span class="hl kwa">false</span><span class="hl opt">; }</span></pre>
129
130 <p>The <tt>reset()</tt> method resets the <tt>modified</tt> attribute.</p>
131
132 <p>Continue with the <tt>iStorage</tt> interface:</tt>
133
134 <pre class="hl"><span class="hl kwb">struct</span> iStorage
135 <span class="hl opt">{</span>
136
137 <span class="hl opt">};</span></pre>
138
139 <p>According to the specification, we need functions to store and query data:</p>
140
141 <pre class="hl">
142 <span class="hl kwc">virtual</span> <span class="hl kwb">bool</span> <span class="hl kwd">save</span><span class="hl opt">(</span>QString <span class="hl kwb">const</span> <span class="hl opt">&amp;</span> name<span class="hl opt">,</span> QExplicitlySharedDataPointer<span class="hl opt">&lt;</span>Storage<span class="hl opt">::</span>Data<span class="hl opt">&gt;</span> data<span class="hl opt">) =</span> <span class="hl num">0</span><span class="hl opt">;</span>
143
144 <span class="hl kwc">virtual</span> QExplicitlySharedDataPointer<span class="hl opt">&lt;</span>Storage<span class="hl opt">::</span>Data<span class="hl opt">&gt;</span> <span class="hl kwd">query</span><span class="hl opt">(</span>QString <span class="hl kwb">const</span> <span class="hl opt">&amp;</span> name<span class="hl opt">)</span> <span class="hl kwb">const</span> <span class="hl opt">=</span> <span class="hl num">0</span><span class="hl opt">;</span></pre>
145
146 <p>The <tt>query()</tt> method returns an explicitly shared shared data pointer, which has the following advantages:</p>
147 <ul>
148 <li>The same data object is shared between multiple modules and if a module changes attributes in the data object, these
149 changes are immediately seen by any other modules;</li>
150 <li>No need to worry about ownership -- the shared data object is deleted when the last module stops using it;</li>
151 <li>The <tt>query()</tt> method can return an empty shared data pointer to indicate that no data objects with the
152 given name exist.</tt>
153 </ul>
154
155 <p>The drawback is that if a module needs a local copy of the data object, it has to use the <tt>QExplicitlySharedDataPointer::detach()</tt> method to create a deep copy of the data object.</p>
156
157 <p>The specification also mentions partial matches where entering "fa" would offer "facebook.com" if it exists. This could be done by
158 using the <tt>QCompleter</tt> class that provides auto completion in Qt widgets like <tt>QLineEdit</tt> and <tt>QComboBox</tt>. The
159 <tt>QCompleter<tt> class needs a <tt>QAbstractItemModel</tt> for the auto completion word list and we can provide it
160 from our <tt>Storage</tt> module:</tt>
161
162 <pre class="hl">
163 <span class="hl kwc">virtual</span> QAbstractItemModel <span class="hl opt">*</span> <span class="hl kwd">autoCompletionModel</span><span class="hl opt">() =</span> <span class="hl num">0</span><span class="hl opt">;</span></pre>
164
165 <p><tt>QAbstractItemModel</tt> is not known at this moment and we need to add a forward class declaration to the beginning of the
166 <tt>istorage.h</tt> file:</p>
167
168 <pre class="hl">
169 <span class="hl kwc">class</span> QAbstractItemModel<span class="hl opt">;</span></pre>
170
171 <p>At the the end of the <tt>istorage.h</tt> file, we declare the <tt>iStorage</tt> interface:</p>
172
173 <pre class="hl"><span class="hl kwd">Q_DECLARE_INTERFACE</span><span class="hl opt">(</span>eVaf<span class="hl opt">::</span>PswGen<span class="hl opt">::</span>iStorage<span class="hl opt">,</span> <span class="hl str">&quot;eVaf.PswGen.iStorage/1.0&quot;</span><span class="hl opt">)</span></pre>
174
175 <p>This is the complete <tt>istorage.h</tt> file:</p>
176
177 <pre class="hl"><span class="hl com">/**</span>
178 <span class="hl com"> * &#64;file PswGen/Storage/istorage.h</span>
179 <span class="hl com"> */</span>
180
181 <span class="hl ppc">#ifndef __PSWGEN_STORAGE_ISTORAGE_H</span>
182 <span class="hl ppc"># define __PSWGEN_STORAGE_ISTORAGE_H</span>
183
184 <span class="hl ppc">#include &lt;QObject&gt;</span>
185 <span class="hl ppc">#include &lt;QString&gt;</span>
186 <span class="hl ppc">#include &lt;QSharedData&gt;</span>
187 <span class="hl ppc">#include &lt;QExplicitlySharedDataPointer&gt;</span>
188
189 <span class="hl kwc">class</span> QAbstractItemModel<span class="hl opt">;</span>
190
191 <span class="hl kwa">namespace</span> eVaf <span class="hl opt">{</span>
192 <span class="hl kwa">namespace</span> PswGen <span class="hl opt">{</span>
193
194 <span class="hl kwa">namespace</span> Storage <span class="hl opt">{</span>
195
196 <span class="hl com">/// Data stored for every password.</span>
197 <span class="hl kwc">class</span> Data <span class="hl opt">:</span> <span class="hl kwc">public</span> QSharedData
198 <span class="hl opt">{</span>
199 <span class="hl kwc">public</span><span class="hl opt">:</span>
200
201 <span class="hl kwd">Data</span><span class="hl opt">(</span>QString <span class="hl kwb">const</span> <span class="hl opt">&amp;</span> name<span class="hl opt">)</span>
202 <span class="hl opt">:</span> <span class="hl kwd">QSharedData</span><span class="hl opt">()</span>
203 <span class="hl opt">,</span> <span class="hl kwd">mModified</span><span class="hl opt">(</span><span class="hl kwa">false</span><span class="hl opt">)</span>
204 <span class="hl opt">,</span> <span class="hl kwd">mName</span><span class="hl opt">(</span>name<span class="hl opt">)</span>
205 <span class="hl opt">,</span> <span class="hl kwd">mLength</span><span class="hl opt">(</span><span class="hl num">0</span><span class="hl opt">)</span>
206 <span class="hl opt">,</span> <span class="hl kwd">mFlags</span><span class="hl opt">(</span><span class="hl num">0</span><span class="hl opt">)</span>
207 <span class="hl opt">{}</span>
208
209 <span class="hl kwd">Data</span><span class="hl opt">(</span>QString <span class="hl kwb">const</span> <span class="hl opt">&amp;</span> name<span class="hl opt">,</span> <span class="hl kwb">int</span> l<span class="hl opt">,</span> uint f <span class="hl opt">=</span> <span class="hl num">0</span><span class="hl opt">)</span>
210 <span class="hl opt">:</span> <span class="hl kwd">QSharedData</span><span class="hl opt">()</span>
211 <span class="hl opt">,</span> <span class="hl kwd">mModified</span><span class="hl opt">(</span><span class="hl kwa">false</span><span class="hl opt">)</span>
212 <span class="hl opt">,</span> <span class="hl kwd">mName</span><span class="hl opt">(</span>name<span class="hl opt">)</span>
213 <span class="hl opt">,</span> <span class="hl kwd">mLength</span><span class="hl opt">(</span>l<span class="hl opt">)</span>
214 <span class="hl opt">,</span> <span class="hl kwd">mFlags</span><span class="hl opt">(</span>f<span class="hl opt">)</span>
215 <span class="hl opt">{}</span>
216
217 <span class="hl slc">/// Name of the password</span>
218 QString <span class="hl kwb">const</span> <span class="hl opt">&amp;</span> <span class="hl kwd">name</span><span class="hl opt">()</span> <span class="hl kwb">const</span> <span class="hl opt">{</span> <span class="hl kwa">return</span> mName<span class="hl opt">; }</span>
219
220 <span class="hl slc">/// Length of the generated password</span>
221 <span class="hl kwb">int</span> <span class="hl kwd">length</span><span class="hl opt">()</span> <span class="hl kwb">const</span> <span class="hl opt">{</span> <span class="hl kwa">return</span> mLength<span class="hl opt">; }</span>
222 <span class="hl kwb">void</span> <span class="hl kwd">setLength</span><span class="hl opt">(</span><span class="hl kwb">int</span> value<span class="hl opt">)</span>
223 <span class="hl opt">{</span>
224 <span class="hl kwa">if</span> <span class="hl opt">(</span>mLength <span class="hl opt">!=</span> value<span class="hl opt">) {</span>
225 mLength <span class="hl opt">=</span> value<span class="hl opt">;</span>
226 mModified <span class="hl opt">=</span> <span class="hl kwa">true</span><span class="hl opt">;</span>
227 <span class="hl opt">}</span>
228 <span class="hl opt">}</span>
229
230 <span class="hl slc">/// Optional flags for the password generator</span>
231 uint <span class="hl kwd">flags</span><span class="hl opt">()</span> <span class="hl kwb">const</span> <span class="hl opt">{</span> <span class="hl kwa">return</span> mFlags<span class="hl opt">; }</span>
232 <span class="hl kwb">void</span> <span class="hl kwd">setFlags</span><span class="hl opt">(</span>uint value<span class="hl opt">)</span>
233 <span class="hl opt">{</span>
234 <span class="hl kwa">if</span> <span class="hl opt">(</span>mFlags <span class="hl opt">!=</span> value<span class="hl opt">) {</span>
235 mFlags <span class="hl opt">=</span> value<span class="hl opt">;</span>
236 mModified <span class="hl opt">=</span> <span class="hl kwa">true</span><span class="hl opt">;</span>
237 <span class="hl opt">}</span>
238 <span class="hl opt">}</span>
239
240 <span class="hl slc">/// Flag indicating that some fields are modified</span>
241 <span class="hl kwb">bool</span> <span class="hl kwd">modified</span><span class="hl opt">()</span> <span class="hl kwb">const</span> <span class="hl opt">{</span> <span class="hl kwa">return</span> mModified<span class="hl opt">; }</span>
242
243 <span class="hl slc">/// Resets the modified flag</span>
244 <span class="hl kwb">void</span> <span class="hl kwd">reset</span><span class="hl opt">() {</span> mModified <span class="hl opt">=</span> <span class="hl kwa">false</span><span class="hl opt">; }</span>
245
246 <span class="hl kwc">private</span><span class="hl opt">:</span>
247
248 <span class="hl kwb">bool</span> mModified<span class="hl opt">;</span>
249 QString mName<span class="hl opt">;</span>
250 <span class="hl kwb">int</span> mLength<span class="hl opt">;</span>
251 uint mFlags<span class="hl opt">;</span>
252
253 <span class="hl opt">};</span>
254
255 <span class="hl opt">}</span> <span class="hl slc">// eVaf::PswGen::Storage</span>
256
257 <span class="hl com">/// Password storage interface.</span>
258 <span class="hl kwb">struct</span> iStorage
259 <span class="hl opt">{</span>
260
261 <span class="hl com">/// Saves the data record</span>
262 <span class="hl kwc">virtual</span> <span class="hl kwb">bool</span> <span class="hl kwd">save</span><span class="hl opt">(</span>QString <span class="hl kwb">const</span> <span class="hl opt">&amp;</span> name<span class="hl opt">,</span> QExplicitlySharedDataPointer<span class="hl opt">&lt;</span>Storage<span class="hl opt">::</span>Data<span class="hl opt">&gt;</span> data<span class="hl opt">) =</span> <span class="hl num">0</span><span class="hl opt">;</span>
263
264 <span class="hl com">/// Returns a data record by the name</span>
265 <span class="hl kwc">virtual</span> QExplicitlySharedDataPointer<span class="hl opt">&lt;</span>Storage<span class="hl opt">::</span>Data<span class="hl opt">&gt;</span> <span class="hl kwd">query</span><span class="hl opt">(</span>QString <span class="hl kwb">const</span> <span class="hl opt">&amp;</span> name<span class="hl opt">)</span> <span class="hl kwb">const</span> <span class="hl opt">=</span> <span class="hl num">0</span><span class="hl opt">;</span>
266
267 <span class="hl com">/// Returns an item model with the names of all the stored passwords</span>
268 <span class="hl kwc">virtual</span> QAbstractItemModel <span class="hl opt">*</span> <span class="hl kwd">autoCompletionModel</span><span class="hl opt">() =</span> <span class="hl num">0</span><span class="hl opt">;</span>
269
270 <span class="hl opt">};</span>
271
272 <span class="hl opt">}</span> <span class="hl slc">// namespace eVaf::PswGen</span>
273 <span class="hl opt">}</span> <span class="hl slc">// namespace eVaf</span>
274
275 <span class="hl kwd">Q_DECLARE_INTERFACE</span><span class="hl opt">(</span>eVaf<span class="hl opt">::</span>PswGen<span class="hl opt">::</span>iStorage<span class="hl opt">,</span> <span class="hl str">&quot;eVaf.PswGen.iStorage/1.0&quot;</span><span class="hl opt">)</span>
276
277 <span class="hl ppc">#endif</span> <span class="hl slc">// istorage.h</span><span class="hl ppc"></span></pre>
278
279 <p>We also create the <tt>iStorage</tt> file so that we can use <tt>#include &lt;Storage/iStorage&gt;</tt> in our other modules:</tt>
280
281 <pre class="hl"><span class="hl ppc">#include </span><span class="hl pps">&quot;istorage.h&quot;</span></pre>
282
283 <h3>Storage module</h3>
284
285 <p>The <tt>Storage<tt> module is simple enough to be derived directly from the <tt>Plugins::iPlugin</tt> interface and needs only one
286 header/source file. In general, I personally prefer short source files and follow the <i>one-class-per-file</i> rule. Only when classes
287 are very simple and closely related I put the into the same source file.</p>
288
289 <p>Create the <tt>module.h</tt> header file in the <tt>src/apps/PswGen/Storage</tt> directory. Include <tt>istorage.h</tt> and
290 <tt>Plugins/iPlugin</tt> header files. We use the <tt>eVaf::PswGen::Storage</tt> namespace for public classes and
291 <tt>eVaf::PswGen::Storage::Internal<tt> namespace for private classes.</p>
292
293 <pre class="hl"><span class="hl ppc">#ifndef __PSWGEN_STORAGE_MODULE_H</span>
294 <span class="hl ppc"># define __PSWGEN_STORAGE_MODULE_H</span>
295
296 <span class="hl ppc">#include</span> <span class="hl pps">&quot;istorage.h&quot;</span><span class="hl ppc"></span>
297 <span class="hl ppc">#include &lt;Plugins/iPlugin&gt;</span>
298
299 <span class="hl kwa">namespace</span> eVaf <span class="hl opt">{</span>
300 <span class="hl kwa">namespace</span> PswGen <span class="hl opt">{</span>
301
302 <span class="hl slc">/// Module that stores options for strong passwords</span>
303 <span class="hl kwa">namespace</span> Storage <span class="hl opt">{</span>
304
305 <span class="hl slc">/// Internal implementation of the Storage module</span>
306 <span class="hl kwa">namespace</span> Internal <span class="hl opt">{</span>
307
308 <span class="hl opt">}</span> <span class="hl slc">// namespace eVaf::PswGen::Storage::Internal</span>
309 <span class="hl opt">}</span> <span class="hl slc">// namespace eVaf::PswGen::Storage</span>
310 <span class="hl opt">}</span> <span class="hl slc">// namespace eVaf::PswGen</span>
311 <span class="hl opt">}</span> <span class="hl slc">// namespace eVaf</span>
312 <span class="hl ppc">#endif</span> <span class="hl slc">// module.h</span><span class="hl ppc"></span></pre>
313
314 <p>We use the same name <tt>Module</tt> for the class that implements the module. This class is public and goes to the
315 <tt>eVaf::PswGen::Storage</tt> namespace:</p>
316
317 <pre class="hl"><span class="hl kwc">class</span> Module <span class="hl opt">:</span> <span class="hl kwc">public</span> Plugins<span class="hl opt">::</span>iPlugin
318 <span class="hl opt">{</span>
319 Q_OBJECT
320
321 <span class="hl kwc">public</span><span class="hl opt">:</span>
322
323 <span class="hl kwd">Module</span><span class="hl opt">();</span>
324
325 <span class="hl kwc">virtual</span> <span class="hl opt">~</span><span class="hl kwd">Module</span><span class="hl opt">();</span>
326
327 <span class="hl opt">};</span></pre>
328
329 <p>Implement pure virtual methods in the <tt>iPlugin</tt> interface:</p>
330
331 <pre class="hl">
332 <span class="hl kwc">virtual</span> <span class="hl kwb">bool</span> <span class="hl kwd">init</span><span class="hl opt">(</span>QString <span class="hl kwb">const</span> <span class="hl opt">&amp;</span> args<span class="hl opt">);</span>
333
334 <span class="hl kwc">virtual</span> <span class="hl kwb">void</span> <span class="hl kwd">done</span><span class="hl opt">();</span>
335
336 <span class="hl kwc">virtual</span> <span class="hl kwb">bool</span> <span class="hl kwd">isReady</span><span class="hl opt">()</span> <span class="hl kwb">const</span> <span class="hl opt">{</span> <span class="hl kwa">return</span> mReady<span class="hl opt">; }</span></pre>
337
338 <p>This module needs more complex initialization that the <tt>Generator</tt> module and we use the <tt>mReady</tt> flag to
339 indicate that the module is fully initialized:</p>
340
341 <pre class="hl">
342 <span class="hl kwc">private</span><span class="hl opt">:</span>
343
344 <span class="hl kwb">bool</span> mReady<span class="hl opt">;</span></pre>
345
346 <p>The <tt>StorageImpl</tt> class is the internal implementation of the <tt>iStorage</tt> interface:</p>
347
348 <pre class="hl">
349 Internal<span class="hl opt">::</span>StorageImpl <span class="hl opt">*</span> mStorage<span class="hl opt">;</span></pre>
350
351 <p>We could declare the <tt>Internal::StorageImpl</tt> class before the <tt>Module</tt> class, but as I like starting with more
352 generic (public) classes and then go into the details, we add a forward declaration to the beginning of the file:</p>
353
354 <pre class="hl">
355 <span class="hl kwa">namespace</span> Internal <span class="hl opt">{</span>
356 <span class="hl kwc">class</span> StorageImpl<span class="hl opt">;</span>
357 <span class="hl opt">}</span> <span class="hl slc">// namespace eVaf::PswGen::Storage::Internal</span></pre>
358
359 <p>The declaration of the <tt>StorageImpl</tt> class goes into the <tt>eVaf::PswGen::Storage::Internal</tt> namespace and the class
360 shall be derived both from <tt>QObject</tt> and <tt>iStorage</tt>. However, since we also need to implement the
361 <tt>QAbstractItemModel</tt> data model for the <tt>iStorage::autoCompletionModel()</tt> method, we derive it from the
362 <tt>QAbstractListModel</tt> class instead. We use the <tt>QAbstractListModel</tt> class because it meets our requirements
363 to return a list of auto completion words.</p>
364
365 <pre class="hl">
366 <span class="hl kwa">namespace</span> Internal <span class="hl opt">{</span>
367
368 <span class="hl kwc">class</span> StorageImpl <span class="hl opt">:</span> <span class="hl kwc">public</span> QAbstractListModel<span class="hl opt">,</span> <span class="hl kwc">public</span> iStorage
369 <span class="hl opt">{</span>
370 Q_OBJECT
371 <span class="hl kwd">Q_INTERFACES</span><span class="hl opt">(</span>eVaf<span class="hl opt">::</span>PswGen<span class="hl opt">::</span>iStorage<span class="hl opt">)</span>
372
373 <span class="hl kwc">public</span><span class="hl opt">:</span>
374
375 <span class="hl kwd">StorageImpl</span><span class="hl opt">();</span>
376
377 <span class="hl kwc">virtual</span> <span class="hl opt">~</span><span class="hl kwd">StorageImpl</span><span class="hl opt">();</span>
378
379 <span class="hl opt">};</span>
380
381 <span class="hl opt">}</span> <span class="hl slc">// namespace eVaf::PswGen::Storage::Internal</span></pre>
382
383 <p>First, we implement pure virtual methods found in the <tt>iStorage</tt> interface:</p>
384
385 <pre class="hl">
386 <span class="hl com">/*</span>
387 <span class="hl com">iStorage interface</span>
388 <span class="hl com">*/</span>
389
390 <span class="hl kwc">virtual</span> <span class="hl kwb">bool</span> <span class="hl kwd">save</span><span class="hl opt">(</span>QString <span class="hl kwb">const</span> <span class="hl opt">&amp;</span> name<span class="hl opt">,</span> QExplicitlySharedDataPointer<span class="hl opt">&lt;</span>Storage<span class="hl opt">::</span>Data<span class="hl opt">&gt;</span> data<span class="hl opt">);</span>
391
392 <span class="hl kwc">virtual</span> QExplicitlySharedDataPointer<span class="hl opt">&lt;</span>Storage<span class="hl opt">::</span>Data<span class="hl opt">&gt;</span> <span class="hl kwd">query</span><span class="hl opt">(</span>QString <span class="hl kwb">const</span> <span class="hl opt">&amp;</span> name<span class="hl opt">)</span> <span class="hl kwb">const</span><span class="hl opt">;</span>
393
394 <span class="hl kwc">virtual</span> QAbstractItemModel <span class="hl opt">*</span> <span class="hl kwd">autoCompletionModel</span><span class="hl opt">() {</span> <span class="hl kwa">return this</span><span class="hl opt">; }</span></pre>
395
396 <p>Since the <tt>QAbstractItemModel</tt> data model is implemented by the same class, we can simply return <tt>this</tt> in the
397 <tt>autoCompletionModel()</tt> model.</p>
398
399 <p>The <tt>QAbstractListModel</tt> class also has pure virtual methods that need to be implemented:</p>
400
401 <pre class="hl">
402 <span class="hl com">/*</span>
403 <span class="hl com">QAbstractListModel methods</span>
404 <span class="hl com">*/</span>
405
406 <span class="hl kwc">virtual</span> <span class="hl kwb">int</span> <span class="hl kwd">rowCount</span><span class="hl opt">(</span>QModelIndex <span class="hl kwb">const</span> <span class="hl opt">&amp;</span> parent<span class="hl opt">)</span> <span class="hl kwb">const</span> <span class="hl opt">{</span> <span class="hl kwa">return</span> mData<span class="hl opt">.</span><span class="hl kwd">count</span><span class="hl opt">(); }</span>
407
408 <span class="hl kwc">virtual</span> QVariant <span class="hl kwd">data</span><span class="hl opt">(</span>QModelIndex <span class="hl kwb">const</span> <span class="hl opt">&amp;</span> index<span class="hl opt">,</span> <span class="hl kwb">int</span> role <span class="hl opt">=</span> Qt<span class="hl opt">::</span>DisplayRole<span class="hl opt">)</span> <span class="hl kwb">const</span><span class="hl opt">;</span></pre>
409
410 <p><tt>mData</tt> here is a container with all the stored data objects, which we add to the <tt>private</tt> section. We use
411 a <tt>QMap&lt;QString, QExplicitlySharedDataPointer&lt;Storage::Data&gt; &gt;</tt> for this purpose as it allows fast lookups
412 by the name string.</p>
413
414 <pre class="hl">
415 <span class="hl kwc">private</span><span class="hl opt">:</span>
416
417 QMap<span class="hl opt">&lt;</span>QString<span class="hl opt">,</span> QExplicitlySharedDataPointer<span class="hl opt">&lt;</span>Storage<span class="hl opt">::</span>Data<span class="hl opt">&gt; &gt;</span> mData<span class="hl opt">;</span></pre>
418
419 <p>Permanent data storage is done using a SQLITE database. We add the database object and a methods to load data from the database. We
420 also need a method to create database tables if they do not exist yet:</p>
421
422 <pre class="hl">
423 QSqlDatabase mDb<span class="hl opt">;</span>
424
425 <span class="hl kwb">bool</span> <span class="hl kwd">createTables</span><span class="hl opt">();</span>
426
427 <span class="hl kwb">bool</span> <span class="hl kwd">loadData</span><span class="hl opt">();</span></pre>
428
429 <p>The database object needs names for the connection and for the database, which we can add as constants to the class:</p>
430
431 <pre class="hl">
432 <span class="hl kwb">static char const</span> <span class="hl opt">*</span> <span class="hl kwb">const</span> DbConnectionName<span class="hl opt">;</span>
433
434 <span class="hl kwb">static char const</span> <span class="hl opt">*</span> <span class="hl kwb">const</span> DbName<span class="hl opt">;</span></pre>
435
436 <p>The database needs to be opened and closed, and the list of data objects populated with data from the database. For this purpose
437 we add <tt>init()</tt> and <tt>done()</tt> methods to the public section of the class. The <tt>init()</tt> method can return
438 <tt>false</tt> if the initialization fails.</p>
439
440 <pre class="hl">
441 <span class="hl kwb">bool</span> <span class="hl kwd">init</span><span class="hl opt">();</span>
442
443 <span class="hl kwb">void</span> <span class="hl kwd">done</span><span class="hl opt">();</span></pre>
444
445 <p>This is the final <tt>module.h</tt> file:</p>
446
447 <pre class="hl"><span class="hl com">/**</span>
448 <span class="hl com"> * &#64;file PswGen/Storage/module.h</span>
449 <span class="hl com"> */</span>
450
451 <span class="hl ppc">#ifndef __PSWGEN_STORAGE_MODULE_H</span>
452 <span class="hl ppc"># define __PSWGEN_STORAGE_MODULE_H</span>
453
454 <span class="hl ppc">#include</span> <span class="hl pps">&quot;istorage.h&quot;</span><span class="hl ppc"></span>
455
456 <span class="hl ppc">#include &lt;Plugins/iPlugin&gt;</span>
457
458 <span class="hl ppc">#include &lt;QObject&gt;</span>
459 <span class="hl ppc">#include &lt;QString&gt;</span>
460 <span class="hl ppc">#include &lt;QAbstractListModel&gt;</span>
461 <span class="hl ppc">#include &lt;QMap&gt;</span>
462 <span class="hl ppc">#include &lt;QtSql/QSqlDatabase&gt;</span>
463
464
465 <span class="hl kwa">namespace</span> eVaf <span class="hl opt">{</span>
466 <span class="hl kwa">namespace</span> PswGen <span class="hl opt">{</span>
467
468 <span class="hl slc">/// Module that stores options for strong passwords</span>
469 <span class="hl kwa">namespace</span> Storage <span class="hl opt">{</span>
470
471 <span class="hl slc">/// Internal implementation of the Storage module</span>
472 <span class="hl kwa">namespace</span> Internal <span class="hl opt">{</span>
473 <span class="hl kwc">class</span> StorageImpl<span class="hl opt">;</span>
474 <span class="hl opt">}</span> <span class="hl slc">// namespace eVaf::PswGen::Storage::Internal</span>
475
476 <span class="hl com">/// Module implementing the iStorage interface.</span>
477 <span class="hl kwc">class</span> Module <span class="hl opt">:</span> <span class="hl kwc">public</span> Plugins<span class="hl opt">::</span>iPlugin
478 <span class="hl opt">{</span>
479 Q_OBJECT
480
481 <span class="hl kwc">public</span><span class="hl opt">:</span>
482
483 <span class="hl kwd">Module</span><span class="hl opt">();</span>
484
485 <span class="hl kwc">virtual</span> <span class="hl opt">~</span><span class="hl kwd">Module</span><span class="hl opt">();</span>
486
487 <span class="hl kwc">virtual</span> <span class="hl kwb">bool</span> <span class="hl kwd">init</span><span class="hl opt">(</span>QString <span class="hl kwb">const</span> <span class="hl opt">&amp;</span> args<span class="hl opt">);</span>
488
489 <span class="hl kwc">virtual</span> <span class="hl kwb">void</span> <span class="hl kwd">done</span><span class="hl opt">();</span>
490
491 <span class="hl kwc">virtual</span> <span class="hl kwb">bool</span> <span class="hl kwd">isReady</span><span class="hl opt">()</span> <span class="hl kwb">const</span> <span class="hl opt">{</span> <span class="hl kwa">return</span> mReady<span class="hl opt">; }</span>
492
493
494 <span class="hl kwc">private</span><span class="hl opt">:</span> <span class="hl slc">// Members</span>
495
496 <span class="hl slc">/// Flag indicating that the module is ready</span>
497 <span class="hl kwb">bool</span> mReady<span class="hl opt">;</span>
498
499 <span class="hl slc">/// iStorage interface instance</span>
500 Internal<span class="hl opt">::</span>StorageImpl <span class="hl opt">*</span> mStorage<span class="hl opt">;</span>
501
502 <span class="hl opt">};</span>
503
504 <span class="hl kwa">namespace</span> Internal <span class="hl opt">{</span>
505
506 <span class="hl com">/// iStorage interface implementation.</span>
507 <span class="hl kwc">class</span> StorageImpl <span class="hl opt">:</span> <span class="hl kwc">public</span> QAbstractListModel<span class="hl opt">,</span> <span class="hl kwc">public</span> iStorage
508 <span class="hl opt">{</span>
509 Q_OBJECT
510 <span class="hl kwd">Q_INTERFACES</span><span class="hl opt">(</span>eVaf<span class="hl opt">::</span>PswGen<span class="hl opt">::</span>iStorage<span class="hl opt">)</span>
511
512 <span class="hl kwc">public</span><span class="hl opt">:</span>
513
514 <span class="hl kwd">StorageImpl</span><span class="hl opt">();</span>
515
516 <span class="hl kwc">virtual</span> <span class="hl opt">~</span><span class="hl kwd">StorageImpl</span><span class="hl opt">();</span>
517
518 <span class="hl kwb">bool</span> <span class="hl kwd">init</span><span class="hl opt">();</span>
519
520 <span class="hl kwb">void</span> <span class="hl kwd">done</span><span class="hl opt">();</span>
521
522 <span class="hl com">/*</span>
523 <span class="hl com">iStorage interface</span>
524 <span class="hl com">*/</span>
525
526 <span class="hl kwc">virtual</span> <span class="hl kwb">bool</span> <span class="hl kwd">save</span><span class="hl opt">(</span>QString <span class="hl kwb">const</span> <span class="hl opt">&amp;</span> name<span class="hl opt">,</span> QExplicitlySharedDataPointer<span class="hl opt">&lt;</span>Storage<span class="hl opt">::</span>Data<span class="hl opt">&gt;</span> data<span class="hl opt">);</span>
527
528 <span class="hl kwc">virtual</span> QExplicitlySharedDataPointer<span class="hl opt">&lt;</span>Storage<span class="hl opt">::</span>Data<span class="hl opt">&gt;</span> <span class="hl kwd">query</span><span class="hl opt">(</span>QString <span class="hl kwb">const</span> <span class="hl opt">&amp;</span> name<span class="hl opt">)</span> <span class="hl kwb">const</span><span class="hl opt">;</span>
529
530 <span class="hl kwc">virtual</span> QAbstractItemModel <span class="hl opt">*</span> <span class="hl kwd">autoCompletionModel</span><span class="hl opt">() {</span> <span class="hl kwa">return this</span><span class="hl opt">; }</span>
531
532 <span class="hl com">/*</span>
533 <span class="hl com">QAbstractListModel methods</span>
534 <span class="hl com">*/</span>
535
536 <span class="hl kwc">virtual</span> <span class="hl kwb">int</span> <span class="hl kwd">rowCount</span><span class="hl opt">(</span>QModelIndex <span class="hl kwb">const</span> <span class="hl opt">&amp;</span> parent<span class="hl opt">)</span> <span class="hl kwb">const</span> <span class="hl opt">{</span> <span class="hl kwa">return</span> mData<span class="hl opt">.</span><span class="hl kwd">count</span><span class="hl opt">(); }</span>
537
538 <span class="hl kwc">virtual</span> QVariant <span class="hl kwd">data</span><span class="hl opt">(</span>QModelIndex <span class="hl kwb">const</span> <span class="hl opt">&amp;</span> index<span class="hl opt">,</span> <span class="hl kwb">int</span> role <span class="hl opt">=</span> Qt<span class="hl opt">::</span>DisplayRole<span class="hl opt">)</span> <span class="hl kwb">const</span><span class="hl opt">;</span>
539
540 <span class="hl kwc">private</span><span class="hl opt">:</span> <span class="hl slc">// Members</span>
541
542 <span class="hl slc">/// Name of the database connection</span>
543 <span class="hl kwb">static char const</span> <span class="hl opt">*</span> <span class="hl kwb">const</span> DbConnectionName<span class="hl opt">;</span>
544
545 <span class="hl slc">/// Name of the database file without path</span>
546 <span class="hl kwb">static char const</span> <span class="hl opt">*</span> <span class="hl kwb">const</span> DbName<span class="hl opt">;</span>
547
548 <span class="hl slc">/// Database connection</span>
549 QSqlDatabase mDb<span class="hl opt">;</span>
550
551 <span class="hl slc">/// List of name/data pairs</span>
552 QMap<span class="hl opt">&lt;</span>QString<span class="hl opt">,</span> QExplicitlySharedDataPointer<span class="hl opt">&lt;</span>Storage<span class="hl opt">::</span>Data<span class="hl opt">&gt; &gt;</span> mData<span class="hl opt">;</span>
553
554
555 <span class="hl kwc">private</span><span class="hl opt">:</span> <span class="hl slc">// Methods</span>
556
557 <span class="hl com">/// Creates database tables if necessary</span>
558 <span class="hl kwb">bool</span> <span class="hl kwd">createTables</span><span class="hl opt">();</span>
559
560 <span class="hl com">/// Loads data from the database</span>
561 <span class="hl kwb">bool</span> <span class="hl kwd">loadData</span><span class="hl opt">();</span>
562
563 <span class="hl opt">};</span>
564
565 <span class="hl opt">}</span> <span class="hl slc">// namespace eVaf::PswGen::Storage::Internal</span>
566 <span class="hl opt">}</span> <span class="hl slc">// namespace eVaf::PswGen::Storage</span>
567 <span class="hl opt">}</span> <span class="hl slc">// namespace eVaf::PswGen</span>
568 <span class="hl opt">}</span> <span class="hl slc">// namespace eVaf</span>
569
570 <span class="hl ppc">#endif</span> <span class="hl slc">// module.h</span><span class="hl ppc"></span></pre>
571
572 <p>Continue implementing the <a href="pswgen07.html">Storage Module</a>.</p>
573
574 </body>
575 </html>