/**************************************************************************** ** ** Copyright (C) 2009 Nokia Corporation and/or its subsidiary(-ies). ** All rights reserved. ** Contact: Nokia Corporation (qt-info@nokia.com) ** ** This file is part of the Qt Assistant of the Qt Toolkit. ** ** $QT_BEGIN_LICENSE:LGPL$ ** No Commercial Usage ** This file contains pre-release code and may not be distributed. ** You may use this file in accordance with the terms and conditions ** contained in the Technology Preview License Agreement accompanying ** this package. ** ** GNU Lesser General Public License Usage ** Alternatively, this file may be used under the terms of the GNU Lesser ** General Public License version 2.1 as published by the Free Software ** Foundation and appearing in the file LICENSE.LGPL included in the ** packaging of this file. Please review the following information to ** ensure the GNU Lesser General Public License version 2.1 requirements ** will be met: http://www.gnu.org/licenses/old-licenses/lgpl-2.1.html. ** ** In addition, as a special exception, Nokia gives you certain additional ** rights. These rights are described in the Nokia Qt LGPL Exception ** version 1.1, included in the file LGPL_EXCEPTION.txt in this package. ** ** If you have questions regarding the use of this file, please contact ** Nokia at qt-info@nokia.com. ** ** ** ** ** ** ** ** ** $QT_END_LICENSE$ ** ****************************************************************************/ #include "mainwindow.h" #include "tabbedbrowser.h" #include "helpdialog.h" #include "config.h" #include "fontsettingsdialog.h" #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include QT_BEGIN_NAMESPACE QList MainWindow::windows; #if defined(Q_WS_WIN) extern Q_CORE_EXPORT int qt_ntfs_permission_lookup; #endif MainWindow::MainWindow() { setUnifiedTitleAndToolBarOnMac(true); ui.setupUi(this); #if defined(Q_WS_WIN) // Workaround for QMimeSourceFactory failing in QFileInfo::isReadable() for // certain user configs. See task: 34372 qt_ntfs_permission_lookup = 0; #endif setupCompleted = false; goActions = QList(); goActionDocFiles = new QMap; windows.append(this); tabs = new TabbedBrowser(this); connect(tabs, SIGNAL(tabCountChanged(int)), this, SLOT(updateTabActions(int))); setCentralWidget(tabs); Config *config = Config::configuration(); updateProfileSettings(); dw = new QDockWidget(this); dw->setAllowedAreas(Qt::LeftDockWidgetArea | Qt::RightDockWidgetArea); dw->setWindowTitle(tr("Sidebar")); dw->setObjectName(QLatin1String("sidebar")); helpDock = new HelpDialog(dw, this); dw->setWidget(helpDock); addDockWidget(Qt::LeftDockWidgetArea, dw); // read geometry configuration setupGoActions(); restoreGeometry(config->windowGeometry()); restoreState(config->mainWindowState()); if (config->sideBarHidden()) dw->hide(); tabs->setup(); QTimer::singleShot(0, this, SLOT(setup())); #if defined(Q_WS_MAC) QMenu *windowMenu = new QMenu(tr("&Window"), this); menuBar()->insertMenu(ui.helpMenu->menuAction(), windowMenu); windowMenu->addAction(tr("Minimize"), this, SLOT(showMinimized()), QKeySequence(tr("Ctrl+M"))); // Use the same forward and backward browser shortcuts as Safari and Internet Explorer do // on the Mac. This means that if you have access to one of those cool Intellimice, the thing // works just fine, since that's how Microsoft hacked it. ui.actionGoPrevious->setShortcut(QKeySequence(Qt::CTRL|Qt::Key_Left)); ui.actionGoNext->setShortcut(QKeySequence(Qt::CTRL|Qt::Key_Right)); static const QLatin1String MacIconPath(":/trolltech/assistant/images/mac"); ui.actionGoNext->setIcon(QIcon(MacIconPath + QLatin1String("/next.png"))); ui.actionGoPrevious->setIcon(QIcon(MacIconPath + QLatin1String("/prev.png"))); ui.actionGoHome->setIcon(QIcon(MacIconPath + QLatin1String("/home.png"))); ui.actionEditCopy->setIcon(QIcon(MacIconPath + QLatin1String("/editcopy.png"))); ui.actionEditCopy->setIcon(QIcon(MacIconPath + QLatin1String("/editcopy.png"))); ui.actionEditFind->setIcon(QIcon(MacIconPath + QLatin1String("/find.png"))); ui.actionFilePrint->setIcon(QIcon(MacIconPath + QLatin1String("/print.png"))); ui.actionZoomOut->setIcon(QIcon(MacIconPath + QLatin1String("/zoomout.png"))); ui.actionZoomIn->setIcon(QIcon(MacIconPath + QLatin1String("/zoomin.png"))); ui.actionSyncToc->setIcon(QIcon(MacIconPath + QLatin1String("/synctoc.png"))); ui.actionHelpWhatsThis->setIcon(QIcon(MacIconPath + QLatin1String("/whatsthis.png"))); #elif defined(Q_WS_X11) ui.actionGoNext->setIcon(QIcon::fromTheme("go-next" , ui.actionGoNext->icon())); ui.actionGoPrevious->setIcon(QIcon::fromTheme("go-previous" , ui.actionGoPrevious->icon())); ui.actionGoHome->setIcon(QIcon::fromTheme("user-home" , ui.actionGoHome->icon())); ui.actionEditCopy->setIcon(QIcon::fromTheme("edit-copy" , ui.actionEditCopy->icon())); ui.actionEditFind->setIcon(QIcon::fromTheme("edit-find" , ui.actionEditFind->icon())); ui.actionFilePrint->setIcon(QIcon::fromTheme("document-print" , ui.actionFilePrint->icon())); ui.actionZoomOut->setIcon(QIcon::fromTheme("zoom-out" , ui.actionZoomOut->icon())); ui.actionZoomIn->setIcon(QIcon::fromTheme("zoom-in" , ui.actionZoomIn->icon())); ui.actionSyncToc->setIcon(QIcon::fromTheme("view-refresh" , ui.actionSyncToc->icon())); #endif } MainWindow::~MainWindow() { windows.removeAll(this); delete goActionDocFiles; } void MainWindow::setup() { if(setupCompleted) return; qApp->setOverrideCursor(QCursor(Qt::WaitCursor)); statusBar()->showMessage(tr("Initializing Qt Assistant...")); setupCompleted = true; helpDock->initialize(); connect(ui.actionGoPrevious, SIGNAL(triggered()), tabs, SLOT(backward())); connect(ui.actionGoNext, SIGNAL(triggered()), tabs, SLOT(forward())); connect(ui.actionEditCopy, SIGNAL(triggered()), tabs, SLOT(copy())); connect(ui.actionFileExit, SIGNAL(triggered()), qApp, SLOT(closeAllWindows())); connect(ui.actionAddBookmark, SIGNAL(triggered()), helpDock, SLOT(addBookmark())); connect(helpDock, SIGNAL(showLink(QString)), this, SLOT(showLink(QString))); connect(helpDock, SIGNAL(showSearchLink(QString,QStringList)), this, SLOT(showSearchLink(QString,QStringList))); connect(ui.bookmarkMenu, SIGNAL(triggered(QAction*)), this, SLOT(showBookmark(QAction*))); connect(ui.actionZoomIn, SIGNAL(triggered()), tabs, SLOT(zoomIn())); connect(ui.actionZoomOut, SIGNAL(triggered()), tabs, SLOT(zoomOut())); connect(ui.actionOpenPage, SIGNAL(triggered()), tabs, SLOT(newTab())); connect(ui.actionClosePage, SIGNAL(triggered()), tabs, SLOT(closeTab())); connect(ui.actionNextPage, SIGNAL(triggered()), tabs, SLOT(nextTab())); connect(ui.actionPrevPage, SIGNAL(triggered()), tabs, SLOT(previousTab())); #if defined(Q_OS_WIN32) || defined(Q_OS_WIN64) QShortcut *acc = new QShortcut(tr("SHIFT+CTRL+="), this); connect(acc, SIGNAL(activated()), ui.actionZoomIn, SIGNAL(triggered())); #endif connect(new QShortcut(tr("Ctrl+T"), this), SIGNAL(activated()), helpDock, SLOT(toggleContents())); connect(new QShortcut(tr("Ctrl+I"), this), SIGNAL(activated()), helpDock, SLOT(toggleIndex())); connect(new QShortcut(tr("Ctrl+B"), this), SIGNAL(activated()), helpDock, SLOT(toggleBookmarks())); connect(new QShortcut(tr("Ctrl+S"), this), SIGNAL(activated()), helpDock, SLOT(toggleSearch())); connect(new QShortcut(tr("Ctrl+]"), this), SIGNAL(activated()), tabs, SLOT(nextTab())); connect(new QShortcut(tr("Ctrl+["), this), SIGNAL(activated()), tabs, SLOT(previousTab())); Config *config = Config::configuration(); setupBookmarkMenu(); QAction *viewsAction = createPopupMenu()->menuAction(); viewsAction->setText(tr("Views")); ui.viewMenu->addAction(viewsAction); const int tabIndex = config->sideBarPage(); helpDock->tabWidget()->setCurrentIndex(tabIndex); // The tab index is 0 by default, so we need to force an upate // to poulate the contents in this case. if (tabIndex == 0) helpDock->currentTabChanged(tabIndex); ui.actionEditFind->setShortcut(QKeySequence::Find); ui.actionEditFindNext->setShortcut(QKeySequence::FindNext); ui.actionEditFindPrev->setShortcut(QKeySequence::FindPrevious); QObject::connect(ui.actionEditFind, SIGNAL(triggered()), tabs, SLOT(find())); QObject::connect(ui.actionEditFindNext, SIGNAL(triggered()), tabs, SLOT(findNext())); QObject::connect(ui.actionEditFindPrev, SIGNAL(triggered()), tabs, SLOT(findPrevious())); connect(ui.actionEditFont_Settings, SIGNAL(triggered()), this, SLOT(showFontSettingsDialog())); qApp->restoreOverrideCursor(); ui.actionGoPrevious->setEnabled(false); ui.actionGoNext->setEnabled(false); ui.actionEditCopy->setEnabled(false); // set the current selected item in the treeview helpDialog()->locateContents(tabs->currentBrowser()->source().toString()); connect(tabs, SIGNAL(browserUrlChanged(QString)), helpDock, SLOT(locateContents(QString))); } void MainWindow::browserTabChanged() { HelpWindow *win = tabs->currentBrowser(); if (win) { QTextCursor cursor(win->textCursor()); ui.actionEditCopy->setEnabled(cursor.hasSelection()); ui.actionGoPrevious->setEnabled(win->isBackwardAvailable()); ui.actionGoNext->setEnabled(win->isForwardAvailable()); } } void MainWindow::copyAvailable(bool yes) { ui.actionEditCopy->setEnabled(yes); } void MainWindow::updateTabActions(int index) { bool enabled = (index > 1) ? true : false; ui.actionPrevPage->setEnabled(enabled); ui.actionNextPage->setEnabled(enabled); ui.actionClosePage->setEnabled(enabled); } void MainWindow::setupGoActions() { Config *config = Config::configuration(); QStringList titles = config->docTitles(); QAction *action = 0; static bool separatorInserted = false; foreach (QAction *a, goActions) { ui.goMenu->removeAction(a); ui.goActionToolbar->removeAction(a); } qDeleteAll(goActions); goActions.clear(); goActionDocFiles->clear(); int addCount = 0; foreach (QString title, titles) { QPixmap pix = config->docIcon(title); if(!pix.isNull()) { if(!separatorInserted) { ui.goMenu->addSeparator(); separatorInserted = true; } action = new QAction(this); action->setText(title); action->setWhatsThis(tr("Displays the main page of a specific documentation set.")); action->setIcon(QIcon(pix)); ui.goMenu->addAction(action); ui.goActionToolbar->addAction(action); goActions.append(action); goActionDocFiles->insert(action, config->indexPage(title)); connect(action, SIGNAL(triggered()), this, SLOT(showGoActionLink())); ++addCount; } } if(!addCount) ui.goActionToolbar->hide(); else ui.goActionToolbar->show(); } bool MainWindow::insertActionSeparator() { ui.goMenu->addSeparator(); ui.Toolbar->addSeparator(); return true; } void MainWindow::closeEvent(QCloseEvent *e) { saveSettings(); e->accept(); } void MainWindow::about() { QMessageBox box(this); box.setText(QString::fromLatin1("
" "

