source: trunk/tools/assistant/compat/lib/qassistantclient.cpp@ 315

Last change on this file since 315 was 2, checked in by Dmitry A. Kuminov, 16 years ago

Initially imported qt-all-opensource-src-4.5.1 from Trolltech.

File size: 14.9 KB
Line 
1/****************************************************************************
2**
3** Copyright (C) 2009 Nokia Corporation and/or its subsidiary(-ies).
4** Contact: Qt Software Information ([email protected])
5**
6** This file is part of the Qt Assistant of the Qt Toolkit.
7**
8** $QT_BEGIN_LICENSE:LGPL$
9** Commercial Usage
10** Licensees holding valid Qt Commercial licenses may use this file in
11** accordance with the Qt Commercial License Agreement provided with the
12** Software or, alternatively, in accordance with the terms contained in
13** a written agreement between you and Nokia.
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 [email protected].
38** $QT_END_LICENSE$
39**
40****************************************************************************/
41
42#include "qassistantclient.h"
43
44#include <qtcpsocket.h>
45#include <qtextstream.h>
46#include <qtimer.h>
47#include <qfileinfo.h>
48#include <qmap.h>
49
50QT_BEGIN_NAMESPACE
51
52class QAssistantClientPrivate
53{
54 friend class QAssistantClient;
55 QStringList arguments;
56};
57
58static QMap<const QAssistantClient*,QAssistantClientPrivate*> *dpointers = 0;
59
60static QAssistantClientPrivate *data( const QAssistantClient *client, bool create=false )
61{
62 if( !dpointers )
63 dpointers = new QMap<const QAssistantClient*,QAssistantClientPrivate*>;
64 QAssistantClientPrivate *d = (*dpointers)[client];
65 if( !d && create ) {
66 d = new QAssistantClientPrivate;
67 dpointers->insert( client, d );
68 }
69 return d;
70}
71
72/*!
73 \class QAssistantClient
74 \obsolete
75 \brief The QAssistantClient class provides a means of using Qt
76 Assistant as an application's help tool.
77
78 \inmodule QtAssistant
79 \ingroup helpsystem
80
81 \bold{Note:} \e{This class is obsolete and only required when using
82 the old Qt Assistant, now called assistant_adp. If you want to use
83 the new Qt Assistant as a remote help viewer, simple create a
84 QProcess instance and specify \tt{assistant} as its executable.
85 The following code shows how to start Qt Assistant and request a
86 certain page to be shown:}
87
88 \snippet doc/src/snippets/code/tools_assistant_compat_lib_qassistantclient.cpp 0
89
90 \e{For a complete example using the Qt Assistant remotely, see the \l
91 {help/remotecontrol}{Remote Control} example.}
92
93 In order to make Qt Assistant act as a customized help tool for
94 your application, you must provide your application with a
95 QAssistantClient object in addition to a \l
96 {assistant-manual.html} {Qt Assistant Document Profile} (\c .adp
97 file) and the associated documentation.
98
99 Note that the QAssistantClient class is not included in the Qt
100 library. To use it you must add the following line to your pro
101 file:
102
103 \snippet doc/src/snippets/code/tools_assistant_compat_lib_qassistantclient.cpp 1
104
105 A QAssistantClient instance can open or close Qt Assistant
106 whenever it is required.
107
108 Once you have created a QAssistantClient instance, specifying the
109 path to the Qt Assistant executable, using Qt Assistant is
110 simple: You can either call the openAssistant() slot to show the
111 defined start page of the documentation, or you can call the
112 showPage() slot to show a particular help page. When you call
113 openAssistant() and showPage(), Qt Assistant will be launched if
114 it isn't already running. When Qt Assistant is running, the
115 isOpen() function returns true.
116
117 When calling showPage() the Qt Assistant instance will also be
118 brought to the foreground if its hidden. The showPage() slot can
119 be called multiple times, while calling openAssistant() several
120 times without closing the application in between, will have no
121 effect.
122
123 You can close Qt Assistant at any time using the closeAssistant()
124 slot. When you call openAssistant(), or you call showPage()
125 without a previous call to openAssistant(), the assistantOpened()
126 signal is emitted. Similarly when closeAssistant() is called,
127 assistantClosed() is emitted. In either case, if an error occurs,
128 error() is emitted.
129
130 One QAssistantClient instance interacts with one Qt Assistant
131 instance, so every time you call openAssistant(), showPage() or
132 closeAssistant() they are applied to the particular Qt Assistant
133 instance associated with the QAssistantClient.
134
135 Qt Assistant's documentation set can be altered using the command
136 line arguments that are passed to the application when it is
137 launched. When started without any options, Qt Assistant displays
138 a default set of documentation. When Qt is installed, the default
139 documentation set in Qt Assistant contains the Qt reference
140 documentation as well as the tools that come with Qt, such as \QD
141 and \c qmake.
142
143 Use the setArguments() function to specify the command line
144 arguments. You can add or remove documentation from Qt Assistant
145 by adding and removing the relevant content files: The command
146 line arguments are \c {-addContentFile file.dcf} and \c
147 {-removeContentFile file.dcf} respectively. You can make Qt
148 Assistant run customized documentation sets that are separate from
149 the Qt documentation, by specifying a profile: \c {-profile
150 myapplication.adp}. The profile format can also be used to alter
151 several of Qt Assistant's properties such as its title and
152 startpage.
153
154 The Documentation Content File (\c .dcf) and Qt Assistant
155 Documentation Profile (\c .adp) formats are documented in the \l
156 {assistant-manual.html}{Qt Assistant Manual}.
157
158 For a complete example using the QAssistantClient class, see the
159 \e{Simple Text Viewer} example. The example shows how you can make
160 Qt Assistant act as a customized help tool for your application
161 using the QAssistantClient class combined with a Qt Assistant
162 Document Profile.
163
164 \sa {Qt Assistant Manual}, {Simple Text Viewer Example}
165*/
166
167/*!
168 \fn void QAssistantClient::assistantOpened()
169
170 This signal is emitted when Qt Assistant is opened and the
171 client-server communication is set up.
172
173 \sa openAssistant(), showPage()
174*/
175
176/*!
177 \fn void QAssistantClient::assistantClosed()
178
179 This signal is emitted when the connection to Qt Assistant is
180 closed. This happens when the user exits Qt Assistant, if an
181 error in the server or client occurs, or if closeAssistant() is
182 called.
183
184 \sa closeAssistant()
185*/
186
187/*!
188 \fn void QAssistantClient::error( const QString &message )
189
190 This signal is emitted if Qt Assistant cannot be started, or if an
191 error occurs during the initialization of the connection between
192 Qt Assistant and the calling application. The \a message provides an
193 explanation of the error.
194*/
195
196/*!
197 Constructs an assistant client with the specified \a parent. For
198 systems other than Mac OS, \a path specifies the path to the Qt
199 Assistant executable. For Mac OS, \a path specifies a directory
200 containing a valid assistant.app bundle. If \a path is the empty
201 string, the system path (\c{%PATH%} or \c $PATH) is used.
202*/
203QAssistantClient::QAssistantClient( const QString &path, QObject *parent )
204 : QObject( parent ), host ( QLatin1String("localhost") )
205{
206#if defined(Q_OS_MAC)
207 const QString assistant = QLatin1String("Assistant_adp");
208#else
209 const QString assistant = QLatin1String("assistant_adp");
210#endif
211
212 if ( path.isEmpty() )
213 assistantCommand = assistant;
214 else {
215 QFileInfo fi( path );
216 if ( fi.isDir() )
217 assistantCommand = path + QLatin1String("/") + assistant;
218 else
219 assistantCommand = path;
220 }
221
222#if defined(Q_OS_MAC)
223 assistantCommand += QLatin1String(".app/Contents/MacOS/Assistant_adp");
224#endif
225
226 socket = new QTcpSocket( this );
227 connect( socket, SIGNAL(connected()),
228 SLOT(socketConnected()) );
229 connect( socket, SIGNAL(disconnected()),
230 SLOT(socketConnectionClosed()) );
231 connect( socket, SIGNAL(error(QAbstractSocket::SocketError)),
232 SLOT(socketError()) );
233 opened = false;
234 proc = new QProcess( this );
235 port = 0;
236 pageBuffer = QLatin1String("");
237 connect( proc, SIGNAL(readyReadStandardError()),
238 this, SLOT(readStdError()) );
239 connect( proc, SIGNAL(error(QProcess::ProcessError)),
240 this, SLOT(procError(QProcess::ProcessError)) );
241}
242
243/*!
244 Destroys the assistant client object.
245*/
246QAssistantClient::~QAssistantClient()
247{
248 if ( proc->state() == QProcess::Running )
249 proc->terminate();
250
251 if( dpointers ) {
252 QAssistantClientPrivate *d = (*dpointers)[ this ];
253 if ( d ) {
254 dpointers->remove(this);
255 delete d;
256 if( dpointers->isEmpty() ) {
257 delete dpointers;
258 dpointers = 0;
259 }
260 }
261 }
262}
263
264/*!
265 Opens Qt Assistant, i.e. sets up the client-server communication
266 between the application and Qt Assistant, and shows the start page
267 specified by the current \l {assistant-manual.html}
268 {Qt Assistant Document Profile}. If there is no specfied profile,
269 and Qt is installed, the default start page is the Qt Reference
270 Documentation's index page.
271
272 If the connection is already established, this function does
273 nothing. Use the showPage() function to show another page. If an
274 error occurs, the error() signal is emitted.
275
276 \sa showPage(), assistantOpened()
277*/
278void QAssistantClient::openAssistant()
279{
280 if ( proc->state() == QProcess::Running )
281 return;
282
283 QStringList args;
284 args.append(QLatin1String("-server"));
285 if( !pageBuffer.isEmpty() ) {
286 args.append( QLatin1String("-file") );
287 args.append( pageBuffer );
288 }
289
290 QAssistantClientPrivate *d = data( this );
291 if( d ) {
292 QStringList::ConstIterator it = d->arguments.constBegin();
293 while( it!=d->arguments.constEnd() ) {
294 args.append( *it );
295 ++it;
296 }
297 }
298
299 connect( proc, SIGNAL(readyReadStandardOutput()),
300 this, SLOT(readPort()) );
301
302 proc->start(assistantCommand, args);
303}
304
305void QAssistantClient::procError(QProcess::ProcessError err)
306{
307 switch (err)
308 {
309 case QProcess::FailedToStart:
310 emit error( tr( "Failed to start Qt Assistant." ) );
311 break;
312 case QProcess::Crashed:
313 emit error( tr( "Qt Assistant crashed." ) );
314 break;
315 default:
316 emit error( tr( "Error while running Qt Assistant." ) );
317 }
318}
319
320void QAssistantClient::readPort()
321{
322 QString p(QString::fromLatin1(proc->readAllStandardOutput()));
323 quint16 port = p.toUShort();
324 if ( port == 0 ) {
325 emit error( tr( "Cannot connect to Qt Assistant." ) );
326 return;
327 }
328 socket->connectToHost( host, port );
329 disconnect( proc, SIGNAL(readyReadStandardOutput()),
330 this, SLOT(readPort()) );
331}
332
333/*!
334 Closes the Qt Assistant instance.
335
336 \sa openAssistant(), assistantClosed()
337*/
338void QAssistantClient::closeAssistant()
339{
340 if ( !opened )
341 return;
342
343 bool blocked = proc->blockSignals(true);
344 proc->terminate();
345 if (!proc->waitForFinished(2000)) {
346 // If the process hasn't died after 2 seconds,
347 // we kill it, causing it to exit immediately.
348 proc->kill();
349 }
350 proc->blockSignals(blocked);
351}
352
353/*!
354 Brings Qt Assistant to the foreground showing the given \a page.
355 The \a page parameter is a path to an HTML file
356 (e.g., QLatin1String("/home/pasquale/superproduct/docs/html/intro.html")).
357
358 If Qt Assistant hasn't been opened yet, this function will call
359 the openAssistant() slot with the specified page as the start
360 page.
361
362 \note The first time Qt Assistant is started, its window will open
363 in front of the application's windows. Subsequent calls to this function
364 will only load the specified pages in Qt Assistant and will not display
365 its window in front of the application's windows.
366
367 \sa openAssistant()
368*/
369void QAssistantClient::showPage( const QString &page )
370{
371 if (opened) {
372 QTextStream os( socket );
373 os << page << QLatin1String("\n");
374 } else {
375 pageBuffer = page;
376
377 if (proc->state() == QProcess::NotRunning) {
378 openAssistant();
379 pageBuffer.clear();
380 return;
381 }
382 }
383}
384
385/*!
386 \property QAssistantClient::open
387 \brief whether Qt Assistant is open
388
389*/
390bool QAssistantClient::isOpen() const
391{
392 return opened;
393}
394
395void QAssistantClient::socketConnected()
396{
397 opened = true;
398 if ( !pageBuffer.isEmpty() )
399 showPage( pageBuffer );
400 emit assistantOpened();
401}
402
403void QAssistantClient::socketConnectionClosed()
404{
405 opened = false;
406 emit assistantClosed();
407}
408
409void QAssistantClient::socketError()
410{
411 QAbstractSocket::SocketError err = socket->error();
412 if (err == QTcpSocket::ConnectionRefusedError)
413 emit error( tr( "Could not connect to Assistant: Connection refused" ) );
414 else if (err == QTcpSocket::HostNotFoundError)
415 emit error( tr( "Could not connect to Assistant: Host not found" ) );
416 else if (err != QTcpSocket::RemoteHostClosedError)
417 emit error( tr( "Communication error" ) );
418}
419
420void QAssistantClient::readStdError()
421{
422 QString errmsg = QString::fromLatin1(proc->readAllStandardError());
423
424 if (!errmsg.isEmpty())
425 emit error( errmsg.simplified() );
426}
427
428/*!
429 \fn void QAssistantClient::setArguments(const QStringList &arguments)
430
431 Sets the command line \a arguments that are passed to Qt Assistant
432 when it is launched.
433
434 The command line arguments can be used to alter Qt Assistant's
435 documentation set. When started without any options, Qt Assistant
436 displays a default set of documentation. When Qt is installed, the
437 default documentation set in Qt Assistant contains the Qt
438 reference documentation as well as the tools that come with Qt,
439 such as Qt Designer and qmake.
440*/
441void QAssistantClient::setArguments( const QStringList &args )
442{
443 QAssistantClientPrivate *d = data( this, true );
444 d->arguments = args;
445}
446
447QT_END_NAMESPACE
Note: See TracBrowser for help on using the repository browser.