From 0a383af776fe4c1c0ac1059dd3732f32cb6e1c7a Mon Sep 17 00:00:00 2001 From: =?utf8?q?Enar=20V=C3=A4ikene?= <enar@vaikene.net> Date: Fri, 23 Sep 2011 13:12:06 +0300 Subject: [PATCH] Added more tutorial sections. --- www/pswgen06.html | 562 +++++++++++++++++++++++++++++++++++++++++++++ www/pswgen07.html | 563 ++++++++++++++++++++++++++++++++++++++++++++++ www/pswgen08.html | 99 ++++++++ 3 files changed, 1224 insertions(+) create mode 100644 www/pswgen06.html create mode 100644 www/pswgen07.html create mode 100644 www/pswgen08.html diff --git a/www/pswgen06.html b/www/pswgen06.html new file mode 100644 index 0000000..aefb6ec --- /dev/null +++ b/www/pswgen06.html @@ -0,0 +1,562 @@ +<!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Transitional//EN" "http://www.w3.org/TR/xhtml1/DTD/xhtml1-transitional.dtd"> +<html lang="et" xmlns="http://www.w3.org/1999/xhtml" xml:lang="et"> + + <head> + <meta http-equiv="CONTENT-TYPE" content="text/html; charset=utf-8" /> + <title>eVaf Tutorial - 06 - Storage Module</title> + <meta name="Author" content="Enar Väikene" /> + <meta name="description" content="eVaf Tutorial" /> + <meta name="keywords" content="evaf c++ application development framework tutorial password generator" /> + <link rel="StyleSheet" href="evaf.css" type="text/css" media="all" /> + <link rel="StyleSheet" href="highlight.css" type="text/css" media="all" /> + </head> + + <body> + + <h1>eVaf Tutorial</h1> + + <h2>06 - Storage Module</h2> + + <p>In this section we start implementing the Storage module. The storage module stores non-sensitive data required to re-generate + passwords. We use a simple SQLITE database in this module, but nothing prevents us replacing it with a more complex storage + module in the future.</p> + + <h3>iStorage interface</h3> + + <p>Once again, we start by defining the interface for the module and create the file <tt>istorage.h</tt> in the + <tt>src/apps/PswGen/Storage</tt> directory:</p> + + <pre class="hl"><span class="hl com">/**</span> +<span class="hl com"> * @file PswGen/Storage/istorage.h</span> +<span class="hl com"> */</span> + +<span class="hl ppc">#ifndef __PSWGEN_STORAGE_ISTORAGE_H</span> +<span class="hl ppc"># define __PSWGEN_STORAGE_ISTORAGE_H</span> +<span class="hl ppc">#endif</span> <span class="hl slc">// istorage.h</span></pre> + + <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 + include headers for <tt>QSharedData</tt> and <tt>QExplicitlySharedDataPointer</tt>. We need a container for the data that + we store and making it shared data object with the benefit of automatic reference counting and memory management makes sense.</p> + + <pre class="hl"><span class="hl ppc">#include <QObject></span> +<span class="hl ppc">#include <QString></span> +<span class="hl ppc">#include <QSharedData></span> +<span class="hl ppc">#include <QExplicitlySharedDataPointer></span></pre> + + <p>Use the <tt>eVaf::PswGen</tt> namespace:</p> + + <pre class="hl"><span class="hl kwa">namespace</span> eVaf <span class="hl opt">{</span> +<span class="hl kwa">namespace</span> PswGen <span class="hl opt">{</span> + +<span class="hl opt">}</span> <span class="hl slc">// namespace eVaf::PswGen</span> +<span class="hl opt">}</span> <span class="hl slc">// namespace eVaf</span></pre> + + <p>The container class for stored data has the following attributes:</p> + <ul> + <li>Name -- Name of the generated password</li> + <li>Length -- Length of the password</li> + <li>Options -- Additional parameters for the password generator</li> + </ul> + + <p>The container class belongs to the Storage module and we use the <tt>eVaf::PswGen::Storage</tt> namespace for it:</p> + + <pre class="hl"><span class="hl kwa">namespace</span> Storage <span class="hl opt">{</span> + +<span class="hl kwc">class</span> Data <span class="hl opt">:</span> <span class="hl kwc">public</span> QSharedData +<span class="hl opt">{</span> +<span class="hl kwc">private</span><span class="hl opt">:</span> + + <span class="hl kwb">bool</span> mModified<span class="hl opt">;</span> + QString mName<span class="hl opt">;</span> + <span class="hl kwb">int</span> mLength<span class="hl opt">;</span> + uint mFlags<span class="hl opt">;</span> + +<span class="hl opt">};</span> + +<span class="hl opt">}</span> <span class="hl slc">// eVaf::PswGen::Storage</span></pre> + + <p>The extra attribute - <tt>mModified</tt> - is used to detect unsaved modifications in the data object.</p> + + <p>Add constructors for the shared data class. Creating a data object without name makes no sense and we include the + name attribute in all our constructors:</p> + + <pre class="hl"><span class="hl kwc">public</span><span class="hl opt">:</span> + + <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 opt">:</span> <span class="hl kwd">QSharedData</span><span class="hl opt">()</span> + <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> + <span class="hl opt">,</span> <span class="hl kwd">mName</span><span class="hl opt">(</span>name<span class="hl opt">)</span> + <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> + <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> + <span class="hl opt">{}</span> + + <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> + <span class="hl opt">:</span> <span class="hl kwd">QSharedData</span><span class="hl opt">()</span> + <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> + <span class="hl opt">,</span> <span class="hl kwd">mName</span><span class="hl opt">(</span>name<span class="hl opt">)</span> + <span class="hl opt">,</span> <span class="hl kwd">mLength</span><span class="hl opt">(</span>l<span class="hl opt">)</span> + <span class="hl opt">,</span> <span class="hl kwd">mFlags</span><span class="hl opt">(</span>f<span class="hl opt">)</span> + <span class="hl opt">{}</span></pre> + + <p>Fianlly, we add getter and setter methods:</p> + + <pre class="hl"> + 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> + + <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> + <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> + <span class="hl opt">{</span> + <span class="hl kwa">if</span> <span class="hl opt">(</span>mLength <span class="hl opt">!=</span> value<span class="hl opt">) {</span> + mLength <span class="hl opt">=</span> value<span class="hl opt">;</span> + mModified <span class="hl opt">=</span> <span class="hl kwa">true</span><span class="hl opt">;</span> + <span class="hl opt">}</span> + <span class="hl opt">}</span> + + 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> + <span class="hl kwb">void</span> <span class="hl kwd">setFlags</span><span class="hl opt">(</span>uint value<span class="hl opt">)</span> + <span class="hl opt">{</span> + <span class="hl kwa">if</span> <span class="hl opt">(</span>mFlags <span class="hl opt">!=</span> value<span class="hl opt">) {</span> + mFlags <span class="hl opt">=</span> value<span class="hl opt">;</span> + mModified <span class="hl opt">=</span> <span class="hl kwa">true</span><span class="hl opt">;</span> + <span class="hl opt">}</span> + <span class="hl opt">}</span> + + <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> + + <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> + + <p>The <tt>reset()</tt> method resets the <tt>modified</tt> attribute.</p> + + <p>Continue with the <tt>iStorage</tt> interface:</tt> + + <pre class="hl"><span class="hl kwb">struct</span> iStorage +<span class="hl opt">{</span> + +<span class="hl opt">};</span></pre> + + <p>According to the specification, we need functions to store and query data:</p> + + <pre class="hl"> + <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> + + <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> + + <p>The specification also mentions partial matches where entering "fa" would offer "facebook.com" if it exists. This could be done by + using the <tt>QCompleter</tt> class that provides auto completion in Qt widgets like <tt>QLineEdit</tt> and <tt>QComboBox</tt>. The + <tt>QCompleter<tt> class needs a <tt>QAbstractItemModel</tt> for the auto completion word list and we can provide it + from our <tt>Storage</tt> module:</tt> + + <pre class="hl"> + <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> + + <p><tt>QAbstractItemModel</tt> is not known at this moment and we need to add a forward class declaration to the beginning of the + <tt>istorage.h</tt> file:</p> + + <pre class="hl"> + <span class="hl kwc">class</span> QAbstractItemModel<span class="hl opt">;</span></pre> + + <p>At the the end of the <tt>istorage.h</tt> file, we declare the <tt>iStorage</tt> interface:</p> + + <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> + + <p>This is the complete <tt>istorage.h</tt> file:</p> + + <pre class="hl"><span class="hl com">/**</span> +<span class="hl com"> * @file PswGen/Storage/istorage.h</span> +<span class="hl com"> */</span> + +<span class="hl ppc">#ifndef __PSWGEN_STORAGE_ISTORAGE_H</span> +<span class="hl ppc"># define __PSWGEN_STORAGE_ISTORAGE_H</span> + +<span class="hl ppc">#include <QObject></span> +<span class="hl ppc">#include <QString></span> +<span class="hl ppc">#include <QSharedData></span> +<span class="hl ppc">#include <QExplicitlySharedDataPointer></span> + +<span class="hl kwc">class</span> QAbstractItemModel<span class="hl opt">;</span> + +<span class="hl kwa">namespace</span> eVaf <span class="hl opt">{</span> +<span class="hl kwa">namespace</span> PswGen <span class="hl opt">{</span> + +<span class="hl kwa">namespace</span> Storage <span class="hl opt">{</span> + +<span class="hl com">/// Data stored for every password.</span> +<span class="hl kwc">class</span> Data <span class="hl opt">:</span> <span class="hl kwc">public</span> QSharedData +<span class="hl opt">{</span> +<span class="hl kwc">public</span><span class="hl opt">:</span> + + <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 opt">:</span> <span class="hl kwd">QSharedData</span><span class="hl opt">()</span> + <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> + <span class="hl opt">,</span> <span class="hl kwd">mName</span><span class="hl opt">(</span>name<span class="hl opt">)</span> + <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> + <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> + <span class="hl opt">{}</span> + + <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> + <span class="hl opt">:</span> <span class="hl kwd">QSharedData</span><span class="hl opt">()</span> + <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> + <span class="hl opt">,</span> <span class="hl kwd">mName</span><span class="hl opt">(</span>name<span class="hl opt">)</span> + <span class="hl opt">,</span> <span class="hl kwd">mLength</span><span class="hl opt">(</span>l<span class="hl opt">)</span> + <span class="hl opt">,</span> <span class="hl kwd">mFlags</span><span class="hl opt">(</span>f<span class="hl opt">)</span> + <span class="hl opt">{}</span> + + <span class="hl slc">/// Name of the password</span> + 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> + + <span class="hl slc">/// Length of the generated password</span> + <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> + <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> + <span class="hl opt">{</span> + <span class="hl kwa">if</span> <span class="hl opt">(</span>mLength <span class="hl opt">!=</span> value<span class="hl opt">) {</span> + mLength <span class="hl opt">=</span> value<span class="hl opt">;</span> + mModified <span class="hl opt">=</span> <span class="hl kwa">true</span><span class="hl opt">;</span> + <span class="hl opt">}</span> + <span class="hl opt">}</span> + + <span class="hl slc">/// Optional flags for the password generator</span> + 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> + <span class="hl kwb">void</span> <span class="hl kwd">setFlags</span><span class="hl opt">(</span>uint value<span class="hl opt">)</span> + <span class="hl opt">{</span> + <span class="hl kwa">if</span> <span class="hl opt">(</span>mFlags <span class="hl opt">!=</span> value<span class="hl opt">) {</span> + mFlags <span class="hl opt">=</span> value<span class="hl opt">;</span> + mModified <span class="hl opt">=</span> <span class="hl kwa">true</span><span class="hl opt">;</span> + <span class="hl opt">}</span> + <span class="hl opt">}</span> + + <span class="hl slc">/// Flag indicating that some fields are modified</span> + <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> + + <span class="hl slc">/// Resets the modified flag</span> + <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> + +<span class="hl kwc">private</span><span class="hl opt">:</span> + + <span class="hl kwb">bool</span> mModified<span class="hl opt">;</span> + QString mName<span class="hl opt">;</span> + <span class="hl kwb">int</span> mLength<span class="hl opt">;</span> + uint mFlags<span class="hl opt">;</span> + +<span class="hl opt">};</span> + +<span class="hl opt">}</span> <span class="hl slc">// eVaf::PswGen::Storage</span> + +<span class="hl com">/// Password storage interface.</span> +<span class="hl kwb">struct</span> iStorage +<span class="hl opt">{</span> + + <span class="hl com">/// Saves the data record</span> + <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> + + <span class="hl com">/// Returns a data record by the name</span> + <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> + + <span class="hl com">/// Returns an item model with the names of all the stored passwords</span> + <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> + +<span class="hl opt">};</span> + +<span class="hl opt">}</span> <span class="hl slc">// namespace eVaf::PswGen</span> +<span class="hl opt">}</span> <span class="hl slc">// namespace eVaf</span> + +<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> + +<span class="hl ppc">#endif</span> <span class="hl slc">// istorage.h</span><span class="hl ppc"></span></pre> + + <p>We also create the <tt>iStorage</tt> file so that we can use <tt>#include <Storage/iStorage></tt> in our other modules:</tt> + + <pre class="hl"><span class="hl ppc">#include </span><span class="hl pps">"istorage.h"</span></pre> + + <h3>Storage module</h3> + + <p>The <tt>Storage<tt> module is simple enough to be derived directly from the <tt>Plugins::iPlugin</tt> interface and needs only one + header/source file. In general, I personally prefer short source files and follow the <i>one-class-per-file</i> rule. Only when classes + are very simple and closely related I put the into the same source file.</p> + + <p>Create the <tt>module.h</tt> header file in the <tt>src/apps/PswGen/Storage</tt> directory. Include <tt>istorage.h</tt> and + <tt>Plugins/iPlugin</tt> header files. We use the <tt>eVaf::PswGen::Storage</tt> namespace for public classes and + <tt>eVaf::PswGen::Storage::Internal<tt> namespace for private classes.</p> + + <pre class="hl"><span class="hl ppc">#ifndef __PSWGEN_STORAGE_MODULE_H</span> +<span class="hl ppc"># define __PSWGEN_STORAGE_MODULE_H</span> + +<span class="hl ppc">#include</span> <span class="hl pps">"istorage.h"</span><span class="hl ppc"></span> +<span class="hl ppc">#include <Plugins/iPlugin></span> + +<span class="hl kwa">namespace</span> eVaf <span class="hl opt">{</span> +<span class="hl kwa">namespace</span> PswGen <span class="hl opt">{</span> + +<span class="hl slc">/// Module that stores options for strong passwords</span> +<span class="hl kwa">namespace</span> Storage <span class="hl opt">{</span> + +<span class="hl slc">/// Internal implementation of the Storage module</span> +<span class="hl kwa">namespace</span> Internal <span class="hl opt">{</span> + +<span class="hl opt">}</span> <span class="hl slc">// namespace eVaf::PswGen::Storage::Internal</span> +<span class="hl opt">}</span> <span class="hl slc">// namespace eVaf::PswGen::Storage</span> +<span class="hl opt">}</span> <span class="hl slc">// namespace eVaf::PswGen</span> +<span class="hl opt">}</span> <span class="hl slc">// namespace eVaf</span> +<span class="hl ppc">#endif</span> <span class="hl slc">// module.h</span><span class="hl ppc"></span></pre> + + <p>We use the same name <tt>Module</tt> for the class that implements the module. This class is public and goes to the + <tt>eVaf::PswGen::Storage</tt> namespace:</p> + + <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 +<span class="hl opt">{</span> + Q_OBJECT + +<span class="hl kwc">public</span><span class="hl opt">:</span> + + <span class="hl kwd">Module</span><span class="hl opt">();</span> + + <span class="hl kwc">virtual</span> <span class="hl opt">~</span><span class="hl kwd">Module</span><span class="hl opt">();</span> + +<span class="hl opt">};</span></pre> + + <p>Implement pure virtual methods in the <tt>iPlugin</tt> interface:</p> + + <pre class="hl"> + <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> + + <span class="hl kwc">virtual</span> <span class="hl kwb">void</span> <span class="hl kwd">done</span><span class="hl opt">();</span> + + <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> + + <p>This module needs more complex initialization that the <tt>Generator</tt> module and we use the <tt>mReady</tt> flag to + indicate that the module is fully initialized:</p> + + <pre class="hl"> +<span class="hl kwc">private</span><span class="hl opt">:</span> + + <span class="hl kwb">bool</span> mReady<span class="hl opt">;</span></pre> + + <p>The <tt>StorageImpl</tt> class is the internal implementation of the <tt>iStorage</tt> interface:</p> + + <pre class="hl"> + Internal<span class="hl opt">::</span>StorageImpl <span class="hl opt">*</span> mStorage<span class="hl opt">;</span></pre> + + <p>We could declare the <tt>Internal::StorageImpl</tt> class before the <tt>Module</tt> class, but as I like starting with more + generic (public) classes and then go into the details, we add a forward declaration to the beginning of the file:</p> + + <pre class="hl"> +<span class="hl kwa">namespace</span> Internal <span class="hl opt">{</span> + <span class="hl kwc">class</span> StorageImpl<span class="hl opt">;</span> +<span class="hl opt">}</span> <span class="hl slc">// namespace eVaf::PswGen::Storage::Internal</span></pre> + + <p>The declaration of the <tt>StorageImpl</tt> class goes into the <tt>eVaf::PswGen::Storage::Internal</tt> namespace and the class + shall be derived both from <tt>QObject</tt> and <tt>iStorage</tt>. However, since we also need to implement the + <tt>QAbstractItemModel</tt> data model for the <tt>iStorage::autoCompletionModel()</tt> method, we derive it from the + <tt>QAbstractListModel</tt> class instead. We use the <tt>QAbstractListModel</tt> class because it meets our requirements + to return a list of auto completion words.</p> + + <pre class="hl"> +<span class="hl kwa">namespace</span> Internal <span class="hl opt">{</span> + +<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 +<span class="hl opt">{</span> + Q_OBJECT + <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> + +<span class="hl kwc">public</span><span class="hl opt">:</span> + + <span class="hl kwd">StorageImpl</span><span class="hl opt">();</span> + + <span class="hl kwc">virtual</span> <span class="hl opt">~</span><span class="hl kwd">StorageImpl</span><span class="hl opt">();</span> + +<span class="hl opt">};</span> + +<span class="hl opt">}</span> <span class="hl slc">// namespace eVaf::PswGen::Storage::Internal</span></pre> + + <p>First, we implement pure virtual methods found in the <tt>iStorage</tt> interface:</p> + + <pre class="hl"> + <span class="hl com">/*</span> + <span class="hl com">iStorage interface</span> + <span class="hl com">*/</span> + + <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 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 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> + + <p>Since the <tt>QAbstractItemModel</tt> data model is implemented by the same class, we can simply return <tt>this</tt> in the + <tt>autoCompletionModel()</tt> model.</p> + + <p>The <tt>QAbstractListModel</tt> class also has pure virtual methods that need to be implemented:</p> + + <pre class="hl"> + <span class="hl com">/*</span> + <span class="hl com">QAbstractListModel methods</span> + <span class="hl com">*/</span> + + <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> + + <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> + + <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 + a <tt>QMap<QString, QExplicitlySharedDataPointer<Storage::Data> ></tt> for this purpose as it allows fast lookups + by the name string.</p> + + <pre class="hl"> +<span class="hl kwc">private</span><span class="hl opt">:</span> + + 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> + + <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 + also need a method to create database tables if they do not exist yet:</p> + + <pre class="hl"> + QSqlDatabase mDb<span class="hl opt">;</span> + + <span class="hl kwb">bool</span> <span class="hl kwd">createTables</span><span class="hl opt">();</span> + + <span class="hl kwb">bool</span> <span class="hl kwd">loadData</span><span class="hl opt">();</span></pre> + + <p>The database object needs names for the connection and for the database, which we can add as constants to the class:</p> + + <pre class="hl"> + <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> + + <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> + + <p>The database needs to be opened and closed, and the list of data objects populated with data from the database. For this purpose + we add <tt>init()</tt> and <tt>done()</tt> methods to the public section of the class. The <tt>init()</tt> method can return + <tt>false</tt> if the initialization fails.</p> + + <pre class="hl"> + <span class="hl kwb">bool</span> <span class="hl kwd">init</span><span class="hl opt">();</span> + + <span class="hl kwb">void</span> <span class="hl kwd">done</span><span class="hl opt">();</span></pre> + + <p>This is the final <tt>module.h</tt> file:</p> + +<pre class="hl"><span class="hl com">/**</span> +<span class="hl com"> * @file PswGen/Storage/module.h</span> +<span class="hl com"> */</span> + +<span class="hl ppc">#ifndef __PSWGEN_STORAGE_MODULE_H</span> +<span class="hl ppc"># define __PSWGEN_STORAGE_MODULE_H</span> + +<span class="hl ppc">#include</span> <span class="hl pps">"istorage.h"</span><span class="hl ppc"></span> + +<span class="hl ppc">#include <Plugins/iPlugin></span> + +<span class="hl ppc">#include <QObject></span> +<span class="hl ppc">#include <QString></span> +<span class="hl ppc">#include <QAbstractListModel></span> +<span class="hl ppc">#include <QMap></span> +<span class="hl ppc">#include <QtSql/QSqlDatabase></span> + + +<span class="hl kwa">namespace</span> eVaf <span class="hl opt">{</span> +<span class="hl kwa">namespace</span> PswGen <span class="hl opt">{</span> + +<span class="hl slc">/// Module that stores options for strong passwords</span> +<span class="hl kwa">namespace</span> Storage <span class="hl opt">{</span> + +<span class="hl slc">/// Internal implementation of the Storage module</span> +<span class="hl kwa">namespace</span> Internal <span class="hl opt">{</span> + <span class="hl kwc">class</span> StorageImpl<span class="hl opt">;</span> +<span class="hl opt">}</span> <span class="hl slc">// namespace eVaf::PswGen::Storage::Internal</span> + +<span class="hl com">/// Module implementing the iStorage interface.</span> +<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 +<span class="hl opt">{</span> + Q_OBJECT + +<span class="hl kwc">public</span><span class="hl opt">:</span> + + <span class="hl kwd">Module</span><span class="hl opt">();</span> + + <span class="hl kwc">virtual</span> <span class="hl opt">~</span><span class="hl kwd">Module</span><span class="hl opt">();</span> + + <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> + + <span class="hl kwc">virtual</span> <span class="hl kwb">void</span> <span class="hl kwd">done</span><span class="hl opt">();</span> + + <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> + + +<span class="hl kwc">private</span><span class="hl opt">:</span> <span class="hl slc">// Members</span> + + <span class="hl slc">/// Flag indicating that the module is ready</span> + <span class="hl kwb">bool</span> mReady<span class="hl opt">;</span> + + <span class="hl slc">/// iStorage interface instance</span> + Internal<span class="hl opt">::</span>StorageImpl <span class="hl opt">*</span> mStorage<span class="hl opt">;</span> + +<span class="hl opt">};</span> + +<span class="hl kwa">namespace</span> Internal <span class="hl opt">{</span> + +<span class="hl com">/// iStorage interface implementation.</span> +<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 +<span class="hl opt">{</span> + Q_OBJECT + <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> + +<span class="hl kwc">public</span><span class="hl opt">:</span> + + <span class="hl kwd">StorageImpl</span><span class="hl opt">();</span> + + <span class="hl kwc">virtual</span> <span class="hl opt">~</span><span class="hl kwd">StorageImpl</span><span class="hl opt">();</span> + + <span class="hl kwb">bool</span> <span class="hl kwd">init</span><span class="hl opt">();</span> + + <span class="hl kwb">void</span> <span class="hl kwd">done</span><span class="hl opt">();</span> + + <span class="hl com">/*</span> + <span class="hl com">iStorage interface</span> + <span class="hl com">*/</span> + + <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 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 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> + + <span class="hl com">/*</span> + <span class="hl com">QAbstractListModel methods</span> + <span class="hl com">*/</span> + + <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> + + <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> + +<span class="hl kwc">private</span><span class="hl opt">:</span> <span class="hl slc">// Members</span> + + <span class="hl slc">/// Name of the database connection</span> + <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> + + <span class="hl slc">/// Name of the database file without path</span> + <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> + + <span class="hl slc">/// Database connection</span> + QSqlDatabase mDb<span class="hl opt">;</span> + + <span class="hl slc">/// List of name/data pairs</span> + 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> + + +<span class="hl kwc">private</span><span class="hl opt">:</span> <span class="hl slc">// Methods</span> + + <span class="hl com">/// Creates database tables if necessary</span> + <span class="hl kwb">bool</span> <span class="hl kwd">createTables</span><span class="hl opt">();</span> + + <span class="hl com">/// Loads data from the database</span> + <span class="hl kwb">bool</span> <span class="hl kwd">loadData</span><span class="hl opt">();</span> + +<span class="hl opt">};</span> + +<span class="hl opt">}</span> <span class="hl slc">// namespace eVaf::PswGen::Storage::Internal</span> +<span class="hl opt">}</span> <span class="hl slc">// namespace eVaf::PswGen::Storage</span> +<span class="hl opt">}</span> <span class="hl slc">// namespace eVaf::PswGen</span> +<span class="hl opt">}</span> <span class="hl slc">// namespace eVaf</span> + +<span class="hl ppc">#endif</span> <span class="hl slc">// module.h</span><span class="hl ppc"></span></pre> + + <p>Continue implementing the <a href="pswgen07.html">Storage Module</a>.</p> + + </body> +</html> diff --git a/www/pswgen07.html b/www/pswgen07.html new file mode 100644 index 0000000..d35d484 --- /dev/null +++ b/www/pswgen07.html @@ -0,0 +1,563 @@ +<!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Transitional//EN" "http://www.w3.org/TR/xhtml1/DTD/xhtml1-transitional.dtd"> +<html lang="et" xmlns="http://www.w3.org/1999/xhtml" xml:lang="et"> + + <head> + <meta http-equiv="CONTENT-TYPE" content="text/html; charset=utf-8" /> + <title>eVaf Tutorial - 07 - Storage Module</title> + <meta name="Author" content="Enar Väikene" /> + <meta name="description" content="eVaf Tutorial" /> + <meta name="keywords" content="evaf c++ application development framework tutorial password generator" /> + <link rel="StyleSheet" href="evaf.css" type="text/css" media="all" /> + <link rel="StyleSheet" href="highlight.css" type="text/css" media="all" /> + </head> + + <body> + + <h1>eVaf Tutorial</h1> + + <h2>07 - Storage Module</h2> + + <p>Create the <tt>module.cpp</tt> file in the <tt>src/apps/PswGen/Storage</tt> directory:</tt> + + <pre class="hl"><span class="hl com">/**</span> +<span class="hl com"> * @file PswGen/Storage/module.cpp</span> +<span class="hl com"> */</span> + +<span class="hl ppc">#include</span> <span class="hl pps">"module.h"</span><span class="hl ppc"></span> +<span class="hl ppc">#include <QtCore></span></pre> + + <p>Copy version information files from the <tt>Generator<tt> module:</p> + + <pre>evaf/src/apps/PswGen/Storage $ <code>cp ../Generator/version.{h,rc} .</code></pre> + + <p>Modify the <tt>version.h</tt> file:</p> + + <pre class="hl"><span class="hl com">/**</span> +<span class="hl com"> * @file PswGen/Storage/version.h</span> +<span class="hl com"> */</span> + +<span class="hl ppc">#ifndef __PSWGEN_STORAGE_VERSION_H</span> +<span class="hl ppc">#define __PSWGEN_STORAGE_VERSION_H</span> + +<span class="hl ppc">#include <version_rc.h></span> + +<span class="hl com">/**</span> +<span class="hl com"> * Module/library version number in the form major,minor,release,build</span> +<span class="hl com"> */</span> +<span class="hl ppc">#define VER_FILE_VERSION 0,1,1,1</span> + +<span class="hl com">/**</span> +<span class="hl com"> * Module/library version number in the string format (shall end with \0)</span> +<span class="hl com"> */</span> +<span class="hl ppc">#define VER_FILE_VERSION_STR</span> <span class="hl pps">"0.1.1.1\0"</span><span class="hl ppc"></span> + +<span class="hl com">/**</span> +<span class="hl com"> * Module/library name (shall end with \0)</span> +<span class="hl com"> */</span> +<span class="hl ppc">#define VER_MODULE_NAME_STR</span> <span class="hl pps">"PswStorage\0"</span><span class="hl ppc"></span> + +<span class="hl com">/**</span> +<span class="hl com"> * Module type (see version_rc.h for all the types)</span> +<span class="hl com"> */</span> +<span class="hl ppc">#define VER_MODULE_TYPE MT_GENERIC</span> + +<span class="hl com">/**</span> +<span class="hl com"> * Module type in the string format (see version_rc for all the types)</span> +<span class="hl com"> */</span> +<span class="hl ppc">#define VER_MODULE_TYPE_STR MT_GENERIC</span> + +<span class="hl com">/**</span> +<span class="hl com"> * Original file name for windows (shall end with \0)</span> +<span class="hl com"> */</span> +<span class="hl ppc">#define VER_ORIGINAL_FILE_NAME_STR</span> <span class="hl pps">"PswStorage.dll\0"</span><span class="hl ppc"></span> + +<span class="hl com">/**</span> +<span class="hl com"> * Description of the module/library (shall end with \0)</span> +<span class="hl com"> */</span> +<span class="hl ppc">#define VER_FILE_DESCRIPTION_STR</span> <span class="hl pps">"Module that stores data for generating strong passwords.\0"</span><span class="hl ppc"></span> + +<span class="hl ppc">#endif</span> <span class="hl slc">// version.h</span><span class="hl ppc"></span></pre> + + <p>Include the <tt>version.h</tt> header file in <tt>module.cpp</tt> and export version information:</p> + + <pre class="hl"> +<span class="hl ppc">#include</span> <span class="hl pps">"version.h"</span><span class="hl ppc"></span> + +<span class="hl kwd">VER_EXPORT_VERSION_INFO</span><span class="hl opt">()</span></pre> + + <p>Make it a proper Qt plugin by using the <tt>Q_EXPORT_PLUGIN2()</tt> macro:</p> + + <pre class="hl"><span class="hl kwd">Q_EXPORT_PLUGIN2</span><span class="hl opt">(</span>VER_MODULE_NAME_STR<span class="hl opt">,</span> eVaf<span class="hl opt">::</span>PswGen<span class="hl opt">::</span>Storage<span class="hl opt">::</span>Module<span class="hl opt">)</span></pre> + + <p>The <tt>Module</tt> class creates the internal <tt>StorageImpl</tt> object in the constructor, but initializes it in the + <tt>init()</tt> method. This way we can return errors from the module if initialization fails. Similarly, we finalize the + internal <tt>StorageImpl</tt> object in the <tt>done()</tt> method and delete in the destructor.</p> + + <p>The module is ready when the internal <tt>StorageImpl</tt> object is initalized and we set the <tt>mReady</tt> flag to + <tt>true</tt> when the initialization is done and back to <tt>false</tt> in the <tt>done()</tt> method.</p> + + <p>The rest of the code sets the name of the object and outputs info messages.</p> + + <pre class="hl">Module<span class="hl opt">::</span><span class="hl kwd">Module</span><span class="hl opt">()</span> + <span class="hl opt">:</span> Plugins<span class="hl opt">::</span><span class="hl kwd">iPlugin</span><span class="hl opt">()</span> + <span class="hl opt">,</span> <span class="hl kwd">mReady</span><span class="hl opt">(</span><span class="hl kwa">false</span><span class="hl opt">)</span> +<span class="hl opt">{</span> + <span class="hl kwd">setObjectName</span><span class="hl opt">(</span><span class="hl kwd">QString</span><span class="hl opt">(</span><span class="hl str">"%1.%2"</span><span class="hl opt">).</span><span class="hl kwd">arg</span><span class="hl opt">(</span>VER_MODULE_NAME_STR<span class="hl opt">).</span><span class="hl kwd">arg</span><span class="hl opt">(</span>__FUNCTION__<span class="hl opt">));</span> + + mStorage <span class="hl opt">=</span> <span class="hl kwa">new</span> Internal<span class="hl opt">::</span>StorageImpl<span class="hl opt">;</span> + + <span class="hl kwd">EVAF_INFO</span><span class="hl opt">(</span><span class="hl str">"%s created"</span><span class="hl opt">,</span> <span class="hl kwd">qPrintable</span><span class="hl opt">(</span><span class="hl kwd">objectName</span><span class="hl opt">()));</span> +<span class="hl opt">}</span> + +Module<span class="hl opt">::~</span><span class="hl kwd">Module</span><span class="hl opt">()</span> +<span class="hl opt">{</span> + <span class="hl kwa">delete</span> mStorage<span class="hl opt">;</span> + + <span class="hl kwd">EVAF_INFO</span><span class="hl opt">(</span><span class="hl str">"%s destroyed"</span><span class="hl opt">,</span> <span class="hl kwd">qPrintable</span><span class="hl opt">(</span><span class="hl kwd">objectName</span><span class="hl opt">()));</span> +<span class="hl opt">}</span> + +<span class="hl kwb">bool</span> Module<span class="hl opt">::</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> +<span class="hl opt">{</span> + <span class="hl kwd">Q_UNUSED</span><span class="hl opt">(</span>args<span class="hl opt">);</span> + + <span class="hl kwa">if</span> <span class="hl opt">(!</span>mStorage<span class="hl opt">-></span><span class="hl kwd">init</span><span class="hl opt">())</span> + <span class="hl kwa">return false</span><span class="hl opt">;</span> + + mReady <span class="hl opt">=</span> <span class="hl kwa">true</span><span class="hl opt">;</span> + + <span class="hl kwd">EVAF_INFO</span><span class="hl opt">(</span><span class="hl str">"%s initialized"</span><span class="hl opt">,</span> <span class="hl kwd">qPrintable</span><span class="hl opt">(</span><span class="hl kwd">objectName</span><span class="hl opt">()));</span> + + <span class="hl kwa">return true</span><span class="hl opt">;</span> +<span class="hl opt">}</span> + +<span class="hl kwb">void</span> Module<span class="hl opt">::</span><span class="hl kwd">done</span><span class="hl opt">()</span> +<span class="hl opt">{</span> + mReady <span class="hl opt">=</span> <span class="hl kwa">false</span><span class="hl opt">;</span> + + mStorage<span class="hl opt">-></span><span class="hl kwd">done</span><span class="hl opt">();</span> + + <span class="hl kwd">EVAF_INFO</span><span class="hl opt">(</span><span class="hl str">"%s finalized"</span><span class="hl opt">,</span> <span class="hl kwd">qPrintable</span><span class="hl opt">(</span><span class="hl kwd">objectName</span><span class="hl opt">()));</span> +<span class="hl opt">}</span></pre> + + <p>The <tt>StorageImpl</tt> class does very little in the constructor and in the destructor:</p> + + <pre class="hl">StorageImpl<span class="hl opt">::</span><span class="hl kwd">StorageImpl</span><span class="hl opt">()</span> + <span class="hl opt">:</span> <span class="hl kwd">QAbstractListModel</span><span class="hl opt">()</span> +<span class="hl opt">{</span> + <span class="hl kwd">setObjectName</span><span class="hl opt">(</span><span class="hl kwd">QString</span><span class="hl opt">(</span><span class="hl str">"%1.iGenerator"</span><span class="hl opt">).</span><span class="hl kwd">arg</span><span class="hl opt">(</span>VER_MODULE_NAME_STR<span class="hl opt">));</span> + + <span class="hl kwd">EVAF_INFO</span><span class="hl opt">(</span><span class="hl str">"%s created"</span><span class="hl opt">,</span> <span class="hl kwd">qPrintable</span><span class="hl opt">(</span><span class="hl kwd">objectName</span><span class="hl opt">()));</span> +<span class="hl opt">}</span> + +StorageImpl<span class="hl opt">::~</span><span class="hl kwd">StorageImpl</span><span class="hl opt">()</span> +<span class="hl opt">{</span> + <span class="hl kwd">EVAF_INFO</span><span class="hl opt">(</span><span class="hl str">"%s destroyed"</span><span class="hl opt">,</span> <span class="hl kwd">qPrintable</span><span class="hl opt">(</span><span class="hl kwd">objectName</span><span class="hl opt">()));</span> +<span class="hl opt">}</span></pre> + + <p>Initialization of the <tt>StorageImpl</tt> class happens in the <tt>init()</tt> method, where we open the database connection, + create tables if necessary and load data from the database. We also register the <tt>iStorage</tt> interface in the global + registry of interfaces.</p> + + <p>We use the <tt>Common::iApp</tt> interface to find the data root directory where the SQLITE database file is going to be + located.</p> + + <pre class="hl"><span class="hl kwb">bool</span> StorageImpl<span class="hl opt">::</span><span class="hl kwd">init</span><span class="hl opt">()</span> +<span class="hl opt">{</span> + <span class="hl slc">// Open the database</span> + <span class="hl kwa">if</span> <span class="hl opt">(!</span>QSqlDatabase<span class="hl opt">::</span><span class="hl kwd">contains</span><span class="hl opt">(</span>DbConnectionName<span class="hl opt">)) {</span> + <span class="hl slc">// No database connection yet</span> + mDb <span class="hl opt">=</span> QSqlDatabase<span class="hl opt">::</span><span class="hl kwd">addDatabase</span><span class="hl opt">(</span><span class="hl str">"QSQLITE"</span><span class="hl opt">,</span> DbConnectionName<span class="hl opt">);</span> + mDb<span class="hl opt">.</span><span class="hl kwd">setDatabaseName</span><span class="hl opt">(</span>Common<span class="hl opt">::</span>iApp<span class="hl opt">::</span><span class="hl kwd">instance</span><span class="hl opt">()-></span><span class="hl kwd">dataRootDir</span><span class="hl opt">() +</span> DbName<span class="hl opt">);</span> + <span class="hl kwa">if</span> <span class="hl opt">(!</span>mDb<span class="hl opt">.</span><span class="hl kwd">open</span><span class="hl opt">()) {</span> + QSqlError err <span class="hl opt">=</span> mDb<span class="hl opt">.</span><span class="hl kwd">lastError</span><span class="hl opt">();</span> + <span class="hl kwd">EVAF_ERROR</span><span class="hl opt">(</span><span class="hl str">"Failed to open database : %s"</span><span class="hl opt">,</span> <span class="hl kwd">qPrintable</span><span class="hl opt">(</span>err<span class="hl opt">.</span><span class="hl kwd">text</span><span class="hl opt">()));</span> + <span class="hl kwa">return false</span><span class="hl opt">;</span> + <span class="hl opt">}</span> + <span class="hl opt">}</span> + <span class="hl kwa">else</span> <span class="hl opt">{</span> + <span class="hl slc">// Database connection already exists</span> + mDb <span class="hl opt">=</span> QSqlDatabase<span class="hl opt">::</span><span class="hl kwd">database</span><span class="hl opt">(</span>DbConnectionName<span class="hl opt">);</span> + <span class="hl opt">}</span> + + <span class="hl slc">// Create tables if necessary</span> + <span class="hl kwa">if</span> <span class="hl opt">(!</span><span class="hl kwd">createTables</span><span class="hl opt">())</span> + <span class="hl kwa">return false</span><span class="hl opt">;</span> + + <span class="hl slc">// Load data</span> + <span class="hl kwa">if</span> <span class="hl opt">(!</span><span class="hl kwd">loadData</span><span class="hl opt">())</span> + <span class="hl kwa">return false</span><span class="hl opt">;</span> + + <span class="hl slc">/// Register our interface</span> + Common<span class="hl opt">::</span>iRegistry<span class="hl opt">::</span><span class="hl kwd">instance</span><span class="hl opt">()-></span><span class="hl kwd">registerInterface</span><span class="hl opt">(</span><span class="hl str">"iStorage"</span><span class="hl opt">,</span> <span class="hl kwa">this</span><span class="hl opt">);</span> + + <span class="hl kwd">EVAF_INFO</span><span class="hl opt">(</span><span class="hl str">"%s initialized"</span><span class="hl opt">,</span> <span class="hl kwd">qPrintable</span><span class="hl opt">(</span><span class="hl kwd">objectName</span><span class="hl opt">()));</span> + + <span class="hl kwa">return true</span><span class="hl opt">;</span> +<span class="hl opt">}</span></pre> + + <p>The finalization of the <tt>StorageImpl</tt> class happens in the <tt>done()</tt> method, where we only need to clear the list + of shared data objects:</p> + + <pre class="hl"><span class="hl kwb">void</span> StorageImpl<span class="hl opt">::</span><span class="hl kwd">done</span><span class="hl opt">()</span> +<span class="hl opt">{</span> + mData<span class="hl opt">.</span><span class="hl kwd">clear</span><span class="hl opt">();</span> + <span class="hl kwd">EVAF_INFO</span><span class="hl opt">(</span><span class="hl str">"%s finalized"</span><span class="hl opt">,</span> <span class="hl kwd">qPrintable</span><span class="hl opt">(</span><span class="hl kwd">objectName</span><span class="hl opt">()));</span> +<span class="hl opt">}</span></pre> + + <p>The <tt>StorageImpl::save()</tt> method verifies that the shared data object is valid and the name not empty. Then it either + adds a new data record to the database or updates an existing one.</p> + + <pre class="hl"><span class="hl kwb">bool</span> StorageImpl<span class="hl opt">::</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 opt">{</span> + <span class="hl kwd">EVAF_TEST_X</span><span class="hl opt">(</span>data<span class="hl opt">,</span> <span class="hl str">"Data cannot be null"</span><span class="hl opt">);</span> + <span class="hl kwd">EVAF_TEST_X</span><span class="hl opt">(!</span>name<span class="hl opt">.</span><span class="hl kwd">isEmpty</span><span class="hl opt">(),</span> <span class="hl str">"Name cannot be empty"</span><span class="hl opt">);</span> + + <span class="hl slc">// Is it an update or a new data record?</span> + <span class="hl kwa">if</span> <span class="hl opt">(</span>mData<span class="hl opt">.</span><span class="hl kwd">constFind</span><span class="hl opt">(</span>name<span class="hl opt">) !=</span> mData<span class="hl opt">.</span><span class="hl kwd">constEnd</span><span class="hl opt">()) {</span> + <span class="hl slc">// This is an update</span> + <span class="hl kwa">if</span> <span class="hl opt">(</span>data<span class="hl opt">-></span><span class="hl kwd">modified</span><span class="hl opt">()) {</span> + QSqlQuery <span class="hl kwd">q</span><span class="hl opt">(</span>mDb<span class="hl opt">);</span> + <span class="hl kwa">if</span> <span class="hl opt">(!</span>q<span class="hl opt">.</span><span class="hl kwd">exec</span><span class="hl opt">(</span><span class="hl kwd">QString</span><span class="hl opt">(</span><span class="hl str">"UPDATE data SET length =</span> <span class="hl esc">\'</span><span class="hl str">%1</span><span class="hl esc">\'</span><span class="hl str">, flags =</span> <span class="hl esc">\'</span><span class="hl str">%2</span><span class="hl esc">\'</span> <span class="hl str">WHERE name =</span> <span class="hl esc">\'</span><span class="hl str">%3</span><span class="hl esc">\'</span><span class="hl str">;"</span><span class="hl opt">)</span> + <span class="hl opt">.</span><span class="hl kwd">arg</span><span class="hl opt">(</span>data<span class="hl opt">-></span><span class="hl kwd">length</span><span class="hl opt">()).</span><span class="hl kwd">arg</span><span class="hl opt">(</span>data<span class="hl opt">-></span><span class="hl kwd">flags</span><span class="hl opt">()).</span><span class="hl kwd">arg</span><span class="hl opt">(</span>name<span class="hl opt">))) {</span> + QSqlError err <span class="hl opt">=</span> mDb<span class="hl opt">.</span><span class="hl kwd">lastError</span><span class="hl opt">();</span> + <span class="hl kwd">EVAF_ERROR</span><span class="hl opt">(</span><span class="hl str">"Failed to update</span> <span class="hl esc">\'</span><span class="hl str">%s</span><span class="hl esc">\'</span> <span class="hl str">: %s"</span><span class="hl opt">,</span> <span class="hl kwd">qPrintable</span><span class="hl opt">(</span>name<span class="hl opt">),</span> <span class="hl kwd">qPrintable</span><span class="hl opt">(</span>err<span class="hl opt">.</span><span class="hl kwd">text</span><span class="hl opt">()));</span> + <span class="hl kwa">return false</span><span class="hl opt">;</span> + <span class="hl opt">}</span> + <span class="hl opt">}</span> + <span class="hl opt">}</span> + <span class="hl kwa">else</span> <span class="hl opt">{</span> + <span class="hl slc">// Store to the database</span> + QSqlQuery <span class="hl kwd">q</span><span class="hl opt">(</span>mDb<span class="hl opt">);</span> + <span class="hl kwa">if</span> <span class="hl opt">(!</span>q<span class="hl opt">.</span><span class="hl kwd">exec</span><span class="hl opt">(</span><span class="hl kwd">QString</span><span class="hl opt">(</span><span class="hl str">"INSERT INTO data (name, length, flags) VALUES (</span><span class="hl esc">\'</span><span class="hl str">%1</span><span class="hl esc">\'</span><span class="hl str">, %2, %3);"</span><span class="hl opt">)</span> + <span class="hl opt">.</span><span class="hl kwd">arg</span><span class="hl opt">(</span>name<span class="hl opt">).</span><span class="hl kwd">arg</span><span class="hl opt">(</span>data<span class="hl opt">-></span><span class="hl kwd">length</span><span class="hl opt">())</span> + <span class="hl opt">.</span><span class="hl kwd">arg</span><span class="hl opt">(</span><span class="hl kwb">int</span><span class="hl opt">(</span>data<span class="hl opt">-></span><span class="hl kwd">flags</span><span class="hl opt">())))) {</span> + QSqlError err <span class="hl opt">=</span> mDb<span class="hl opt">.</span><span class="hl kwd">lastError</span><span class="hl opt">();</span> + <span class="hl kwd">EVAF_ERROR</span><span class="hl opt">(</span><span class="hl str">"Failed to insert</span> <span class="hl esc">\'</span><span class="hl str">%s</span><span class="hl esc">\'</span> <span class="hl str">: %s"</span><span class="hl opt">,</span> <span class="hl kwd">qPrintable</span><span class="hl opt">(</span>name<span class="hl opt">),</span> <span class="hl kwd">qPrintable</span><span class="hl opt">(</span>err<span class="hl opt">.</span><span class="hl kwd">text</span><span class="hl opt">()));</span> + <span class="hl kwa">return false</span><span class="hl opt">;</span> + <span class="hl opt">}</span> + + <span class="hl slc">// Store also into the local hash</span> + mData<span class="hl opt">.</span><span class="hl kwd">insert</span><span class="hl opt">(</span>name<span class="hl opt">,</span> data<span class="hl opt">);</span> + + <span class="hl slc">// Reset the model</span> + <span class="hl kwd">reset</span><span class="hl opt">();</span> + <span class="hl opt">}</span> + + data<span class="hl opt">-></span><span class="hl kwd">reset</span><span class="hl opt">();</span> + + <span class="hl kwa">return true</span><span class="hl opt">;</span> +<span class="hl opt">}</span></pre> + + <p>Calling the <tt>reset()</tt> method resets the <tt>QAbstractItemModel</tt> data model and assures that the associated widget + updates the <tt>QCompleter</tt> with a fresh list of auto completion words. Resetting the data model in this case is fine as + long as the data model is simple and the list short. The proper way would be finding out the actual insertion point and using + <tt>beginInsertRows()</tt> and <tt>endInsertRows()</tt> methods.</p> + + <p>Querying data is much simpler thanks to the internal <tt>QMap</tt> container:</p> + + <pre class="hl">QExplicitlySharedDataPointer<span class="hl opt"><</span>Storage<span class="hl opt">::</span>Data<span class="hl opt">></span> StorageImpl<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> + 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>const_iterator it <span class="hl opt">=</span> mData<span class="hl opt">.</span><span class="hl kwd">constFind</span><span class="hl opt">(</span>name<span class="hl opt">);</span> + <span class="hl kwa">if</span> <span class="hl opt">(</span>it <span class="hl opt">!=</span> mData<span class="hl opt">.</span><span class="hl kwd">constEnd</span><span class="hl opt">())</span> + <span class="hl kwa">return</span> it<span class="hl opt">.</span><span class="hl kwd">value</span><span class="hl opt">();</span> + <span class="hl kwa">else</span> + <span class="hl kwa">return</span> QExplicitlySharedDataPointer<span class="hl opt"><</span>Storage<span class="hl opt">::</span>Data<span class="hl opt">>();</span> +<span class="hl opt">}</span></pre> + + <p>We return an empty <tt>QExplicitlySharedDataPointer</tt> object if no data objects with the given name exists.</p> + + <p>The <tt>data()</tt> method returns names of data objects for the <tt>QCompleter</tt> auto completion list of words:</p> + + <pre class="hl">QVariant StorageImpl<span class="hl opt">::</span><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> <span class="hl kwb">const</span> +<span class="hl opt">{</span> + <span class="hl kwa">if</span> <span class="hl opt">(!</span>index<span class="hl opt">.</span><span class="hl kwd">isValid</span><span class="hl opt">() ||</span> index<span class="hl opt">.</span><span class="hl kwd">row</span><span class="hl opt">() <</span> <span class="hl num">0</span> <span class="hl opt">||</span> index<span class="hl opt">.</span><span class="hl kwd">row</span><span class="hl opt">() >=</span> mData<span class="hl opt">.</span><span class="hl kwd">size</span><span class="hl opt">() ||</span> index<span class="hl opt">.</span><span class="hl kwd">column</span><span class="hl opt">() !=</span> <span class="hl num">0</span><span class="hl opt">)</span> + <span class="hl kwa">return</span> <span class="hl kwd">QVariant</span><span class="hl opt">();</span> + + <span class="hl kwa">if</span> <span class="hl opt">(</span>role <span class="hl opt">==</span> Qt<span class="hl opt">::</span>EditRole <span class="hl opt">||</span> role <span class="hl opt">==</span> Qt<span class="hl opt">::</span>DisplayRole<span class="hl opt">)</span> + <span class="hl kwa">return</span> mData<span class="hl opt">.</span><span class="hl kwd">keys</span><span class="hl opt">().</span><span class="hl kwd">at</span><span class="hl opt">(</span>index<span class="hl opt">.</span><span class="hl kwd">row</span><span class="hl opt">());</span> + + <span class="hl kwa">return</span> <span class="hl kwd">QVariant</span><span class="hl opt">();</span> +<span class="hl opt">}</span></pre> + + <p>The <tt>createTabled()</tt> method creates the <tt>data</tt> table if it does not exist. This function could be improved to + alter the <tt>data</tt> table if it exists, but is from an older version. Right now we assume that if the table exists, it + is good for our application:</p> + + <pre class="hl"><span class="hl kwb">bool</span> StorageImpl<span class="hl opt">::</span><span class="hl kwd">createTables</span><span class="hl opt">()</span> +<span class="hl opt">{</span> + QSqlQuery <span class="hl kwd">q</span><span class="hl opt">(</span>mDb<span class="hl opt">);</span> + <span class="hl kwa">if</span> <span class="hl opt">(!</span>q<span class="hl opt">.</span><span class="hl kwd">exec</span><span class="hl opt">(</span><span class="hl str">"SELECT name FROM sqlite_master WHERE type=</span><span class="hl esc">\'</span><span class="hl str">table</span><span class="hl esc">\'</span> <span class="hl str">AND name=</span><span class="hl esc">\'</span><span class="hl str">data</span><span class="hl esc">\'</span><span class="hl str">;"</span><span class="hl opt">)) {</span> + QSqlError err <span class="hl opt">=</span> mDb<span class="hl opt">.</span><span class="hl kwd">lastError</span><span class="hl opt">();</span> + <span class="hl kwd">EVAF_ERROR</span><span class="hl opt">(</span><span class="hl str">"Failed to query database : %s"</span><span class="hl opt">,</span> <span class="hl kwd">qPrintable</span><span class="hl opt">(</span>err<span class="hl opt">.</span><span class="hl kwd">text</span><span class="hl opt">()));</span> + <span class="hl kwa">return false</span><span class="hl opt">;</span> + <span class="hl opt">}</span> + + <span class="hl kwa">if</span> <span class="hl opt">(</span>q<span class="hl opt">.</span><span class="hl kwd">isActive</span><span class="hl opt">() &&</span> q<span class="hl opt">.</span><span class="hl kwd">isSelect</span><span class="hl opt">() &&</span> q<span class="hl opt">.</span><span class="hl kwd">first</span><span class="hl opt">())</span> + <span class="hl kwa">return true</span><span class="hl opt">;</span> <span class="hl slc">// We already have a table called 'data'</span> + + <span class="hl slc">// Create the 'data' table</span> + <span class="hl kwa">if</span> <span class="hl opt">(!</span>q<span class="hl opt">.</span><span class="hl kwd">exec</span><span class="hl opt">(</span><span class="hl str">"CREATE TABLE data (name text primary key not null, length integer, flags integer);"</span><span class="hl opt">)) {</span> + QSqlError err <span class="hl opt">=</span> mDb<span class="hl opt">.</span><span class="hl kwd">lastError</span><span class="hl opt">();</span> + <span class="hl kwd">EVAF_ERROR</span><span class="hl opt">(</span><span class="hl str">"Failed to create table</span> <span class="hl esc">\'</span><span class="hl str">data</span><span class="hl esc">\'</span> <span class="hl str">: %s"</span><span class="hl opt">,</span> <span class="hl kwd">qPrintable</span><span class="hl opt">(</span>err<span class="hl opt">.</span><span class="hl kwd">text</span><span class="hl opt">()));</span> + <span class="hl kwa">return false</span><span class="hl opt">;</span> + <span class="hl opt">}</span> + + <span class="hl kwa">return true</span><span class="hl opt">;</span> +<span class="hl opt">}</span></pre> + + <p>Finally, the <tt>loadData()</tt> method loads all the data records from the database to the memory:</p> + + <pre class="hl"><span class="hl kwb">bool</span> StorageImpl<span class="hl opt">::</span><span class="hl kwd">loadData</span><span class="hl opt">()</span> +<span class="hl opt">{</span> + QSqlQuery <span class="hl kwd">q</span><span class="hl opt">(</span>mDb<span class="hl opt">);</span> + <span class="hl kwa">if</span> <span class="hl opt">(!</span>q<span class="hl opt">.</span><span class="hl kwd">exec</span><span class="hl opt">(</span><span class="hl str">"SELECT name, length, flags FROM data;"</span><span class="hl opt">)) {</span> + QSqlError err <span class="hl opt">=</span> mDb<span class="hl opt">.</span><span class="hl kwd">lastError</span><span class="hl opt">();</span> + <span class="hl kwd">EVAF_ERROR</span><span class="hl opt">(</span><span class="hl str">"Failed to query database : %s"</span><span class="hl opt">,</span> <span class="hl kwd">qPrintable</span><span class="hl opt">(</span>err<span class="hl opt">.</span><span class="hl kwd">text</span><span class="hl opt">()));</span> + <span class="hl kwa">return false</span><span class="hl opt">;</span> + <span class="hl opt">}</span> + + <span class="hl kwa">while</span> <span class="hl opt">(</span>q<span class="hl opt">.</span><span class="hl kwd">next</span><span class="hl opt">()) {</span> + QString name <span class="hl opt">=</span> q<span class="hl opt">.</span><span class="hl kwd">value</span><span class="hl opt">(</span><span class="hl num">0</span><span class="hl opt">).</span><span class="hl kwd">toString</span><span class="hl opt">();</span> + QExplicitlySharedDataPointer<span class="hl opt"><</span>Storage<span class="hl opt">::</span>Data<span class="hl opt">></span> <span class="hl kwd">data</span><span class="hl opt">(</span><span class="hl kwa">new</span> Storage<span class="hl opt">::</span><span class="hl kwd">Data</span><span class="hl opt">(</span>name<span class="hl opt">,</span> q<span class="hl opt">.</span><span class="hl kwd">value</span><span class="hl opt">(</span><span class="hl num">1</span><span class="hl opt">).</span><span class="hl kwd">toInt</span><span class="hl opt">(),</span> <span class="hl kwd">uint</span><span class="hl opt">(</span>q<span class="hl opt">.</span><span class="hl kwd">value</span><span class="hl opt">(</span><span class="hl num">2</span><span class="hl opt">).</span><span class="hl kwd">toInt</span><span class="hl opt">())));</span> + mData<span class="hl opt">.</span><span class="hl kwd">insert</span><span class="hl opt">(</span>name<span class="hl opt">,</span> data<span class="hl opt">);</span> + <span class="hl opt">}</span> + + <span class="hl kwd">reset</span><span class="hl opt">();</span> + + <span class="hl kwa">return true</span><span class="hl opt">;</span> +<span class="hl opt">}</span></pre> + + <p>Resetting the <tt>QAbstractItemModel</tt> data model here is ok, becase before loading any data the model is supposed to be + empty.</p> + + <p>Here is the complete <tt>module.cpp</tt> file: + + <pre class="hl"><span class="hl com">/**</span> +<span class="hl com"> * @file PswGen/Storage/module.cpp</span> +<span class="hl com"> */</span> + +<span class="hl ppc">#include</span> <span class="hl pps">"module.h"</span><span class="hl ppc"></span> +<span class="hl ppc">#include</span> <span class="hl pps">"version.h"</span><span class="hl ppc"></span> + +<span class="hl ppc">#include <Common/Globals></span> +<span class="hl ppc">#include <Common/iLogger></span> +<span class="hl ppc">#include <Common/iRegistry></span> +<span class="hl ppc">#include <Common/iApp></span> + +<span class="hl ppc">#include <QtCore></span> +<span class="hl ppc">#include <QtSql/QtSql></span> + +<span class="hl kwd">VER_EXPORT_VERSION_INFO</span><span class="hl opt">()</span> +<span class="hl kwd">Q_EXPORT_PLUGIN2</span><span class="hl opt">(</span>VER_MODULE_NAME_STR<span class="hl opt">,</span> eVaf<span class="hl opt">::</span>PswGen<span class="hl opt">::</span>Storage<span class="hl opt">::</span>Module<span class="hl opt">)</span> + +<span class="hl kwa">using namespace</span> eVaf<span class="hl opt">;</span> +<span class="hl kwa">using namespace</span> eVaf<span class="hl opt">::</span>PswGen<span class="hl opt">;</span> +<span class="hl kwa">using namespace</span> eVaf<span class="hl opt">::</span>PswGen<span class="hl opt">::</span>Storage<span class="hl opt">;</span> + +Module<span class="hl opt">::</span><span class="hl kwd">Module</span><span class="hl opt">()</span> + <span class="hl opt">:</span> Plugins<span class="hl opt">::</span><span class="hl kwd">iPlugin</span><span class="hl opt">()</span> + <span class="hl opt">,</span> <span class="hl kwd">mReady</span><span class="hl opt">(</span><span class="hl kwa">false</span><span class="hl opt">)</span> +<span class="hl opt">{</span> + <span class="hl kwd">setObjectName</span><span class="hl opt">(</span><span class="hl kwd">QString</span><span class="hl opt">(</span><span class="hl str">"%1.%2"</span><span class="hl opt">).</span><span class="hl kwd">arg</span><span class="hl opt">(</span>VER_MODULE_NAME_STR<span class="hl opt">).</span><span class="hl kwd">arg</span><span class="hl opt">(</span>__FUNCTION__<span class="hl opt">));</span> + + mStorage <span class="hl opt">=</span> <span class="hl kwa">new</span> Internal<span class="hl opt">::</span>StorageImpl<span class="hl opt">;</span> + + <span class="hl kwd">EVAF_INFO</span><span class="hl opt">(</span><span class="hl str">"%s created"</span><span class="hl opt">,</span> <span class="hl kwd">qPrintable</span><span class="hl opt">(</span><span class="hl kwd">objectName</span><span class="hl opt">()));</span> +<span class="hl opt">}</span> + +Module<span class="hl opt">::~</span><span class="hl kwd">Module</span><span class="hl opt">()</span> +<span class="hl opt">{</span> + <span class="hl kwa">delete</span> mStorage<span class="hl opt">;</span> + + <span class="hl kwd">EVAF_INFO</span><span class="hl opt">(</span><span class="hl str">"%s destroyed"</span><span class="hl opt">,</span> <span class="hl kwd">qPrintable</span><span class="hl opt">(</span><span class="hl kwd">objectName</span><span class="hl opt">()));</span> +<span class="hl opt">}</span> + +<span class="hl kwb">bool</span> Module<span class="hl opt">::</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> +<span class="hl opt">{</span> + <span class="hl kwd">Q_UNUSED</span><span class="hl opt">(</span>args<span class="hl opt">);</span> + + <span class="hl kwa">if</span> <span class="hl opt">(!</span>mStorage<span class="hl opt">-></span><span class="hl kwd">init</span><span class="hl opt">())</span> + <span class="hl kwa">return false</span><span class="hl opt">;</span> + + mReady <span class="hl opt">=</span> <span class="hl kwa">true</span><span class="hl opt">;</span> + + <span class="hl kwd">EVAF_INFO</span><span class="hl opt">(</span><span class="hl str">"%s initialized"</span><span class="hl opt">,</span> <span class="hl kwd">qPrintable</span><span class="hl opt">(</span><span class="hl kwd">objectName</span><span class="hl opt">()));</span> + + <span class="hl kwa">return true</span><span class="hl opt">;</span> +<span class="hl opt">}</span> + +<span class="hl kwb">void</span> Module<span class="hl opt">::</span><span class="hl kwd">done</span><span class="hl opt">()</span> +<span class="hl opt">{</span> + mReady <span class="hl opt">=</span> <span class="hl kwa">false</span><span class="hl opt">;</span> + + mStorage<span class="hl opt">-></span><span class="hl kwd">done</span><span class="hl opt">();</span> + + <span class="hl kwd">EVAF_INFO</span><span class="hl opt">(</span><span class="hl str">"%s finalized"</span><span class="hl opt">,</span> <span class="hl kwd">qPrintable</span><span class="hl opt">(</span><span class="hl kwd">objectName</span><span class="hl opt">()));</span> +<span class="hl opt">}</span> + +<span class="hl kwa">using namespace</span> eVaf<span class="hl opt">::</span>PswGen<span class="hl opt">::</span>Storage<span class="hl opt">::</span>Internal<span class="hl opt">;</span> + +<span class="hl kwb">char const</span> <span class="hl opt">*</span> <span class="hl kwb">const</span> StorageImpl<span class="hl opt">::</span>DbConnectionName <span class="hl opt">=</span> <span class="hl str">"PswGenDB"</span><span class="hl opt">;</span> + +<span class="hl kwb">char const</span> <span class="hl opt">*</span> <span class="hl kwb">const</span> StorageImpl<span class="hl opt">::</span>DbName <span class="hl opt">=</span> <span class="hl str">"PswGen.sqlite"</span><span class="hl opt">;</span> + +StorageImpl<span class="hl opt">::</span><span class="hl kwd">StorageImpl</span><span class="hl opt">()</span> + <span class="hl opt">:</span> <span class="hl kwd">QAbstractListModel</span><span class="hl opt">()</span> +<span class="hl opt">{</span> + <span class="hl kwd">setObjectName</span><span class="hl opt">(</span><span class="hl kwd">QString</span><span class="hl opt">(</span><span class="hl str">"%1.iGenerator"</span><span class="hl opt">).</span><span class="hl kwd">arg</span><span class="hl opt">(</span>VER_MODULE_NAME_STR<span class="hl opt">));</span> + + <span class="hl kwd">EVAF_INFO</span><span class="hl opt">(</span><span class="hl str">"%s created"</span><span class="hl opt">,</span> <span class="hl kwd">qPrintable</span><span class="hl opt">(</span><span class="hl kwd">objectName</span><span class="hl opt">()));</span> +<span class="hl opt">}</span> + +StorageImpl<span class="hl opt">::~</span><span class="hl kwd">StorageImpl</span><span class="hl opt">()</span> +<span class="hl opt">{</span> + <span class="hl kwd">EVAF_INFO</span><span class="hl opt">(</span><span class="hl str">"%s destroyed"</span><span class="hl opt">,</span> <span class="hl kwd">qPrintable</span><span class="hl opt">(</span><span class="hl kwd">objectName</span><span class="hl opt">()));</span> +<span class="hl opt">}</span> + +<span class="hl kwb">bool</span> StorageImpl<span class="hl opt">::</span><span class="hl kwd">init</span><span class="hl opt">()</span> +<span class="hl opt">{</span> + <span class="hl slc">// Open the database</span> + <span class="hl kwa">if</span> <span class="hl opt">(!</span>QSqlDatabase<span class="hl opt">::</span><span class="hl kwd">contains</span><span class="hl opt">(</span>DbConnectionName<span class="hl opt">)) {</span> + <span class="hl slc">// No database connection yet</span> + mDb <span class="hl opt">=</span> QSqlDatabase<span class="hl opt">::</span><span class="hl kwd">addDatabase</span><span class="hl opt">(</span><span class="hl str">"QSQLITE"</span><span class="hl opt">,</span> DbConnectionName<span class="hl opt">);</span> + mDb<span class="hl opt">.</span><span class="hl kwd">setDatabaseName</span><span class="hl opt">(</span>Common<span class="hl opt">::</span>iApp<span class="hl opt">::</span><span class="hl kwd">instance</span><span class="hl opt">()-></span><span class="hl kwd">dataRootDir</span><span class="hl opt">() +</span> DbName<span class="hl opt">);</span> + <span class="hl kwa">if</span> <span class="hl opt">(!</span>mDb<span class="hl opt">.</span><span class="hl kwd">open</span><span class="hl opt">()) {</span> + QSqlError err <span class="hl opt">=</span> mDb<span class="hl opt">.</span><span class="hl kwd">lastError</span><span class="hl opt">();</span> + <span class="hl kwd">EVAF_ERROR</span><span class="hl opt">(</span><span class="hl str">"Failed to open database : %s"</span><span class="hl opt">,</span> <span class="hl kwd">qPrintable</span><span class="hl opt">(</span>err<span class="hl opt">.</span><span class="hl kwd">text</span><span class="hl opt">()));</span> + <span class="hl kwa">return false</span><span class="hl opt">;</span> + <span class="hl opt">}</span> + <span class="hl opt">}</span> + <span class="hl kwa">else</span> <span class="hl opt">{</span> + <span class="hl slc">// Database connection already exists</span> + mDb <span class="hl opt">=</span> QSqlDatabase<span class="hl opt">::</span><span class="hl kwd">database</span><span class="hl opt">(</span>DbConnectionName<span class="hl opt">);</span> + <span class="hl opt">}</span> + + <span class="hl slc">// Create tables if necessary</span> + <span class="hl kwa">if</span> <span class="hl opt">(!</span><span class="hl kwd">createTables</span><span class="hl opt">())</span> + <span class="hl kwa">return false</span><span class="hl opt">;</span> + + <span class="hl slc">// Load data</span> + <span class="hl kwa">if</span> <span class="hl opt">(!</span><span class="hl kwd">loadData</span><span class="hl opt">())</span> + <span class="hl kwa">return false</span><span class="hl opt">;</span> + + <span class="hl slc">/// Register our interface</span> + Common<span class="hl opt">::</span>iRegistry<span class="hl opt">::</span><span class="hl kwd">instance</span><span class="hl opt">()-></span><span class="hl kwd">registerInterface</span><span class="hl opt">(</span><span class="hl str">"iStorage"</span><span class="hl opt">,</span> <span class="hl kwa">this</span><span class="hl opt">);</span> + + <span class="hl kwd">EVAF_INFO</span><span class="hl opt">(</span><span class="hl str">"%s initialized"</span><span class="hl opt">,</span> <span class="hl kwd">qPrintable</span><span class="hl opt">(</span><span class="hl kwd">objectName</span><span class="hl opt">()));</span> + + <span class="hl kwa">return true</span><span class="hl opt">;</span> +<span class="hl opt">}</span> + +<span class="hl kwb">void</span> StorageImpl<span class="hl opt">::</span><span class="hl kwd">done</span><span class="hl opt">()</span> +<span class="hl opt">{</span> + mData<span class="hl opt">.</span><span class="hl kwd">clear</span><span class="hl opt">();</span> + <span class="hl kwd">EVAF_INFO</span><span class="hl opt">(</span><span class="hl str">"%s finalized"</span><span class="hl opt">,</span> <span class="hl kwd">qPrintable</span><span class="hl opt">(</span><span class="hl kwd">objectName</span><span class="hl opt">()));</span> +<span class="hl opt">}</span> + +<span class="hl kwb">bool</span> StorageImpl<span class="hl opt">::</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 opt">{</span> + <span class="hl kwd">EVAF_TEST_X</span><span class="hl opt">(</span>data<span class="hl opt">,</span> <span class="hl str">"Data cannot be null"</span><span class="hl opt">);</span> + <span class="hl kwd">EVAF_TEST_X</span><span class="hl opt">(!</span>name<span class="hl opt">.</span><span class="hl kwd">isEmpty</span><span class="hl opt">(),</span> <span class="hl str">"Name cannot be empty"</span><span class="hl opt">);</span> + + <span class="hl slc">// Is it an update or a new data record?</span> + <span class="hl kwa">if</span> <span class="hl opt">(</span>mData<span class="hl opt">.</span><span class="hl kwd">constFind</span><span class="hl opt">(</span>name<span class="hl opt">) !=</span> mData<span class="hl opt">.</span><span class="hl kwd">constEnd</span><span class="hl opt">()) {</span> + <span class="hl slc">// This is an update</span> + <span class="hl kwa">if</span> <span class="hl opt">(</span>data<span class="hl opt">-></span><span class="hl kwd">modified</span><span class="hl opt">()) {</span> + QSqlQuery <span class="hl kwd">q</span><span class="hl opt">(</span>mDb<span class="hl opt">);</span> + <span class="hl kwa">if</span> <span class="hl opt">(!</span>q<span class="hl opt">.</span><span class="hl kwd">exec</span><span class="hl opt">(</span><span class="hl kwd">QString</span><span class="hl opt">(</span><span class="hl str">"UPDATE data SET length =</span> <span class="hl esc">\'</span><span class="hl str">%1</span><span class="hl esc">\'</span><span class="hl str">, flags =</span> <span class="hl esc">\'</span><span class="hl str">%2</span><span class="hl esc">\'</span> <span class="hl str">WHERE name =</span> <span class="hl esc">\'</span><span class="hl str">%3</span><span class="hl esc">\'</span><span class="hl str">;"</span><span class="hl opt">)</span> + <span class="hl opt">.</span><span class="hl kwd">arg</span><span class="hl opt">(</span>data<span class="hl opt">-></span><span class="hl kwd">length</span><span class="hl opt">()).</span><span class="hl kwd">arg</span><span class="hl opt">(</span>data<span class="hl opt">-></span><span class="hl kwd">flags</span><span class="hl opt">()).</span><span class="hl kwd">arg</span><span class="hl opt">(</span>name<span class="hl opt">))) {</span> + QSqlError err <span class="hl opt">=</span> mDb<span class="hl opt">.</span><span class="hl kwd">lastError</span><span class="hl opt">();</span> + <span class="hl kwd">EVAF_ERROR</span><span class="hl opt">(</span><span class="hl str">"Failed to update</span> <span class="hl esc">\'</span><span class="hl str">%s</span><span class="hl esc">\'</span> <span class="hl str">: %s"</span><span class="hl opt">,</span> <span class="hl kwd">qPrintable</span><span class="hl opt">(</span>name<span class="hl opt">),</span> <span class="hl kwd">qPrintable</span><span class="hl opt">(</span>err<span class="hl opt">.</span><span class="hl kwd">text</span><span class="hl opt">()));</span> + <span class="hl kwa">return false</span><span class="hl opt">;</span> + <span class="hl opt">}</span> + <span class="hl opt">}</span> + <span class="hl opt">}</span> + <span class="hl kwa">else</span> <span class="hl opt">{</span> + <span class="hl slc">// Store to the database</span> + QSqlQuery <span class="hl kwd">q</span><span class="hl opt">(</span>mDb<span class="hl opt">);</span> + <span class="hl kwa">if</span> <span class="hl opt">(!</span>q<span class="hl opt">.</span><span class="hl kwd">exec</span><span class="hl opt">(</span><span class="hl kwd">QString</span><span class="hl opt">(</span><span class="hl str">"INSERT INTO data (name, length, flags) VALUES (</span><span class="hl esc">\'</span><span class="hl str">%1</span><span class="hl esc">\'</span><span class="hl str">, %2, %3);"</span><span class="hl opt">)</span> + <span class="hl opt">.</span><span class="hl kwd">arg</span><span class="hl opt">(</span>name<span class="hl opt">).</span><span class="hl kwd">arg</span><span class="hl opt">(</span>data<span class="hl opt">-></span><span class="hl kwd">length</span><span class="hl opt">())</span> + <span class="hl opt">.</span><span class="hl kwd">arg</span><span class="hl opt">(</span><span class="hl kwb">int</span><span class="hl opt">(</span>data<span class="hl opt">-></span><span class="hl kwd">flags</span><span class="hl opt">())))) {</span> + QSqlError err <span class="hl opt">=</span> mDb<span class="hl opt">.</span><span class="hl kwd">lastError</span><span class="hl opt">();</span> + <span class="hl kwd">EVAF_ERROR</span><span class="hl opt">(</span><span class="hl str">"Failed to insert</span> <span class="hl esc">\'</span><span class="hl str">%s</span><span class="hl esc">\'</span> <span class="hl str">: %s"</span><span class="hl opt">,</span> <span class="hl kwd">qPrintable</span><span class="hl opt">(</span>name<span class="hl opt">),</span> <span class="hl kwd">qPrintable</span><span class="hl opt">(</span>err<span class="hl opt">.</span><span class="hl kwd">text</span><span class="hl opt">()));</span> + <span class="hl kwa">return false</span><span class="hl opt">;</span> + <span class="hl opt">}</span> + + <span class="hl slc">// Store also into the local hash</span> + mData<span class="hl opt">.</span><span class="hl kwd">insert</span><span class="hl opt">(</span>name<span class="hl opt">,</span> data<span class="hl opt">);</span> + + <span class="hl slc">// Reset the model</span> + <span class="hl kwd">reset</span><span class="hl opt">();</span> + <span class="hl opt">}</span> + + data<span class="hl opt">-></span><span class="hl kwd">reset</span><span class="hl opt">();</span> + + <span class="hl kwa">return true</span><span class="hl opt">;</span> +<span class="hl opt">}</span> + +QExplicitlySharedDataPointer<span class="hl opt"><</span>Storage<span class="hl opt">::</span>Data<span class="hl opt">></span> StorageImpl<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> + 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>const_iterator it <span class="hl opt">=</span> mData<span class="hl opt">.</span><span class="hl kwd">constFind</span><span class="hl opt">(</span>name<span class="hl opt">);</span> + <span class="hl kwa">if</span> <span class="hl opt">(</span>it <span class="hl opt">!=</span> mData<span class="hl opt">.</span><span class="hl kwd">constEnd</span><span class="hl opt">())</span> + <span class="hl kwa">return</span> it<span class="hl opt">.</span><span class="hl kwd">value</span><span class="hl opt">();</span> + <span class="hl kwa">else</span> + <span class="hl kwa">return</span> QExplicitlySharedDataPointer<span class="hl opt"><</span>Storage<span class="hl opt">::</span>Data<span class="hl opt">>();</span> +<span class="hl opt">}</span> + +QVariant StorageImpl<span class="hl opt">::</span><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> <span class="hl kwb">const</span> +<span class="hl opt">{</span> + <span class="hl kwa">if</span> <span class="hl opt">(!</span>index<span class="hl opt">.</span><span class="hl kwd">isValid</span><span class="hl opt">() ||</span> index<span class="hl opt">.</span><span class="hl kwd">row</span><span class="hl opt">() <</span> <span class="hl num">0</span> <span class="hl opt">||</span> index<span class="hl opt">.</span><span class="hl kwd">row</span><span class="hl opt">() >=</span> mData<span class="hl opt">.</span><span class="hl kwd">size</span><span class="hl opt">() ||</span> index<span class="hl opt">.</span><span class="hl kwd">column</span><span class="hl opt">() !=</span> <span class="hl num">0</span><span class="hl opt">)</span> + <span class="hl kwa">return</span> <span class="hl kwd">QVariant</span><span class="hl opt">();</span> + + <span class="hl kwa">if</span> <span class="hl opt">(</span>role <span class="hl opt">==</span> Qt<span class="hl opt">::</span>EditRole <span class="hl opt">||</span> role <span class="hl opt">==</span> Qt<span class="hl opt">::</span>DisplayRole<span class="hl opt">)</span> + <span class="hl kwa">return</span> mData<span class="hl opt">.</span><span class="hl kwd">keys</span><span class="hl opt">().</span><span class="hl kwd">at</span><span class="hl opt">(</span>index<span class="hl opt">.</span><span class="hl kwd">row</span><span class="hl opt">());</span> + + <span class="hl kwa">return</span> <span class="hl kwd">QVariant</span><span class="hl opt">();</span> +<span class="hl opt">}</span> + +<span class="hl kwb">bool</span> StorageImpl<span class="hl opt">::</span><span class="hl kwd">createTables</span><span class="hl opt">()</span> +<span class="hl opt">{</span> + QSqlQuery <span class="hl kwd">q</span><span class="hl opt">(</span>mDb<span class="hl opt">);</span> + <span class="hl kwa">if</span> <span class="hl opt">(!</span>q<span class="hl opt">.</span><span class="hl kwd">exec</span><span class="hl opt">(</span><span class="hl str">"SELECT name FROM sqlite_master WHERE type=</span><span class="hl esc">\'</span><span class="hl str">table</span><span class="hl esc">\'</span> <span class="hl str">AND name=</span><span class="hl esc">\'</span><span class="hl str">data</span><span class="hl esc">\'</span><span class="hl str">;"</span><span class="hl opt">)) {</span> + QSqlError err <span class="hl opt">=</span> mDb<span class="hl opt">.</span><span class="hl kwd">lastError</span><span class="hl opt">();</span> + <span class="hl kwd">EVAF_ERROR</span><span class="hl opt">(</span><span class="hl str">"Failed to query database : %s"</span><span class="hl opt">,</span> <span class="hl kwd">qPrintable</span><span class="hl opt">(</span>err<span class="hl opt">.</span><span class="hl kwd">text</span><span class="hl opt">()));</span> + <span class="hl kwa">return false</span><span class="hl opt">;</span> + <span class="hl opt">}</span> + + <span class="hl kwa">if</span> <span class="hl opt">(</span>q<span class="hl opt">.</span><span class="hl kwd">isActive</span><span class="hl opt">() &&</span> q<span class="hl opt">.</span><span class="hl kwd">isSelect</span><span class="hl opt">() &&</span> q<span class="hl opt">.</span><span class="hl kwd">first</span><span class="hl opt">())</span> + <span class="hl kwa">return true</span><span class="hl opt">;</span> <span class="hl slc">// We already have a table called 'data'</span> + + <span class="hl slc">// Create the 'data' table</span> + <span class="hl kwa">if</span> <span class="hl opt">(!</span>q<span class="hl opt">.</span><span class="hl kwd">exec</span><span class="hl opt">(</span><span class="hl str">"CREATE TABLE data (name text primary key not null, length integer, flags integer);"</span><span class="hl opt">)) {</span> + QSqlError err <span class="hl opt">=</span> mDb<span class="hl opt">.</span><span class="hl kwd">lastError</span><span class="hl opt">();</span> + <span class="hl kwd">EVAF_ERROR</span><span class="hl opt">(</span><span class="hl str">"Failed to create table</span> <span class="hl esc">\'</span><span class="hl str">data</span><span class="hl esc">\'</span> <span class="hl str">: %s"</span><span class="hl opt">,</span> <span class="hl kwd">qPrintable</span><span class="hl opt">(</span>err<span class="hl opt">.</span><span class="hl kwd">text</span><span class="hl opt">()));</span> + <span class="hl kwa">return false</span><span class="hl opt">;</span> + <span class="hl opt">}</span> + + <span class="hl kwa">return true</span><span class="hl opt">;</span> +<span class="hl opt">}</span> + +<span class="hl kwb">bool</span> StorageImpl<span class="hl opt">::</span><span class="hl kwd">loadData</span><span class="hl opt">()</span> +<span class="hl opt">{</span> + QSqlQuery <span class="hl kwd">q</span><span class="hl opt">(</span>mDb<span class="hl opt">);</span> + <span class="hl kwa">if</span> <span class="hl opt">(!</span>q<span class="hl opt">.</span><span class="hl kwd">exec</span><span class="hl opt">(</span><span class="hl str">"SELECT name, length, flags FROM data;"</span><span class="hl opt">)) {</span> + QSqlError err <span class="hl opt">=</span> mDb<span class="hl opt">.</span><span class="hl kwd">lastError</span><span class="hl opt">();</span> + <span class="hl kwd">EVAF_ERROR</span><span class="hl opt">(</span><span class="hl str">"Failed to query database : %s"</span><span class="hl opt">,</span> <span class="hl kwd">qPrintable</span><span class="hl opt">(</span>err<span class="hl opt">.</span><span class="hl kwd">text</span><span class="hl opt">()));</span> + <span class="hl kwa">return false</span><span class="hl opt">;</span> + <span class="hl opt">}</span> + + <span class="hl kwa">while</span> <span class="hl opt">(</span>q<span class="hl opt">.</span><span class="hl kwd">next</span><span class="hl opt">()) {</span> + QString name <span class="hl opt">=</span> q<span class="hl opt">.</span><span class="hl kwd">value</span><span class="hl opt">(</span><span class="hl num">0</span><span class="hl opt">).</span><span class="hl kwd">toString</span><span class="hl opt">();</span> + QExplicitlySharedDataPointer<span class="hl opt"><</span>Storage<span class="hl opt">::</span>Data<span class="hl opt">></span> <span class="hl kwd">data</span><span class="hl opt">(</span><span class="hl kwa">new</span> Storage<span class="hl opt">::</span><span class="hl kwd">Data</span><span class="hl opt">(</span>name<span class="hl opt">,</span> q<span class="hl opt">.</span><span class="hl kwd">value</span><span class="hl opt">(</span><span class="hl num">1</span><span class="hl opt">).</span><span class="hl kwd">toInt</span><span class="hl opt">(),</span> <span class="hl kwd">uint</span><span class="hl opt">(</span>q<span class="hl opt">.</span><span class="hl kwd">value</span><span class="hl opt">(</span><span class="hl num">2</span><span class="hl opt">).</span><span class="hl kwd">toInt</span><span class="hl opt">())));</span> + mData<span class="hl opt">.</span><span class="hl kwd">insert</span><span class="hl opt">(</span>name<span class="hl opt">,</span> data<span class="hl opt">);</span> + <span class="hl opt">}</span> + + <span class="hl kwd">reset</span><span class="hl opt">();</span> + + <span class="hl kwa">return true</span><span class="hl opt">;</span> +<span class="hl opt">}</span></pre> + + <p>Next -- <a href="pswgen08.html">Building Storage Module</a>.</p> + + </body> +</html> diff --git a/www/pswgen08.html b/www/pswgen08.html new file mode 100644 index 0000000..761927a --- /dev/null +++ b/www/pswgen08.html @@ -0,0 +1,99 @@ +<!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Transitional//EN" "http://www.w3.org/TR/xhtml1/DTD/xhtml1-transitional.dtd"> +<html lang="et" xmlns="http://www.w3.org/1999/xhtml" xml:lang="et"> + + <head> + <meta http-equiv="CONTENT-TYPE" content="text/html; charset=utf-8" /> + <title>eVaf Tutorial - 08 - Building Storage Module</title> + <meta name="Author" content="Enar Väikene" /> + <meta name="description" content="eVaf Tutorial" /> + <meta name="keywords" content="evaf c++ application development framework tutorial password generator" /> + <link rel="StyleSheet" href="evaf.css" type="text/css" media="all" /> + <link rel="StyleSheet" href="highlight.css" type="text/css" media="all" /> + </head> + + <body> + + <h1>eVaf Tutorial</h1> + + <h2>08 - Buiding Storage Module</h2> + + <h3>CMakeLists.txt</h3> + + <p>Copy an existing <tt>CMakeLists.txt</tt> file from the <tt>Generator</tt> module:</p> + + <pre>evaf/src/apps/PswGen/Storage $ <code>cp ../CMakeLists.txt .</code></pre> + + <p>We only need to modify the <tt>TARGET</tt> variable and set <tt>QT_USE_QTSQL</tt> to <tt>TRUE</tt>:</p> + + <pre class="hl"><span class="hl com"># Name of the target</span> +<span class="hl kwa">set</span><span class="hl opt">(</span>TARGET PswStorage<span class="hl opt">)</span> + +<span class="hl com"># Qt modules</span> +<span class="hl kwa">set</span><span class="hl opt">(</span>QT_USE_QTSQL TRUE<span class="hl opt">)</span></pre> + + <p>Here is the final <tt>CMakeLists.txt</tt> file:</p> + +<pre class="hl"><span class="hl com"># src/apps/PswGen/Storage/CMakeLists.txt</span> + +<span class="hl com"># Name of the target</span> +<span class="hl kwa">set</span><span class="hl opt">(</span>TARGET PswStorage<span class="hl opt">)</span> + +<span class="hl com"># Qt modules</span> +<span class="hl kwa">set</span><span class="hl opt">(</span>QT_USE_QTSQL TRUE<span class="hl opt">)</span> +<span class="hl kwa">set</span><span class="hl opt">(</span>QT_DONT_USE_QTGUI TRUE<span class="hl opt">)</span> +<span class="hl kwa">include</span><span class="hl opt">(</span><span class="hl kwd">${QT_USE_FILE}</span><span class="hl opt">)</span> + +<span class="hl com"># Include directories</span> +<span class="hl kwa">include_directories</span><span class="hl opt">(</span><span class="hl kwd">${eVaf_INCLUDE}<span class="hl opt">)</span> + +<span class="hl com"># Required eVaf libraries</span> +<span class="hl kwa">set</span><span class="hl opt">(</span>eVaf_LIBRARIES CommonLib PluginsLib<span class="hl opt">)</span> + +<span class="hl com"># Source files</span> +<span class="hl kwa">set</span><span class="hl opt">(</span>SRCS + module.cpp +<span class="hl opt">)</span> + +<span class="hl com"># Header files for the Qt meta-object compiler</span> +<span class="hl kwa">set</span><span class="hl opt">(</span>MOC_HDRS + module.h +<span class="hl opt">)</span> + +<span class="hl com"># Version info resource file for Windows builds</span> +<span class="hl kwa">if</span><span class="hl opt">(</span><span class="hl kwb">WIN32</span><span class="hl opt">)</span> + <span class="hl kwa">set</span><span class="hl opt">(</span>SRCS <span class="hl kwd">${SRCS}</span> version.rc<span class="hl opt">)</span> +<span class="hl kwa">endif</span><span class="hl opt">(</span><span class="hl kwb">WIN32</span><span class="hl opt">)</span> + +<span class="hl com"># Run the Qt meta-object compiler</span> +<span class="hl kwd">qt4_wrap_cpp</span><span class="hl opt">(</span>MOC_SRCS <span class="hl kwd">${MOC_HDRS}</span><span class="hl opt">)</span> + +<span class="hl com"># Compile the module</span> +<span class="hl kwa">add_library</span><span class="hl opt">(</span><span class="hl kwd">${TARGET}</span> <span class="hl kwb">SHARED</span> <span class="hl kwd">${SRCS} ${MOC_SRCS}</span><span class="hl opt">)</span> + +<span class="hl com"># Link the module</span> +<span class="hl kwa">target_link_libraries</span><span class="hl opt">(</span><span class="hl kwd">${TARGET} ${QT_LIBRARIES} ${eVaf_LIBRARIES}</span><span class="hl opt">)</span></pre> + + <p>Open the <tt>CMakeLists.txt</tt> file in the parent directory and add the command to include the <tt>Storage</tt> + sub-directory:</p> + + <pre class="hl"><span class="hl com"># src/apps/PswGen/CMakeLists.txt</span> +<span class="hl com"># ...</span> +<span class="hl kwa">add_subdirectory</span><span class="hl opt">(</span>Storage<span class="hl opt">)</span></pre> + + <h3>Building the module</h3> + + <p>Go to the previously made <tt>build</tt> directory and build the module:</p> + + <pre>evaf $ <code>cd build</code> +evaf/build $ <code>make PswStorage</code></pre> + + <p>Check the <tt>bin</tt> directory, which should now contain a new library:</p> + + <pre>evaf/build $ <code>ls bin</code> +libCommonLib.so* libPluginsLib.so* libPswGen.so* <b>libPswStorage.so*</b> +evaf/build $</pre> + + <p>In the next section <a href="pswgen09.html">09 - GUI Module</a> we write the Graphical User Interface Module.</p> + + </body> +</html> -- 2.49.0