%1

" "

Version %2

" "

Copyright (C) 2009 Nokia Corporation and/or its subsidiary(-ies).

") .arg(tr("Qt Assistant")).arg(QLatin1String(QT_VERSION_STR))); box.setWindowTitle(tr("Qt Assistant")); box.setIcon(QMessageBox::NoIcon); box.exec(); } void MainWindow::on_actionAboutApplication_triggered() { QString url = Config::configuration()->aboutURL(); if (url == QLatin1String("about_qt")) { QMessageBox::aboutQt(this, QLatin1String("Qt Assistant")); return; } QString text; if (url.startsWith(QLatin1String("file:"))) url = url.mid(5); QFile file(url); if(file.exists() && file.open(QFile::ReadOnly)) text = QString::fromUtf8(file.readAll()); if(text.isNull()) text = tr("Failed to open about application contents in file: '%1'").arg(url); QFileInfo fi(file); QString path = QDir::cleanPath(fi.absolutePath()); if (!QDir::searchPaths(QLatin1String("aboutImages")).contains(path)) QDir::addSearchPath(QLatin1String("aboutImages"), path); QMessageBox box(this); box.setText(text); box.setWindowTitle(Config::configuration()->aboutApplicationMenuText()); box.setIcon(QMessageBox::NoIcon); box.exec(); } void MainWindow::on_actionAboutAssistant_triggered() { about(); } void MainWindow::on_actionGoHome_triggered() { QString home = MainWindow::urlifyFileName(Config::configuration()->homePage()); showLink(home); } QString MainWindow::urlifyFileName(const QString &fileName) { QString name = fileName; QUrl url(name); #if defined(Q_OS_WIN32) if (!url.isValid() || url.scheme().isEmpty() || url.scheme().toLower() != QLatin1String("file:")) { int i = name.indexOf(QLatin1Char('#')); QString anchor = name.mid(i); name = name.toLower(); if (i > -1) name.replace(i, anchor.length(), anchor); name.replace(QLatin1Char('\\'), QLatin1Char('/')); foreach (QFileInfo drive, QDir::drives()) { if (name.startsWith(drive.absolutePath().toLower())) { name = QLatin1String("file:") + name; break; } } } #else if (!url.isValid() || url.scheme().isEmpty()) name.prepend(QLatin1String("file:")); #endif return name; } #ifndef QT_NO_PRINTER class PrintThread : public QThread { QPrinter _printer; QTextDocument *_document; public: PrintThread(QObject *parent) : QThread(parent), _printer(QPrinter::HighResolution), _document(0) { } ~PrintThread() { wait(); } QPrinter *printer() { return &_printer; } void start(QTextDocument *document) { _document = document->clone(); _document->moveToThread(this); QThread::start(); } protected: void run() { _document->print(printer()); delete _document; _document = 0; } }; #endif //QT_NO_PRINTER void MainWindow::on_actionFilePrint_triggered() { #ifndef QT_NO_PRINTER if (!QFontDatabase::supportsThreadedFontRendering()) { QPrinter printer(QPrinter::HighResolution); QPrintDialog dlg(&printer, this); if (dlg.exec() == QDialog::Accepted) { qApp->setOverrideCursor(Qt::WaitCursor); tabs->currentBrowser()->document()->print(&printer); qApp->restoreOverrideCursor(); } return; } PrintThread *thread = new PrintThread(this); QPrintDialog dlg(thread->printer(), this); if (dlg.exec() == QDialog::Accepted) { connect(thread, SIGNAL(finished()), SLOT(printingFinished())); connect(thread, SIGNAL(finished()), thread, SLOT(deleteLater())); qApp->setOverrideCursor(Qt::BusyCursor); thread->start(tabs->currentBrowser()->document()); } else { delete thread; } #else Q_ASSERT("No printing support"); #endif } void MainWindow::printingFinished() { qApp->restoreOverrideCursor(); } void MainWindow::updateBookmarkMenu() { for(QList::Iterator it = windows.begin(); it != windows.end(); ++it) (*it)->setupBookmarkMenu(); } void MainWindow::setupBookmarkMenu() { ui.bookmarkMenu->clear(); bookmarks.clear(); ui.bookmarkMenu->addAction(ui.actionAddBookmark); QFile f(QDir::homePath() + QLatin1String("/.assistant/bookmarks.") + Config::configuration()->profileName()); if (!f.open(QFile::ReadOnly)) return; QTextStream ts(&f); ui.bookmarkMenu->addSeparator(); while (!ts.atEnd()) { QString title = ts.readLine(); QString link = ts.readLine(); bookmarks.insert(ui.bookmarkMenu->addAction(title), link); } } void MainWindow::showBookmark(QAction *action) { if (bookmarks.contains(action)) showLink(bookmarks.value(action)); } void MainWindow::showLinkFromClient(const QString &link) { setWindowState(windowState() & ~Qt::WindowMinimized); raise(); activateWindow(); QString l = MainWindow::urlifyFileName(link); showLink(l); if (isMinimized()) showNormal(); } void MainWindow::showLink(const QString &link) { if(link.isEmpty()) qWarning("The link is empty!"); // don't fill the history with the same url more then once if (link == tabs->currentBrowser()->source().toString()) return; QUrl url(link); QFileInfo fi(url.toLocalFile()); tabs->setSource(url.toString()); tabs->currentBrowser()->setFocus(); } void MainWindow::showLinks(const QStringList &links) { if (links.size() == 0) { qWarning("MainWindow::showLinks() - Empty link"); return; } if (links.size() == 1) { showLink(MainWindow::urlifyFileName(links.first())); return; } QStringList::ConstIterator it = links.begin(); // Initial showing, The tab is empty so update that without creating it first if (!tabs->currentBrowser()->source().isValid()) { QPair browser; browser.first = tabs->currentBrowser(); browser.second = links.first(); pendingBrowsers.append(browser); tabs->setTitle(tabs->currentBrowser(), tr("...")); } ++it; while(it != links.end()) { QPair browser; browser.first = tabs->newBackgroundTab(); browser.second = *it; pendingBrowsers.append(browser); ++it; } startTimer(50); return; } void MainWindow::removePendingBrowser(HelpWindow *win) { if (!pendingBrowsers.count()) return; QMutableListIterator > it(pendingBrowsers); while (it.hasNext()) { QPair browser = it.next(); if (browser.first == win) { it.remove(); break; } } } void MainWindow::timerEvent(QTimerEvent *e) { QPair browser = pendingBrowsers.first(); pendingBrowsers.pop_front(); if (pendingBrowsers.size() == 0) killTimer(e->timerId()); browser.first->setSource(MainWindow::urlifyFileName(browser.second)); } void MainWindow::showQtHelp() { showLink(QLibraryInfo::location(QLibraryInfo::DocumentationPath) + QLatin1String("/html/index.html")); } MainWindow* MainWindow::newWindow() { saveSettings(); MainWindow *mw = new MainWindow; mw->move(geometry().topLeft()); if (isMaximized()) mw->showMaximized(); else mw->show(); mw->on_actionGoHome_triggered(); return mw; } void MainWindow::saveSettings() { Config *config = Config::configuration(); config->setSideBarPage(helpDock->tabWidget()->currentIndex()); config->setWindowGeometry(saveGeometry()); config->setMainWindowState(saveState()); // Create list of the tab urls QStringList lst; QList browsers = tabs->browsers(); foreach (HelpWindow *browser, browsers) lst << browser->source().toString(); config->setSource(lst); config->save(); } TabbedBrowser* MainWindow::browsers() const { return tabs; } void MainWindow::showSearchLink(const QString &link, const QStringList &terms) { HelpWindow * hw = tabs->currentBrowser(); hw->blockScrolling(true); hw->setCursor(Qt::WaitCursor); if (hw->source() == link) hw->reload(); else showLink(link); hw->setCursor(Qt::ArrowCursor); hw->viewport()->setUpdatesEnabled(false); QTextCharFormat marker; marker.setForeground(Qt::red); QTextCursor firstHit; QTextCursor c = hw->textCursor(); c.beginEditBlock(); foreach (QString term, terms) { c.movePosition(QTextCursor::Start); hw->setTextCursor(c); bool found = hw->find(term, QTextDocument::FindWholeWords); while (found) { QTextCursor hit = hw->textCursor(); if (firstHit.isNull() || hit.position() < firstHit.position()) firstHit = hit; hit.mergeCharFormat(marker); found = hw->find(term, QTextDocument::FindWholeWords); } } if (firstHit.isNull()) { firstHit = hw->textCursor(); firstHit.movePosition(QTextCursor::Start); } firstHit.clearSelection(); c.endEditBlock(); hw->setTextCursor(firstHit); hw->blockScrolling(false); hw->viewport()->setUpdatesEnabled(true); } void MainWindow::showGoActionLink() { const QObject *origin = sender(); if(!origin || QString::fromLatin1(origin->metaObject()->className()) != QString::fromLatin1("QAction")) return; QAction *action = (QAction*) origin; QString docfile = *(goActionDocFiles->find(action)); showLink(MainWindow::urlifyFileName(docfile)); } void MainWindow::on_actionHelpAssistant_triggered() { showLink(Config::configuration()->assistantDocPath() + QLatin1String("/assistant-manual.html")); } HelpDialog* MainWindow::helpDialog() const { return helpDock; } void MainWindow::backwardAvailable(bool enable) { ui.actionGoPrevious->setEnabled(enable); } void MainWindow::forwardAvailable(bool enable) { ui.actionGoNext->setEnabled(enable); } void MainWindow::updateProfileSettings() { Config *config = Config::configuration(); #ifndef Q_WS_MAC setWindowIcon(config->applicationIcon()); #endif ui.helpMenu->clear(); //ui.helpMenu->addAction(ui.actionHelpAssistant); //ui.helpMenu->addSeparator(); ui.helpMenu->addAction(ui.actionAboutAssistant); if (!config->aboutApplicationMenuText().isEmpty()) ui.helpMenu->addAction(ui.actionAboutApplication); ui.helpMenu->addSeparator(); ui.helpMenu->addAction(ui.actionHelpWhatsThis); ui.actionAboutApplication->setText(config->aboutApplicationMenuText()); if(!config->title().isNull()) setWindowTitle(config->title()); } void MainWindow::setupPopupMenu(QMenu *m) { m->addAction(ui.actionNewWindow); m->addAction(ui.actionOpenPage); m->addAction(ui.actionClosePage); m->addSeparator(); m->addAction(ui.actionSaveAs); m->addSeparator(); m->addAction(ui.actionGoPrevious); m->addAction(ui.actionGoNext); m->addAction(ui.actionGoHome); m->addSeparator(); m->addAction(ui.actionZoomIn); m->addAction(ui.actionZoomOut); m->addSeparator(); m->addAction(ui.actionEditCopy); m->addAction(ui.actionEditFind); } void MainWindow::on_actionSyncToc_triggered() { HelpWindow *w = tabs->currentBrowser(); if(w) { qApp->setOverrideCursor(QCursor(Qt::WaitCursor)); QString link = w->source().toString(); helpDock->locateContents(link); helpDock->tabWidget()->setCurrentIndex(0); qApp->restoreOverrideCursor(); } } void MainWindow::on_actionNewWindow_triggered() { newWindow()->show(); } void MainWindow::on_actionClose_triggered() { close(); } void MainWindow::on_actionHelpWhatsThis_triggered() { QWhatsThis::enterWhatsThisMode(); } void MainWindow::on_actionSaveAs_triggered() { QString fileName; QUrl url = tabs->currentBrowser()->source(); if (url.isValid()) { QFileInfo fi(url.toLocalFile()); fileName = fi.fileName(); } fileName = QFileDialog::getSaveFileName(this, tr("Save Page"), fileName); if (fileName.isEmpty()) return; QFile file(fileName); if (!file.open(QIODevice::WriteOnly)) { QMessageBox::critical(this, tr("Save Page"), tr("Cannot open file for writing!")); return; } QFileInfo fi(fileName); QString fn = fi.fileName(); int i = fn.lastIndexOf(QLatin1Char('.')); if (i > -1) fn = fn.left(i); QString relativeDestPath = fn + QLatin1String("_images"); QDir destDir(fi.absolutePath() + QDir::separator() + relativeDestPath); bool imgDirAvailable = destDir.exists(); if (!imgDirAvailable) imgDirAvailable = destDir.mkdir(destDir.absolutePath()); // save images QTextDocument *doc = tabs->currentBrowser()->document()->clone(); if (url.isValid() && imgDirAvailable) { QTextBlock::iterator it; for (QTextBlock block = doc->begin(); block != doc->end(); block = block.next()) { for (it = block.begin(); !(it.atEnd()); ++it) { QTextFragment fragment = it.fragment(); if (fragment.isValid()) { QTextImageFormat fm = fragment.charFormat().toImageFormat(); if (fm.isValid() && !fm.name().isEmpty()) { QUrl imagePath = tabs->currentBrowser()->source().resolved(fm.name()); if (!imagePath.isValid()) continue; QString from = imagePath.toLocalFile(); QString destName = fm.name(); int j = destName.lastIndexOf(QLatin1Char('/')); if (j > -1) destName = destName.mid(j+1); QFileInfo info(from); if (info.exists()) { if (!QFile::copy(from, destDir.absolutePath() + QDir::separator() + destName)) continue; fm.setName(QLatin1String("./") + relativeDestPath + QLatin1String("/") + destName); QTextCursor cursor(doc); cursor.setPosition(fragment.position()); cursor.setPosition(fragment.position() + fragment.length(), QTextCursor::KeepAnchor); cursor.setCharFormat(fm); } } } } } } QString src = doc->toHtml(QByteArray("utf-8")); QTextStream s(&file); s.setCodec("utf-8"); s << src; s.flush(); file.close(); } void MainWindow::showFontSettingsDialog() { Config *config = Config::configuration(); FontSettings settings = config->fontSettings(); { // It is important that the dialog be deleted before UI mode changes. FontSettingsDialog dialog; if (!dialog.showDialog(&settings)) return; } config->setFontPointSize(settings.browserFont.pointSizeF()); config->setFontSettings(settings); updateApplicationFontSettings(settings); } void MainWindow::updateApplicationFontSettings(FontSettings &settings) { QFont font = settings.windowFont; if (this->font() != font) qApp->setFont(font, "QWidget"); font = settings.browserFont; QList browsers = tabs->browsers(); foreach (HelpWindow *browser, browsers) { if (browser->font() != font) browser->setFont(font); } } QT_END_NAMESPACE