Sophie

Sophie

distrib > Mageia > 7 > i586 > by-pkgid > 1dd17e0d683ef79b4bb6872bbf359d7f > files > 7842

qt4-doc-4.8.7-26.2.mga7.noarch.rpm

<?xml version="1.0" encoding="UTF-8"?>
<!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Strict//EN" "http://www.w3.org/TR/xhtml1/DTD/xhtml1-strict.dtd">
<html xmlns="http://www.w3.org/1999/xhtml" xml:lang="en_US" lang="en_US">
<head>
  <meta http-equiv="Content-Type" content="text/html; charset=utf-8" />
<!-- webftpclient.qdoc -->
  <title>Qt 4.8: Web FTP Client Example</title>
  <link rel="stylesheet" type="text/css" href="style/style.css" />
  <script src="scripts/jquery.js" type="text/javascript"></script>
  <script src="scripts/functions.js" type="text/javascript"></script>
  <link rel="stylesheet" type="text/css" href="style/superfish.css" />
  <link rel="stylesheet" type="text/css" href="style/narrow.css" />
  <!--[if IE]>
<meta name="MSSmartTagsPreventParsing" content="true">
<meta http-equiv="imagetoolbar" content="no">
<![endif]-->
<!--[if lt IE 7]>
<link rel="stylesheet" type="text/css" href="style/style_ie6.css">
<![endif]-->
<!--[if IE 7]>
<link rel="stylesheet" type="text/css" href="style/style_ie7.css">
<![endif]-->
<!--[if IE 8]>
<link rel="stylesheet" type="text/css" href="style/style_ie8.css">
<![endif]-->

<script src="scripts/superfish.js" type="text/javascript"></script>
<script src="scripts/narrow.js" type="text/javascript"></script>

</head>
<body class="" onload="CheckEmptyAndLoadList();">
 <div class="header" id="qtdocheader">
    <div class="content"> 
    <div id="nav-logo">
      <a href="index.html">Home</a></div>
    <a href="index.html" class="qtref"><span>Qt Reference Documentation</span></a>
    <div id="narrowsearch"></div>
    <div id="nav-topright">
      <ul>
        <li class="nav-topright-home"><a href="http://qt.digia.com/">Qt HOME</a></li>
        <li class="nav-topright-dev"><a href="http://qt-project.org/">DEV</a></li>
        <li class="nav-topright-doc nav-topright-doc-active"><a href="http://qt-project.org/doc/">
          DOC</a></li>
        <li class="nav-topright-blog"><a href="http://blog.qt.digia.com/">BLOG</a></li>
      </ul>
    </div>
    <div id="shortCut">
      <ul>
        <li class="shortCut-topleft-inactive"><span><a href="index.html">Qt 4.8</a></span></li>
        <li class="shortCut-topleft-active"><a href="http://qt-project.org/doc/">ALL VERSIONS        </a></li>
      </ul>
     </div>
 <ul class="sf-menu" id="narrowmenu"> 
             <li><a href="#">API Lookup</a> 
                 <ul> 
                     <li><a href="classes.html">Class index</a></li> 
           <li><a href="functions.html">Function index</a></li> 
           <li><a href="modules.html">Modules</a></li> 
           <li><a href="namespaces.html">Namespaces</a></li> 
           <li><a href="qtglobal.html">Global Declarations</a></li> 
           <li><a href="qdeclarativeelements.html">QML elements</a></li> 
             </ul> 
             </li> 
             <li><a href="#">Qt Topics</a> 
                 <ul> 
                        <li><a href="qt-basic-concepts.html">Programming with Qt</a></li>  
                        <li><a href="qtquick.html">Device UIs &amp; Qt Quick</a></li>  
                        <li><a href="qt-gui-concepts.html">UI Design with Qt</a></li>  
                        <li><a href="supported-platforms.html">Supported Platforms</a></li>  
                        <li><a href="technology-apis.html">Qt and Key Technologies</a></li>  
                        <li><a href="best-practices.html">How-To's and Best Practices</a></li>  
              </ul> 
                 </li> 
                 <li><a href="#">Examples</a> 
                     <ul> 
                       <li><a href="all-examples.html">Examples</a></li> 
                       <li><a href="tutorials.html">Tutorials</a></li> 
                       <li><a href="demos.html">Demos</a></li> 
                       <li><a href="qdeclarativeexamples.html">QML Examples</a></li> 
                </ul> 
                     </li> 
                 </ul> 
    </div>
  </div>
  <div class="wrapper">
    <div class="hd">
      <span></span>
    </div>
    <div class="bd group">
      <div class="sidebar">
        <div class="searchlabel">
          Search index:</div>
        <div class="search" id="sidebarsearch">
          <form id="qtdocsearch" action="" onsubmit="return false;">
            <fieldset>
              <input type="text" name="searchstring" id="pageType" value="" />
 <div id="resultdialog"> 
 <a href="#" id="resultclose">Close</a> 
 <p id="resultlinks" class="all"><a href="#" id="showallresults">All</a> | <a href="#" id="showapiresults">API</a> | <a href="#" id="showarticleresults">Articles</a> | <a href="#" id="showexampleresults">Examples</a></p> 
 <p id="searchcount" class="all"><span id="resultcount"></span><span id="apicount"></span><span id="articlecount"></span><span id="examplecount"></span>&nbsp;results:</p> 
 <ul id="resultlist" class="all"> 
 </ul> 
 </div> 
            </fieldset>
          </form>
        </div>
        <div class="box first bottombar" id="lookup">
          <h2 title="API Lookup"><span></span>
            API Lookup</h2>
          <div  id="list001" class="list">
          <ul id="ul001" >
              <li class="defaultLink"><a href="classes.html">Class index</a></li>
              <li class="defaultLink"><a href="functions.html">Function index</a></li>
              <li class="defaultLink"><a href="modules.html">Modules</a></li>
              <li class="defaultLink"><a href="namespaces.html">Namespaces</a></li>
              <li class="defaultLink"><a href="qtglobal.html">Global Declarations</a></li>
              <li class="defaultLink"><a href="qdeclarativeelements.html">QML elements</a></li>
            </ul> 
          </div>
        </div>
        <div class="box bottombar" id="topics">
          <h2 title="Qt Topics"><span></span>
            Qt Topics</h2>
          <div id="list002" class="list">
            <ul id="ul002" >
               <li class="defaultLink"><a href="qt-basic-concepts.html">Programming with Qt</a></li> 
               <li class="defaultLink"><a href="qtquick.html">Device UIs &amp; Qt Quick</a></li> 
               <li class="defaultLink"><a href="qt-gui-concepts.html">UI Design with Qt</a></li> 
               <li class="defaultLink"><a href="supported-platforms.html">Supported Platforms</a></li>  
               <li class="defaultLink"><a href="technology-apis.html">Qt and Key Technologies</a></li> 
               <li class="defaultLink"><a href="best-practices.html">How-To's and Best Practices</a></li> 
            </ul>  
          </div>
        </div>
        <div class="box" id="examples">
          <h2 title="Examples"><span></span>
            Examples</h2>
          <div id="list003" class="list">
        <ul id="ul003">
              <li class="defaultLink"><a href="all-examples.html">Examples</a></li>
              <li class="defaultLink"><a href="tutorials.html">Tutorials</a></li>
              <li class="defaultLink"><a href="demos.html">Demos</a></li>
              <li class="defaultLink"><a href="qdeclarativeexamples.html">QML Examples</a></li>
            </ul> 
          </div>
        </div>
      </div>
      <div class="wrap">
        <div class="toolbar">
          <div class="breadcrumb toolblock">
            <ul>
              <li class="first"><a href="index.html">Home</a></li>
              <!--  Breadcrumbs go here -->
