<h3>iGenerator interface</h3>
- <p>We start by defining the interface for the module. For this create the file <tt>igenerator.h</tt> in the
+ <p>We start by defining the interface for the module and create the file <tt>igenerator.h</tt> in the
<tt>src/apps/pswGen/Generator</tt> directory:</p>
<pre class="hl"><span class="hl com">/**</span>
<span class="hl ppc">#endif</span> <span class="hl slc">// igenerator.h</span><span class="hl ppc"></span></pre>
- <p>The interface class needs to be derived from <tt>QObject</tt> and we also need <tt>QString</tt> for input
- data and generated passwords:</p>
+ <p>We need to include some Qt header files -- <tt>QObject</tt> is almost always needed and <tt>QString</tt> we need for input data and generated
+ passwords:</p>
<pre class="hl"><span class="hl ppc">#include <QObject></span>
<span class="hl ppc">#include <QString></span></pre>
<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>We call the interface class <tt>iGenerator</tt>:
+ <p>We call the interface class <tt>iGenerator</tt>. For pure abstract classes I personally prefer using the <tt>struct</tt> keyword, but
+ <tt>class</tt> works as well if you remember to add the <tt>public</tt> keyword to make methods in the class public.</p>
- <pre class="hl"><span class="hl kwc">class</span> iGenerator <span class="hl opt">:</span> <span class="hl kwc">public</span> QObject
+ <pre class="hl"><span class="hl kwc">struct</span> iGenerator
<span class="hl opt">{</span>
- Q_OBJECT
-<span class="hl kwc">public</span><span class="hl opt">:</span>
-<span class="hl opt">};</span></pre>
-
- <p>All the interface classes need a default constructor and an empty virtual destructor. Do not perform any actions
- in these constructors and destructors. Instead, leave it up to the class that implements the interface.</p>
- <pre class="hl"><span class="hl slc">/// Interface constructor</span>
-<span class="hl kwd">iGenerator</span><span class="hl opt">() :</span> <span class="hl kwd">QObject</span><span class="hl opt">() {}</span>
-<span class="hl slc">/// Empty virtual destructor</span>
-<span class="hl kwc">virtual</span> <span class="hl opt">~</span><span class="hl kwd">iGenerator</span><span class="hl opt">() {}</span></pre>
+<span class="hl opt">};</span></pre>
- <p>Now we add the functionality to the interface and according to the specification we need two functions -- one that
+ <p>We add functionality to the interface and according to the specification we need two functions -- one that
generates passwords and another that returns the maximum length of the password:</p>
<pre class="hl"><span class="hl kwc">virtual</span> QString <span class="hl kwd">generatePassword</span><span class="hl opt">(</span>QString <span class="hl kwb">const</span> <span class="hl opt">&</span> name<span class="hl opt">,</span> QString <span class="hl kwb">const</span> <span class="hl opt">&</span> masterPassword<span class="hl opt">,</span> <span class="hl kwb">int</span> length<span class="hl opt">,</span> uint flags <span class="hl opt">=</span> <span class="hl num">0</span><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>
<p>I am training myself to use the style of writing declarations like <tt>"QString const &"</tt>, which refers to a non-mutable <tt>QString</tt> object similar to <tt>"int maxLength() const"</tt>, which is a function that does not modify the object's data members. Feel free to use the traditional way of writing <tt>"const QString &"</tt> if this looks weird to you.</p>
- <p>The <tt>iGenerator</tt> interface needs to be visible for other modules and marked for export. We do this by creating the <tt>src/apps/PswGen/Generator/lib.h file, which defines the <tt>PSWGEN_GENERATOR_EXPORT</tt> macro:</p>
- <pre class="hl"><span class="hl com">/**</span>
-<span class="hl com"> * @file src/apps/PswGen/Generator/lib.h</span>
-<span class="hl com"> */</span>
-<span class="hl ppc">#ifndef __PSWGEN_GENERATOR_LIB_H</span>
-<span class="hl ppc"># define __PSWGEN_GENERATOR_LIB_H</span>
-
-<span class="hl ppc">#include <QtCore/qglobal.h></span>
+ <p>We use the <tt>Q_DECLARE_INTERFACE</tt> macro to add Qt meta-data to the interface. eVaf interfaces are type-casted using the <tt>qobject_cast<>()</tt> template function and it requires meta-data to verify type and version of the interface. The <tt>Q_DECLARE_INTERFACE</tt> macro has to be
+ outside of any namespaces and we add it to the end of the file:</p>
-<span class="hl ppc">#if defined(PSWGEN_GENERATOR_LIBRARY)</span>
-<span class="hl ppc"># define PSWGEN_GENERATOR_EXPORT Q_DECL_EXPORT</span>
-<span class="hl ppc">#else</span>
-<span class="hl ppc"># define PSWGEN_GENERATOR_EXPORT Q_DECL_IMPORT</span>
-<span class="hl ppc">#endif</span>
-<span class="hl ppc">#endif</span> <span class="hl slc">// libgen.h</span><span class="hl ppc"></span></pre>
-
- <p>Then we include this new header file in our interface header file and modify the <tt>iGenerator</tt> class definition by adding
- the <tt>PSWGEN_GENERATOR_EXPORT</tt> macro to it:</p>
- <pre class="hl"><span class="hl ppc">#include</span> <span class="hl pps">"lib.h"</span><span class="hl ppc"></span>
-
-/// ...
-
-<span class="hl kwc">class</span> PSWGEN_GENERATOR_EXPORT iGenerator <span class="hl opt">:</span> <span class="hl kwc">public</span> QObject</pre>
+ <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>iGenerator<span class="hl opt">,</span> <span class="hl str">"eVaf.PswGen.iGenerator/1.0"</span><span class="hl opt">)</span></pre>
<p>This is pretty much all we need to add to the <tt>iGenerator</tt> interface and here is the final file:</p>
<span class="hl ppc">#ifndef __PSWGEN_GENERATOR_IGENERATOR_H</span>
<span class="hl ppc"># define __PSWGEN_GENERATOR_IGENERATOR_H</span>
-<span class="hl ppc">#include</span> <span class="hl pps">"lib.h"</span><span class="hl ppc"></span>
-
<span class="hl ppc">#include <QObject></span>
<span class="hl ppc">#include <QString></span>
<span class="hl kwa">namespace</span> PswGen <span class="hl opt">{</span>
<span class="hl com">/// Password generator interface.</span>
-<span class="hl kwc">class</span> PSWGEN_GENERATOR_EXPORT iGenerator <span class="hl opt">:</span> <span class="hl kwc">public</span> QObject
+<span class="hl kwb">struct</span> iGenerator
<span class="hl opt">{</span>
- Q_OBJECT
-
-<span class="hl kwc">public</span><span class="hl opt">:</span>
-
- <span class="hl slc">/// Interface constructor</span>
- <span class="hl kwd">iGenerator</span><span class="hl opt">() :</span> <span class="hl kwd">QObject</span><span class="hl opt">() {}</span>
-
- <span class="hl slc">/// Empty virtual destructor</span>
- <span class="hl kwc">virtual</span> <span class="hl opt">~</span><span class="hl kwd">iGenerator</span><span class="hl opt">() {}</span>
-
<span class="hl com">/// Generates a strong password</span>
<span class="hl kwc">virtual</span> QString <span class="hl kwd">generatePassword</span><span class="hl opt">(</span>QString <span class="hl kwb">const</span> <span class="hl opt">&</span> name<span class="hl opt">,</span> QString <span class="hl kwb">const</span> <span class="hl opt">&</span> masterPassword<span class="hl opt">,</span> <span class="hl kwb">int</span> length<span class="hl opt">,</span> uint flags <span class="hl opt">=</span> <span class="hl num">0</span><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 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">// igenerator.h</span><span class="hl ppc"></span>
-</pre>
+<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>iGenerator<span class="hl opt">,</span> <span class="hl str">"eVaf.PswGen.iGenerator/1.0"</span><span class="hl opt">)</span>
+
+<span class="hl ppc">#endif</span> <span class="hl slc">// igenerator.h</span><span class="hl ppc"></span></pre>
<p>As a final touch, we create a file called <tt>iGenerator</tt> with the following content:</p>
<pre class="hl"><span class="hl ppc">#include</span> <span class="hl pps">"igenerator.h"</span><span class="hl ppc"></span></pre>
<span class="hl opt">}</span> <span class="hl slc">// namespace eVaf</span></pre>
<p>We call the class that implements the module simply <tt>Module</tt>. This is a public class and goes into the
- <tt>eVaf::PswGen::Generator</tt> namespace</tt>. We however, do not need to export it as we did with the <tt>iGenerator</tt>
- interface class, as this will be done by Qt.</p>
+ <tt>eVaf::PswGen::Generator</tt> namespace</tt>.</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>
}</span></pre>
- <p>The <tt>iPlugin</tt> interface has three abstract methods that we need to implement in our class -- <tt>init()</tt>,
- <tt>done()</tt> and <tt>isReady()</tt>. Since this simple module is always ready, we can return <tt>true</tt> in the
+ <p>The <tt>iPlugin</tt> interface has three pure virtual methods that we need to implement in our class -- <tt>init()</tt>,
+ <tt>done()</tt> and <tt>isReady()</tt>. Since this simple module is always ready, we can return always <tt>true</tt> in the
<tt>isReady()</tt> function. More complex modules can use a private <tt>mReady</tt> variable, which they set to <tt>true</tt>
once all the initialization is done.</tt>
<span class="hl opt">}</span> <span class="hl slc">// namespace eVaf::PswGen::Generator::Internal</span></pre>
<p>Then we can move forward and implement the <tt>iGenerator</tt> interface, which we already happened to call
- <tt>GeneratorImpl</tt>. This class goes into the <tt>eVaf::PswGen::Generator::Internal</tt> namespace:</p>
+ <tt>GeneratorImpl</tt>. This class goes into the <tt>eVaf::PswGen::Generator::Internal</tt> namespace.</p>
+
+ <p>The <tt>GeneratorImpl</tt> class needs to be derived both from <tt>QObject</tt> and from <tt>iGenerator</tt>. We also have to use the
+ <tt>Q_INTERFACES</tt> macro to include Qt meta-data for the <tt>iGenerator</tt> interface:</p>
-<pre class="hl"><span class="hl kwc">class</span> GeneratorImpl <span class="hl opt">:</span> <span class="hl kwc">public</span> iGenerator
+<pre class="hl"><span class="hl kwc">class</span> GeneratorImpl <span class="hl opt">:</span> <span class="hl kwc">public</span> QObject<span class="hl opt">,</span> <span class="hl kwc">public</span> iGenerator
<span class="hl opt">{</span>
- Q_OBJECT
+ <span class="hl kwd">Q_OBJECT</span>
+ <span class="hl kwd">Q_INTERFACES</span><span class="hl opt">(</span>eVaf::PswGen::iGenerator<span class="hl opt">)</span>
<span class="hl kwc">public</span><span class="hl opt">:</span>
<span class="hl kwc">class</span> GeneratorImpl<span class="hl opt">;</span>
<span class="hl opt">}</span> <span class="hl slc">// namespace eVaf::PswGen::Generator::Internal</span>
-<span class="hl com">/// Plugins/iPlugin interface implementation.</span>
+<span class="hl com">/// Plugins::iPlugin interface implementation.</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 kwd">Q_OBJECT</span>
<span class="hl kwc">public</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 true</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">/// iGenerator interface instance</span>
Internal<span class="hl opt">::</span>GeneratorImpl <span class="hl opt">*</span> mGenerator<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"> /// iGenerator interface implementation.</span>
-<span class="hl kwc">class</span> GeneratorImpl <span class="hl opt">:</span> <span class="hl kwc">public</span> iGenerator
+<span class="hl com">/// iGenerator interface implementation.</span>
+<span class="hl kwc">class</span> GeneratorImpl <span class="hl opt">:</span> <span class="hl kwc">public</span> QObject<span class="hl opt">,</span> <span class="hl kwc">public</span> iGenerator
<span class="hl opt">{</span>
- Q_OBJECT
+ <span class="hl kwd">Q_OBJECT</span>
+ <span class="hl kwd">Q_INTERFACES</span><span class="hl opt">(</span>eVaf<span class="hl opt">::</span>PswGen<span class="hl opt">::</span>iGenerator<span class="hl opt">)</span>
<span class="hl kwc">public</span><span class="hl opt">:</span>
<span class="hl kwc">virtual</span> QString <span class="hl kwd">generatePassword</span><span class="hl opt">(</span>QString <span class="hl kwb">const</span> <span class="hl opt">&</span> name<span class="hl opt">,</span> QString <span class="hl kwb">const</span> <span class="hl opt">&</span> masterPassword<span class="hl opt">,</span> <span class="hl kwb">int</span> length<span class="hl opt">,</span> uint flags <span class="hl opt">=</span> <span class="hl num">0</span><span class="hl opt">)</span> <span class="hl kwb">const</span><span class="hl opt">;</span>
- <span class="hl kwc">virtual</span> <span class="hl kwb">int</span> <span class="hl kwd">maxLength</span><span class="hl opt">()</span> <span class="hl kwb">const;</span>
-
+ <span class="hl kwc">virtual</span> <span class="hl kwb">int</span> <span class="hl kwd">maxLength</span><span class="hl opt">()</span> <span class="hl kwb">const</span> <span class="hl opt">{</span> <span class="hl kwa">return</span> <span class="hl num">24</span><span class="hl opt">; }</span>
<span class="hl opt">};</span>
<span class="hl opt">}</span> <span class="hl slc">// namespace eVaf::PswGen::Generator::Internal</span>
+
<span class="hl opt">}</span> <span class="hl slc">// namespace eVaf::PswGen::Generator</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>