0
|
1 |
/****************************************************************************
|
|
2 |
**
|
|
3 |
** Copyright (C) 2009 Nokia Corporation and/or its subsidiary(-ies).
|
|
4 |
** All rights reserved.
|
|
5 |
** Contact: Nokia Corporation (qt-info@nokia.com)
|
|
6 |
**
|
|
7 |
** This file is part of the Qt Assistant of the Qt Toolkit.
|
|
8 |
**
|
|
9 |
** $QT_BEGIN_LICENSE:LGPL$
|
|
10 |
** No Commercial Usage
|
|
11 |
** This file contains pre-release code and may not be distributed.
|
|
12 |
** You may use this file in accordance with the terms and conditions
|
|
13 |
** contained in the Technology Preview License Agreement accompanying
|
|
14 |
** this package.
|
|
15 |
**
|
|
16 |
** GNU Lesser General Public License Usage
|
|
17 |
** Alternatively, this file may be used under the terms of the GNU Lesser
|
|
18 |
** General Public License version 2.1 as published by the Free Software
|
|
19 |
** Foundation and appearing in the file LICENSE.LGPL included in the
|
|
20 |
** packaging of this file. Please review the following information to
|
|
21 |
** ensure the GNU Lesser General Public License version 2.1 requirements
|
|
22 |
** will be met: http://www.gnu.org/licenses/old-licenses/lgpl-2.1.html.
|
|
23 |
**
|
|
24 |
** In addition, as a special exception, Nokia gives you certain additional
|
|
25 |
** rights. These rights are described in the Nokia Qt LGPL Exception
|
|
26 |
** version 1.1, included in the file LGPL_EXCEPTION.txt in this package.
|
|
27 |
**
|
|
28 |
** If you have questions regarding the use of this file, please contact
|
|
29 |
** Nokia at qt-info@nokia.com.
|
|
30 |
**
|
|
31 |
**
|
|
32 |
**
|
|
33 |
**
|
|
34 |
**
|
|
35 |
**
|
|
36 |
**
|
|
37 |
**
|
|
38 |
** $QT_END_LICENSE$
|
|
39 |
**
|
|
40 |
****************************************************************************/
|
|
41 |
|
|
42 |
#include "mainwindow.h"
|
|
43 |
#include "tabbedbrowser.h"
|
|
44 |
#include "helpdialog.h"
|
|
45 |
#include "config.h"
|
|
46 |
#include "fontsettingsdialog.h"
|
|
47 |
|
|
48 |
#include <QDockWidget>
|
|
49 |
#include <QDir>
|
|
50 |
#include <QTimer>
|
|
51 |
#include <QStatusBar>
|
|
52 |
#include <QShortcut>
|
|
53 |
#include <QMessageBox>
|
|
54 |
#include <QPainter>
|
|
55 |
#include <QEventLoop>
|
|
56 |
#include <QtEvents>
|
|
57 |
#include <QFontDatabase>
|
|
58 |
#include <QWhatsThis>
|
|
59 |
#include <QTextDocumentFragment>
|
|
60 |
#include <QLibraryInfo>
|
|
61 |
#include <QPrinter>
|
|
62 |
#include <QPrintDialog>
|
|
63 |
#include <QAbstractTextDocumentLayout>
|
|
64 |
#include <QTextDocument>
|
|
65 |
#include <QTextObject>
|
|
66 |
#include <QFileDialog>
|
|
67 |
#include <QThread>
|
|
68 |
|
|
69 |
QT_BEGIN_NAMESPACE
|
|
70 |
|
|
71 |
QList<MainWindow*> MainWindow::windows;
|
|
72 |
|
|
73 |
#if defined(Q_WS_WIN)
|
|
74 |
extern Q_CORE_EXPORT int qt_ntfs_permission_lookup;
|
|
75 |
#endif
|
|
76 |
|
|
77 |
MainWindow::MainWindow()
|
|
78 |
{
|
|
79 |
setUnifiedTitleAndToolBarOnMac(true);
|
|
80 |
ui.setupUi(this);
|
|
81 |
|
|
82 |
#if defined(Q_WS_WIN)
|
|
83 |
// Workaround for QMimeSourceFactory failing in QFileInfo::isReadable() for
|
|
84 |
// certain user configs. See task: 34372
|
|
85 |
qt_ntfs_permission_lookup = 0;
|
|
86 |
#endif
|
|
87 |
setupCompleted = false;
|
|
88 |
|
|
89 |
goActions = QList<QAction*>();
|
|
90 |
goActionDocFiles = new QMap<QAction*,QString>;
|
|
91 |
|
|
92 |
windows.append(this);
|
|
93 |
tabs = new TabbedBrowser(this);
|
|
94 |
connect(tabs, SIGNAL(tabCountChanged(int)), this, SLOT(updateTabActions(int)));
|
|
95 |
setCentralWidget(tabs);
|
|
96 |
|
|
97 |
Config *config = Config::configuration();
|
|
98 |
|
|
99 |
updateProfileSettings();
|
|
100 |
|
|
101 |
dw = new QDockWidget(this);
|
|
102 |
dw->setAllowedAreas(Qt::LeftDockWidgetArea | Qt::RightDockWidgetArea);
|
|
103 |
dw->setWindowTitle(tr("Sidebar"));
|
|
104 |
dw->setObjectName(QLatin1String("sidebar"));
|
|
105 |
helpDock = new HelpDialog(dw, this);
|
|
106 |
dw->setWidget(helpDock);
|
|
107 |
|
|
108 |
addDockWidget(Qt::LeftDockWidgetArea, dw);
|
|
109 |
|
|
110 |
// read geometry configuration
|
|
111 |
setupGoActions();
|
|
112 |
|
|
113 |
restoreGeometry(config->windowGeometry());
|
|
114 |
restoreState(config->mainWindowState());
|
|
115 |
if (config->sideBarHidden())
|
|
116 |
dw->hide();
|
|
117 |
|
|
118 |
tabs->setup();
|
|
119 |
QTimer::singleShot(0, this, SLOT(setup()));
|
|
120 |
#if defined(Q_WS_MAC)
|
|
121 |
QMenu *windowMenu = new QMenu(tr("&Window"), this);
|
|
122 |
menuBar()->insertMenu(ui.helpMenu->menuAction(), windowMenu);
|
|
123 |
windowMenu->addAction(tr("Minimize"), this,
|
|
124 |
SLOT(showMinimized()), QKeySequence(tr("Ctrl+M")));
|
|
125 |
// Use the same forward and backward browser shortcuts as Safari and Internet Explorer do
|
|
126 |
// on the Mac. This means that if you have access to one of those cool Intellimice, the thing
|
|
127 |
// works just fine, since that's how Microsoft hacked it.
|
|
128 |
ui.actionGoPrevious->setShortcut(QKeySequence(Qt::CTRL|Qt::Key_Left));
|
|
129 |
ui.actionGoNext->setShortcut(QKeySequence(Qt::CTRL|Qt::Key_Right));
|
|
130 |
|
|
131 |
static const QLatin1String MacIconPath(":/trolltech/assistant/images/mac");
|
|
132 |
ui.actionGoNext->setIcon(QIcon(MacIconPath + QLatin1String("/next.png")));
|
|
133 |
ui.actionGoPrevious->setIcon(QIcon(MacIconPath + QLatin1String("/prev.png")));
|
|
134 |
ui.actionGoHome->setIcon(QIcon(MacIconPath + QLatin1String("/home.png")));
|
|
135 |
ui.actionEditCopy->setIcon(QIcon(MacIconPath + QLatin1String("/editcopy.png")));
|
|
136 |
ui.actionEditCopy->setIcon(QIcon(MacIconPath + QLatin1String("/editcopy.png")));
|
|
137 |
ui.actionEditFind->setIcon(QIcon(MacIconPath + QLatin1String("/find.png")));
|
|
138 |
ui.actionFilePrint->setIcon(QIcon(MacIconPath + QLatin1String("/print.png")));
|
|
139 |
ui.actionZoomOut->setIcon(QIcon(MacIconPath + QLatin1String("/zoomout.png")));
|
|
140 |
ui.actionZoomIn->setIcon(QIcon(MacIconPath + QLatin1String("/zoomin.png")));
|
|
141 |
ui.actionSyncToc->setIcon(QIcon(MacIconPath + QLatin1String("/synctoc.png")));
|
|
142 |
ui.actionHelpWhatsThis->setIcon(QIcon(MacIconPath + QLatin1String("/whatsthis.png")));
|
|
143 |
#elif defined(Q_WS_X11)
|
|
144 |
ui.actionGoNext->setIcon(QIcon::fromTheme("go-next" , ui.actionGoNext->icon()));
|
|
145 |
ui.actionGoPrevious->setIcon(QIcon::fromTheme("go-previous" , ui.actionGoPrevious->icon()));
|
|
146 |
ui.actionGoHome->setIcon(QIcon::fromTheme("user-home" , ui.actionGoHome->icon()));
|
|
147 |
ui.actionEditCopy->setIcon(QIcon::fromTheme("edit-copy" , ui.actionEditCopy->icon()));
|
|
148 |
ui.actionEditFind->setIcon(QIcon::fromTheme("edit-find" , ui.actionEditFind->icon()));
|
|
149 |
ui.actionFilePrint->setIcon(QIcon::fromTheme("document-print" , ui.actionFilePrint->icon()));
|
|
150 |
ui.actionZoomOut->setIcon(QIcon::fromTheme("zoom-out" , ui.actionZoomOut->icon()));
|
|
151 |
ui.actionZoomIn->setIcon(QIcon::fromTheme("zoom-in" , ui.actionZoomIn->icon()));
|
|
152 |
ui.actionSyncToc->setIcon(QIcon::fromTheme("view-refresh" , ui.actionSyncToc->icon()));
|
|
153 |
#endif
|
|
154 |
}
|
|
155 |
|
|
156 |
MainWindow::~MainWindow()
|
|
157 |
{
|
|
158 |
windows.removeAll(this);
|
|
159 |
delete goActionDocFiles;
|
|
160 |
}
|
|
161 |
|
|
162 |
void MainWindow::setup()
|
|
163 |
{
|
|
164 |
if(setupCompleted)
|
|
165 |
return;
|
|
166 |
|
|
167 |
qApp->setOverrideCursor(QCursor(Qt::WaitCursor));
|
|
168 |
statusBar()->showMessage(tr("Initializing Qt Assistant..."));
|
|
169 |
setupCompleted = true;
|
|
170 |
helpDock->initialize();
|
|
171 |
connect(ui.actionGoPrevious, SIGNAL(triggered()), tabs, SLOT(backward()));
|
|
172 |
connect(ui.actionGoNext, SIGNAL(triggered()), tabs, SLOT(forward()));
|
|
173 |
connect(ui.actionEditCopy, SIGNAL(triggered()), tabs, SLOT(copy()));
|
|
174 |
connect(ui.actionFileExit, SIGNAL(triggered()), qApp, SLOT(closeAllWindows()));
|
|
175 |
connect(ui.actionAddBookmark, SIGNAL(triggered()),
|
|
176 |
helpDock, SLOT(addBookmark()));
|
|
177 |
connect(helpDock, SIGNAL(showLink(QString)),
|
|
178 |
this, SLOT(showLink(QString)));
|
|
179 |
connect(helpDock, SIGNAL(showSearchLink(QString,QStringList)),
|
|
180 |
this, SLOT(showSearchLink(QString,QStringList)));
|
|
181 |
|
|
182 |
connect(ui.bookmarkMenu, SIGNAL(triggered(QAction*)),
|
|
183 |
this, SLOT(showBookmark(QAction*)));
|
|
184 |
connect(ui.actionZoomIn, SIGNAL(triggered()), tabs, SLOT(zoomIn()));
|
|
185 |
connect(ui.actionZoomOut, SIGNAL(triggered()), tabs, SLOT(zoomOut()));
|
|
186 |
|
|
187 |
connect(ui.actionOpenPage, SIGNAL(triggered()), tabs, SLOT(newTab()));
|
|
188 |
connect(ui.actionClosePage, SIGNAL(triggered()), tabs, SLOT(closeTab()));
|
|
189 |
connect(ui.actionNextPage, SIGNAL(triggered()), tabs, SLOT(nextTab()));
|
|
190 |
connect(ui.actionPrevPage, SIGNAL(triggered()), tabs, SLOT(previousTab()));
|
|
191 |
|
|
192 |
|
|
193 |
#if defined(Q_OS_WIN32) || defined(Q_OS_WIN64)
|
|
194 |
QShortcut *acc = new QShortcut(tr("SHIFT+CTRL+="), this);
|
|
195 |
connect(acc, SIGNAL(activated()), ui.actionZoomIn, SIGNAL(triggered()));
|
|
196 |
#endif
|
|
197 |
|
|
198 |
connect(new QShortcut(tr("Ctrl+T"), this), SIGNAL(activated()), helpDock, SLOT(toggleContents()));
|
|
199 |
connect(new QShortcut(tr("Ctrl+I"), this), SIGNAL(activated()), helpDock, SLOT(toggleIndex()));
|
|
200 |
connect(new QShortcut(tr("Ctrl+B"), this), SIGNAL(activated()), helpDock, SLOT(toggleBookmarks()));
|
|
201 |
connect(new QShortcut(tr("Ctrl+S"), this), SIGNAL(activated()), helpDock, SLOT(toggleSearch()));
|
|
202 |
connect(new QShortcut(tr("Ctrl+]"), this), SIGNAL(activated()), tabs, SLOT(nextTab()));
|
|
203 |
connect(new QShortcut(tr("Ctrl+["), this), SIGNAL(activated()), tabs, SLOT(previousTab()));
|
|
204 |
|
|
205 |
Config *config = Config::configuration();
|
|
206 |
|
|
207 |
setupBookmarkMenu();
|
|
208 |
|
|
209 |
QAction *viewsAction = createPopupMenu()->menuAction();
|
|
210 |
viewsAction->setText(tr("Views"));
|
|
211 |
ui.viewMenu->addAction(viewsAction);
|
|
212 |
|
|
213 |
const int tabIndex = config->sideBarPage();
|
|
214 |
helpDock->tabWidget()->setCurrentIndex(tabIndex);
|
|
215 |
// The tab index is 0 by default, so we need to force an upate
|
|
216 |
// to poulate the contents in this case.
|
|
217 |
if (tabIndex == 0)
|
|
218 |
helpDock->currentTabChanged(tabIndex);
|
|
219 |
|
|
220 |
ui.actionEditFind->setShortcut(QKeySequence::Find);
|
|
221 |
ui.actionEditFindNext->setShortcut(QKeySequence::FindNext);
|
|
222 |
ui.actionEditFindPrev->setShortcut(QKeySequence::FindPrevious);
|
|
223 |
|
|
224 |
QObject::connect(ui.actionEditFind, SIGNAL(triggered()), tabs, SLOT(find()));
|
|
225 |
QObject::connect(ui.actionEditFindNext, SIGNAL(triggered()), tabs, SLOT(findNext()));
|
|
226 |
QObject::connect(ui.actionEditFindPrev, SIGNAL(triggered()), tabs, SLOT(findPrevious()));
|
|
227 |
connect(ui.actionEditFont_Settings, SIGNAL(triggered()), this, SLOT(showFontSettingsDialog()));
|
|
228 |
|
|
229 |
qApp->restoreOverrideCursor();
|
|
230 |
ui.actionGoPrevious->setEnabled(false);
|
|
231 |
ui.actionGoNext->setEnabled(false);
|
|
232 |
ui.actionEditCopy->setEnabled(false);
|
|
233 |
|
|
234 |
// set the current selected item in the treeview
|
|
235 |
helpDialog()->locateContents(tabs->currentBrowser()->source().toString());
|
|
236 |
connect(tabs, SIGNAL(browserUrlChanged(QString)), helpDock, SLOT(locateContents(QString)));
|
|
237 |
}
|
|
238 |
|
|
239 |
void MainWindow::browserTabChanged()
|
|
240 |
{
|
|
241 |
HelpWindow *win = tabs->currentBrowser();
|
|
242 |
if (win) {
|
|
243 |
QTextCursor cursor(win->textCursor());
|
|
244 |
ui.actionEditCopy->setEnabled(cursor.hasSelection());
|
|
245 |
ui.actionGoPrevious->setEnabled(win->isBackwardAvailable());
|
|
246 |
ui.actionGoNext->setEnabled(win->isForwardAvailable());
|
|
247 |
}
|
|
248 |
}
|
|
249 |
|
|
250 |
void MainWindow::copyAvailable(bool yes)
|
|
251 |
{
|
|
252 |
ui.actionEditCopy->setEnabled(yes);
|
|
253 |
}
|
|
254 |
|
|
255 |
void MainWindow::updateTabActions(int index)
|
|
256 |
{
|
|
257 |
bool enabled = (index > 1) ? true : false;
|
|
258 |
ui.actionPrevPage->setEnabled(enabled);
|
|
259 |
ui.actionNextPage->setEnabled(enabled);
|
|
260 |
ui.actionClosePage->setEnabled(enabled);
|
|
261 |
}
|
|
262 |
|
|
263 |
void MainWindow::setupGoActions()
|
|
264 |
{
|
|
265 |
Config *config = Config::configuration();
|
|
266 |
QStringList titles = config->docTitles();
|
|
267 |
QAction *action = 0;
|
|
268 |
|
|
269 |
static bool separatorInserted = false;
|
|
270 |
|
|
271 |
foreach (QAction *a, goActions) {
|
|
272 |
ui.goMenu->removeAction(a);
|
|
273 |
ui.goActionToolbar->removeAction(a);
|
|
274 |
}
|
|
275 |
qDeleteAll(goActions);
|
|
276 |
goActions.clear();
|
|
277 |
goActionDocFiles->clear();
|
|
278 |
|
|
279 |
int addCount = 0;
|
|
280 |
|
|
281 |
foreach (QString title, titles) {
|
|
282 |
QPixmap pix = config->docIcon(title);
|
|
283 |
if(!pix.isNull()) {
|
|
284 |
if(!separatorInserted) {
|
|
285 |
ui.goMenu->addSeparator();
|
|
286 |
separatorInserted = true;
|
|
287 |
}
|
|
288 |
action = new QAction(this);
|
|
289 |
action->setText(title);
|
|
290 |
action->setWhatsThis(tr("Displays the main page of a specific documentation set."));
|
|
291 |
action->setIcon(QIcon(pix));
|
|
292 |
ui.goMenu->addAction(action);
|
|
293 |
ui.goActionToolbar->addAction(action);
|
|
294 |
goActions.append(action);
|
|
295 |
goActionDocFiles->insert(action, config->indexPage(title));
|
|
296 |
connect(action, SIGNAL(triggered()),
|
|
297 |
this, SLOT(showGoActionLink()));
|
|
298 |
++addCount;
|
|
299 |
}
|
|
300 |
}
|
|
301 |
if(!addCount)
|
|
302 |
ui.goActionToolbar->hide();
|
|
303 |
else
|
|
304 |
ui.goActionToolbar->show();
|
|
305 |
|
|
306 |
}
|
|
307 |
|
|
308 |
bool MainWindow::insertActionSeparator()
|
|
309 |
{
|
|
310 |
ui.goMenu->addSeparator();
|
|
311 |
ui.Toolbar->addSeparator();
|
|
312 |
return true;
|
|
313 |
}
|
|
314 |
|
|
315 |
void MainWindow::closeEvent(QCloseEvent *e)
|
|
316 |
{
|
|
317 |
saveSettings();
|
|
318 |
e->accept();
|
|
319 |
}
|
|
320 |
|
|
321 |
void MainWindow::about()
|
|
322 |
{
|
|
323 |
QMessageBox box(this);
|
|
324 |
|
|
325 |
box.setText(QString::fromLatin1("<center><img src=\":/trolltech/assistant/images/assistant-128.png\">"
|
|
326 |
"<h3>%1</h3>"
|
|
327 |
"<p>Version %2</p></center>"
|
|
328 |
"<p>Copyright (C) 2009 Nokia Corporation and/or its subsidiary(-ies).</p>")
|
|
329 |
.arg(tr("Qt Assistant")).arg(QLatin1String(QT_VERSION_STR)));
|
|
330 |
box.setWindowTitle(tr("Qt Assistant"));
|
|
331 |
box.setIcon(QMessageBox::NoIcon);
|
|
332 |
box.exec();
|
|
333 |
}
|
|
334 |
|
|
335 |
void MainWindow::on_actionAboutApplication_triggered()
|
|
336 |
{
|
|
337 |
QString url = Config::configuration()->aboutURL();
|
|
338 |
if (url == QLatin1String("about_qt")) {
|
|
339 |
QMessageBox::aboutQt(this, QLatin1String("Qt Assistant"));
|
|
340 |
return;
|
|
341 |
}
|
|
342 |
QString text;
|
|
343 |
if (url.startsWith(QLatin1String("file:")))
|
|
344 |
url = url.mid(5);
|
|
345 |
QFile file(url);
|
|
346 |
if(file.exists() && file.open(QFile::ReadOnly))
|
|
347 |
text = QString::fromUtf8(file.readAll());
|
|
348 |
if(text.isNull())
|
|
349 |
text = tr("Failed to open about application contents in file: '%1'").arg(url);
|
|
350 |
|
|
351 |
QFileInfo fi(file);
|
|
352 |
QString path = QDir::cleanPath(fi.absolutePath());
|
|
353 |
if (!QDir::searchPaths(QLatin1String("aboutImages")).contains(path))
|
|
354 |
QDir::addSearchPath(QLatin1String("aboutImages"), path);
|
|
355 |
|
|
356 |
QMessageBox box(this);
|
|
357 |
box.setText(text);
|
|
358 |
box.setWindowTitle(Config::configuration()->aboutApplicationMenuText());
|
|
359 |
box.setIcon(QMessageBox::NoIcon);
|
|
360 |
box.exec();
|
|
361 |
}
|
|
362 |
|
|
363 |
void MainWindow::on_actionAboutAssistant_triggered()
|
|
364 |
{
|
|
365 |
about();
|
|
366 |
}
|
|
367 |
|
|
368 |
void MainWindow::on_actionGoHome_triggered()
|
|
369 |
{
|
|
370 |
QString home = MainWindow::urlifyFileName(Config::configuration()->homePage());
|
|
371 |
showLink(home);
|
|
372 |
}
|
|
373 |
|
|
374 |
QString MainWindow::urlifyFileName(const QString &fileName)
|
|
375 |
{
|
|
376 |
QString name = fileName;
|
|
377 |
QUrl url(name);
|
|
378 |
|
|
379 |
#if defined(Q_OS_WIN32)
|
|
380 |
if (!url.isValid() || url.scheme().isEmpty() || url.scheme().toLower() != QLatin1String("file:")) {
|
|
381 |
int i = name.indexOf(QLatin1Char('#'));
|
|
382 |
QString anchor = name.mid(i);
|
|
383 |
name = name.toLower();
|
|
384 |
if (i > -1)
|
|
385 |
name.replace(i, anchor.length(), anchor);
|
|
386 |
name.replace(QLatin1Char('\\'), QLatin1Char('/'));
|
|
387 |
foreach (QFileInfo drive, QDir::drives()) {
|
|
388 |
if (name.startsWith(drive.absolutePath().toLower())) {
|
|
389 |
name = QLatin1String("file:") + name;
|
|
390 |
break;
|
|
391 |
}
|
|
392 |
}
|
|
393 |
}
|
|
394 |
#else
|
|
395 |
if (!url.isValid() || url.scheme().isEmpty())
|
|
396 |
name.prepend(QLatin1String("file:"));
|
|
397 |
#endif
|
|
398 |
return name;
|
|
399 |
}
|
|
400 |
|
|
401 |
#ifndef QT_NO_PRINTER
|
|
402 |
class PrintThread : public QThread
|
|
403 |
{
|
|
404 |
QPrinter _printer;
|
|
405 |
QTextDocument *_document;
|
|
406 |
|
|
407 |
public:
|
|
408 |
PrintThread(QObject *parent)
|
|
409 |
: QThread(parent), _printer(QPrinter::HighResolution), _document(0)
|
|
410 |
{
|
|
411 |
}
|
|
412 |
~PrintThread()
|
|
413 |
{
|
|
414 |
wait();
|
|
415 |
}
|
|
416 |
|
|
417 |
QPrinter *printer()
|
|
418 |
{
|
|
419 |
return &_printer;
|
|
420 |
}
|
|
421 |
|
|
422 |
void start(QTextDocument *document)
|
|
423 |
{
|
|
424 |
_document = document->clone();
|
|
425 |
_document->moveToThread(this);
|
|
426 |
QThread::start();
|
|
427 |
}
|
|
428 |
|
|
429 |
protected:
|
|
430 |
void run()
|
|
431 |
{
|
|
432 |
_document->print(printer());
|
|
433 |
delete _document;
|
|
434 |
_document = 0;
|
|
435 |
}
|
|
436 |
};
|
|
437 |
#endif //QT_NO_PRINTER
|
|
438 |
|
|
439 |
void MainWindow::on_actionFilePrint_triggered()
|
|
440 |
{
|
|
441 |
#ifndef QT_NO_PRINTER
|
|
442 |
if (!QFontDatabase::supportsThreadedFontRendering()) {
|
|
443 |
QPrinter printer(QPrinter::HighResolution);
|
|
444 |
|
|
445 |
QPrintDialog dlg(&printer, this);
|
|
446 |
if (dlg.exec() == QDialog::Accepted) {
|
|
447 |
qApp->setOverrideCursor(Qt::WaitCursor);
|
|
448 |
tabs->currentBrowser()->document()->print(&printer);
|
|
449 |
qApp->restoreOverrideCursor();
|
|
450 |
}
|
|
451 |
return;
|
|
452 |
}
|
|
453 |
|
|
454 |
PrintThread *thread = new PrintThread(this);
|
|
455 |
|
|
456 |
QPrintDialog dlg(thread->printer(), this);
|
|
457 |
if (dlg.exec() == QDialog::Accepted) {
|
|
458 |
connect(thread, SIGNAL(finished()), SLOT(printingFinished()));
|
|
459 |
connect(thread, SIGNAL(finished()), thread, SLOT(deleteLater()));
|
|
460 |
|
|
461 |
qApp->setOverrideCursor(Qt::BusyCursor);
|
|
462 |
thread->start(tabs->currentBrowser()->document());
|
|
463 |
} else {
|
|
464 |
delete thread;
|
|
465 |
}
|
|
466 |
#else
|
|
467 |
Q_ASSERT("No printing support");
|
|
468 |
#endif
|
|
469 |
}
|
|
470 |
|
|
471 |
void MainWindow::printingFinished()
|
|
472 |
{
|
|
473 |
qApp->restoreOverrideCursor();
|
|
474 |
}
|
|
475 |
|
|
476 |
void MainWindow::updateBookmarkMenu()
|
|
477 |
{
|
|
478 |
for(QList<MainWindow*>::Iterator it = windows.begin(); it != windows.end(); ++it)
|
|
479 |
(*it)->setupBookmarkMenu();
|
|
480 |
}
|
|
481 |
|
|
482 |
void MainWindow::setupBookmarkMenu()
|
|
483 |
{
|
|
484 |
ui.bookmarkMenu->clear();
|
|
485 |
bookmarks.clear();
|
|
486 |
ui.bookmarkMenu->addAction(ui.actionAddBookmark);
|
|
487 |
|
|
488 |
QFile f(QDir::homePath() + QLatin1String("/.assistant/bookmarks.") +
|
|
489 |
Config::configuration()->profileName());
|
|
490 |
if (!f.open(QFile::ReadOnly))
|
|
491 |
return;
|
|
492 |
QTextStream ts(&f);
|
|
493 |
ui.bookmarkMenu->addSeparator();
|
|
494 |
while (!ts.atEnd()) {
|
|
495 |
QString title = ts.readLine();
|
|
496 |
QString link = ts.readLine();
|
|
497 |
bookmarks.insert(ui.bookmarkMenu->addAction(title), link);
|
|
498 |
}
|
|
499 |
}
|
|
500 |
|
|
501 |
void MainWindow::showBookmark(QAction *action)
|
|
502 |
{
|
|
503 |
if (bookmarks.contains(action))
|
|
504 |
showLink(bookmarks.value(action));
|
|
505 |
}
|
|
506 |
|
|
507 |
void MainWindow::showLinkFromClient(const QString &link)
|
|
508 |
{
|
|
509 |
setWindowState(windowState() & ~Qt::WindowMinimized);
|
|
510 |
raise();
|
|
511 |
activateWindow();
|
|
512 |
QString l = MainWindow::urlifyFileName(link);
|
|
513 |
showLink(l);
|
|
514 |
if (isMinimized())
|
|
515 |
showNormal();
|
|
516 |
}
|
|
517 |
|
|
518 |
void MainWindow::showLink(const QString &link)
|
|
519 |
{
|
|
520 |
if(link.isEmpty())
|
|
521 |
qWarning("The link is empty!");
|
|
522 |
|
|
523 |
// don't fill the history with the same url more then once
|
|
524 |
if (link == tabs->currentBrowser()->source().toString())
|
|
525 |
return;
|
|
526 |
|
|
527 |
QUrl url(link);
|
|
528 |
QFileInfo fi(url.toLocalFile());
|
|
529 |
tabs->setSource(url.toString());
|
|
530 |
tabs->currentBrowser()->setFocus();
|
|
531 |
}
|
|
532 |
|
|
533 |
void MainWindow::showLinks(const QStringList &links)
|
|
534 |
{
|
|
535 |
if (links.size() == 0) {
|
|
536 |
qWarning("MainWindow::showLinks() - Empty link");
|
|
537 |
return;
|
|
538 |
}
|
|
539 |
|
|
540 |
if (links.size() == 1) {
|
|
541 |
showLink(MainWindow::urlifyFileName(links.first()));
|
|
542 |
return;
|
|
543 |
}
|
|
544 |
|
|
545 |
QStringList::ConstIterator it = links.begin();
|
|
546 |
// Initial showing, The tab is empty so update that without creating it first
|
|
547 |
if (!tabs->currentBrowser()->source().isValid()) {
|
|
548 |
QPair<HelpWindow*, QString> browser;
|
|
549 |
browser.first = tabs->currentBrowser();
|
|
550 |
browser.second = links.first();
|
|
551 |
pendingBrowsers.append(browser);
|
|
552 |
tabs->setTitle(tabs->currentBrowser(), tr("..."));
|
|
553 |
}
|
|
554 |
++it;
|
|
555 |
|
|
556 |
while(it != links.end()) {
|
|
557 |
QPair<HelpWindow*, QString> browser;
|
|
558 |
browser.first = tabs->newBackgroundTab();
|
|
559 |
browser.second = *it;
|
|
560 |
pendingBrowsers.append(browser);
|
|
561 |
++it;
|
|
562 |
}
|
|
563 |
|
|
564 |
startTimer(50);
|
|
565 |
return;
|
|
566 |
}
|
|
567 |
|
|
568 |
void MainWindow::removePendingBrowser(HelpWindow *win)
|
|
569 |
{
|
|
570 |
if (!pendingBrowsers.count())
|
|
571 |
return;
|
|
572 |
|
|
573 |
QMutableListIterator<QPair<HelpWindow*, QString> > it(pendingBrowsers);
|
|
574 |
while (it.hasNext()) {
|
|
575 |
QPair<HelpWindow*, QString> browser = it.next();
|
|
576 |
if (browser.first == win) {
|
|
577 |
it.remove();
|
|
578 |
break;
|
|
579 |
}
|
|
580 |
}
|
|
581 |
}
|
|
582 |
|
|
583 |
void MainWindow::timerEvent(QTimerEvent *e)
|
|
584 |
{
|
|
585 |
QPair<HelpWindow*, QString> browser = pendingBrowsers.first();
|
|
586 |
pendingBrowsers.pop_front();
|
|
587 |
|
|
588 |
if (pendingBrowsers.size() == 0)
|
|
589 |
killTimer(e->timerId());
|
|
590 |
|
|
591 |
browser.first->setSource(MainWindow::urlifyFileName(browser.second));
|
|
592 |
}
|
|
593 |
|
|
594 |
void MainWindow::showQtHelp()
|
|
595 |
{
|
|
596 |
showLink(QLibraryInfo::location(QLibraryInfo::DocumentationPath) +
|
|
597 |
QLatin1String("/html/index.html"));
|
|
598 |
}
|
|
599 |
|
|
600 |
MainWindow* MainWindow::newWindow()
|
|
601 |
{
|
|
602 |
saveSettings();
|
|
603 |
MainWindow *mw = new MainWindow;
|
|
604 |
mw->move(geometry().topLeft());
|
|
605 |
if (isMaximized())
|
|
606 |
mw->showMaximized();
|
|
607 |
else
|
|
608 |
mw->show();
|
|
609 |
mw->on_actionGoHome_triggered();
|
|
610 |
return mw;
|
|
611 |
}
|
|
612 |
|
|
613 |
void MainWindow::saveSettings()
|
|
614 |
{
|
|
615 |
Config *config = Config::configuration();
|
|
616 |
|
|
617 |
config->setSideBarPage(helpDock->tabWidget()->currentIndex());
|
|
618 |
config->setWindowGeometry(saveGeometry());
|
|
619 |
config->setMainWindowState(saveState());
|
|
620 |
|
|
621 |
// Create list of the tab urls
|
|
622 |
QStringList lst;
|
|
623 |
QList<HelpWindow*> browsers = tabs->browsers();
|
|
624 |
foreach (HelpWindow *browser, browsers)
|
|
625 |
lst << browser->source().toString();
|
|
626 |
config->setSource(lst);
|
|
627 |
config->save();
|
|
628 |
}
|
|
629 |
|
|
630 |
TabbedBrowser* MainWindow::browsers() const
|
|
631 |
{
|
|
632 |
return tabs;
|
|
633 |
}
|
|
634 |
|
|
635 |
void MainWindow::showSearchLink(const QString &link, const QStringList &terms)
|
|
636 |
{
|
|
637 |
HelpWindow * hw = tabs->currentBrowser();
|
|
638 |
hw->blockScrolling(true);
|
|
639 |
hw->setCursor(Qt::WaitCursor);
|
|
640 |
if (hw->source() == link)
|
|
641 |
hw->reload();
|
|
642 |
else
|
|
643 |
showLink(link);
|
|
644 |
hw->setCursor(Qt::ArrowCursor);
|
|
645 |
|
|
646 |
hw->viewport()->setUpdatesEnabled(false);
|
|
647 |
|
|
648 |
QTextCharFormat marker;
|
|
649 |
marker.setForeground(Qt::red);
|
|
650 |
|
|
651 |
QTextCursor firstHit;
|
|
652 |
|
|
653 |
QTextCursor c = hw->textCursor();
|
|
654 |
c.beginEditBlock();
|
|
655 |
foreach (QString term, terms) {
|
|
656 |
c.movePosition(QTextCursor::Start);
|
|
657 |
hw->setTextCursor(c);
|
|
658 |
|
|
659 |
bool found = hw->find(term, QTextDocument::FindWholeWords);
|
|
660 |
while (found) {
|
|
661 |
QTextCursor hit = hw->textCursor();
|
|
662 |
if (firstHit.isNull() || hit.position() < firstHit.position())
|
|
663 |
firstHit = hit;
|
|
664 |
|
|
665 |
hit.mergeCharFormat(marker);
|
|
666 |
found = hw->find(term, QTextDocument::FindWholeWords);
|
|
667 |
}
|
|
668 |
}
|
|
669 |
|
|
670 |
if (firstHit.isNull()) {
|
|
671 |
firstHit = hw->textCursor();
|
|
672 |
firstHit.movePosition(QTextCursor::Start);
|
|
673 |
}
|
|
674 |
firstHit.clearSelection();
|
|
675 |
c.endEditBlock();
|
|
676 |
hw->setTextCursor(firstHit);
|
|
677 |
|
|
678 |
hw->blockScrolling(false);
|
|
679 |
hw->viewport()->setUpdatesEnabled(true);
|
|
680 |
}
|
|
681 |
|
|
682 |
|
|
683 |
void MainWindow::showGoActionLink()
|
|
684 |
{
|
|
685 |
const QObject *origin = sender();
|
|
686 |
if(!origin ||
|
|
687 |
QString::fromLatin1(origin->metaObject()->className()) != QString::fromLatin1("QAction"))
|
|
688 |
return;
|
|
689 |
|
|
690 |
QAction *action = (QAction*) origin;
|
|
691 |
QString docfile = *(goActionDocFiles->find(action));
|
|
692 |
showLink(MainWindow::urlifyFileName(docfile));
|
|
693 |
}
|
|
694 |
|
|
695 |
void MainWindow::on_actionHelpAssistant_triggered()
|
|
696 |
{
|
|
697 |
showLink(Config::configuration()->assistantDocPath() + QLatin1String("/assistant-manual.html"));
|
|
698 |
}
|
|
699 |
|
|
700 |
HelpDialog* MainWindow::helpDialog() const
|
|
701 |
{
|
|
702 |
return helpDock;
|
|
703 |
}
|
|
704 |
|
|
705 |
void MainWindow::backwardAvailable(bool enable)
|
|
706 |
{
|
|
707 |
ui.actionGoPrevious->setEnabled(enable);
|
|
708 |
}
|
|
709 |
|
|
710 |
void MainWindow::forwardAvailable(bool enable)
|
|
711 |
{
|
|
712 |
ui.actionGoNext->setEnabled(enable);
|
|
713 |
}
|
|
714 |
|
|
715 |
void MainWindow::updateProfileSettings()
|
|
716 |
{
|
|
717 |
Config *config = Config::configuration();
|
|
718 |
#ifndef Q_WS_MAC
|
|
719 |
setWindowIcon(config->applicationIcon());
|
|
720 |
#endif
|
|
721 |
ui.helpMenu->clear();
|
|
722 |
//ui.helpMenu->addAction(ui.actionHelpAssistant);
|
|
723 |
//ui.helpMenu->addSeparator();
|
|
724 |
ui.helpMenu->addAction(ui.actionAboutAssistant);
|
|
725 |
if (!config->aboutApplicationMenuText().isEmpty())
|
|
726 |
ui.helpMenu->addAction(ui.actionAboutApplication);
|
|
727 |
ui.helpMenu->addSeparator();
|
|
728 |
ui.helpMenu->addAction(ui.actionHelpWhatsThis);
|
|
729 |
|
|
730 |
ui.actionAboutApplication->setText(config->aboutApplicationMenuText());
|
|
731 |
|
|
732 |
if(!config->title().isNull())
|
|
733 |
setWindowTitle(config->title());
|
|
734 |
}
|
|
735 |
|
|
736 |
void MainWindow::setupPopupMenu(QMenu *m)
|
|
737 |
{
|
|
738 |
m->addAction(ui.actionNewWindow);
|
|
739 |
m->addAction(ui.actionOpenPage);
|
|
740 |
m->addAction(ui.actionClosePage);
|
|
741 |
m->addSeparator();
|
|
742 |
m->addAction(ui.actionSaveAs);
|
|
743 |
m->addSeparator();
|
|
744 |
m->addAction(ui.actionGoPrevious);
|
|
745 |
m->addAction(ui.actionGoNext);
|
|
746 |
m->addAction(ui.actionGoHome);
|
|
747 |
m->addSeparator();
|
|
748 |
m->addAction(ui.actionZoomIn);
|
|
749 |
m->addAction(ui.actionZoomOut);
|
|
750 |
m->addSeparator();
|
|
751 |
m->addAction(ui.actionEditCopy);
|
|
752 |
m->addAction(ui.actionEditFind);
|
|
753 |
}
|
|
754 |
|
|
755 |
void MainWindow::on_actionSyncToc_triggered()
|
|
756 |
{
|
|
757 |
HelpWindow *w = tabs->currentBrowser();
|
|
758 |
if(w) {
|
|
759 |
qApp->setOverrideCursor(QCursor(Qt::WaitCursor));
|
|
760 |
QString link = w->source().toString();
|
|
761 |
helpDock->locateContents(link);
|
|
762 |
helpDock->tabWidget()->setCurrentIndex(0);
|
|
763 |
qApp->restoreOverrideCursor();
|
|
764 |
}
|
|
765 |
}
|
|
766 |
|
|
767 |
void MainWindow::on_actionNewWindow_triggered()
|
|
768 |
{
|
|
769 |
newWindow()->show();
|
|
770 |
}
|
|
771 |
|
|
772 |
void MainWindow::on_actionClose_triggered()
|
|
773 |
{
|
|
774 |
close();
|
|
775 |
}
|
|
776 |
|
|
777 |
void MainWindow::on_actionHelpWhatsThis_triggered()
|
|
778 |
{
|
|
779 |
QWhatsThis::enterWhatsThisMode();
|
|
780 |
}
|
|
781 |
|
|
782 |
void MainWindow::on_actionSaveAs_triggered()
|
|
783 |
{
|
|
784 |
QString fileName;
|
|
785 |
QUrl url = tabs->currentBrowser()->source();
|
|
786 |
if (url.isValid()) {
|
|
787 |
QFileInfo fi(url.toLocalFile());
|
|
788 |
fileName = fi.fileName();
|
|
789 |
}
|
|
790 |
fileName = QFileDialog::getSaveFileName(this, tr("Save Page"), fileName);
|
|
791 |
if (fileName.isEmpty())
|
|
792 |
return;
|
|
793 |
|
|
794 |
QFile file(fileName);
|
|
795 |
if (!file.open(QIODevice::WriteOnly)) {
|
|
796 |
QMessageBox::critical(this, tr("Save Page"), tr("Cannot open file for writing!"));
|
|
797 |
return;
|
|
798 |
}
|
|
799 |
|
|
800 |
QFileInfo fi(fileName);
|
|
801 |
QString fn = fi.fileName();
|
|
802 |
int i = fn.lastIndexOf(QLatin1Char('.'));
|
|
803 |
if (i > -1)
|
|
804 |
fn = fn.left(i);
|
|
805 |
QString relativeDestPath = fn + QLatin1String("_images");
|
|
806 |
QDir destDir(fi.absolutePath() + QDir::separator() + relativeDestPath);
|
|
807 |
bool imgDirAvailable = destDir.exists();
|
|
808 |
if (!imgDirAvailable)
|
|
809 |
imgDirAvailable = destDir.mkdir(destDir.absolutePath());
|
|
810 |
|
|
811 |
// save images
|
|
812 |
QTextDocument *doc = tabs->currentBrowser()->document()->clone();
|
|
813 |
if (url.isValid() && imgDirAvailable) {
|
|
814 |
QTextBlock::iterator it;
|
|
815 |
for (QTextBlock block = doc->begin(); block != doc->end(); block = block.next()) {
|
|
816 |
for (it = block.begin(); !(it.atEnd()); ++it) {
|
|
817 |
QTextFragment fragment = it.fragment();
|
|
818 |
if (fragment.isValid()) {
|
|
819 |
QTextImageFormat fm = fragment.charFormat().toImageFormat();
|
|
820 |
if (fm.isValid() && !fm.name().isEmpty()) {
|
|
821 |
QUrl imagePath = tabs->currentBrowser()->source().resolved(fm.name());
|
|
822 |
if (!imagePath.isValid())
|
|
823 |
continue;
|
|
824 |
QString from = imagePath.toLocalFile();
|
|
825 |
QString destName = fm.name();
|
|
826 |
int j = destName.lastIndexOf(QLatin1Char('/'));
|
|
827 |
if (j > -1)
|
|
828 |
destName = destName.mid(j+1);
|
|
829 |
QFileInfo info(from);
|
|
830 |
if (info.exists()) {
|
|
831 |
if (!QFile::copy(from, destDir.absolutePath()
|
|
832 |
+ QDir::separator() + destName))
|
|
833 |
continue;
|
|
834 |
fm.setName(QLatin1String("./") + relativeDestPath + QLatin1String("/") + destName);
|
|
835 |
QTextCursor cursor(doc);
|
|
836 |
cursor.setPosition(fragment.position());
|
|
837 |
cursor.setPosition(fragment.position() + fragment.length(),
|
|
838 |
QTextCursor::KeepAnchor);
|
|
839 |
cursor.setCharFormat(fm);
|
|
840 |
}
|
|
841 |
}
|
|
842 |
}
|
|
843 |
}
|
|
844 |
}
|
|
845 |
}
|
|
846 |
QString src = doc->toHtml(QByteArray("utf-8"));
|
|
847 |
QTextStream s(&file);
|
|
848 |
s.setCodec("utf-8");
|
|
849 |
s << src;
|
|
850 |
s.flush();
|
|
851 |
file.close();
|
|
852 |
}
|
|
853 |
|
|
854 |
void MainWindow::showFontSettingsDialog()
|
|
855 |
{
|
|
856 |
Config *config = Config::configuration();
|
|
857 |
FontSettings settings = config->fontSettings();
|
|
858 |
|
|
859 |
{ // It is important that the dialog be deleted before UI mode changes.
|
|
860 |
FontSettingsDialog dialog;
|
|
861 |
if (!dialog.showDialog(&settings))
|
|
862 |
return;
|
|
863 |
}
|
|
864 |
|
|
865 |
config->setFontPointSize(settings.browserFont.pointSizeF());
|
|
866 |
config->setFontSettings(settings);
|
|
867 |
|
|
868 |
updateApplicationFontSettings(settings);
|
|
869 |
}
|
|
870 |
|
|
871 |
void MainWindow::updateApplicationFontSettings(FontSettings &settings)
|
|
872 |
{
|
|
873 |
QFont font = settings.windowFont;
|
|
874 |
if (this->font() != font)
|
|
875 |
qApp->setFont(font, "QWidget");
|
|
876 |
|
|
877 |
font = settings.browserFont;
|
|
878 |
QList<HelpWindow*> browsers = tabs->browsers();
|
|
879 |
foreach (HelpWindow *browser, browsers) {
|
|
880 |
if (browser->font() != font)
|
|
881 |
browser->setFont(font);
|
|
882 |
}
|
|
883 |
}
|
|
884 |
|
|
885 |
QT_END_NAMESPACE
|