]> vaikene.ee Git - evaf/blobdiff - www/pswgen03.html
Changed tutorial files to follow the changes in the PswGen application.
[evaf] / www / pswgen03.html
index 056da8e42145a4b3c1f15656e206c67b8cb92497..88597303ef115b5dd96da7dc8187875d7be021d0 100644 (file)
@@ -23,7 +23,7 @@
 
         <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>
@@ -34,8 +34,8 @@
 
 <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 &lt;QObject&gt;</span>
 <span class="hl ppc">#include &lt;QString&gt;</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">&amp;</span> name<span class="hl opt">,</span> QString <span class="hl kwb">const</span> <span class="hl opt">&amp;</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 &amp;"</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 &amp;"</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"> * &#64;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 &lt;QtCore/qglobal.h&gt;</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&lt;&gt;()</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">&quot;lib.h&quot;</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">&quot;eVaf.PswGen.iGenerator/1.0&quot;</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">&quot;lib.h&quot;</span><span class="hl ppc"></span>
-
 <span class="hl ppc">#include &lt;QObject&gt;</span>
 <span class="hl ppc">#include &lt;QString&gt;</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">&amp;</span> name<span class="hl opt">,</span> QString <span class="hl kwb">const</span> <span class="hl opt">&amp;</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">&quot;eVaf.PswGen.iGenerator/1.0&quot;</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">&quot;igenerator.h&quot;</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">&amp;</span> name<span class="hl opt">,</span> QString <span class="hl kwb">const</span> <span class="hl opt">&amp;</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>