+<!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>