<li><a href="all-examples.html">Examples</a></li>
<li>Web FTP Client Example</li>
            </ul>
          </div>
          <div class="toolbuttons toolblock">
            <ul>
              <li id="smallA" class="t_button">A</li>
              <li id="medA" class="t_button active">A</li>
              <li id="bigA" class="t_button">A</li>
              <li id="print" class="t_button"><a href="javascript:this.print();">
                <span>Print</span></a></li>
            </ul>
        </div>
        </div>
        <div class="content mainContent">
<div class="toc">
<h3><a name="toc">Contents</a></h3>
<ul>
<li class="level1"><a href="#introduction">Introduction</a></li>
<li class="level1"><a href="#network-access">Network Access</a></li>
<li class="level1"><a href="#creating-a-new-network-manager">Creating a New Network Manager</a></li>
<li class="level1"><a href="#creating-a-custom-reply">Creating a Custom Reply</a></li>
<li class="level2"><a href="#fetching-data-from-the-server">Fetching Data from the Server</a></li>
<li class="level2"><a href="#preparing-content-for-the-reader">Preparing Content for the Reader</a></li>
<li class="level2"><a href="#supplying-data-to-the-browser">Supplying Data to the Browser</a></li>
<li class="level1"><a href="#enabling-the-protocol">Enabling the Protocol</a></li>
<li class="level1"><a href="#summary">Summary</a></li>
</ul>
</div>
<h1 class="title">Web FTP Client Example</h1>
<span class="subtitle"></span>
<!-- $$$webkit/webftpclient-description -->
<div class="descr"> <a name="details"></a>
<p>Files:</p>
<ul>
<li><a href="webkit-webftpclient-downloader-cpp.html">webkit/webftpclient/downloader.cpp</a></li>
<li><a href="webkit-webftpclient-downloader-h.html">webkit/webftpclient/downloader.h</a></li>
<li><a href="webkit-webftpclient-ftpreply-cpp.html">webkit/webftpclient/ftpreply.cpp</a></li>
<li><a href="webkit-webftpclient-ftpreply-h.html">webkit/webftpclient/ftpreply.h</a></li>
<li><a href="webkit-webftpclient-ftpview-cpp.html">webkit/webftpclient/ftpview.cpp</a></li>
<li><a href="webkit-webftpclient-ftpview-h.html">webkit/webftpclient/ftpview.h</a></li>
<li><a href="webkit-webftpclient-networkaccessmanager-cpp.html">webkit/webftpclient/networkaccessmanager.cpp</a></li>
<li><a href="webkit-webftpclient-networkaccessmanager-h.html">webkit/webftpclient/networkaccessmanager.h</a></li>
<li><a href="webkit-webftpclient-main-cpp.html">webkit/webftpclient/main.cpp</a></li>
<li><a href="webkit-webftpclient-webftpclient-pro.html">webkit/webftpclient/webftpclient.pro</a></li>
</ul>
<p>The Web FTP Client example shows how to add support for a new protocol to <a href="qtwebkit.html">QtWebKit</a>-based applications.<p class="centerAlign"><img src="images/webkit-webftpclient.png" alt="An FTP client displaying the contents of the ftp.qt.nokia.com site." /></p><a name="introduction"></a>
<h2>Introduction</h2>
<p>The <a href="qtwebkit.html">QtWebKit</a> module presents many ways to integrate the worlds of native desktop and mobile applications and the Web, making it possible for developers to extend and combine features found in Qt and WebKit to create new ones. In this article, we examine the use of Qt's network access API with WebKit and show how to turn <a href="qwebview.html">QWebView</a> into a simple FTP client.</p>
<p>In the <a href="webkit-webplugin.html">Web Plugin Example</a>, we extended Qt's WebKit integration by showing how to add custom widgets to Web pages. In the article, we used <a href="qnetworkrequest.html">QNetworkRequest</a> to ask for content for display in a widget, and we obtained the data returned by the server by reading from the corresponding <a href="qnetworkreply.html">QNetworkReply</a>.</p>
<p>Qt's network access API is a technology that aims to replace much, but not all, of the functionality provided by the <a href="qhttp.html" class="obsolete">QHttp<sup>(obsolete)</sup></a> and <a href="qftp.html">QFtp</a> classes. Although the network access API is a Qt-specific technology, the <a href="qtwebkit.html">QtWebKit</a> module integrates this Qt technology with WebKit to enable customization of the browser engine by Qt application developers. It also means that we can control how the browser engine obtains and renders content.</p>
<p>Since <a href="qnetworkrequest.html">QNetworkRequest</a> and <a href="qnetworkreply.html">QNetworkReply</a> are designed to provide a reusable abstraction for network operations, it seems obvious to use these classes to add FTP support to browsers written using <a href="qtwebkit.html">QtWebKit</a>. To do this, we first need to examine the network access classes before we see how the <a href="qtwebkit.html">QtWebKit</a> module uses them to manage network operations.</p>
<a name="network-access"></a>
<h2>Network Access</h2>
<p>The central class in Qt's network access API is <a href="qnetworkaccessmanager.html">QNetworkAccessManager</a>. This class performs the work of dispatching requests to remote servers and handling incoming replies. Applications typically construct an instance of this class and use it for all high level network communication.</p>
<p>Applications create <a href="qnetworkrequest.html">QNetworkRequest</a> objects, each of them specifying a URL where the request is to be sent and containing meta-data that will be understood by the server. Each request is dispatched by passing it to a function in the network manager &mdash; there are different functions corresponding to different kinds of operations, such as <a href="qnetworkaccessmanager.html#get">get()</a>, <a href="qnetworkaccessmanager.html#put">put()</a> and <a href="qnetworkaccessmanager.html#post">post()</a>. Each of these functions returns a <a href="qnetworkreply.html">QNetworkReply</a> object which is used to obtain the content sent in the reply, as well as any meta-data that describes it.</p>
<p>The <a href="qtwebkit.html">QtWebKit</a> module provides the <a href="qwebpage.html">QWebPage</a> class which represents the content displayed in a <a href="qwebview.html">QWebView</a> widget. Behind the scenes, this class uses a default network access manager to handle network communication. This default manager works perfectly well for fetching content over HTTP from <tt>http://</tt> URLs, but only supports fetching of files over FTP when using <tt>ftp://</tt> URLs.</p>
<p>Fortunately, <a href="qwebpage.html">QWebPage</a> provides the <a href="qwebpage.html#setNetworkAccessManager">setNetworkAccessManager()</a> function that allows the default manager to be replaced with one with more features. This lets us add improved support for FTP quite easily if we can write a new manager that supports <tt>ftp://</tt> URLs.</p>
<p>The process of replacing the manager and using a new one with an existing <a href="qwebpage.html">QWebPage</a> object can be broken up into three steps:</p>
<ol class="1">
<li>Creating a new <a href="qnetworkaccessmanager.html">QNetworkAccessManager</a> subclass.</li>
<li>Creating a new <a href="qnetworkreply.html">QNetworkReply</a> subclass to deal with the FTP protocol.</li>
<li>Setting the new manager on the <a href="qwebpage.html">QWebPage</a>.</li>
</ol>
<p>Additionally, to provide a reasonable user experience, we should also handle content that the browser engine cannot display. To do this, we create a custom <tt>Downloader</tt> object. We will briefly return to this topic later.</p>
<a name="creating-a-new-network-manager"></a>
<h2>Creating a New Network Manager</h2>
<p>Replacing an existing network manager for a <a href="qwebpage.html">QWebPage</a> is conceptually simple: we subclass <a href="qnetworkaccessmanager.html">QNetworkAccessManager</a> and reimplement its <a href="qnetworkaccessmanager.html#createRequest">createRequest()</a> function to check for URLs with the <tt>ftp</tt> scheme. However, we want to ensure that the manager uses any existing cache and proxy settings that may have been set up for the existing manager used by the <a href="qwebpage.html">QWebPage</a>.</p>
<p>To keep the existing proxy and cache, we give our network manager a constructor that accepts the old manager as an argument. In the constructor, we reuse the settings from the old manager.</p>
<pre class="cpp"> NetworkAccessManager<span class="operator">::</span>NetworkAccessManager(<span class="type"><a href="qnetworkaccessmanager.html">QNetworkAccessManager</a></span> <span class="operator">*</span>manager<span class="operator">,</span> <span class="type"><a href="qobject.html">QObject</a></span> <span class="operator">*</span>parent)
     : <span class="type"><a href="qnetworkaccessmanager.html">QNetworkAccessManager</a></span>(parent)
 {
     setCache(manager<span class="operator">-</span><span class="operator">&gt;</span>cache());
     setCookieJar(manager<span class="operator">-</span><span class="operator">&gt;</span>cookieJar());
     setProxy(manager<span class="operator">-</span><span class="operator">&gt;</span>proxy());
     setProxyFactory(manager<span class="operator">-</span><span class="operator">&gt;</span>proxyFactory());
 }</pre>
