12#include <QtCore/QRegularExpression>
13#include <QtCore/QTimer>
15#include <QtGui/QKeyEvent>
16#include <QtWidgets/QMenu>
18#include <QtPrintSupport/QPageSetupDialog>
19#include <QtPrintSupport/QPrintDialog>
20#include <QtPrintSupport/QPrintPreviewDialog>
21#include <QtPrintSupport/QPrinter>
23#include <QtWidgets/QStackedWidget>
24#include <QtWidgets/QTextBrowser>
25#include <QtWidgets/QVBoxLayout>
27#include <QtHelp/QHelpSearchEngine>
31using namespace Qt::StringLiterals;
39TabBar::TabBar(QWidget *parent)
44 setDocumentMode(
true);
47 setShape(QTabBar::RoundedNorth);
48 setContextMenuPolicy(Qt::CustomContextMenu);
49 setSizePolicy(QSizePolicy(QSizePolicy::Maximum, QSizePolicy::Preferred,
50 QSizePolicy::TabWidget));
51 connect(
this, &QTabBar::currentChanged,
52 this, &TabBar::slotCurrentChanged);
53 connect(
this, &QTabBar::tabCloseRequested,
54 this, &TabBar::slotTabCloseRequested);
55 connect(
this, &QWidget::customContextMenuRequested,
56 this, &TabBar::slotCustomContextMenuRequested);
64int TabBar::addNewTab(
const QString &title)
67 const int index = addTab(title);
68 setTabsClosable(count() > 1);
75 for (
int i = 0; i < count(); ++i) {
87 for (
int i = 0; i < count(); ++i) {
94 setTabsClosable(count() > 1);
100 for (
int i = 0; i < count(); ++i) {
102 QString title = data->title();
103 title.replace(u'&',
"&&"_L1);
104 setTabText(i, title.isEmpty() ? tr(
"(Untitled)") : title);
108void TabBar::slotCurrentChanged(
int index)
111 emit currentTabChanged(tabData(index).value<HelpViewer*>());
114void TabBar::slotTabCloseRequested(
int index)
120void TabBar::slotCustomContextMenuRequested(
const QPoint &pos)
123 const int tab = tabAt(pos);
127 QMenu menu(QString(),
this);
131 const bool enableAction = count() > 1;
132 QAction *closePage = menu.addAction(tr(
"&Close Tab"));
133 closePage->setEnabled(enableAction);
135 QAction *closePages = menu.addAction(tr(
"Close Other Tabs"));
136 closePages->setEnabled(enableAction);
141 QAction *newBookmark = menu.addAction(tr(
"Add Bookmark for this Page..."));
142 const QString &url = viewer->source().toString();
143 if (url.isEmpty() || url ==
"about:blank"_L1)
144 newBookmark->setEnabled(
false);
146 QAction *pickedAction = menu.exec(mapToGlobal(pos));
147 if (pickedAction == closePage)
148 slotTabCloseRequested(tab);
149 else if (pickedAction == closePages) {
150 for (
int i = count() - 1; i >= 0; --i) {
152 slotTabCloseRequested(i);
154 }
else if (pickedAction == newBookmark)
155 emit addBookmark(viewer->title(), url);
170 staticCentralWidget =
this;
171 QVBoxLayout *vboxLayout =
new QVBoxLayout(
this);
173 vboxLayout->setContentsMargins(QMargins());
174 vboxLayout->setSpacing(0);
175 vboxLayout->addWidget(m_tabBar);
177 vboxLayout->addWidget(m_stackedWidget);
178 vboxLayout->addWidget(m_findWidget);
179 m_findWidget->hide();
181 connect(m_findWidget, &FindWidget::findNext,
this, &CentralWidget::findNext);
183 connect(m_findWidget, &FindWidget::find,
this, &CentralWidget::find);
185 connect(m_tabBar, &TabBar::addBookmark,
this, &CentralWidget::addBookmark);
191 QStringList zoomFactors;
192 QStringList currentPages;
193 for (
int i = 0; i < m_stackedWidget->count(); ++i) {
195 const QUrl &source = viewer->source();
196 if (source.isValid()) {
197 currentPages << source.toString();
198 zoomFactors << QString::number(viewer->scale());
203 helpEngine.setLastShownPages(currentPages);
204 helpEngine.setLastZoomFactors(zoomFactors);
215 return staticCentralWidget;
251 return static_cast<
HelpViewer*>(m_stackedWidget->widget(index));
257 return static_cast<
HelpViewer *>(m_stackedWidget->currentWidget());
263 page->installEventFilter(
this);
264 page->setFocus(Qt::OtherFocusReason);
265 connectSignals(page);
266 const int index = m_stackedWidget->addWidget(page);
267 m_tabBar->setTabData(m_tabBar->addNewTab(page->title()),
268 QVariant::fromValue(viewerAt(index)));
269 connect(page, &HelpViewer::titleChanged, m_tabBar, &TabBar::titleChanged);
272 connect(currentHelpViewer(), &HelpViewer::loadFinished,
273 this, &CentralWidget::highlightSearchTerms);
282 m_stackedWidget->removeWidget(m_stackedWidget->widget(index));
284 emit currentViewerChanged();
290 return m_stackedWidget->currentIndex();
297 m_stackedWidget->setCurrentWidget(page);
298 emit currentViewerChanged();
304 connect(m_tabBar, &TabBar::currentTabChanged, OpenPagesManager::instance(),
305 QOverload<HelpViewer *>::of(&OpenPagesManager::setCurrentPage));
310#if QT_CONFIG(clipboard)
311void CentralWidget::copy()
314 currentHelpViewer()->copy();
351 m_stackedWidget->setCurrentIndex((m_stackedWidget->currentIndex() + 1)
352 % m_stackedWidget->count());
364 m_stackedWidget->setCurrentIndex((m_stackedWidget->currentIndex() - 1)
365 % m_stackedWidget->count());
371#if !defined(QT_NO_PRINTER) && !defined(QT_NO_PRINTDIALOG)
373 QPrintDialog dlg(m_printer,
this);
375 if (!currentHelpViewer()->selectedText().isEmpty())
376 dlg.setOption(QAbstractPrintDialog::PrintSelection);
377 dlg.setOption(QAbstractPrintDialog::PrintPageRange);
378 dlg.setOption(QAbstractPrintDialog::PrintCollateCopies);
379 dlg.setWindowTitle(tr(
"Print Document"));
380 if (dlg.exec() == QDialog::Accepted)
388#if !defined(QT_NO_PRINTER) && !defined(QT_NO_PRINTDIALOG)
390 QPageSetupDialog dlg(m_printer);
398#if !defined(QT_NO_PRINTER) && !defined(QT_NO_PRINTDIALOG)
400 QPrintPreviewDialog preview(m_printer,
this);
401 preview.resize(m_printer->width(), m_printer->height());
402 connect(&preview, &QPrintPreviewDialog::paintRequested,
403 this, &CentralWidget::printPreviewToPrinter);
412 viewer->setSource(url);
413 viewer->setFocus(Qt::OtherFocusReason);
419 connect(currentHelpViewer(), &HelpViewer::loadFinished,
420 this, &CentralWidget::highlightSearchTerms);
422 currentHelpViewer()->setFocus(Qt::OtherFocusReason);
428 find(m_findWidget->text(),
true,
false);
434 find(m_findWidget->text(),
false,
false);
442 HelpViewer::FindFlags flags;
444 flags |= HelpViewer::FindBackward;
445 if (m_findWidget->caseSensitive())
446 flags |= HelpViewer::FindCaseSensitively;
447 found = viewer->findText(ttf, flags, incremental,
false);
450 if (!found && ttf.isEmpty())
453 if (!m_findWidget->isVisible())
473 const int count = m_stackedWidget->count();
474 const QFont &font = viewerAt(count - 1)->viewerFont();
475 for (
int i = 0; i < count; ++i)
489 const QString &text = e->text();
490 if (text.startsWith(u'/')) {
491 if (!m_findWidget->isVisible()) {
497 QWidget::keyPressEvent(e);
508 QWidget *receiver = m_stackedWidget;
511 QTimer::singleShot(1, receiver,
512 QOverload<>::of(&QWidget::setFocus));
520 QHelpSearchEngine *searchEngine =
522 const QString searchInput = searchEngine->searchInput();
523 const bool wholePhrase = searchInput.startsWith(u'"') &&
524 searchInput.endsWith(u'"');
525 const QStringList &words = wholePhrase ? QStringList(searchInput.mid(1, searchInput.size() - 2)) :
526 searchInput.split(QRegularExpression(
"\\W+"), Qt::SkipEmptyParts);
528 for (
const QString &word : words)
529 viewer->findText(word, {},
false,
true);
531 this, &CentralWidget::highlightSearchTerms);
546 emit sourceChanged(url);
552 QUrl resolvedLink = m_resolvedLinks.value(link);
553 if (!link.isEmpty() && resolvedLink.isEmpty()) {
555 m_resolvedLinks.insert(link, resolvedLink);
557 emit highlighted(resolvedLink);
567 m_printer =
new QPrinter(QPrinter::ScreenResolution);
574#if defined(BROWSER_QTWEBKIT)
575 connect(page, &HelpViewer::printRequested,
576 this, &CentralWidget::print);
578#if QT_CONFIG(clipboard)
579 connect(page, &HelpViewer::copyAvailable,
580 this, &CentralWidget::copyAvailable);
586 connect(page, &HelpViewer::sourceChanged,
587 this, &CentralWidget::handleSourceChanged);
588 connect(page, QOverload<
const QUrl &>::of(&HelpViewer::highlighted),
589 this, &CentralWidget::slotHighlighted);
595 if (e->type() != QEvent::KeyPress)
596 return QWidget::eventFilter(object, e);
599 QKeyEvent *keyEvent =
static_cast<QKeyEvent*> (e);
600 if (viewer == object && keyEvent->key() == Qt::Key_Backspace) {
602#if defined(BROWSER_QTWEBKIT)
604 if (!viewer->hasFocus())
609 return QWidget::eventFilter(object, e);
QHelpSearchEngine * searchEngine() const
static HelpEngineWrapper & instance()
void setLastTabPage(int lastPage)
void forwardAvailable(bool enabled)
bool isForwardAvailable() const
void backwardAvailable(bool enabled)
bool isBackwardAvailable() const
HelpViewer * createBlankPage()
static OpenPagesManager * instance()
void setCurrent(HelpViewer *viewer)
void removeTabAt(HelpViewer *viewer)
Combined button and popup list for selecting options.