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 <p>Next:
<a href=
"pswgen07.html">07 - Storage Module
</a>, Previous:
<a href=
"pswgen05.html">05 - Building Generator Module
</a></p>
18 <h1>eVaf Tutorial
</h1>
20 <h2>06 - Storage Module
</h2>
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>
26 <h3>iStorage interface
</h3>
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>
31 <pre class=
"hl"><span class=
"hl com">/**
</span>
32 <span class=
"hl com"> *
@file PswGen/Storage/istorage.h
</span>
33 <span class=
"hl com"> */
</span>
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>
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>
43 <pre class=
"hl"><span class=
"hl ppc">#include
<QObject
></span>
44 <span class=
"hl ppc">#include
<QString
></span>
45 <span class=
"hl ppc">#include
<QSharedData
></span>
46 <span class=
"hl ppc">#include
<QExplicitlySharedDataPointer
></span></pre>
48 <p>Use the
<tt>eVaf::PswGen
</tt> namespace:
</p>
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>
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>
56 <p>The container class for stored data has the following attributes:
</p>
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>
63 <p>The container class belongs to the Storage module and we use the
<tt>eVaf::PswGen::Storage
</tt> namespace for it:
</p>
65 <pre class=
"hl"><span class=
"hl kwa">namespace
</span> Storage
<span class=
"hl opt">{
</span>
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>
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>
76 <span class=
"hl opt">};
</span>
78 <span class=
"hl opt">}
</span> <span class=
"hl slc">// eVaf::PswGen::Storage
</span></pre>
80 <p>The extra attribute -
<tt>mModified
</tt> - is used to detect unsaved modifications in the data object.
</p>
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>
85 <pre class=
"hl"><span class=
"hl kwc">public
</span><span class=
"hl opt">:
</span>
87 <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>
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>
95 <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>
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>
103 <p>Fianlly, we add getter and setter methods:
</p>
106 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>
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>
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>
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>
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>
130 <p>The
<tt>reset()
</tt> method resets the
<tt>modified
</tt> attribute.
</p>
132 <p>Continue with the
<tt>iStorage
</tt> interface:
</tt>
134 <pre class=
"hl"><span class=
"hl kwb">struct
</span> iStorage
135 <span class=
"hl opt">{
</span>
137 <span class=
"hl opt">};
</span></pre>
139 <p>According to the specification, we need functions to store and query data:
</p>
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">&</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>
144 <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>
146 <p>The
<tt>query()
</tt> method returns an explicitly shared shared data pointer, which has the following advantages:
</p>
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>
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>
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>
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>
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>
169 <span class=
"hl kwc">class
</span> QAbstractItemModel
<span class=
"hl opt">;
</span></pre>
171 <p>At the the end of the
<tt>istorage.h
</tt> file, we declare the
<tt>iStorage
</tt> interface:
</p>
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">"eVaf.PswGen.iStorage/
1.0"</span><span class=
"hl opt">)
</span></pre>
175 <p>This is the complete
<tt>istorage.h
</tt> file:
</p>
177 <pre class=
"hl"><span class=
"hl com">/**
</span>
178 <span class=
"hl com"> *
@file PswGen/Storage/istorage.h
</span>
179 <span class=
"hl com"> */
</span>
181 <span class=
"hl ppc">#ifndef __PSWGEN_STORAGE_ISTORAGE_H
</span>
182 <span class=
"hl ppc"># define __PSWGEN_STORAGE_ISTORAGE_H
</span>
184 <span class=
"hl ppc">#include
<QObject
></span>
185 <span class=
"hl ppc">#include
<QString
></span>
186 <span class=
"hl ppc">#include
<QSharedData
></span>
187 <span class=
"hl ppc">#include
<QExplicitlySharedDataPointer
></span>
189 <span class=
"hl kwc">class
</span> QAbstractItemModel
<span class=
"hl opt">;
</span>
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>
194 <span class=
"hl kwa">namespace
</span> Storage
<span class=
"hl opt">{
</span>
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>
201 <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>
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>
209 <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>
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>
217 <span class=
"hl slc">/// Name of the password
</span>
218 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>
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>
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>
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>
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>
246 <span class=
"hl kwc">private
</span><span class=
"hl opt">:
</span>
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>
253 <span class=
"hl opt">};
</span>
255 <span class=
"hl opt">}
</span> <span class=
"hl slc">// eVaf::PswGen::Storage
</span>
257 <span class=
"hl com">/// Password storage interface.
</span>
258 <span class=
"hl kwb">struct
</span> iStorage
259 <span class=
"hl opt">{
</span>
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">&</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>
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"><</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>
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>
270 <span class=
"hl opt">};
</span>
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>
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">"eVaf.PswGen.iStorage/
1.0"</span><span class=
"hl opt">)
</span>
277 <span class=
"hl ppc">#endif
</span> <span class=
"hl slc">// istorage.h
</span><span class=
"hl ppc"></span></pre>
279 <p>We also create the
<tt>iStorage
</tt> file so that we can use
<tt>#include
<Storage/iStorage
></tt> in our other modules:
</tt>
281 <pre class=
"hl"><span class=
"hl ppc">#include
</span><span class=
"hl pps">"istorage.h
"</span></pre>
283 <h3>Storage module
</h3>
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>
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>
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>
296 <span class=
"hl ppc">#include
</span> <span class=
"hl pps">"istorage.h
"</span><span class=
"hl ppc"></span>
297 <span class=
"hl ppc">#include
<Plugins/iPlugin
></span>
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>
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>
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>
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>
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>
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>
321 <span class=
"hl kwc">public
</span><span class=
"hl opt">:
</span>
323 <span class=
"hl kwd">Module
</span><span class=
"hl opt">();
</span>
325 <span class=
"hl kwc">virtual
</span> <span class=
"hl opt">~
</span><span class=
"hl kwd">Module
</span><span class=
"hl opt">();
</span>
327 <span class=
"hl opt">};
</span></pre>
329 <p>Implement pure virtual methods in the
<tt>iPlugin
</tt> interface:
</p>
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">&</span> args
<span class=
"hl opt">);
</span>
334 <span class=
"hl kwc">virtual
</span> <span class=
"hl kwb">void
</span> <span class=
"hl kwd">done
</span><span class=
"hl opt">();
</span>
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>
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>
342 <span class=
"hl kwc">private
</span><span class=
"hl opt">:
</span>
344 <span class=
"hl kwb">bool
</span> mReady
<span class=
"hl opt">;
</span></pre>
346 <p>The
<tt>StorageImpl
</tt> class is the internal implementation of the
<tt>iStorage
</tt> interface:
</p>
349 Internal
<span class=
"hl opt">::
</span>StorageImpl
<span class=
"hl opt">*
</span> mStorage
<span class=
"hl opt">;
</span></pre>
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>
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>
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>
366 <span class=
"hl kwa">namespace
</span> Internal
<span class=
"hl opt">{
</span>
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>
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>
373 <span class=
"hl kwc">public
</span><span class=
"hl opt">:
</span>
375 <span class=
"hl kwd">StorageImpl
</span><span class=
"hl opt">();
</span>
377 <span class=
"hl kwc">virtual
</span> <span class=
"hl opt">~
</span><span class=
"hl kwd">StorageImpl
</span><span class=
"hl opt">();
</span>
379 <span class=
"hl opt">};
</span>
381 <span class=
"hl opt">}
</span> <span class=
"hl slc">// namespace eVaf::PswGen::Storage::Internal
</span></pre>
383 <p>First, we implement pure virtual methods found in the
<tt>iStorage
</tt> interface:
</p>
386 <span class=
"hl com">/*
</span>
387 <span class=
"hl com">iStorage interface
</span>
388 <span class=
"hl com">*/
</span>
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">&</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>
392 <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>
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>
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>
399 <p>The
<tt>QAbstractListModel
</tt> class also has pure virtual methods that need to be implemented:
</p>
402 <span class=
"hl com">/*
</span>
403 <span class=
"hl com">QAbstractListModel methods
</span>
404 <span class=
"hl com">*/
</span>
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">&</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>
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">&</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>
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
<QString, QExplicitlySharedDataPointer
<Storage::Data
> ></tt> for this purpose as it allows fast lookups
412 by the name string.
</p>
415 <span class=
"hl kwc">private
</span><span class=
"hl opt">:
</span>
417 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>
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>
423 QSqlDatabase mDb
<span class=
"hl opt">;
</span>
425 <span class=
"hl kwb">bool
</span> <span class=
"hl kwd">createTables
</span><span class=
"hl opt">();
</span>
427 <span class=
"hl kwb">bool
</span> <span class=
"hl kwd">loadData
</span><span class=
"hl opt">();
</span></pre>
429 <p>The database object needs names for the connection and for the database, which we can add as constants to the class:
</p>
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>
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>
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>
441 <span class=
"hl kwb">bool
</span> <span class=
"hl kwd">init
</span><span class=
"hl opt">();
</span>
443 <span class=
"hl kwb">void
</span> <span class=
"hl kwd">done
</span><span class=
"hl opt">();
</span></pre>
445 <p>This is the final
<tt>module.h
</tt> file:
</p>
447 <pre class=
"hl"><span class=
"hl com">/**
</span>
448 <span class=
"hl com"> *
@file PswGen/Storage/module.h
</span>
449 <span class=
"hl com"> */
</span>
451 <span class=
"hl ppc">#ifndef __PSWGEN_STORAGE_MODULE_H
</span>
452 <span class=
"hl ppc"># define __PSWGEN_STORAGE_MODULE_H
</span>
454 <span class=
"hl ppc">#include
</span> <span class=
"hl pps">"istorage.h
"</span><span class=
"hl ppc"></span>
456 <span class=
"hl ppc">#include
<Plugins/iPlugin
></span>
458 <span class=
"hl ppc">#include
<QObject
></span>
459 <span class=
"hl ppc">#include
<QString
></span>
460 <span class=
"hl ppc">#include
<QAbstractListModel
></span>
461 <span class=
"hl ppc">#include
<QMap
></span>
462 <span class=
"hl ppc">#include
<QtSql/QSqlDatabase
></span>
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>
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>
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>
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>
481 <span class=
"hl kwc">public
</span><span class=
"hl opt">:
</span>
483 <span class=
"hl kwd">Module
</span><span class=
"hl opt">();
</span>
485 <span class=
"hl kwc">virtual
</span> <span class=
"hl opt">~
</span><span class=
"hl kwd">Module
</span><span class=
"hl opt">();
</span>
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">&</span> args
<span class=
"hl opt">);
</span>
489 <span class=
"hl kwc">virtual
</span> <span class=
"hl kwb">void
</span> <span class=
"hl kwd">done
</span><span class=
"hl opt">();
</span>
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>
494 <span class=
"hl kwc">private
</span><span class=
"hl opt">:
</span> <span class=
"hl slc">// Members
</span>
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>
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>
502 <span class=
"hl opt">};
</span>
504 <span class=
"hl kwa">namespace
</span> Internal
<span class=
"hl opt">{
</span>
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>
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>
512 <span class=
"hl kwc">public
</span><span class=
"hl opt">:
</span>
514 <span class=
"hl kwd">StorageImpl
</span><span class=
"hl opt">();
</span>
516 <span class=
"hl kwc">virtual
</span> <span class=
"hl opt">~
</span><span class=
"hl kwd">StorageImpl
</span><span class=
"hl opt">();
</span>
518 <span class=
"hl kwb">bool
</span> <span class=
"hl kwd">init
</span><span class=
"hl opt">();
</span>
520 <span class=
"hl kwb">void
</span> <span class=
"hl kwd">done
</span><span class=
"hl opt">();
</span>
522 <span class=
"hl com">/*
</span>
523 <span class=
"hl com">iStorage interface
</span>
524 <span class=
"hl com">*/
</span>
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">&</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>
528 <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>
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>
532 <span class=
"hl com">/*
</span>
533 <span class=
"hl com">QAbstractListModel methods
</span>
534 <span class=
"hl com">*/
</span>
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">&</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>
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">&</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>
540 <span class=
"hl kwc">private
</span><span class=
"hl opt">:
</span> <span class=
"hl slc">// Members
</span>
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>
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>
548 <span class=
"hl slc">/// Database connection
</span>
549 QSqlDatabase mDb
<span class=
"hl opt">;
</span>
551 <span class=
"hl slc">/// List of name/data pairs
</span>
552 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>
555 <span class=
"hl kwc">private
</span><span class=
"hl opt">:
</span> <span class=
"hl slc">// Methods
</span>
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>
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>
563 <span class=
"hl opt">};
</span>
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>
570 <span class=
"hl ppc">#endif
</span> <span class=
"hl slc">// module.h
</span><span class=
"hl ppc"></span></pre>
572 <p>Continue implementing the
<a href=
"pswgen07.html">Storage Module
</a>.
</p>