<p>The <tt>createRequest()</tt> function is used to create and dispatch requests to remote servers for each of the different kinds of operation that the API presents to the developer. Since we are only interested in performing simple fetches of resources using the <tt>ftp</tt> scheme, we filter out other schemes and other kinds of operation, delegating the task of handling these to the default implementation.</p>
<pre class="cpp"> <span class="type"><a href="qnetworkreply.html">QNetworkReply</a></span> <span class="operator">*</span>NetworkAccessManager<span class="operator">::</span>createRequest(
     <span class="type"><a href="qnetworkaccessmanager.html">QNetworkAccessManager</a></span><span class="operator">::</span>Operation operation<span class="operator">,</span> <span class="keyword">const</span> <span class="type"><a href="qnetworkrequest.html">QNetworkRequest</a></span> <span class="operator">&amp;</span>request<span class="operator">,</span>
     <span class="type"><a href="qiodevice.html">QIODevice</a></span> <span class="operator">*</span>device)
 {
     <span class="keyword">if</span> (request<span class="operator">.</span>url()<span class="operator">.</span>scheme() <span class="operator">!</span><span class="operator">=</span> <span class="string">&quot;ftp&quot;</span>)
         <span class="keyword">return</span> <span class="type"><a href="qnetworkaccessmanager.html">QNetworkAccessManager</a></span><span class="operator">::</span>createRequest(operation<span class="operator">,</span> request<span class="operator">,</span> device);

     <span class="keyword">if</span> (operation <span class="operator">=</span><span class="operator">=</span> GetOperation)
         <span class="comment">// Handle ftp:// URLs separately by creating custom QNetworkReply</span>
         <span class="comment">// objects.</span>
         <span class="keyword">return</span> <span class="keyword">new</span> FtpReply(request<span class="operator">.</span>url());
     <span class="keyword">else</span>
         <span class="keyword">return</span> <span class="type"><a href="qnetworkaccessmanager.html">QNetworkAccessManager</a></span><span class="operator">::</span>createRequest(operation<span class="operator">,</span> request<span class="operator">,</span> device);
 }</pre>
