1 /***************************************************************************
3 ** This file is part of Qt Creator
5 ** Copyright (c) 2008-2009 Nokia Corporation and/or its subsidiary(-ies).
7 ** Contact: Qt Software Information (qt-info@nokia.com)
10 ** Non-Open Source Usage
12 ** Licensees may use this file in accordance with the Qt Beta Version
13 ** License Agreement, Agreement version 2.2 provided with the Software or,
14 ** alternatively, in accordance with the terms contained in a written
15 ** agreement between you and Nokia.
17 ** GNU General Public License Usage
19 ** Alternatively, this file may be used under the terms of the GNU General
20 ** Public License versions 2.0 or 3.0 as published by the Free Software
21 ** Foundation and appearing in the file LICENSE.GPL included in the packaging
22 ** of this file. Please review the following information to ensure GNU
23 ** General Public Licensing requirements will be met:
25 ** http://www.fsf.org/licensing/licenses/info/GPLv2.html and
26 ** http://www.gnu.org/copyleft/gpl.html.
28 ** In addition, as a special exception, Nokia gives you certain additional
29 ** rights. These rights are described in the Nokia Qt GPL Exception
30 ** version 1.3, included in the file GPL_EXCEPTION.txt in this package.
32 ***************************************************************************/
34 #include "centralwidget.h"
35 #include "helpviewer.h"
36 #include "topicchooser.h"
38 #include <QtCore/QDir>
39 #include <QtCore/QEvent>
40 #include <QtCore/QTimer>
42 #include <QtGui/QMenu>
43 #include <QtGui/QLabel>
44 #include <QtGui/QLayout>
45 #include <QtGui/QPrinter>
46 #include <QtGui/QLineEdit>
47 #include <QtGui/QCheckBox>
48 #include <QtGui/QTabBar>
49 #include <QtGui/QTabWidget>
50 #include <QtGui/QToolButton>
51 #include <QtGui/QMouseEvent>
52 #include <QtGui/QFocusEvent>
53 #include <QtGui/QMainWindow>
54 #include <QtGui/QSpacerItem>
55 #include <QtGui/QTextCursor>
56 #include <QtGui/QPrintDialog>
57 #include <QtGui/QApplication>
58 #include <QtGui/QTextDocumentFragment>
59 #include <QtGui/QPrintPreviewDialog>
60 #include <QtGui/QPageSetupDialog>
62 #include <QtHelp/QHelpEngine>
64 #include <coreplugin/coreconstants.h>
66 using namespace Help::Internal
;
69 HelpViewer
* helpViewerFromTabPosition(const QTabWidget
*widget
, const QPoint
&point
)
71 QTabBar
*tabBar
= qFindChild
<QTabBar
*>(widget
);
72 for (int i
= 0; i
< tabBar
->count(); ++i
) {
73 if (tabBar
->tabRect(i
).contains(point
))
74 return qobject_cast
<HelpViewer
*>(widget
->widget(i
));
78 CentralWidget
*staticCentralWidget
= 0;
81 CentralWidget::CentralWidget(QHelpEngine
*engine
, QWidget
*parent
)
89 globalActionList
.clear();
90 collectionFile
= helpEngine
->collectionFile();
92 QString system
= QLatin1String("win");
95 system
= QLatin1String("mac");
98 tabWidget
= new QTabWidget
;
99 tabWidget
->setDocumentMode(true);
100 tabWidget
->setMovable(true);
101 connect(tabWidget
, SIGNAL(tabCloseRequested(int)), this, SLOT(closeTab(int)));
102 connect(tabWidget
, SIGNAL(currentChanged(int)), this, SLOT(currentPageChanged(int)));
104 QToolButton
*newTabButton
= new QToolButton(this);
105 newTabButton
->setAutoRaise(true);
106 newTabButton
->setToolTip(tr("Add new page"));
107 newTabButton
->setIcon(QIcon(QString::fromUtf8(":/trolltech/assistant/images/%1/addtab.png").arg(system
)));
109 tabWidget
->setCornerWidget(newTabButton
, Qt::TopLeftCorner
);
110 connect(newTabButton
, SIGNAL(clicked()), this, SLOT(newTab()));
112 QVBoxLayout
*vboxLayout
= new QVBoxLayout(this);
113 vboxLayout
->setMargin(0);
114 vboxLayout
->addWidget(tabWidget
);
116 QTabBar
*tabBar
= qFindChild
<QTabBar
*>(tabWidget
);
118 tabBar
->installEventFilter(this);
119 tabBar
->setContextMenuPolicy(Qt::CustomContextMenu
);
120 connect(tabBar
, SIGNAL(customContextMenuRequested(const QPoint
&)),
121 this, SLOT(showTabBarContextMenu(const QPoint
&)));
124 staticCentralWidget
= this;
127 CentralWidget::~CentralWidget()
130 QString currentPages
;
131 QHelpEngineCore
engine(collectionFile
, 0);
133 if (engine
.setupData()) {
134 for (int i
= 0; i
< tabWidget
->count(); ++i
) {
135 HelpViewer
*viewer
= qobject_cast
<HelpViewer
*>(tabWidget
->widget(i
));
136 if (viewer
&& viewer
->source().isValid())
137 currentPages
.append(viewer
->source().toString()).append(QLatin1Char('|'));
139 engine
.setCustomValue(QLatin1String("LastTabPage"), lastTabPage
);
140 engine
.setCustomValue(QLatin1String("LastShownPages"), currentPages
);
144 CentralWidget
*CentralWidget::instance()
146 return staticCentralWidget
;
149 void CentralWidget::newTab()
151 HelpViewer
* viewer
= currentHelpViewer();
153 setSourceInNewTab(viewer
->source());
156 void CentralWidget::zoomIn()
158 HelpViewer
* viewer
= currentHelpViewer();
163 void CentralWidget::zoomOut()
165 HelpViewer
* viewer
= currentHelpViewer();
170 void CentralWidget::nextPage()
172 if (tabWidget
->currentIndex() < tabWidget
->count() -1)
173 tabWidget
->setCurrentIndex(tabWidget
->currentIndex() +1);
175 tabWidget
->setCurrentIndex(0);
178 void CentralWidget::resetZoom()
180 HelpViewer
* viewer
= currentHelpViewer();
185 void CentralWidget::previousPage()
187 int index
= tabWidget
->currentIndex() -1;
189 tabWidget
->setCurrentIndex(index
);
191 tabWidget
->setCurrentIndex(tabWidget
->count() -1);
194 void CentralWidget::closeTab()
196 closeTab(tabWidget
->currentIndex());
199 void CentralWidget::closeTab(int index
)
201 HelpViewer
* viewer
= helpViewerAtIndex(index
);
202 if (!viewer
|| tabWidget
->count() == 1)
205 tabWidget
->removeTab(index
);
206 QTimer::singleShot(0, viewer
, SLOT(deleteLater()));
209 void CentralWidget::setSource(const QUrl
&url
)
211 HelpViewer
* viewer
= currentHelpViewer();
212 HelpViewer
* lastViewer
= qobject_cast
<HelpViewer
*>(tabWidget
->widget(lastTabPage
));
214 if (!viewer
&& !lastViewer
) {
215 viewer
= new HelpViewer(helpEngine
, this);
216 viewer
->installEventFilter(this);
217 lastTabPage
= tabWidget
->addTab(viewer
, QString());
218 tabWidget
->setCurrentIndex(lastTabPage
);
220 qApp
->processEvents();
224 viewer
->setSource(url
);
225 currentPageChanged(lastTabPage
);
226 viewer
->setFocus(Qt::OtherFocusReason
);
227 tabWidget
->setCurrentIndex(lastTabPage
);
228 tabWidget
->setTabText(lastTabPage
, quoteTabTitle(viewer
->documentTitle()));
231 void CentralWidget::setLastShownPages()
233 const QStringList lastShownPageList
=
234 helpEngine
->customValue(QLatin1String("LastShownPages")). toString().
235 split(QLatin1Char('|'), QString::SkipEmptyParts
);
237 if (!lastShownPageList
.isEmpty()) {
238 foreach (const QString
& page
, lastShownPageList
)
239 setSourceInNewTab(page
);
241 tabWidget
->setCurrentIndex(helpEngine
->
242 customValue(QLatin1String("LastTabPage"), 0).toInt());
244 QUrl
url(helpEngine
->findFile(QUrl("qthelp://com.trolltech.qt.440/qdoc/index.html")));
245 if (!url
.isValid()) {
246 url
.setUrl(QString("qthelp://com.nokia.qtcreator.%1%2/doc/index.html").
247 arg(IDE_VERSION_MAJOR
).arg(IDE_VERSION_MINOR
));
255 bool CentralWidget::hasSelection() const
257 const HelpViewer
* viewer
= currentHelpViewer();
258 return viewer
? viewer
->hasSelection() : false;
261 QUrl
CentralWidget::currentSource() const
263 const HelpViewer
* viewer
= currentHelpViewer();
265 return viewer
->source();
270 QString
CentralWidget::currentTitle() const
272 const HelpViewer
* viewer
= currentHelpViewer();
274 return viewer
->documentTitle();
279 void CentralWidget::copySelection()
281 HelpViewer
* viewer
= currentHelpViewer();
286 void CentralWidget::initPrinter()
288 #ifndef QT_NO_PRINTER
290 printer
= new QPrinter(QPrinter::HighResolution
);
294 void CentralWidget::print()
296 #ifndef QT_NO_PRINTER
297 HelpViewer
* viewer
= currentHelpViewer();
303 QPrintDialog
*dlg
= new QPrintDialog(printer
, this);
304 #if defined(QT_NO_WEBKIT)
305 if (viewer
->textCursor().hasSelection())
306 dlg
->addEnabledOption(QAbstractPrintDialog::PrintSelection
);
308 dlg
->addEnabledOption(QAbstractPrintDialog::PrintPageRange
);
309 dlg
->addEnabledOption(QAbstractPrintDialog::PrintCollateCopies
);
310 dlg
->setWindowTitle(tr("Print Document"));
311 if (dlg
->exec() == QDialog::Accepted
) {
312 viewer
->print(printer
);
318 void CentralWidget::printPreview()
320 #ifndef QT_NO_PRINTER
322 QPrintPreviewDialog
preview(printer
, this);
323 connect(&preview
, SIGNAL(paintRequested(QPrinter
*)), SLOT(printPreview(QPrinter
*)));
328 void CentralWidget::printPreview(QPrinter
*p
)
330 #ifndef QT_NO_PRINTER
331 HelpViewer
*viewer
= currentHelpViewer();
337 void CentralWidget::pageSetup()
339 #ifndef QT_NO_PRINTER
341 QPageSetupDialog
dlg(printer
);
346 bool CentralWidget::isHomeAvailable() const
348 return currentHelpViewer() ? true : false;
351 void CentralWidget::home()
353 HelpViewer
* viewer
= currentHelpViewer();
358 bool CentralWidget::isForwardAvailable() const
360 const HelpViewer
* viewer
= currentHelpViewer();
362 return viewer
->isForwardAvailable();
367 void CentralWidget::forward()
369 HelpViewer
* viewer
= currentHelpViewer();
374 bool CentralWidget::isBackwardAvailable() const
376 const HelpViewer
* viewer
= currentHelpViewer();
378 return viewer
->isBackwardAvailable();
383 void CentralWidget::backward()
385 HelpViewer
* viewer
= currentHelpViewer();
391 QList
<QAction
*> CentralWidget::globalActions() const
393 return globalActionList
;
396 void CentralWidget::setGlobalActions(const QList
<QAction
*> &actions
)
398 globalActionList
= actions
;
401 void CentralWidget::setSourceInNewTab(const QUrl
&url
)
403 HelpViewer
* viewer
= new HelpViewer(helpEngine
, this);
404 viewer
->installEventFilter(this);
405 viewer
->setSource(url
);
406 viewer
->setFocus(Qt::OtherFocusReason
);
407 tabWidget
->setCurrentIndex(tabWidget
->addTab(viewer
,
408 quoteTabTitle(viewer
->documentTitle())));
410 #if defined(QT_NO_WEBIT)
411 QFont font
= qApp
->font();
412 if (helpEngine
->customValue(QLatin1String("useBrowserFont")).toBool())
413 font
= qVariantValue
<QFont
>(helpEngine
->customValue(QLatin1String("browserFont")));
414 viewer
->setFont(font
);
416 QWebView
* view
= qobject_cast
<QWebView
*> (viewer
);
418 QWebSettings
* settings
= QWebSettings::globalSettings();
419 int fontSize
= settings
->fontSize(QWebSettings::DefaultFontSize
);
420 QString fontFamily
= settings
->fontFamily(QWebSettings::StandardFont
);
422 settings
= view
->settings();
423 settings
->setFontSize(QWebSettings::DefaultFontSize
, fontSize
);
424 settings
->setFontFamily(QWebSettings::StandardFont
, fontFamily
);
431 HelpViewer
*CentralWidget::newEmptyTab()
433 HelpViewer
* viewer
= new HelpViewer(helpEngine
, this);
434 viewer
->installEventFilter(this);
435 viewer
->setFocus(Qt::OtherFocusReason
);
436 #if defined(QT_NO_WEBKIT)
437 viewer
->setDocumentTitle(tr("unknown"));
439 tabWidget
->setCurrentIndex(tabWidget
->addTab(viewer
, tr("unknown")));
445 void CentralWidget::connectSignals()
447 const HelpViewer
* viewer
= currentHelpViewer();
449 connect(viewer
, SIGNAL(copyAvailable(bool)), this, SIGNAL(copyAvailable(bool)));
450 connect(viewer
, SIGNAL(forwardAvailable(bool)), this, SIGNAL(forwardAvailable(bool)));
451 connect(viewer
, SIGNAL(backwardAvailable(bool)), this, SIGNAL(backwardAvailable(bool)));
452 connect(viewer
, SIGNAL(sourceChanged(const QUrl
&)), this, SIGNAL(sourceChanged(const QUrl
&)));
453 connect(viewer
, SIGNAL(highlighted(const QString
&)), this, SIGNAL(highlighted(const QString
&)));
455 connect(viewer
, SIGNAL(sourceChanged(const QUrl
&)), this, SLOT(setTabTitle(const QUrl
&)));
459 HelpViewer
*CentralWidget::helpViewerAtIndex(int index
) const
461 return qobject_cast
<HelpViewer
*>(tabWidget
->widget(index
));
464 HelpViewer
*CentralWidget::currentHelpViewer() const
466 return qobject_cast
<HelpViewer
*>(tabWidget
->currentWidget());
469 void CentralWidget::activateTab(bool onlyHelpViewer
)
471 if (currentHelpViewer()) {
472 currentHelpViewer()->setFocus();
477 tabWidget
->setCurrentIndex(idx
);
478 tabWidget
->currentWidget()->setFocus();
482 void CentralWidget::setTabTitle(const QUrl
& url
)
484 int tab
= lastTabPage
;
485 HelpViewer
* viewer
= currentHelpViewer();
487 #if !defined(QT_NO_WEBKIT)
488 if (!viewer
|| viewer
->source() != url
) {
489 QTabBar
*tabBar
= qFindChild
<QTabBar
*>(tabWidget
);
490 for (tab
= 0; tab
< tabBar
->count(); ++tab
) {
491 viewer
= qobject_cast
<HelpViewer
*>(tabWidget
->widget(tab
));
492 if (viewer
&& viewer
->source() == url
)
499 tabWidget
->setTabText(tab
,
500 quoteTabTitle(viewer
->documentTitle().trimmed()));
504 void CentralWidget::currentPageChanged(int index
)
506 const HelpViewer
*viewer
= currentHelpViewer();
508 if (viewer
|| tabWidget
->count() == 1)
511 bool enabled
= false;
513 enabled
= tabWidget
->count() > 1;
515 tabWidget
->setTabsClosable(enabled
);
516 tabWidget
->cornerWidget(Qt::TopLeftCorner
)->setEnabled(true);
518 emit
currentViewerChanged();
521 void CentralWidget::showTabBarContextMenu(const QPoint
&point
)
523 HelpViewer
* viewer
= helpViewerFromTabPosition(tabWidget
, point
);
527 QTabBar
*tabBar
= qFindChild
<QTabBar
*>(tabWidget
);
529 QMenu
menu(QLatin1String(""), tabBar
);
530 QAction
*new_page
= menu
.addAction(tr("Add New Page"));
531 QAction
*close_page
= menu
.addAction(tr("Close This Page"));
532 QAction
*close_pages
= menu
.addAction(tr("Close Other Pages"));
534 QAction
*newBookmark
= menu
.addAction(tr("Add Bookmark for this Page..."));
536 if (tabBar
->count() == 1) {
537 close_page
->setEnabled(false);
538 close_pages
->setEnabled(false);
541 QAction
*picked_action
= menu
.exec(tabBar
->mapToGlobal(point
));
545 if (picked_action
== new_page
)
546 setSourceInNewTab(viewer
->source());
548 if (picked_action
== close_page
) {
549 tabWidget
->removeTab(tabWidget
->indexOf(viewer
));
550 QTimer::singleShot(0, viewer
, SLOT(deleteLater()));
553 if (picked_action
== close_pages
) {
554 int currentPage
= tabWidget
->indexOf(viewer
);
555 for (int i
= tabBar
->count() -1; i
>= 0; --i
) {
556 viewer
= qobject_cast
<HelpViewer
*>(tabWidget
->widget(i
));
557 if (i
!= currentPage
&& viewer
) {
558 tabWidget
->removeTab(i
);
559 QTimer::singleShot(0, viewer
, SLOT(deleteLater()));
567 if (picked_action
== newBookmark
)
568 emit
addNewBookmark(viewer
->documentTitle(), viewer
->source().toString());
571 // if we have a current help viewer then this is the 'focus proxy', otherwise
572 // it's the tab widget itself
573 // this is needed, so an embedding program can just set the focus to the central widget
574 // and it does TheRightThing
575 void CentralWidget::focusInEvent(QFocusEvent
* /* event */)
577 if (currentHelpViewer())
578 QTimer::singleShot(1, currentHelpViewer(), SLOT(setFocus()));
580 QTimer::singleShot(1, tabWidget
, SLOT(setFocus()));
583 bool CentralWidget::eventFilter(QObject
*object
, QEvent
*e
)
585 if (currentHelpViewer() == object
&& e
->type() == QEvent::KeyPress
){
586 QKeyEvent
*ke
= static_cast<QKeyEvent
*>(e
);
587 if (ke
->key() == Qt::Key_Backspace
) {
588 HelpViewer
*viewer
= currentHelpViewer();
589 if (viewer
&& viewer
->isBackwardAvailable())
595 QTabBar
*tabBar
= qobject_cast
<QTabBar
*>(object
);
596 bool mousRel
= e
->type() == QEvent::MouseButtonRelease
;
597 bool dblClick
= e
->type() == QEvent::MouseButtonDblClick
;
599 if (tabBar
&& (mousRel
|| dblClick
)) {
600 QMouseEvent
*mouseEvent
= static_cast<QMouseEvent
*>(e
);
601 HelpViewer
*viewer
= helpViewerFromTabPosition(tabWidget
, mouseEvent
->pos());
602 if (tabWidget
->count() <= 1)
603 return QWidget::eventFilter(object
, e
);
605 if (viewer
&& (mouseEvent
->button() == Qt::MidButton
|| dblClick
)) {
606 tabWidget
->removeTab(tabWidget
->indexOf(viewer
));
607 QTimer::singleShot(0, viewer
, SLOT(deleteLater()));
608 currentPageChanged(tabWidget
->currentIndex());
612 return QWidget::eventFilter(object
, e
);
615 void CentralWidget::updateBrowserFont()
617 #if defined(QT_NO_WEBKIT)
618 QFont font
= qApp
->font();
619 if (helpEngine
->customValue(QLatin1String("useBrowserFont")).toBool())
620 font
= qVariantValue
<QFont
>(helpEngine
->customValue(QLatin1String("browserFont")));
623 for (int i
= 0; i
< tabWidget
->count(); ++i
) {
624 widget
= tabWidget
->widget(i
);
625 if (widget
->font() != font
)
626 widget
->setFont(font
);
629 QWebSettings
* settings
= QWebSettings::globalSettings();
630 int fontSize
= settings
->fontSize(QWebSettings::DefaultFontSize
);
631 QString fontFamily
= settings
->fontFamily(QWebSettings::StandardFont
);
633 QWebView
* widget
= 0;
634 for (int i
= 0; i
< tabWidget
->count(); ++i
) {
635 widget
= qobject_cast
<QWebView
*> (tabWidget
->widget(i
));
637 settings
= widget
->settings();
638 settings
->setFontSize(QWebSettings::DefaultFontSize
, fontSize
);
639 settings
->setFontFamily(QWebSettings::StandardFont
, fontFamily
);
645 bool CentralWidget::find(const QString
&txt
, QTextDocument::FindFlags findFlags
,
648 HelpViewer
* viewer
= currentHelpViewer();
650 #if !defined(QT_NO_WEBKIT)
651 Q_UNUSED(incremental
);
653 QWebPage::FindFlags options
= QWebPage::FindWrapsAroundDocument
;
654 if (findFlags
& QTextDocument::FindBackward
)
655 options
|= QWebPage::FindBackward
;
656 if (findFlags
& QTextDocument::FindCaseSensitively
)
657 options
|= QWebPage::FindCaseSensitively
;
659 return viewer
->findText(txt
, options
);
664 QTextDocument
*doc
= 0;
665 QTextBrowser
*browser
= 0;
668 doc
= viewer
->document();
669 cursor
= viewer
->textCursor();
670 browser
= qobject_cast
<QTextBrowser
*>(viewer
);
673 if (tabWidget->currentWidget() == m_searchWidget) {
674 QTextBrowser* browser = qFindChild<QTextBrowser*>(m_searchWidget);
676 doc = browser->document();
677 cursor = browser->textCursor();
681 if (!browser
|| !doc
|| cursor
.isNull())
684 cursor
.setPosition(cursor
.selectionStart());
686 QTextCursor found
= doc
->find(txt
, cursor
, findFlags
);
687 if (found
.isNull()) {
688 if ((findFlags
&QTextDocument::FindBackward
) == 0)
689 cursor
.movePosition(QTextCursor::Start
);
691 cursor
.movePosition(QTextCursor::End
);
692 found
= doc
->find(txt
, cursor
, findFlags
);
693 if (found
.isNull()) {
697 if (!found
.isNull()) {
698 viewer
->setTextCursor(found
);
704 void CentralWidget::showTopicChooser(const QMap
<QString
, QUrl
> &links
,
705 const QString
&keyword
)
707 TopicChooser
tc(this, keyword
, links
);
708 if (tc
.exec() == QDialog::Accepted
)
709 setSource(tc
.link());
712 void CentralWidget::copy()
714 HelpViewer
* viewer
= currentHelpViewer();
719 QString
CentralWidget::quoteTabTitle(const QString
&title
) const
722 return s
.replace(QLatin1Char('&'), QLatin1String("&&"));