Update references to online documentation.
[qt:qt-ios-plaszma.git] / tools / assistant / tools / assistant / installdialog.cpp
1 /****************************************************************************
2 **
3 ** Copyright (C) 2009 Nokia Corporation and/or its subsidiary(-ies).
4 ** Contact: Nokia Corporation (qt-info@nokia.com)
5 **
6 ** This file is part of the Qt Assistant of the Qt Toolkit.
7 **
8 ** $QT_BEGIN_LICENSE:LGPL$
9 ** No Commercial Usage
10 ** This file contains pre-release code and may not be distributed.
11 ** You may use this file in accordance with the terms and conditions
12 ** contained in the either Technology Preview License Agreement or the
13 ** Beta Release License Agreement.
14 **
15 ** GNU Lesser General Public License Usage
16 ** Alternatively, this file may be used under the terms of the GNU Lesser
17 ** General Public License version 2.1 as published by the Free Software
18 ** Foundation and appearing in the file LICENSE.LGPL included in the
19 ** packaging of this file.  Please review the following information to
20 ** ensure the GNU Lesser General Public License version 2.1 requirements
21 ** will be met: http://www.gnu.org/licenses/old-licenses/lgpl-2.1.html.
22 **
23 ** In addition, as a special exception, Nokia gives you certain
24 ** additional rights. These rights are described in the Nokia Qt LGPL
25 ** Exception version 1.0, included in the file LGPL_EXCEPTION.txt in this
26 ** package.
27 **
28 ** GNU General Public License Usage
29 ** Alternatively, this file may be used under the terms of the GNU
30 ** General Public License version 3.0 as published by the Free Software
31 ** Foundation and appearing in the file LICENSE.GPL included in the
32 ** packaging of this file.  Please review the following information to
33 ** ensure the GNU General Public License version 3.0 requirements will be
34 ** met: http://www.gnu.org/copyleft/gpl.html.
35 **
36 ** If you are unsure which license is appropriate for your use, please
37 ** contact the sales department at http://qt.nokia.com/contact.
38 ** $QT_END_LICENSE$
39 **
40 ****************************************************************************/
41
42 #include "installdialog.h"
43
44 #include <QtCore/QTimer>
45 #include <QtCore/QUrl>
46 #include <QtCore/QBuffer>
47 #include <QtCore/QDir>
48 #include <QtCore/QFile>
49 #include <QtCore/QCryptographicHash>
50
51 #include <QtGui/QMessageBox>
52 #include <QtGui/QFileDialog>
53
54 #include <QtHelp/QHelpEngineCore>
55
56 #include <QtNetwork/QHttp>
57
58 QT_BEGIN_NAMESPACE
59 #ifndef QT_NO_HTTP
60
61 #define QCH_FILENAME  92943
62 #define QCH_NAMESPACE 92944
63 #define QCH_CHECKSUM  92945
64
65 InstallDialog::InstallDialog(QHelpEngineCore *helpEngine, QWidget *parent,
66                              const QString &host, int port)
67     : QDialog(parent), m_helpEngine(helpEngine), m_host(host), m_port(port)
68 {
69     m_ui.setupUi(this);
70     
71     m_ui.installButton->setEnabled(false);
72     m_ui.cancelButton->setEnabled(false);
73     m_ui.pathLineEdit->setText(QFileInfo(m_helpEngine->collectionFile()).absolutePath());
74     m_ui.progressBar->hide();
75
76     m_windowTitle = tr("Install Documentation");
77
78     m_http = new QHttp(this);
79     connect(m_http, SIGNAL(requestFinished(int, bool)),
80             this, SLOT(httpRequestFinished(int, bool)));
81     connect(m_http, SIGNAL(dataReadProgress(int, int)),
82             this, SLOT(updateDataReadProgress(int, int)));
83     connect(m_http, SIGNAL(responseHeaderReceived(const QHttpResponseHeader &)),
84             this, SLOT(readResponseHeader(const QHttpResponseHeader &)));
85     connect(m_ui.installButton, SIGNAL(clicked()), this, SLOT(install()));
86     connect(m_ui.cancelButton, SIGNAL(clicked()), this, SLOT(cancelDownload()));
87     connect(m_ui.browseButton, SIGNAL(clicked()), this, SLOT(browseDirectories()));
88
89     connect(m_ui.listWidget, SIGNAL(itemChanged(QListWidgetItem*)),
90         this, SLOT(updateInstallButton()));
91
92     QTimer::singleShot(0, this, SLOT(init()));
93 }
94
95 InstallDialog::~InstallDialog()
96 {
97 }
98
99 QStringList InstallDialog::installedDocumentations() const
100 {
101     return m_installedDocumentations;
102 }
103
104 void InstallDialog::init()
105 {
106     m_ui.statusLabel->setText(tr("Downloading documentation info..."));
107     m_ui.progressBar->show();
108     
109     QUrl url(QLatin1String("http://qt.nokia.com/doc/assistantdocs/docs.txt"));
110     m_buffer = new QBuffer();
111     m_buffer->open(QBuffer::ReadWrite);
112
113     if (m_port > -1)
114         m_http->setProxy(m_host, m_port);
115     m_http->setHost(url.host());
116     m_httpAborted = false;
117     m_docInfoId = m_http->get(url.path(), m_buffer);
118
119     m_ui.cancelButton->setEnabled(true);
120     m_ui.closeButton->setEnabled(false);    
121 }
122
123 void InstallDialog::updateInstallButton()
124 {
125     QListWidgetItem *item = 0;
126     for (int i=0; i<m_ui.listWidget->count(); ++i) {
127         item = m_ui.listWidget->item(i);
128         if (item->checkState() == Qt::Checked
129             && item->flags() & Qt::ItemIsEnabled) {
130             m_ui.installButton->setEnabled(true);
131             return;
132         }       
133     }
134     m_ui.installButton->setEnabled(false);
135 }
136
137 void InstallDialog::updateDocItemList()
138 {
139     QStringList registeredDocs = m_helpEngine->registeredDocumentations();
140     QListWidgetItem *item = 0;
141     for (int i=0; i<m_ui.listWidget->count(); ++i) {
142         item = m_ui.listWidget->item(i);
143         QString ns = item->data(QCH_NAMESPACE).toString();
144         if (!ns.isEmpty() && registeredDocs.contains(ns)) {
145             item->setFlags(Qt::ItemIsUserCheckable);
146             item->setCheckState(Qt::Checked);
147         }
148         item->setCheckState(Qt::Unchecked);
149     }
150 }
151
152 void InstallDialog::cancelDownload()
153 {
154     m_ui.statusLabel->setText(tr("Download canceled."));
155     m_httpAborted = true;
156     m_itemsToInstall.clear();
157     m_http->abort();
158     m_ui.cancelButton->setEnabled(false);
159     m_ui.closeButton->setEnabled(true);
160     updateInstallButton();
161 }
162
163 void InstallDialog::install()
164 {
165     QListWidgetItem *item = 0;
166     for (int i=0; i<m_ui.listWidget->count(); ++i) {
167         item = m_ui.listWidget->item(i);
168         if (item->checkState() == Qt::Checked)
169             m_itemsToInstall.append(item);
170     }
171     m_ui.installButton->setEnabled(false);
172     downloadNextFile();
173 }
174
175 void InstallDialog::downloadNextFile()
176 {
177     if (!m_itemsToInstall.count()) {
178         m_ui.cancelButton->setEnabled(false);
179         m_ui.closeButton->setEnabled(true);
180         m_ui.statusLabel->setText(tr("Done."));
181         m_ui.progressBar->hide();
182         updateDocItemList();
183         updateInstallButton();
184         return;
185     }
186
187     QListWidgetItem *item = m_itemsToInstall.dequeue();
188     m_currentCheckSum = item->data(QCH_CHECKSUM).toString();
189     QString fileName = item->data(QCH_FILENAME).toString();
190     QString saveFileName = m_ui.pathLineEdit->text() + QDir::separator()
191         + fileName;
192
193     if (QFile::exists(saveFileName)
194         && QMessageBox::information(this, m_windowTitle,
195         tr("The file %1 already exists. Do you want to overwrite it?")
196         .arg(saveFileName), QMessageBox::Yes | QMessageBox::No,
197         QMessageBox::Yes) == QMessageBox::No) {
198         installFile(saveFileName);
199         downloadNextFile();
200         return;        
201     }
202
203     m_file = new QFile(saveFileName);
204     if (!m_file->open(QIODevice::WriteOnly|QIODevice::Truncate)) {
205         QMessageBox::information(this, m_windowTitle,
206             tr("Unable to save the file %1: %2.")
207             .arg(saveFileName).arg(m_file->errorString()));
208         delete m_file;
209         m_file = 0;
210         downloadNextFile();
211         return;
212     }
213
214     m_ui.statusLabel->setText(tr("Downloading %1...").arg(fileName));
215     m_ui.progressBar->show();
216
217     QLatin1String urlStr("http://qt.nokia.com/doc/assistantdocs/%1");
218     QUrl url(QString(urlStr).arg(fileName));    
219     
220     m_httpAborted = false;
221     m_docId = m_http->get(url.path(), m_file);
222     
223     m_ui.cancelButton->setEnabled(true);
224     m_ui.closeButton->setEnabled(false);    
225 }
226
227 void InstallDialog::httpRequestFinished(int requestId, bool error)
228 {
229     if (requestId == m_docInfoId  && m_buffer) {        
230         m_ui.progressBar->hide();
231         if (error) {
232             QMessageBox::information(this, m_windowTitle,
233                 tr("Download failed: %1.")
234                 .arg(m_http->errorString()));
235         } else if (!m_httpAborted) {
236             QStringList registeredDocs = m_helpEngine->registeredDocumentations();
237             m_buffer->seek(0);
238             while (m_buffer->canReadLine()) {
239                 QByteArray ba = m_buffer->readLine();
240                 QStringList lst = QString::fromAscii(ba.constData()).split(QLatin1Char('|'));
241                 if (lst.count() != 4) {
242                     QMessageBox::information(this, m_windowTitle,
243                         tr("Documentation info file is corrupt!"));
244                 } else {
245                     QListWidgetItem *item = new QListWidgetItem(m_ui.listWidget);
246                     item->setText(lst.at(2).trimmed());
247                     item->setData(QCH_FILENAME, lst.first());
248                     item->setData(QCH_NAMESPACE, lst.at(1));
249                     item->setData(QCH_CHECKSUM, lst.last().trimmed());
250                 }
251             }
252             updateDocItemList();
253         }
254         if (m_buffer)
255             m_buffer->close();
256         delete m_buffer;
257         m_buffer = 0;
258         m_ui.statusLabel->setText(tr("Done."));
259         m_ui.cancelButton->setEnabled(false);        
260         m_ui.closeButton->setEnabled(true);
261         updateInstallButton();
262     } else if (requestId == m_docId) {        
263         m_file->close();
264         if (!m_httpAborted) {
265             QString checkSum;
266             if (m_file->open(QIODevice::ReadOnly)) {                
267                 QByteArray digest = QCryptographicHash::hash(m_file->readAll(),
268                     QCryptographicHash::Md5);
269                 m_file->close();
270                 checkSum = QString::fromLatin1(digest.toHex());             
271             }            
272             if (error) {
273                 m_file->remove();
274                 QMessageBox::warning(this, m_windowTitle,
275                     tr("Download failed: %1.")
276                     .arg(m_http->errorString()));
277             } else if (checkSum.isEmpty() || m_currentCheckSum != checkSum) {
278                 m_file->remove();
279                 QMessageBox::warning(this, m_windowTitle,
280                     tr("Download failed: Downloaded file is corrupted."));
281             } else {
282                 m_ui.statusLabel->setText(tr("Installing documentation %1...")
283                     .arg(QFileInfo(m_file->fileName()).fileName()));
284                 m_ui.progressBar->setMaximum(0);
285                 m_ui.statusLabel->setText(tr("Done."));
286                 installFile(m_file->fileName());                
287             }
288         } else {
289             m_file->remove();
290         }
291         delete m_file;
292         m_file = 0;
293         downloadNextFile();
294     }
295 }
296
297 void InstallDialog::installFile(const QString &fileName)
298 {
299     if (m_helpEngine->registerDocumentation(fileName)) {
300         m_installedDocumentations
301             .append(QHelpEngineCore::namespaceName(fileName));
302     } else {
303         QMessageBox::information(this, m_windowTitle,
304             tr("Error while installing documentation:\n%1")
305             .arg(m_helpEngine->error()));
306     }
307 }
308
309 void InstallDialog::readResponseHeader(const QHttpResponseHeader &responseHeader)
310 {
311     if (responseHeader.statusCode() != 200) {
312         QMessageBox::information(this, m_windowTitle,
313             tr("Download failed: %1.")
314             .arg(responseHeader.reasonPhrase()));
315         m_httpAborted = true;
316         m_ui.progressBar->hide();
317         m_http->abort();
318         return;
319     }
320 }
321
322 void InstallDialog::updateDataReadProgress(int bytesRead, int totalBytes)
323 {
324     if (m_httpAborted)
325         return;
326
327     m_ui.progressBar->setMaximum(totalBytes);
328     m_ui.progressBar->setValue(bytesRead);
329 }
330
331 void InstallDialog::browseDirectories()
332 {
333     QString dir = QFileDialog::getExistingDirectory(this, m_windowTitle,
334         m_ui.pathLineEdit->text());
335     if (!dir.isEmpty())
336         m_ui.pathLineEdit->setText(dir);
337 }
338
339 #endif
340 QT_END_NAMESPACE