<p>Here, we construct and return an instance of the <tt>FtpReply</tt> class. This class performs most of the work of handling the FTP protocol.</p>
<a name="creating-a-custom-reply"></a>
<h2>Creating a Custom Reply</h2>
<p>The network access API is designed to be simple to use: we set up a request, dispatch it using the network manager, and obtain a <a href="qnetworkreply.html">QNetworkReply</a> object. If we are not interested in the reply's meta-data, we can simply read the data using its <a href="qiodevice.html#readAll">readAll()</a> function because <a href="qnetworkreply.html">QNetworkReply</a> is a <a href="qiodevice.html">QIODevice</a> subclass.</p>
<p>In order to keep the API so simple, however, we need to perform some work behind the scenes. In this case, that means that we must perform a series of communications with the FTP server. Fortunately, we can use the existing implementation provided by <a href="qftp.html">QFtp</a> to perform the low level work.</p>
<p>In the <tt>FtpReply</tt> class, we need to reimplement four functions in the API to ensure that it will work correctly. These functions, <a href="qnetworkreply.html#abort">abort()</a>, <a href="qiodevice.html#bytesAvailable">bytesAvailable()</a>, <a href="qiodevice.html#isSequential">isSequential()</a>, <a href="qiodevice.html#readData">readData()</a>, rely on the rest of the implementation to fill a <a href="qbytearray.html">QByteArray</a> with data and use an integer offset to track how much has been read from the device by the browser.</p>
<pre class="cpp"> <span class="keyword">class</span> FtpReply : <span class="keyword">public</span> <span class="type"><a href="qnetworkreply.html">QNetworkReply</a></span>
 {
     Q_OBJECT

 <span class="keyword">public</span>:
     FtpReply(<span class="keyword">const</span> <span class="type"><a href="qurl.html">QUrl</a></span> <span class="operator">&amp;</span>url);
     <span class="type">void</span> abort();
     <span class="type"><a href="qtglobal.html#qint64-typedef">qint64</a></span> bytesAvailable() <span class="keyword">const</span>;
     <span class="type">bool</span> isSequential() <span class="keyword">const</span>;

 <span class="keyword">protected</span>:
     <span class="type"><a href="qtglobal.html#qint64-typedef">qint64</a></span> readData(<span class="type">char</span> <span class="operator">*</span>data<span class="operator">,</span> <span class="type"><a href="qtglobal.html#qint64-typedef">qint64</a></span> maxSize);

 <span class="keyword">private</span> <span class="keyword">slots</span>:
     <span class="type">void</span> processCommand(<span class="type">int</span> command<span class="operator">,</span> <span class="type">bool</span> error);
     <span class="type">void</span> processListInfo(<span class="keyword">const</span> <span class="type"><a href="qurlinfo.html">QUrlInfo</a></span> <span class="operator">&amp;</span>urlInfo);
     <span class="type">void</span> processData();

 <span class="keyword">private</span>:
     <span class="type">void</span> setContent();
     <span class="type">void</span> setListContent();

     <span class="type"><a href="qftp.html">QFtp</a></span> <span class="operator">*</span>ftp;
     <span class="type"><a href="qlist.html">QList</a></span><span class="operator">&lt;</span><span class="type"><a href="qurlinfo.html">QUrlInfo</a></span><span class="operator">&gt;</span> items;
     <span class="type"><a href="qbytearray.html">QByteArray</a></span> content;
     <span class="type"><a href="qtglobal.html#qint64-typedef">qint64</a></span> offset;
     <span class="type"><a href="qstringlist.html">QStringList</a></span> units;
 };</pre>
<p>The <tt>processCommand()</tt>, <tt>processListInfo</tt> and <tt>processData()</tt> slots handle interaction with the FTP server. The private <tt>setContent()</tt> and <tt>setListContent()</tt> functions are used to add meta-data to the reply and compose HTML for the browser to display.</p>
<p>Two of the private variables hold information about the data obtained from the FTP server: <tt>items</tt> is updated to contain information about each file found at a given URL, and <tt>content</tt> contains the raw data obtained from the server. The <tt>offset</tt> variable is used to track how much data has been read by the browser from the reply.</p>
<p>In the constructor, we construct a <a href="qftp.html">QFtp</a> object and connect the signals and slots that form the basis of the interaction with the FTP server. The high level communication is reported by the <a href="qftp.html#commandFinished">commandFinished()</a> signal. New data from the server is reported by the <a href="porting4.html#qftp">QFtp::</a>readyRead()} signal. Individual items in an FTP directory listing are reported by the <a href="qftp.html#listInfo">listInfo()</a> signal.</p>
<pre class="cpp"> FtpReply<span class="operator">::</span>FtpReply(<span class="keyword">const</span> <span class="type"><a href="qurl.html">QUrl</a></span> <span class="operator">&amp;</span>url)
     : <span class="type"><a href="qnetworkreply.html">QNetworkReply</a></span>()
 {
     ftp <span class="operator">=</span> <span class="keyword">new</span> <span class="type"><a href="qftp.html">QFtp</a></span>(<span class="keyword">this</span>);
     connect(ftp<span class="operator">,</span> SIGNAL(listInfo(<span class="type"><a href="qurlinfo.html">QUrlInfo</a></span>))<span class="operator">,</span> <span class="keyword">this</span><span class="operator">,</span> SLOT(processListInfo(<span class="type"><a href="qurlinfo.html">QUrlInfo</a></span>)));
     connect(ftp<span class="operator">,</span> SIGNAL(readyRead())<span class="operator">,</span> <span class="keyword">this</span><span class="operator">,</span> SLOT(processData()));
     connect(ftp<span class="operator">,</span> SIGNAL(commandFinished(<span class="type">int</span><span class="operator">,</span> <span class="type">bool</span>))<span class="operator">,</span> <span class="keyword">this</span><span class="operator">,</span> SLOT(processCommand(<span class="type">int</span><span class="operator">,</span> <span class="type">bool</span>)));

     offset <span class="operator">=</span> <span class="number">0</span>;
     units <span class="operator">=</span> <span class="type"><a href="qstringlist.html">QStringList</a></span>() <span class="operator">&lt;</span><span class="operator">&lt;</span> tr(<span class="string">&quot;bytes&quot;</span>) <span class="operator">&lt;</span><span class="operator">&lt;</span> tr(<span class="string">&quot;K&quot;</span>) <span class="operator">&lt;</span><span class="operator">&lt;</span> tr(<span class="string">&quot;M&quot;</span>) <span class="operator">&lt;</span><span class="operator">&lt;</span> tr(<span class="string">&quot;G&quot;</span>)
                           <span class="operator">&lt;</span><span class="operator">&lt;</span> tr(<span class="string">&quot;Ti&quot;</span>) <span class="operator">&lt;</span><span class="operator">&lt;</span> tr(<span class="string">&quot;Pi&quot;</span>) <span class="operator">&lt;</span><span class="operator">&lt;</span> tr(<span class="string">&quot;Ei&quot;</span>) <span class="operator">&lt;</span><span class="operator">&lt;</span> tr(<span class="string">&quot;Zi&quot;</span>)
                           <span class="operator">&lt;</span><span class="operator">&lt;</span> tr(<span class="string">&quot;Yi&quot;</span>);

     setUrl(url);
     ftp<span class="operator">-</span><span class="operator">&gt;</span>connectToHost(url<span class="operator">.</span>host());
 }</pre>
