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">
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" />
16 <h1>eVaf Tutorial
</h1>
18 <h2>06 - Storage Module
</h2>
20 <p>In this section we start implementing the Storage module. The storage module stores non-sensitive data required to re-generate
21 passwords. We use a simple SQLITE database in this module, but nothing prevents us replacing it with a more complex storage
22 module in the future.
</p>
24 <h3>iStorage interface
</h3>
26 <p>Once again, we start by defining the interface for the module and create the file
<tt>istorage.h
</tt> in the
27 <tt>src/apps/PswGen/Storage
</tt> directory:
</p>
29 <pre class=
"hl"><span class=
"hl com">/**
</span>
30 <span class=
"hl com"> *
@file PswGen/Storage/istorage.h
</span>
31 <span class=
"hl com"> */
</span>
33 <span class=
"hl ppc">#ifndef __PSWGEN_STORAGE_ISTORAGE_H
</span>
34 <span class=
"hl ppc"># define __PSWGEN_STORAGE_ISTORAGE_H
</span>
35 <span class=
"hl ppc">#endif
</span> <span class=
"hl slc">// istorage.h
</span></pre>
37 <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
38 include headers for
<tt>QSharedData
</tt> and
<tt>QExplicitlySharedDataPointer
</tt>. We need a container for the data that
39 we store and making it shared data object with the benefit of automatic reference counting and memory management makes sense.
</p>
41 <pre class=
"hl"><span class=
"hl ppc">#include
<QObject
></span>
42 <span class=
"hl ppc">#include
<QString
></span>
43 <span class=
"hl ppc">#include
<QSharedData
></span>
44 <span class=
"hl ppc">#include
<QExplicitlySharedDataPointer
></span></pre>
46 <p>Use the
<tt>eVaf::PswGen
</tt> namespace:
</p>
48 <pre class=
"hl"><span class=
"hl kwa">namespace
</span> eVaf
<span class=
"hl opt">{
</span>
49 <span class=
"hl kwa">namespace
</span> PswGen
<span class=
"hl opt">{
</span>
51 <span class=
"hl opt">}
</span> <span class=
"hl slc">// namespace eVaf::PswGen
</span>
52 <span class=
"hl opt">}
</span> <span class=
"hl slc">// namespace eVaf
</span></pre>
54 <p>The container class for stored data has the following attributes:
</p>
56 <li>Name -- Name of the generated password
</li>
57 <li>Length -- Length of the password
</li>
58 <li>Options -- Additional parameters for the password generator
</li>
61 <p>The container class belongs to the Storage module and we use the
<tt>eVaf::PswGen::Storage
</tt> namespace for it:
</p>
63 <pre class=
"hl"><span class=
"hl kwa">namespace
</span> Storage
<span class=
"hl opt">{
</span>
65 <span class=
"hl kwc">class
</span> Data
<span class=
"hl opt">:
</span> <span class=
"hl kwc">public
</span> QSharedData
66 <span class=
"hl opt">{
</span>
67 <span class=
"hl kwc">private
</span><span class=
"hl opt">:
</span>
69 <span class=
"hl kwb">bool
</span> mModified
<span class=
"hl opt">;
</span>
70 QString mName
<span class=
"hl opt">;
</span>
71 <span class=
"hl kwb">int
</span> mLength
<span class=
"hl opt">;
</span>
72 uint mFlags
<span class=
"hl opt">;
</span>
74 <span class=
"hl opt">};
</span>
76 <span class=
"hl opt">}
</span> <span class=
"hl slc">// eVaf::PswGen::Storage
</span></pre>
78 <p>The extra attribute -
<tt>mModified
</tt> - is used to detect unsaved modifications in the data object.
</p>
80 <p>Add constructors for the shared data class. Creating a data object without name makes no sense and we include the
81 name attribute in all our constructors:
</p>
83 <pre class=
"hl"><span class=
"hl kwc">public
</span><span class=
"hl opt">:
</span>
85 <span class=
"hl kwd">Data
</span><span class=
"hl opt">(
</span>QString
<span class=
"hl kwb">const
</span> <span class=
"hl opt">&</span> name
<span class=
"hl opt">)
</span>
86 <span class=
"hl opt">:
</span> <span class=
"hl kwd">QSharedData
</span><span class=
"hl opt">()
</span>
87 <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>
88 <span class=
"hl opt">,
</span> <span class=
"hl kwd">mName
</span><span class=
"hl opt">(
</span>name
<span class=
"hl opt">)
</span>
89 <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>
90 <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>
91 <span class=
"hl opt">{}
</span>
93 <span class=
"hl kwd">Data
</span><span class=
"hl opt">(
</span>QString
<span class=
"hl kwb">const
</span> <span class=
"hl opt">&</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>
94 <span class=
"hl opt">:
</span> <span class=
"hl kwd">QSharedData
</span><span class=
"hl opt">()
</span>
95 <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>
96 <span class=
"hl opt">,
</span> <span class=
"hl kwd">mName
</span><span class=
"hl opt">(
</span>name
<span class=
"hl opt">)
</span>
97 <span class=
"hl opt">,
</span> <span class=
"hl kwd">mLength
</span><span class=
"hl opt">(
</span>l
<span class=
"hl opt">)
</span>
98 <span class=
"hl opt">,
</span> <span class=
"hl kwd">mFlags
</span><span class=
"hl opt">(
</span>f
<span class=
"hl opt">)
</span>
99 <span class=
"hl opt">{}
</span></pre>
101 <p>Fianlly, we add getter and setter methods:
</p>
104 QString
<span class=
"hl kwb">const
</span> <span class=
"hl opt">&</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>
106 <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>
107 <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>
108 <span class=
"hl opt">{
</span>
109 <span class=
"hl kwa">if
</span> <span class=
"hl opt">(
</span>mLength
<span class=
"hl opt">!=
</span> value
<span class=
"hl opt">) {
</span>
110 mLength
<span class=
"hl opt">=
</span> value
<span class=
"hl opt">;
</span>
111 mModified
<span class=
"hl opt">=
</span> <span class=
"hl kwa">true
</span><span class=
"hl opt">;
</span>
112 <span class=
"hl opt">}
</span>
113 <span class=
"hl opt">}
</span>
115 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>
116 <span class=
"hl kwb">void
</span> <span class=
"hl kwd">setFlags
</span><span class=
"hl opt">(
</span>uint value
<span class=
"hl opt">)
</span>
117 <span class=
"hl opt">{
</span>
118 <span class=
"hl kwa">if
</span> <span class=
"hl opt">(
</span>mFlags
<span class=
"hl opt">!=
</span> value
<span class=
"hl opt">) {
</span>
119 mFlags
<span class=
"hl opt">=
</span> value
<span class=
"hl opt">;
</span>
120 mModified
<span class=
"hl opt">=
</span> <span class=
"hl kwa">true
</span><span class=
"hl opt">;
</span>
121 <span class=
"hl opt">}
</span>
122 <span class=
"hl opt">}
</span>
124 <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>
126 <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>
128 <p>The
<tt>reset()
</tt> method resets the
<tt>modified
</tt> attribute.
</p>
130 <p>Continue with the
<tt>iStorage
</tt> interface:
</tt>
132 <pre class=
"hl"><span class=
"hl kwb">struct
</span> iStorage
133 <span class=
"hl opt">{
</span>
135 <span class=
"hl opt">};
</span></pre>
137 <p>According to the specification, we need functions to store and query data:
</p>
140 <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">&</span> name
<span class=
"hl opt">,
</span> QExplicitlySharedDataPointer
<span class=
"hl opt"><</span>Storage
<span class=
"hl opt">::
</span>Data
<span class=
"hl opt">></span> data
<span class=
"hl opt">) =
</span> <span class=
"hl num">0</span><span class=
"hl opt">;
</span>
142 <span class=
"hl kwc">virtual
</span> QExplicitlySharedDataPointer
<span class=
"hl opt"><</span>Storage
<span class=
"hl opt">::
</span>Data
<span class=
"hl opt">></span> <span class=
"hl kwd">query
</span><span class=
"hl opt">(
</span>QString
<span class=
"hl kwb">const
</span> <span class=
"hl opt">&</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>
144 <p>The
<tt>query()
</tt> method returns an explicitly shared shared data pointer, which has the following advantages:
</p>
146 <li>The same data object is shared between multiple modules and if a module changes attributes in the data object, these
147 changes are immediately seen by any other modules;
</li>
148 <li>No need to worry about ownership -- the shared data object is deleted when the last module stops using it;
</li>
149 <li>The
<tt>query()
</tt> method can return an empty shared data pointer to indicate that no data objects with the
150 given name exist.
</tt>
153 <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>
155 <p>The specification also mentions partial matches where entering "fa" would offer "facebook.com" if it exists. This could be done by
156 using the
<tt>QCompleter
</tt> class that provides auto completion in Qt widgets like
<tt>QLineEdit
</tt> and
<tt>QComboBox
</tt>. The
157 <tt>QCompleter
<tt> class needs a
<tt>QAbstractItemModel
</tt> for the auto completion word list and we can provide it
158 from our
<tt>Storage
</tt> module:
</tt>
161 <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>
163 <p><tt>QAbstractItemModel
</tt> is not known at this moment and we need to add a forward class declaration to the beginning of the
164 <tt>istorage.h
</tt> file:
</p>
167 <span class=
"hl kwc">class
</span> QAbstractItemModel
<span class=
"hl opt">;
</span></pre>
169 <p>At the the end of the
<tt>istorage.h
</tt> file, we declare the
<tt>iStorage
</tt> interface:
</p>
171 <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">"eVaf.PswGen.iStorage/
1.0"</span><span class=
"hl opt">)
</span></pre>
173 <p>This is the complete
<tt>istorage.h
</tt> file:
</p>
175 <pre class=
"hl"><span class=
"hl com">/**
</span>
176 <span class=
"hl com"> *
@file PswGen/Storage/istorage.h
</span>
177 <span class=
"hl com"> */
</span>
179 <span class=
"hl ppc">#ifndef __PSWGEN_STORAGE_ISTORAGE_H
</span>
180 <span class=
"hl ppc"># define __PSWGEN_STORAGE_ISTORAGE_H
</span>
182 <span class=
"hl ppc">#include
<QObject
></span>
183 <span class=
"hl ppc">#include
<QString
></span>
184 <span class=
"hl ppc">#include
<QSharedData
></span>
185 <span class=
"hl ppc">#include
<QExplicitlySharedDataPointer
></span>
187 <span class=
"hl kwc">class
</span> QAbstractItemModel
<span class=
"hl opt">;
</span>
189 <span class=
"hl kwa">namespace
</span> eVaf
<span class=
"hl opt">{
</span>
190 <span class=
"hl kwa">namespace
</span> PswGen
<span class=
"hl opt">{
</span>
192 <span class=
"hl kwa">namespace
</span> Storage
<span class=
"hl opt">{
</span>
194 <span class=
"hl com">/// Data stored for every password.
</span>
195 <span class=
"hl kwc">class
</span> Data
<span class=
"hl opt">:
</span> <span class=
"hl kwc">public
</span> QSharedData
196 <span class=
"hl opt">{
</span>
197 <span class=
"hl kwc">public
</span><span class=
"hl opt">:
</span>
199 <span class=
"hl kwd">Data
</span><span class=
"hl opt">(
</span>QString
<span class=
"hl kwb">const
</span> <span class=
"hl opt">&</span> name
<span class=
"hl opt">)
</span>
200 <span class=
"hl opt">:
</span> <span class=
"hl kwd">QSharedData
</span><span class=
"hl opt">()
</span>
201 <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>
202 <span class=
"hl opt">,
</span> <span class=
"hl kwd">mName
</span><span class=
"hl opt">(
</span>name
<span class=
"hl opt">)
</span>
203 <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>
204 <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>
205 <span class=
"hl opt">{}
</span>
207 <span class=
"hl kwd">Data
</span><span class=
"hl opt">(
</span>QString
<span class=
"hl kwb">const
</span> <span class=
"hl opt">&</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>
208 <span class=
"hl opt">:
</span> <span class=
"hl kwd">QSharedData
</span><span class=
"hl opt">()
</span>
209 <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>
210 <span class=
"hl opt">,
</span> <span class=
"hl kwd">mName
</span><span class=
"hl opt">(
</span>name
<span class=
"hl opt">)
</span>
211 <span class=
"hl opt">,
</span> <span class=
"hl kwd">mLength
</span><span class=
"hl opt">(
</span>l
<span class=
"hl opt">)
</span>
212 <span class=
"hl opt">,
</span> <span class=
"hl kwd">mFlags
</span><span class=
"hl opt">(
</span>f
<span class=
"hl opt">)
</span>
213 <span class=
"hl opt">{}
</span>
215 <span class=
"hl slc">/// Name of the password
</span>
216 QString
<span class=
"hl kwb">const
</span> <span class=
"hl opt">&</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>
218 <span class=
"hl slc">/// Length of the generated password
</span>
219 <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>
220 <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>
221 <span class=
"hl opt">{
</span>
222 <span class=
"hl kwa">if
</span> <span class=
"hl opt">(
</span>mLength
<span class=
"hl opt">!=
</span> value
<span class=
"hl opt">) {
</span>
223 mLength
<span class=
"hl opt">=
</span> value
<span class=
"hl opt">;
</span>
224 mModified
<span class=
"hl opt">=
</span> <span class=
"hl kwa">true
</span><span class=
"hl opt">;
</span>
225 <span class=
"hl opt">}
</span>
226 <span class=
"hl opt">}
</span>
228 <span class=
"hl slc">/// Optional flags for the password generator
</span>
229 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>
230 <span class=
"hl kwb">void
</span> <span class=
"hl kwd">setFlags
</span><span class=
"hl opt">(
</span>uint value
<span class=
"hl opt">)
</span>
231 <span class=
"hl opt">{
</span>
232 <span class=
"hl kwa">if
</span> <span class=
"hl opt">(
</span>mFlags
<span class=
"hl opt">!=
</span> value
<span class=
"hl opt">) {
</span>
233 mFlags
<span class=
"hl opt">=
</span> value
<span class=
"hl opt">;
</span>
234 mModified
<span class=
"hl opt">=
</span> <span class=
"hl kwa">true
</span><span class=
"hl opt">;
</span>
235 <span class=
"hl opt">}
</span>
236 <span class=
"hl opt">}
</span>
238 <span class=
"hl slc">/// Flag indicating that some fields are modified
</span>
239 <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>
241 <span class=
"hl slc">/// Resets the modified flag
</span>
242 <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>
244 <span class=
"hl kwc">private
</span><span class=
"hl opt">:
</span>
246 <span class=
"hl kwb">bool
</span> mModified
<span class=
"hl opt">;
</span>
247 QString mName
<span class=
"hl opt">;
</span>
248 <span class=
"hl kwb">int
</span> mLength
<span class=
"hl opt">;
</span>
249 uint mFlags
<span class=
"hl opt">;
</span>
251 <span class=
"hl opt">};
</span>
253 <span class=
"hl opt">}
</span> <span class=
"hl slc">// eVaf::PswGen::Storage
</span>
255 <span class=
"hl com">/// Password storage interface.
</span>
256 <span class=
"hl kwb">struct
</span> iStorage
257 <span class=
"hl opt">{
</span>
259 <span class=
"hl com">/// Saves the data record
</span>
260 <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">&</span> name
<span class=
"hl opt">,
</span> QExplicitlySharedDataPointer
<span class=
"hl opt"><</span>Storage
<span class=
"hl opt">::
</span>Data
<span class=
"hl opt">></span> data
<span class=
"hl opt">) =
</span> <span class=
"hl num">0</span><span class=
"hl opt">;
</span>
262 <span class=
"hl com">/// Returns a data record by the name
</span>
263 <span class=
"hl kwc">virtual
</span> QExplicitlySharedDataPointer
<span class=
"hl opt"><</span>Storage
<span class=
"hl opt">::
</span>Data
<span class=
"hl opt">></span> <span class=
"hl kwd">query
</span><span class=
"hl opt">(
</span>QString
<span class=
"hl kwb">const
</span> <span class=
"hl opt">&</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>
265 <span class=
"hl com">/// Returns an item model with the names of all the stored passwords
</span>
266 <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>
268 <span class=
"hl opt">};
</span>
270 <span class=
"hl opt">}
</span> <span class=
"hl slc">// namespace eVaf::PswGen
</span>
271 <span class=
"hl opt">}
</span> <span class=
"hl slc">// namespace eVaf
</span>
273 <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">"eVaf.PswGen.iStorage/
1.0"</span><span class=
"hl opt">)
</span>
275 <span class=
"hl ppc">#endif
</span> <span class=
"hl slc">// istorage.h
</span><span class=
"hl ppc"></span></pre>
277 <p>We also create the
<tt>iStorage
</tt> file so that we can use
<tt>#include
<Storage/iStorage
></tt> in our other modules:
</tt>
279 <pre class=
"hl"><span class=
"hl ppc">#include
</span><span class=
"hl pps">"istorage.h
"</span></pre>
281 <h3>Storage module
</h3>
283 <p>The
<tt>Storage
<tt> module is simple enough to be derived directly from the
<tt>Plugins::iPlugin
</tt> interface and needs only one
284 header/source file. In general, I personally prefer short source files and follow the
<i>one-class-per-file
</i> rule. Only when classes
285 are very simple and closely related I put the into the same source file.
</p>
287 <p>Create the
<tt>module.h
</tt> header file in the
<tt>src/apps/PswGen/Storage
</tt> directory. Include
<tt>istorage.h
</tt> and
288 <tt>Plugins/iPlugin
</tt> header files. We use the
<tt>eVaf::PswGen::Storage
</tt> namespace for public classes and
289 <tt>eVaf::PswGen::Storage::Internal
<tt> namespace for private classes.
</p>
291 <pre class=
"hl"><span class=
"hl ppc">#ifndef __PSWGEN_STORAGE_MODULE_H
</span>
292 <span class=
"hl ppc"># define __PSWGEN_STORAGE_MODULE_H
</span>
294 <span class=
"hl ppc">#include
</span> <span class=
"hl pps">"istorage.h
"</span><span class=
"hl ppc"></span>
295 <span class=
"hl ppc">#include
<Plugins/iPlugin
></span>
297 <span class=
"hl kwa">namespace
</span> eVaf
<span class=
"hl opt">{
</span>
298 <span class=
"hl kwa">namespace
</span> PswGen
<span class=
"hl opt">{
</span>
300 <span class=
"hl slc">/// Module that stores options for strong passwords
</span>
301 <span class=
"hl kwa">namespace
</span> Storage
<span class=
"hl opt">{
</span>
303 <span class=
"hl slc">/// Internal implementation of the Storage module
</span>
304 <span class=
"hl kwa">namespace
</span> Internal
<span class=
"hl opt">{
</span>
306 <span class=
"hl opt">}
</span> <span class=
"hl slc">// namespace eVaf::PswGen::Storage::Internal
</span>
307 <span class=
"hl opt">}
</span> <span class=
"hl slc">// namespace eVaf::PswGen::Storage
</span>
308 <span class=
"hl opt">}
</span> <span class=
"hl slc">// namespace eVaf::PswGen
</span>
309 <span class=
"hl opt">}
</span> <span class=
"hl slc">// namespace eVaf
</span>
310 <span class=
"hl ppc">#endif
</span> <span class=
"hl slc">// module.h
</span><span class=
"hl ppc"></span></pre>
312 <p>We use the same name
<tt>Module
</tt> for the class that implements the module. This class is public and goes to the
313 <tt>eVaf::PswGen::Storage
</tt> namespace:
</p>
315 <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
316 <span class=
"hl opt">{
</span>
319 <span class=
"hl kwc">public
</span><span class=
"hl opt">:
</span>
321 <span class=
"hl kwd">Module
</span><span class=
"hl opt">();
</span>
323 <span class=
"hl kwc">virtual
</span> <span class=
"hl opt">~
</span><span class=
"hl kwd">Module
</span><span class=
"hl opt">();
</span>
325 <span class=
"hl opt">};
</span></pre>
327 <p>Implement pure virtual methods in the
<tt>iPlugin
</tt> interface:
</p>
330 <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">&</span> args
<span class=
"hl opt">);
</span>
332 <span class=
"hl kwc">virtual
</span> <span class=
"hl kwb">void
</span> <span class=
"hl kwd">done
</span><span class=
"hl opt">();
</span>
334 <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>
336 <p>This module needs more complex initialization that the
<tt>Generator
</tt> module and we use the
<tt>mReady
</tt> flag to
337 indicate that the module is fully initialized:
</p>
340 <span class=
"hl kwc">private
</span><span class=
"hl opt">:
</span>
342 <span class=
"hl kwb">bool
</span> mReady
<span class=
"hl opt">;
</span></pre>
344 <p>The
<tt>StorageImpl
</tt> class is the internal implementation of the
<tt>iStorage
</tt> interface:
</p>
347 Internal
<span class=
"hl opt">::
</span>StorageImpl
<span class=
"hl opt">*
</span> mStorage
<span class=
"hl opt">;
</span></pre>
349 <p>We could declare the
<tt>Internal::StorageImpl
</tt> class before the
<tt>Module
</tt> class, but as I like starting with more
350 generic (public) classes and then go into the details, we add a forward declaration to the beginning of the file:
</p>
353 <span class=
"hl kwa">namespace
</span> Internal
<span class=
"hl opt">{
</span>
354 <span class=
"hl kwc">class
</span> StorageImpl
<span class=
"hl opt">;
</span>
355 <span class=
"hl opt">}
</span> <span class=
"hl slc">// namespace eVaf::PswGen::Storage::Internal
</span></pre>
357 <p>The declaration of the
<tt>StorageImpl
</tt> class goes into the
<tt>eVaf::PswGen::Storage::Internal
</tt> namespace and the class
358 shall be derived both from
<tt>QObject
</tt> and
<tt>iStorage
</tt>. However, since we also need to implement the
359 <tt>QAbstractItemModel
</tt> data model for the
<tt>iStorage::autoCompletionModel()
</tt> method, we derive it from the
360 <tt>QAbstractListModel
</tt> class instead. We use the
<tt>QAbstractListModel
</tt> class because it meets our requirements
361 to return a list of auto completion words.
</p>
364 <span class=
"hl kwa">namespace
</span> Internal
<span class=
"hl opt">{
</span>
366 <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
367 <span class=
"hl opt">{
</span>
369 <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>
371 <span class=
"hl kwc">public
</span><span class=
"hl opt">:
</span>
373 <span class=
"hl kwd">StorageImpl
</span><span class=
"hl opt">();
</span>
375 <span class=
"hl kwc">virtual
</span> <span class=
"hl opt">~
</span><span class=
"hl kwd">StorageImpl
</span><span class=
"hl opt">();
</span>
377 <span class=
"hl opt">};
</span>
379 <span class=
"hl opt">}
</span> <span class=
"hl slc">// namespace eVaf::PswGen::Storage::Internal
</span></pre>
381 <p>First, we implement pure virtual methods found in the
<tt>iStorage
</tt> interface:
</p>
384 <span class=
"hl com">/*
</span>
385 <span class=
"hl com">iStorage interface
</span>
386 <span class=
"hl com">*/
</span>
388 <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">&</span> name
<span class=
"hl opt">,
</span> QExplicitlySharedDataPointer
<span class=
"hl opt"><</span>Storage
<span class=
"hl opt">::
</span>Data
<span class=
"hl opt">></span> data
<span class=
"hl opt">);
</span>
390 <span class=
"hl kwc">virtual
</span> QExplicitlySharedDataPointer
<span class=
"hl opt"><</span>Storage
<span class=
"hl opt">::
</span>Data
<span class=
"hl opt">></span> <span class=
"hl kwd">query
</span><span class=
"hl opt">(
</span>QString
<span class=
"hl kwb">const
</span> <span class=
"hl opt">&</span> name
<span class=
"hl opt">)
</span> <span class=
"hl kwb">const
</span><span class=
"hl opt">;
</span>
392 <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>
394 <p>Since the
<tt>QAbstractItemModel
</tt> data model is implemented by the same class, we can simply return
<tt>this
</tt> in the
395 <tt>autoCompletionModel()
</tt> model.
</p>
397 <p>The
<tt>QAbstractListModel
</tt> class also has pure virtual methods that need to be implemented:
</p>
400 <span class=
"hl com">/*
</span>
401 <span class=
"hl com">QAbstractListModel methods
</span>
402 <span class=
"hl com">*/
</span>
404 <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">&</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>
406 <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">&</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>
408 <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
409 a
<tt>QMap
<QString, QExplicitlySharedDataPointer
<Storage::Data
> ></tt> for this purpose as it allows fast lookups
410 by the name string.
</p>
413 <span class=
"hl kwc">private
</span><span class=
"hl opt">:
</span>
415 QMap
<span class=
"hl opt"><</span>QString
<span class=
"hl opt">,
</span> QExplicitlySharedDataPointer
<span class=
"hl opt"><</span>Storage
<span class=
"hl opt">::
</span>Data
<span class=
"hl opt">> ></span> mData
<span class=
"hl opt">;
</span></pre>
417 <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
418 also need a method to create database tables if they do not exist yet:
</p>
421 QSqlDatabase mDb
<span class=
"hl opt">;
</span>
423 <span class=
"hl kwb">bool
</span> <span class=
"hl kwd">createTables
</span><span class=
"hl opt">();
</span>
425 <span class=
"hl kwb">bool
</span> <span class=
"hl kwd">loadData
</span><span class=
"hl opt">();
</span></pre>
427 <p>The database object needs names for the connection and for the database, which we can add as constants to the class:
</p>
430 <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>
432 <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>
434 <p>The database needs to be opened and closed, and the list of data objects populated with data from the database. For this purpose
435 we add
<tt>init()
</tt> and
<tt>done()
</tt> methods to the public section of the class. The
<tt>init()
</tt> method can return
436 <tt>false
</tt> if the initialization fails.
</p>
439 <span class=
"hl kwb">bool
</span> <span class=
"hl kwd">init
</span><span class=
"hl opt">();
</span>
441 <span class=
"hl kwb">void
</span> <span class=
"hl kwd">done
</span><span class=
"hl opt">();
</span></pre>
443 <p>This is the final
<tt>module.h
</tt> file:
</p>
445 <pre class=
"hl"><span class=
"hl com">/**
</span>
446 <span class=
"hl com"> *
@file PswGen/Storage/module.h
</span>
447 <span class=
"hl com"> */
</span>
449 <span class=
"hl ppc">#ifndef __PSWGEN_STORAGE_MODULE_H
</span>
450 <span class=
"hl ppc"># define __PSWGEN_STORAGE_MODULE_H
</span>
452 <span class=
"hl ppc">#include
</span> <span class=
"hl pps">"istorage.h
"</span><span class=
"hl ppc"></span>
454 <span class=
"hl ppc">#include
<Plugins/iPlugin
></span>
456 <span class=
"hl ppc">#include
<QObject
></span>
457 <span class=
"hl ppc">#include
<QString
></span>
458 <span class=
"hl ppc">#include
<QAbstractListModel
></span>
459 <span class=
"hl ppc">#include
<QMap
></span>
460 <span class=
"hl ppc">#include
<QtSql/QSqlDatabase
></span>
463 <span class=
"hl kwa">namespace
</span> eVaf
<span class=
"hl opt">{
</span>
464 <span class=
"hl kwa">namespace
</span> PswGen
<span class=
"hl opt">{
</span>
466 <span class=
"hl slc">/// Module that stores options for strong passwords
</span>
467 <span class=
"hl kwa">namespace
</span> Storage
<span class=
"hl opt">{
</span>
469 <span class=
"hl slc">/// Internal implementation of the Storage module
</span>
470 <span class=
"hl kwa">namespace
</span> Internal
<span class=
"hl opt">{
</span>
471 <span class=
"hl kwc">class
</span> StorageImpl
<span class=
"hl opt">;
</span>
472 <span class=
"hl opt">}
</span> <span class=
"hl slc">// namespace eVaf::PswGen::Storage::Internal
</span>
474 <span class=
"hl com">/// Module implementing the iStorage interface.
</span>
475 <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
476 <span class=
"hl opt">{
</span>
479 <span class=
"hl kwc">public
</span><span class=
"hl opt">:
</span>
481 <span class=
"hl kwd">Module
</span><span class=
"hl opt">();
</span>
483 <span class=
"hl kwc">virtual
</span> <span class=
"hl opt">~
</span><span class=
"hl kwd">Module
</span><span class=
"hl opt">();
</span>
485 <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">&</span> args
<span class=
"hl opt">);
</span>
487 <span class=
"hl kwc">virtual
</span> <span class=
"hl kwb">void
</span> <span class=
"hl kwd">done
</span><span class=
"hl opt">();
</span>
489 <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 <span class=
"hl kwc">private
</span><span class=
"hl opt">:
</span> <span class=
"hl slc">// Members
</span>
494 <span class=
"hl slc">/// Flag indicating that the module is ready
</span>
495 <span class=
"hl kwb">bool
</span> mReady
<span class=
"hl opt">;
</span>
497 <span class=
"hl slc">/// iStorage interface instance
</span>
498 Internal
<span class=
"hl opt">::
</span>StorageImpl
<span class=
"hl opt">*
</span> mStorage
<span class=
"hl opt">;
</span>
500 <span class=
"hl opt">};
</span>
502 <span class=
"hl kwa">namespace
</span> Internal
<span class=
"hl opt">{
</span>
504 <span class=
"hl com">/// iStorage interface implementation.
</span>
505 <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
506 <span class=
"hl opt">{
</span>
508 <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>
510 <span class=
"hl kwc">public
</span><span class=
"hl opt">:
</span>
512 <span class=
"hl kwd">StorageImpl
</span><span class=
"hl opt">();
</span>
514 <span class=
"hl kwc">virtual
</span> <span class=
"hl opt">~
</span><span class=
"hl kwd">StorageImpl
</span><span class=
"hl opt">();
</span>
516 <span class=
"hl kwb">bool
</span> <span class=
"hl kwd">init
</span><span class=
"hl opt">();
</span>
518 <span class=
"hl kwb">void
</span> <span class=
"hl kwd">done
</span><span class=
"hl opt">();
</span>
520 <span class=
"hl com">/*
</span>
521 <span class=
"hl com">iStorage interface
</span>
522 <span class=
"hl com">*/
</span>
524 <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">&</span> name
<span class=
"hl opt">,
</span> QExplicitlySharedDataPointer
<span class=
"hl opt"><</span>Storage
<span class=
"hl opt">::
</span>Data
<span class=
"hl opt">></span> data
<span class=
"hl opt">);
</span>
526 <span class=
"hl kwc">virtual
</span> QExplicitlySharedDataPointer
<span class=
"hl opt"><</span>Storage
<span class=
"hl opt">::
</span>Data
<span class=
"hl opt">></span> <span class=
"hl kwd">query
</span><span class=
"hl opt">(
</span>QString
<span class=
"hl kwb">const
</span> <span class=
"hl opt">&</span> name
<span class=
"hl opt">)
</span> <span class=
"hl kwb">const
</span><span class=
"hl opt">;
</span>
528 <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>
530 <span class=
"hl com">/*
</span>
531 <span class=
"hl com">QAbstractListModel methods
</span>
532 <span class=
"hl com">*/
</span>
534 <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">&</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>
536 <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">&</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>
538 <span class=
"hl kwc">private
</span><span class=
"hl opt">:
</span> <span class=
"hl slc">// Members
</span>
540 <span class=
"hl slc">/// Name of the database connection
</span>
541 <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>
543 <span class=
"hl slc">/// Name of the database file without path
</span>
544 <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>
546 <span class=
"hl slc">/// Database connection
</span>
547 QSqlDatabase mDb
<span class=
"hl opt">;
</span>
549 <span class=
"hl slc">/// List of name/data pairs
</span>
550 QMap
<span class=
"hl opt"><</span>QString
<span class=
"hl opt">,
</span> QExplicitlySharedDataPointer
<span class=
"hl opt"><</span>Storage
<span class=
"hl opt">::
</span>Data
<span class=
"hl opt">> ></span> mData
<span class=
"hl opt">;
</span>
553 <span class=
"hl kwc">private
</span><span class=
"hl opt">:
</span> <span class=
"hl slc">// Methods
</span>
555 <span class=
"hl com">/// Creates database tables if necessary
</span>
556 <span class=
"hl kwb">bool
</span> <span class=
"hl kwd">createTables
</span><span class=
"hl opt">();
</span>
558 <span class=
"hl com">/// Loads data from the database
</span>
559 <span class=
"hl kwb">bool
</span> <span class=
"hl kwd">loadData
</span><span class=
"hl opt">();
</span>
561 <span class=
"hl opt">};
</span>
563 <span class=
"hl opt">}
</span> <span class=
"hl slc">// namespace eVaf::PswGen::Storage::Internal
</span>
564 <span class=
"hl opt">}
</span> <span class=
"hl slc">// namespace eVaf::PswGen::Storage
</span>
565 <span class=
"hl opt">}
</span> <span class=
"hl slc">// namespace eVaf::PswGen
</span>
566 <span class=
"hl opt">}
</span> <span class=
"hl slc">// namespace eVaf
</span>
568 <span class=
"hl ppc">#endif
</span> <span class=
"hl slc">// module.h
</span><span class=
"hl ppc"></span></pre>
570 <p>Continue implementing the
<a href=
"pswgen07.html">Storage Module
</a>.
</p>