tools/assistant/compat/mainwindow.cpp
changeset 0 1918ee327afb
child 4 3b1da2848fc7
equal deleted inserted replaced
-1:000000000000 0:1918ee327afb
       
     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