<p>We also initialize the <tt>offset</tt> into the data that represents the number of bytes that the browser has read from the reply. Additionally, we define a list of units for use with the <tt>setListContent()</tt> function. The last two tasks performed in the constructor are to set the URL of the reply so that the browser can tell where it came from, and to connect to the FTP server.</p>
<a name="fetching-data-from-the-server"></a>
<h3>Fetching Data from the Server</h3>
<p>All communication with the server is handled by the <tt>processCommand()</tt> slot, which acts on responses from the server and tells us when a command we have issued has completed. This slot performs the task of logging in to the server when connection has occurred (the <a href="qftp.html#Command-enum">ConnectToHost</a> command has completed), asking for a list of files when logged in (<a href="qftp.html#Command-enum">Login</a> has completed), preparing a page with a listing when all file information has been received (<a href="qftp.html#Command-enum">List</a> has completed), and setting the current content for the reply when data has been fetched from the server (<a href="qftp.html#Command-enum">Get</a> has completed).</p>
<pre class="cpp"> <span class="type">void</span> FtpReply<span class="operator">::</span>processCommand(<span class="type">int</span><span class="operator">,</span> <span class="type">bool</span> err)
 {
     <span class="keyword">if</span> (err) {
         setError(ContentNotFoundError<span class="operator">,</span> tr(<span class="string">&quot;Unknown command&quot;</span>));
         <span class="keyword">emit</span> error(ContentNotFoundError);
         <span class="keyword">return</span>;
     }

     <span class="keyword">switch</span> (ftp<span class="operator">-</span><span class="operator">&gt;</span>currentCommand()) {
     <span class="keyword">case</span> <span class="type"><a href="qftp.html">QFtp</a></span><span class="operator">::</span>ConnectToHost:
         ftp<span class="operator">-</span><span class="operator">&gt;</span>login();
         <span class="keyword">break</span>;

     <span class="keyword">case</span> <span class="type"><a href="qftp.html">QFtp</a></span><span class="operator">::</span>Login:
         ftp<span class="operator">-</span><span class="operator">&gt;</span>list(url()<span class="operator">.</span>path());
         <span class="keyword">break</span>;

     <span class="keyword">case</span> <span class="type"><a href="qftp.html">QFtp</a></span><span class="operator">::</span>List:
         <span class="keyword">if</span> (items<span class="operator">.</span>size() <span class="operator">=</span><span class="operator">=</span> <span class="number">1</span>)
             ftp<span class="operator">-</span><span class="operator">&gt;</span>get(url()<span class="operator">.</span>path());
         <span class="keyword">else</span>
             setListContent();
         <span class="keyword">break</span>;

     <span class="keyword">case</span> <span class="type"><a href="qftp.html">QFtp</a></span><span class="operator">::</span>Get:
         setContent();

     <span class="keyword">default</span>:
         ;
     }
 }</pre>
<p>The result of the <a href="qftp.html#Command-enum">List</a> command is handled by looking at the number of items obtained from the server. The items themselves are recorded by the <tt>processListInfo()</tt> slot. When a <a href="qftp.html#Command-enum">List</a> command is complete, we can count the number of items received and determine whether or not we should create a file listing, or try to fetch the file instead by invoking a <a href="qftp.html#Command-enum">Get</a> command.</p>
<pre class="cpp"> <span class="type">void</span> FtpReply<span class="operator">::</span>processListInfo(<span class="keyword">const</span> <span class="type"><a href="qurlinfo.html">QUrlInfo</a></span> <span class="operator">&amp;</span>urlInfo)
 {
     items<span class="operator">.</span>append(urlInfo);
 }</pre>
<p>Since the reply will only be used once, we can simply append items to a list and never bother to clear it.</p>
<p>The <tt>processData()</tt> slot simply appends data obtained from the FTP server to the <a href="qbytearray.html">QByteArray</a> containing the content to be supplied to the browser.</p>
<pre class="cpp"> <span class="type">void</span> FtpReply<span class="operator">::</span>processData()
 {
     content <span class="operator">+</span><span class="operator">=</span> ftp<span class="operator">-</span><span class="operator">&gt;</span>readAll();
 }</pre>
<p>Data is appended to the <tt>content</tt> array until the connection to the FTP server is closed, either by the reply or by the server itself. One of the ways in which this happens is when a <a href="qftp.html#Command-enum">Get</a> command completes. At this point, the <tt>setContent()</tt> function is called from within the <tt>processCommand()</tt> function.</p>
<pre class="cpp"> <span class="type">void</span> FtpReply<span class="operator">::</span>setContent()
 {
     open(ReadOnly <span class="operator">|</span> Unbuffered);
     setHeader(<span class="type"><a href="qnetworkrequest.html">QNetworkRequest</a></span><span class="operator">::</span>ContentLengthHeader<span class="operator">,</span> <span class="type"><a href="qvariant.html">QVariant</a></span>(content<span class="operator">.</span>size()));
     <span class="keyword">emit</span> readyRead();
     <span class="keyword">emit</span> finished();
     ftp<span class="operator">-</span><span class="operator">&gt;</span>close();
 }</pre>
<p>Here, we prepare the reply for use by the browser by opening it for unbuffered reading and setting the header that reports the amount of data held by the reply. We emit signals that indicate that the network operation has finished and that it has data to be read. Since we are no longer interested in the FTP server, we close the connection to it.</p>
<a name="preparing-content-for-the-reader"></a>
<h3>Preparing Content for the Reader</h3>
<p>Another way in which the reply closes the connection to the server is when the <tt>setListContent()</tt> function is called from the <tt>processCommand()</tt> function. Most of the implementation of this function involves transforming the information about the items held in the reply's private <tt>items</tt> variable to HTML.</p>
<pre class="cpp"> <span class="type">void</span> FtpReply<span class="operator">::</span>setListContent()
 {
     <span class="type"><a href="qurl.html">QUrl</a></span> u <span class="operator">=</span> url();
     <span class="keyword">if</span> (<span class="operator">!</span>u<span class="operator">.</span>path()<span class="operator">.</span>endsWith(<span class="string">&quot;/&quot;</span>))
         u<span class="operator">.</span>setPath(u<span class="operator">.</span>path() <span class="operator">+</span> <span class="string">&quot;/&quot;</span>);

     <span class="type"><a href="qstring.html">QString</a></span> base_url <span class="operator">=</span> url()<span class="operator">.</span>toString();
     <span class="type"><a href="qstring.html">QString</a></span> base_path <span class="operator">=</span> u<span class="operator">.</span>path();

     open(ReadOnly <span class="operator">|</span> Unbuffered);
     <span class="type"><a href="qstring.html">QString</a></span> content(
         <span class="string">&quot;&lt;html&gt;\n&quot;</span>
         <span class="string">&quot;&lt;head&gt;\n&quot;</span>
         <span class="string">&quot;  &lt;title&gt;&quot;</span> <span class="operator">+</span> <span class="type"><a href="qt.html">Qt</a></span><span class="operator">::</span>escape(base_url) <span class="operator">+</span> <span class="string">&quot;&lt;/title&gt;\n&quot;</span>
         <span class="string">&quot;  &lt;style type=\&quot;text/css\&quot;&gt;\n&quot;</span>
         <span class="string">&quot;  th { background-color: #aaaaaa; color: black }\n&quot;</span>
         <span class="string">&quot;  table { border: solid 1px #aaaaaa }\n&quot;</span>
         <span class="string">&quot;  tr.odd { background-color: #dddddd; color: black\n }\n&quot;</span>
         <span class="string">&quot;  tr.even { background-color: white; color: black\n }\n&quot;</span>
         <span class="string">&quot;  &lt;/style&gt;\n&quot;</span>
         <span class="string">&quot;&lt;/head&gt;\n\n&quot;</span>
         <span class="string">&quot;&lt;body&gt;\n&quot;</span>
         <span class="string">&quot;&lt;h1&gt;&quot;</span> <span class="operator">+</span> tr(<span class="string">&quot;Listing for %1&quot;</span>)<span class="operator">.</span>arg(base_path) <span class="operator">+</span> <span class="string">&quot;&lt;/h1&gt;\n\n&quot;</span>
         <span class="string">&quot;&lt;table align=\&quot;center\&quot; cellspacing=\&quot;0\&quot; width=\&quot;90%\&quot;&gt;\n&quot;</span>
         <span class="string">&quot;&lt;tr&gt;&lt;th&gt;Name&lt;/th&gt;&lt;th&gt;Size&lt;/th&gt;&lt;/tr&gt;\n&quot;</span>);

     <span class="type"><a href="qurl.html">QUrl</a></span> parent <span class="operator">=</span> u<span class="operator">.</span>resolved(<span class="type"><a href="qurl.html">QUrl</a></span>(<span class="string">&quot;..&quot;</span>));

     <span class="keyword">if</span> (parent<span class="operator">.</span>isParentOf(u))

         content <span class="operator">+</span><span class="operator">=</span> <span class="type"><a href="qstring.html">QString</a></span>(<span class="string">&quot;&lt;tr&gt;&lt;td&gt;&lt;strong&gt;&lt;a href=\&quot;&quot;</span> <span class="operator">+</span> parent<span class="operator">.</span>toString() <span class="operator">+</span> <span class="string">&quot;\&quot;&gt;&quot;</span>
             <span class="operator">+</span> tr(<span class="string">&quot;Parent directory&quot;</span>) <span class="operator">+</span> <span class="string">&quot;&lt;/a&gt;&lt;/strong&gt;&lt;/td&gt;&lt;td&gt;&lt;/td&gt;&lt;/tr&gt;\n&quot;</span>);

     <span class="type">int</span> i <span class="operator">=</span> <span class="number">0</span>;
     foreach (<span class="keyword">const</span> <span class="type"><a href="qurlinfo.html">QUrlInfo</a></span> <span class="operator">&amp;</span>item<span class="operator">,</span> items) {

         <span class="type"><a href="qurl.html">QUrl</a></span> child <span class="operator">=</span> u<span class="operator">.</span>resolved(<span class="type"><a href="qurl.html">QUrl</a></span>(item<span class="operator">.</span>name()));

         <span class="keyword">if</span> (i <span class="operator">=</span><span class="operator">=</span> <span class="number">0</span>)
             content <span class="operator">+</span><span class="operator">=</span> <span class="type"><a href="qstring.html">QString</a></span>(<span class="string">&quot;&lt;tr class=\&quot;odd\&quot;&gt;&quot;</span>);
         <span class="keyword">else</span>
             content <span class="operator">+</span><span class="operator">=</span> <span class="type"><a href="qstring.html">QString</a></span>(<span class="string">&quot;&lt;tr class=\&quot;even\&quot;&gt;&quot;</span>);

         content <span class="operator">+</span><span class="operator">=</span> <span class="type"><a href="qstring.html">QString</a></span>(<span class="string">&quot;&lt;td&gt;&lt;a href=\&quot;&quot;</span> <span class="operator">+</span> child<span class="operator">.</span>toString() <span class="operator">+</span> <span class="string">&quot;\&quot;&gt;&quot;</span>
                            <span class="operator">+</span> <span class="type"><a href="qt.html">Qt</a></span><span class="operator">::</span>escape(item<span class="operator">.</span>name()) <span class="operator">+</span> <span class="string">&quot;&lt;/a&gt;&lt;/td&gt;&quot;</span>);

         <span class="type"><a href="qtglobal.html#qint64-typedef">qint64</a></span> size <span class="operator">=</span> item<span class="operator">.</span>size();
         <span class="type">int</span> unit <span class="operator">=</span> <span class="number">0</span>;
         <span class="keyword">while</span> (size) {
             <span class="type"><a href="qtglobal.html#qint64-typedef">qint64</a></span> new_size <span class="operator">=</span> size<span class="operator">/</span><span class="number">1024</span>;
             <span class="keyword">if</span> (new_size <span class="operator">&amp;</span><span class="operator">&amp;</span> unit <span class="operator">&lt;</span> units<span class="operator">.</span>size()) {
                 size <span class="operator">=</span> new_size;
                 unit <span class="operator">+</span><span class="operator">=</span> <span class="number">1</span>;
             } <span class="keyword">else</span>
                 <span class="keyword">break</span>;
         }

         <span class="keyword">if</span> (item<span class="operator">.</span>isFile())
             content <span class="operator">+</span><span class="operator">=</span> <span class="type"><a href="qstring.html">QString</a></span>(<span class="string">&quot;&lt;td&gt;&quot;</span> <span class="operator">+</span> <span class="type"><a href="qstring.html">QString</a></span><span class="operator">::</span>number(size) <span class="operator">+</span> <span class="string">&quot; &quot;</span>
                                <span class="operator">+</span> units<span class="operator">[</span>unit<span class="operator">]</span> <span class="operator">+</span> <span class="string">&quot;&lt;/td&gt;&lt;/tr&gt;\n&quot;</span>);
         <span class="keyword">else</span>
             content <span class="operator">+</span><span class="operator">=</span> <span class="type"><a href="qstring.html">QString</a></span>(<span class="string">&quot;&lt;td&gt;&lt;/td&gt;&lt;/tr&gt;\n&quot;</span>);

         i <span class="operator">=</span> <span class="number">1</span> <span class="operator">-</span> i;
     }

     content <span class="operator">+</span><span class="operator">=</span> <span class="type"><a href="qstring.html">QString</a></span>(<span class="string">&quot;&lt;/table&gt;\n&quot;</span>
                        <span class="string">&quot;&lt;/body&gt;\n&quot;</span>
                        <span class="string">&quot;&lt;/html&gt;\n&quot;</span>);

     <span class="keyword">this</span><span class="operator">-</span><span class="operator">&gt;</span>content <span class="operator">=</span> content<span class="operator">.</span>toUtf8();

     setHeader(<span class="type"><a href="qnetworkrequest.html">QNetworkRequest</a></span><span class="operator">::</span>ContentTypeHeader<span class="operator">,</span> <span class="type"><a href="qvariant.html">QVariant</a></span>(<span class="string">&quot;text/html; charset=UTF-8&quot;</span>));
     setHeader(<span class="type"><a href="qnetworkrequest.html">QNetworkRequest</a></span><span class="operator">::</span>ContentLengthHeader<span class="operator">,</span> <span class="type"><a href="qvariant.html">QVariant</a></span>(<span class="keyword">this</span><span class="operator">-</span><span class="operator">&gt;</span>content<span class="operator">.</span>size()));
     <span class="keyword">emit</span> readyRead();
     <span class="keyword">emit</span> finished();
     ftp<span class="operator">-</span><span class="operator">&gt;</span>close();
 }</pre>
<p>Once the HTML description of the files has been composed in a <a href="qstring.html">QString</a>, we convert it to a UTF-8 encoded set of bytes which we store in the reply's private <tt>content</tt> variable. In this case, the <a href="qbytearray.html">QByteArray</a> holds HTML instead of file data. We set the reply's headers to indicate that it contains UTF-8 encoded HTML with a certain length, and we emit the <a href="qiodevice.html#readyRead">readyRead()</a> and <a href="qnetworkreply.html#finished">finished()</a> signals to let the browser know that it can start reading the content.</p>
<a name="supplying-data-to-the-browser"></a>
<h3>Supplying Data to the Browser</h3>
<p>We reimplement four <a href="qiodevice.html">QIODevice</a> functions to provide basic read-only behavior, simply supplying the data held in the <tt>content</tt> array.</p>
<p>We do not support aborting of the reply, so our <tt>abort()</tt> implementation is empty.</p>
<pre class="cpp"> <span class="type">void</span> FtpReply<span class="operator">::</span>abort()
 {
 }</pre>
<p>Similarly, we do not support random access reading, so <tt>isSequential()</tt> is reimplemented to always return true.</p>
<pre class="cpp"> <span class="type">bool</span> FtpReply<span class="operator">::</span>isSequential() <span class="keyword">const</span>
 {
     <span class="keyword">return</span> <span class="keyword">true</span>;
 }</pre>
<p>The <tt>bytesAvailable()</tt> function returns the total number of bytes held by the reply minus the value of <tt>offset</tt>, which is the number of bytes we have already supplied to the reader.</p>
<pre class="cpp"> <span class="type"><a href="qtglobal.html#qint64-typedef">qint64</a></span> FtpReply<span class="operator">::</span>bytesAvailable() <span class="keyword">const</span>
 {
     <span class="keyword">return</span> content<span class="operator">.</span>size() <span class="operator">-</span> offset <span class="operator">+</span> <span class="type"><a href="qiodevice.html">QIODevice</a></span><span class="operator">::</span>bytesAvailable();
 }
 <span class="type"><a href="qtglobal.html#qint64-typedef">qint64</a></span> FtpReply<span class="operator">::</span>readData(<span class="type">char</span> <span class="operator">*</span>data<span class="operator">,</span> <span class="type"><a href="qtglobal.html#qint64-typedef">qint64</a></span> maxSize)
 {
     <span class="keyword">if</span> (offset <span class="operator">&lt;</span> content<span class="operator">.</span>size()) {
         <span class="type"><a href="qtglobal.html#qint64-typedef">qint64</a></span> number <span class="operator">=</span> <a href="qtglobal.html#qMin">qMin</a>(maxSize<span class="operator">,</span> content<span class="operator">.</span>size() <span class="operator">-</span> offset);
         memcpy(data<span class="operator">,</span> content<span class="operator">.</span>constData() <span class="operator">+</span> offset<span class="operator">,</span> number);
         offset <span class="operator">+</span><span class="operator">=</span> number;
         <span class="keyword">return</span> number;
     } <span class="keyword">else</span>
         <span class="keyword">return</span> <span class="operator">-</span><span class="number">1</span>;
 }</pre>
<p>The <tt>readData()</tt> reimplementation tries to return as much data to the reader as it will allow, copying bytes directly to the appropriate location in memory. The <tt>offset</tt> variable is updated to keep track of how many bytes have been read.</p>
<a name="enabling-the-protocol"></a>
<h2>Enabling the Protocol</h2>
<p>Now that we have an FTP-enabled network manager and a reply that can handle communication with FTP servers, we can now enable the manager for a given <a href="qwebpage.html">QWebPage</a>. We derive the <tt>FtpView</tt> class from <a href="qwebview.html">QWebView</a> and configure its behavior in its constructor.</p>
<p>As we mentioned earlier, we pass the original network manager to the newly-created manager and pass the new manager to the <a href="qwebpage.html">QWebPage</a> belonging to the browser. This enables our network manager for the content it displays.</p>
<pre class="cpp"> FtpView<span class="operator">::</span>FtpView()
 {
     <span class="type"><a href="qnetworkaccessmanager.html">QNetworkAccessManager</a></span> <span class="operator">*</span>oldManager <span class="operator">=</span> page()<span class="operator">-</span><span class="operator">&gt;</span>networkAccessManager();
     NetworkAccessManager <span class="operator">*</span>newManager <span class="operator">=</span> <span class="keyword">new</span> NetworkAccessManager(oldManager<span class="operator">,</span> <span class="keyword">this</span>);
     page()<span class="operator">-</span><span class="operator">&gt;</span>setNetworkAccessManager(newManager);

     page()<span class="operator">-</span><span class="operator">&gt;</span>setForwardUnsupportedContent(<span class="keyword">true</span>);
     downloader <span class="operator">=</span> <span class="keyword">new</span> Downloader(<span class="keyword">this</span><span class="operator">,</span> newManager);

     connect(page()<span class="operator">,</span> SIGNAL(unsupportedContent(<span class="type"><a href="qnetworkreply.html">QNetworkReply</a></span> <span class="operator">*</span>))<span class="operator">,</span>
             downloader<span class="operator">,</span> SLOT(saveFile(<span class="type"><a href="qnetworkreply.html">QNetworkReply</a></span> <span class="operator">*</span>)));
     connect(page()<span class="operator">,</span> SIGNAL(downloadRequested(<span class="keyword">const</span> <span class="type"><a href="qnetworkrequest.html">QNetworkRequest</a></span> <span class="operator">&amp;</span>))<span class="operator">,</span>
             downloader<span class="operator">,</span> SLOT(startDownload(<span class="keyword">const</span> <span class="type"><a href="qnetworkrequest.html">QNetworkRequest</a></span> <span class="operator">&amp;</span>)));

     connect(<span class="keyword">this</span><span class="operator">,</span> SIGNAL(urlChanged(<span class="keyword">const</span> <span class="type"><a href="qurl.html">QUrl</a></span> <span class="operator">&amp;</span>))<span class="operator">,</span>
             <span class="keyword">this</span><span class="operator">,</span> SLOT(updateWindowTitle(<span class="keyword">const</span> <span class="type"><a href="qurl.html">QUrl</a></span> <span class="operator">&amp;</span>)));
 }</pre>
<p>We also go to some effort to handle content that WebKit does not natively support, using a <tt>Downloader</tt> helper class to manage this and files that the user downloads via the browser's <b>Save Link..&#x2e;</b> context menu entry.</p>
<p>In the example's <tt>main()</tt> function, we perform the usual steps to initialize our Qt application. We choose an appropriate starting URL for the <tt>FtpView</tt> widget to open before running the application's event loop.</p>
<pre class="cpp"> <span class="type">int</span> main(<span class="type">int</span> argc<span class="operator">,</span> <span class="type">char</span> <span class="operator">*</span>argv<span class="operator">[</span><span class="operator">]</span>)
 {
     <span class="type"><a href="qapplication.html">QApplication</a></span> app(argc<span class="operator">,</span> argv);

     FtpView view;
     view<span class="operator">.</span>setUrl(<span class="type"><a href="qurl.html">QUrl</a></span>(<span class="string">&quot;ftp://ftp.qt.nokia.com&quot;</span>));
     view<span class="operator">.</span>show();

     <span class="keyword">return</span> app<span class="operator">.</span>exec();
 }</pre>
<a name="summary"></a>
<h2>Summary</h2>
<p>As we have seen, enabling support for another protocol and URL scheme in <a href="qtwebkit.html">QtWebKit</a> is a fairly simple process involving the creation of a network manager and custom reply object. The implementation challenges are mostly related to how the protocol is handled by the custom <a href="qnetworkreply.html">QNetworkReply</a> subclass where, in our case, we need to issue the appropriate commands in the correct order to obtain data from the FTP server.</p>
<p>We also need to ensure that that the reply emits the appropriate signals to inform the browser that it has content to be read. Our implementation is intentionally simple, only notifying the browser with the <a href="qiodevice.html#readyRead">readyRead()</a> signal when <i>all</i> the content is ready to read and emitting the <a href="qnetworkreply.html#finished">finished()</a> signal to indicate that communication is complete; a more sophisticated approach would interleave the commands sent to the server with the emission of signals, allowing the browser to read content as data is obtained from the FTP server.</p>
<p>The reply also needs to be open for reading. Forgetting to call the <a href="qiodevice.html#open">open()</a> function is a common error to make when dealing with devices, but in this case it is the reply's responsibility to open itself. It must indicate how much content it has for the browser to read. As we have seen, this is done by setting the reply's <a href="qnetworkrequest.html#KnownHeaders-enum">ContentLengthHeader</a> header with the appropriate value. With this information available, the browser can read from the reply when the content becomes available, displaying a directory listing or downloading content depending on the type of data supplied.</p>
<p>We can use the approach described in this article to enable support for other protocols by writing or extending a network manager to handle URL schemes such as <tt>mailto</tt>, <tt>sip</tt>, <tt>news</tt>, <tt>file</tt> and <tt>ldap</tt>. Applications that integrate Web content with information from other sources can also provide custom URL schemes as long as care is taken not to use an existing public scheme.</p>
</div>
<!-- @@@webkit/webftpclient -->
      </div>
    </div>
    </div> 
    <div class="ft">
      <span></span>
    </div>
  </div> 
  <div class="footer">
    <p>
      <acronym title="Copyright">&copy;</acronym> 2015 The Qt Company Ltd.
      Documentation contributions included herein are the copyrights of
      their respective owners.</p>
    <br />
    <p>
      The documentation provided herein is licensed under the terms of the
      <a href="http://www.gnu.org/licenses/fdl.html">GNU Free Documentation
      License version 1.3</a> as published by the Free Software Foundation.</p>
    <p>
      Documentation sources may be obtained from <a href="http://www.qt-project.org">
      www.qt-project.org</a>.</p>
    <br />
    <p>
      Qt and respective logos are trademarks of The Qt Company Ltd 
      in Finland and/or other countries worldwide. All other trademarks are property
      of their respective owners. <a title="Privacy Policy"
      href="http://en.gitorious.org/privacy_policy/">Privacy Policy</a></p>
  </div>

  <script src="scripts/functions.js" type="text/javascript"></script>
</body>
</html>