10#include <QInputDialog>
13#include <QWebEngineProfile>
14#include <QWebEngineHistory>
15#include <QWebEngineSettings>
16#include <QWebEngineFindTextResult>
17#include <QRegularExpression>
18#include <QWebEngineCookieStore>
19#include <QStandardPaths>
21#include <QApplication>
22#include <QDesktopServices>
23#if QT_VERSION >= QT_VERSION_CHECK(6, 9, 0)
24 #include <QWebEngineProfileBuilder>
26#if QT_VERSION >= QT_VERSION_CHECK(6, 10, 0)
27 #include <QWebEngineExtensionManager>
29#include <QLoggingCategory>
31#include "RabbitCommonDir.h"
32#include "RabbitCommonTools.h"
34#include "CaptureFullPage.h"
35#include "FrmHistory.h"
36#include "AddressCompleter.h"
37#include "AutoCompleteLineEdit.h"
38#include "FrmBookmark.h"
39#include "FrmAddBookmark.h"
40#include "DlgSettings.h"
41#include "ParameterGlobal.h"
42#include "ProtocolManager.h"
43#include "FrmWebBrowser.h"
45static Q_LOGGING_CATEGORY(log,
"WebBrowser.Browser")
55 , m_pAddBookmark(
nullptr)
57 , m_pFindNext(
nullptr)
58 , m_pFindPrevious(
nullptr)
59 , m_pZoomOriginal(
nullptr)
62 , m_pFavAction(
nullptr)
65 , m_pAddPageIncognito(
nullptr)
66 , m_pAddWindow(
nullptr)
68 , m_pPrintToPdf(
nullptr)
69 , m_pAddWindowIncognito(
nullptr)
70 , m_pDownload(
nullptr)
71 , m_pInspector(
nullptr)
73 , m_pUrlLineEdit(
nullptr)
74 , m_pProgressBar(
nullptr)
76 , m_DownloadManager(pPara)
77 , m_pCapturePage(
nullptr)
78 , m_pCaptureFulPage(
nullptr)
80 , m_pMultimediaRecord(
nullptr)
82 qDebug(log) << Q_FUNC_INFO;
85 setWindowIcon(QIcon::fromTheme(
"web-browser"));
87 QVBoxLayout* pLayout =
new QVBoxLayout(
this);
91 pLayout->setSpacing(0);
92 pLayout->setContentsMargins(0, 0, 0, 0);
95 m_pToolBar =
new QToolBar(
this);
97 pLayout->addWidget(m_pToolBar);
100 m_pBack = m_pToolBar->addAction(
101 QIcon::fromTheme(
"go-previous"), tr(
"Back"),
104 if(pWeb && pWeb->page())
105 pWeb->page()->action(QWebEnginePage::Back)->trigger();
107 m_pBack->setEnabled(
false);
108 m_pBack->setShortcuts(QKeySequence::Back);
109 m_pBack->setStatusTip(m_pBack->text());
110 m_pForward = m_pToolBar->addAction(
111 QIcon::fromTheme(
"go-next"), tr(
"Forward"),
114 if(pWeb && pWeb->page())
115 pWeb->page()->action(QWebEnginePage::Forward)->trigger();
117 m_pForward->setEnabled(
false);
118 m_pForward->setShortcuts(QKeySequence::Forward);
119 m_pForward->setStatusTip(m_pForward->text());
120 m_pRefresh = m_pToolBar->addAction(
121 QIcon::fromTheme(
"view-refresh"), tr(
"Refresh"),
124 if(pWeb && pWeb->page())
125 pWeb->page()->action(QWebEnginePage::Reload)->trigger();
127 m_pRefresh->setShortcuts(QKeySequence::Refresh);
128 m_pRefresh->setStatusTip(m_pRefresh->text());
130 m_pUrlLineEdit =
new QLineEdit(
this);
131 m_pFavAction =
new QAction(m_pUrlLineEdit);
132 m_pUrlLineEdit->addAction(m_pFavAction, QLineEdit::LeadingPosition);
133 m_pUrlLineEdit->setClearButtonEnabled(
true);
134 m_pUrl = m_pToolBar->addWidget(m_pUrlLineEdit);
135 m_pGo =
new QAction(QIcon::fromTheme(
"go-next"), tr(
"go"), m_pUrlLineEdit);
136 m_pGo->setStatusTip(m_pGo->text());
137 check = connect(m_pGo, &QAction::triggered,
this, &CFrmWebBrowser::slotReturnPressed);
139 m_pUrlLineEdit->addAction(m_pGo, QLineEdit::TrailingPosition);
140 m_pGo->setVisible(
false);
141 check = connect(m_pUrlLineEdit, &QLineEdit::textEdited,
142 this, [&](
const QString &text){
143 QLineEdit* pLineEdit = qobject_cast<QLineEdit*>(sender());
146 if(m_pGo->isVisible())
147 m_pGo->setVisible(
false);
149 if(!m_pGo->isVisible())
150 m_pGo->setVisible(
true);
156 auto pAddressCompleter =
new CAddressCompleter(&m_pPara->m_HistoryDatabase,
this);
157 pAddressCompleter->attachToLineEdit(m_pUrlLineEdit);
159 pAddressCompleter->setMaxVisibleItems(m_pPara->GetAddCompleterLines());
160 check = connect(pAddressCompleter, &CAddressCompleter::urlSelected,
161 this, &CFrmWebBrowser::slotUrlSelected);
163 check = connect(pAddressCompleter, &CAddressCompleter::searchRequested,
164 this, [&](
const QString& keyword) {
165 qDebug(log) <<
"CAddressCompleter::searchRequested keyword:" << keyword;
169 szSearch = m_pPara->GetSearchEngine();
170 szUrl = szSearch.replace(m_pPara->GetSearchRelaceString(),
171 QUrl::toPercentEncoding(keyword));
173 slotUrlSelected(szUrl);
177 check = connect(pAddressCompleter, &CAddressCompleter::sigCommand,
178 this, [&](
const QString& cmd) {
179 if(cmd.startsWith(
"@setting")) {
181 RC_SHOW_WINDOW(&dlg);
182 }
else if(cmd.startsWith(
"@history")) {
184 }
else if(cmd.startsWith(
"@bookmark")) {
190 m_pAddBookmark = m_pToolBar->addAction(
191 QIcon::fromTheme(
"user-bookmarks"),
192 tr(
"Add bookmark"),
this, SLOT(slotAddBookmark()));
194 m_pAddPage = m_pToolBar->addAction(QIcon::fromTheme(
"add"), tr(
"Add tab page"),
196 CreateWindow(QWebEnginePage::WebBrowserTab);
197 if(!m_pPara->GetTabUrl().isEmpty()) {
198 m_pUrlLineEdit->setText(m_pPara->GetTabUrl());
202 m_pAddPage->setStatusTip(m_pAddPage->text());
203 m_pAddPage->setShortcuts(QKeySequence::AddTab);
205 m_pDownload = m_pToolBar->addAction(
206 QIcon::fromTheme(
"emblem-downloads"), tr(
"Download Manager"));
207 m_pDownload->setCheckable(
true);
208 m_pDownload->setStatusTip(m_pDownload->text());
209 m_pDownload->setShortcut(QKeySequence(Qt::CTRL | Qt::Key_D));
210 check = connect(m_pDownload, &QAction::toggled,
211 this, [&](
bool checked){
213 m_DownloadManager.show();
215 m_DownloadManager.hide();
218 check = connect(&m_DownloadManager, &CFrmDownloadManager::sigVisible,
this,
221 m_pDownload->setChecked(visible);
225 m_pProgressBar =
new QProgressBar(
this);
227 pLayout->addWidget(m_pProgressBar);
228 m_pProgressBar->setMaximumHeight(1);
229 m_pProgressBar->setTextVisible(
false);
230 m_pProgressBar->show();
231 m_pProgressBar->setStyleSheet(
"QProgressBar {border: 0px} QProgressBar::chunk {background-color: #da4453}");
234 m_pTab =
new QTabWidget(
this);
236 m_pTab->setTabsClosable(
true);
237 m_pTab->setUsesScrollButtons(
true);
238 m_pTab->setMovable(
true);
239 m_pTab->setElideMode(Qt::TextElideMode::ElideRight);
240 pLayout->addWidget(m_pTab);
242 check = connect(m_pTab, &QTabWidget::currentChanged,
243 this, &CFrmWebBrowser::slotTabCurrentChanged);
245 check = connect(m_pTab, &QTabWidget::tabCloseRequested,
246 this, &CFrmWebBrowser::slotTabCloseRequested);
249 m_DownloadManager.hide();
250 QWebEngineProfile::defaultProfile()->setDownloadPath(m_pPara->GetDownloadFolder());
251 check = connect(QWebEngineProfile::defaultProfile(), &QWebEngineProfile::downloadRequested,
252 &m_DownloadManager, &CFrmDownloadManager::slotDownloadRequested);
254 check = connect(m_pPara, &CParameterWebBrowser::sigDownloadFolderChanged,
256 QWebEngineProfile::defaultProfile()->setDownloadPath(m_pPara->GetDownloadFolder());
258 m_profile->setDownloadPath(m_pPara->GetDownloadFolder());
265 m_pMenuBar =
new QMenuBar(
this);
267 m_Menu.setTitle(tr(
"Operate"));
268 m_pMenuBar->addMenu(&m_Menu);
269 pLayout->setMenuBar(m_pMenuBar);
273 check = connect(&m_tmRecord, &QTimer::timeout,
this, &CFrmWebBrowser::slotRecordTimeout);
277CFrmWebBrowser::~CFrmWebBrowser()
279 qDebug(log) << Q_FUNC_INFO;
281 m_pToolBar->deleteLater();
282 m_pToolBar =
nullptr;
285 m_pTab->deleteLater();
289 if(m_pPara->GetClearCookie() && m_profile)
290 m_profile->cookieStore()->deleteAllCookies();
291 if(m_pPara->GetClearHttpCache() && m_profile)
292 m_profile->clearHttpCache();
295QMenu* CFrmWebBrowser::GetMenu(QWidget *parent)
297 if(m_Menu.actions().isEmpty())
302QWebEngineView* CFrmWebBrowser::CreateWindow(
303 QWebEnginePage::WebWindowType type,
bool offTheRecord)
305 qDebug(log) <<
"Create window:" << type;
307 CFrmWebView* pView =
nullptr;
309 case QWebEnginePage::WebBrowserTab: {
310 auto pTab = CreateTab(&pView, offTheRecord);
311 if(!pTab || !m_pTab)
break;
312 int index = m_pTab->addTab(pTab, pView->favIcon(), tr(
"New page"));
314 m_pTab->setCurrentIndex(index);
317 case QWebEnginePage::WebBrowserBackgroundTab: {
318 auto pTab = CreateTab(&pView, offTheRecord);
319 if(!pTab || !m_pTab)
break;
320 int index = m_pTab->currentIndex();
321 m_pTab->addTab(pTab, pView->favIcon(), tr(
"New page"));
322 if(-1 < index && index != m_pTab->currentIndex())
323 m_pTab->setCurrentIndex(index);
326 case QWebEnginePage::WebBrowserWindow: {
327 auto pWin =
new CFrmWebBrowser(m_pPara,
true);
329 pView = qobject_cast<CFrmWebView*>(
330 pWin->CreateWindow(QWebEnginePage::WebBrowserTab));
331 pWin->setAttribute(Qt::WA_DeleteOnClose);
332 auto pMainWin = RabbitCommon::CTools::GetMainWindow();
334 pWin->resize(pMainWin->frameGeometry().width(),
335 pMainWin->frameGeometry().height());
340 case QWebEnginePage::WebDialog: {
342 auto popup =
new CFrmPopup(GetProfile(offTheRecord),
this);
343 pView = popup->GetView();
354 check = connect(pWeb, &CFrmWebView::sigDevToolsRequested,
357 m_pInspector->setChecked(
true);
360 check = connect(pWeb, &CFrmWebView::sigWebActionEnabledChanged,
361 this, [
this, pWeb](QWebEnginePage::WebAction webAction,
bool enabled){
362 if(!IsCurrentView(pWeb))
return;
364 case QWebEnginePage::WebAction::Back:
365 m_pBack->setEnabled(enabled);
367 case QWebEnginePage::WebAction::Forward:
368 m_pForward->setEnabled(enabled);
370 case QWebEnginePage::WebAction::Reload: {
371 m_pRefresh->setEnabled(enabled);
372 if(m_pRefresh->isEnabled())
373 m_pToolBar->insertAction(m_pUrl, m_pRefresh);
375 m_pToolBar->removeAction(m_pRefresh);
378 case QWebEnginePage::WebAction::Stop: {
379 m_pStop->setEnabled(enabled);
380 if(m_pStop->isEnabled())
381 m_pToolBar->insertAction(m_pUrl, m_pStop);
383 m_pToolBar->removeAction(m_pStop);
390 check = connect(pWeb, &QWebEngineView::urlChanged,
391 this, [&](
const QUrl &url) {
392 CFrmWebView* pWeb = qobject_cast<CFrmWebView*>(sender());
393 if(IsCurrentView(pWeb))
394 m_pUrlLineEdit->setText(url.toString());
396 m_pPara->m_HistoryDatabase.addHistoryEntry(url.toString());
400 check = connect(pWeb, &CFrmWebView::titleChanged,
401 this, [&](
const QString &title) {
402 CFrmWebView* pWeb = qobject_cast<CFrmWebView*>(sender());
403 int index = IndexOfTab(pWeb);
406 m_pTab->setTabText(index, title);
407 setWindowTitle(title);
411 m_pPara->m_HistoryDatabase.updateHistoryEntry(pWeb->url().toString(), title);
415 check = connect(pWeb, &CFrmWebView::favIconChanged,
416 this, [&](
const QIcon &icon){
417 CFrmWebView* pWeb = qobject_cast<CFrmWebView*>(sender());
418 int index = IndexOfTab(pWeb);
421 m_pTab->setTabIcon(index, icon);
422 m_pFavAction->setIcon(icon);
427 m_pPara->m_HistoryDatabase.updateHistoryEntry(pWeb->url().toString(), QString(), icon);
431 check = connect(pWeb, &CFrmWebView::sigLinkHovered,
432 this, &CFrmWebBrowser::sigInformation);
434 check = connect(pWeb, &CFrmWebView::sigCloseRequested,
435 this, &CFrmWebBrowser::slotViewCloseRequested);
437 check = connect(pWeb, &CFrmWebView::loadProgress,
438 this, [&](
int progress){
439 CFrmWebView* pWeb = qobject_cast<CFrmWebView*>(sender());
440 if(IsCurrentView(pWeb))
441 m_pProgressBar->setValue(progress);
444 m_pProgressBar->setValue(pWeb->progress());
445#if QT_VERSION >= QT_VERSION_CHECK(6, 2, 0)
446 check = connect(pWeb, &CFrmWebView::printFinished,
447 this, &CFrmWebBrowser::slotPrintFinished);
449 check = connect(pWeb, &CFrmWebView::pdfPrintingFinished,
450 this, &CFrmWebBrowser::slotPdfPrintingFinished);
455QWebEngineProfile* CFrmWebBrowser::GetProfile(
bool offTheRecord)
458 return QWebEngineProfile::defaultProfile();
460 return m_profile.get();
462 QSettings set(RabbitCommon::CDir::Instance()->GetDirUserConfig()
463 + QDir::separator() +
"WebBrowser.ini",
464 QSettings::IniFormat);
465 QString name =
"io.github.KangLin.RabbitRemoteControl";
466#if QT_VERSION >= QT_VERSION_CHECK(6, 9, 0)
467 name +=
"_" + QLatin1StringView(qWebEngineChromiumVersion());
468 name = set.value(
"Profile/Name", name).toString();
469 QWebEngineProfileBuilder profileBuilder;
470 m_profile.reset(profileBuilder.createProfile(name));
472 name = set.value(
"Profile/Name", name).toString();
473 m_profile.reset(
new QWebEngineProfile(name));
476 return QWebEngineProfile::defaultProfile();
478 set.setValue(
"Profile/Name", name);
480 m_profile->settings()->setAttribute(QWebEngineSettings::PluginsEnabled,
true);
481 m_profile->settings()->setAttribute(QWebEngineSettings::DnsPrefetchEnabled,
true);
482 m_profile->settings()->setAttribute(QWebEngineSettings::LocalContentCanAccessRemoteUrls,
true);
483 m_profile->settings()->setAttribute(QWebEngineSettings::LocalContentCanAccessFileUrls,
false);
484#if QT_VERSION >= QT_VERSION_CHECK(5, 6, 0)
485 m_profile->settings()->setAttribute(QWebEngineSettings::FullScreenSupportEnabled,
true);
487#if QT_VERSION >= QT_VERSION_CHECK(5, 7, 0)
488 m_profile->settings()->setAttribute(QWebEngineSettings::ScreenCaptureEnabled,
true);
490#if QT_VERSION >= QT_VERSION_CHECK(5, 8, 0)
491 m_profile->settings()->setAttribute(QWebEngineSettings::AllowRunningInsecureContent,
true);
493#if QT_VERSION > QT_VERSION_CHECK(6, 0, 0)
494 m_profile->settings()->setAttribute(QWebEngineSettings::PlaybackRequiresUserGesture,
false);
496 m_profile->setDownloadPath(m_pPara->GetDownloadFolder());
497 bool check = connect(m_profile.get(), &QWebEngineProfile::downloadRequested,
498 &m_DownloadManager, &CFrmDownloadManager::slotDownloadRequested);
503 qDebug(log) <<
"User agent:" << m_profile->httpUserAgent()
504 <<
"Persistent path:" << m_profile->persistentStoragePath()
505 <<
"Cache path:" << m_profile->cachePath()
506 <<
"Storage name:" << m_profile->storageName()
507 <<
"Cookie:" << m_profile->cookieStore()
508 <<
"Is off the Record:" << m_profile->isOffTheRecord()
509 <<
"Download:" << m_profile->downloadPath()
510#if QT_VERSION > QT_VERSION_CHECK(6, 10, 0)
511 <<
"Extension path:" << m_profile->extensionManager()->installPath()
513#if QT_VERSION > QT_VERSION_CHECK(6, 8, 0)
515 <<
"persistentPermissionsPolicy:" << m_profile->persistentPermissionsPolicy()
517 <<
"persistentCookiesPolicy:" << m_profile->persistentCookiesPolicy()
518 <<
"httpCacheMaximumSize:" << m_profile->httpCacheMaximumSize()
520 return m_profile.get();
523CFrmWebView *CFrmWebBrowser::CreateWebView(
bool offTheRecord)
525 auto pView =
new CFrmWebView(
this);
527 auto profile = GetProfile(offTheRecord);
528 CProtocolManager manager;
529 manager.registerAllProcotol(profile);
533 auto page =
new QWebEnginePage(profile, pView);
534 pView->setPage(page);
539QWidget* CFrmWebBrowser::CreateTab(
CFrmWebView **view,
bool offTheRecord)
541 QSplitter *pSplitter =
new QSplitter(Qt::Vertical,
this);
543 pSplitter->setSizePolicy(QSizePolicy::Expanding, QSizePolicy::Expanding);
545 CFrmWebView* pWeb =
nullptr;
550 pWeb = CreateWebView(offTheRecord);
554 pWeb = CreateWebView(offTheRecord);
557 pSplitter->addWidget(pWeb);
564CFrmWebView *CFrmWebBrowser::CurrentView(ViewType type)
566 if(!m_pTab)
return nullptr;
567 auto w = m_pTab->currentWidget();
568 if(!w)
return nullptr;
569 QSplitter *pSplitter = qobject_cast<QSplitter*>(w);
570 if(!pSplitter)
return nullptr;
571 int index = (int)type;
572 if(0 > index && pSplitter->count() <= index)
return nullptr;
573 return qobject_cast<CFrmWebView*>(pSplitter->widget(index));
576CFrmWebView* CFrmWebBrowser::GetView(
int index, ViewType type)
578 if(0 > index || !m_pTab || m_pTab->count() <= index)
return nullptr;
579 auto w = m_pTab->widget(index);
580 if(!w)
return nullptr;
581 QSplitter *pSplitter = qobject_cast<QSplitter*>(w);
582 if(!pSplitter)
return nullptr;
584 if(0 > idx && pSplitter->count() <= idx)
return nullptr;
585 return qobject_cast<CFrmWebView*>(pSplitter->widget(idx));
588bool CFrmWebBrowser::IsCurrentView(
CFrmWebView *pView)
590 if(!m_pTab)
return false;
591 auto w = m_pTab->currentWidget();
593 QSplitter *pSplitter = qobject_cast<QSplitter*>(w);
594 if(!pSplitter)
return false;
595 return -1 != pSplitter->indexOf(pView);
601 if(!pView)
return nRet;
602 QWidget* p = qobject_cast<QWidget*>(pView->parent());
605 nRet = m_pTab->indexOf(p);
609int CFrmWebBrowser::InitMenu(QMenu *pMenu)
613 pMenu->addAction(m_pBack);
614 pMenu->addAction(m_pForward);
615 pMenu->addAction(m_pRefresh);
616 m_pStop = pMenu->addAction(
617 QIcon::fromTheme(
"media-playback-stop"), tr(
"Stop"),
this, [&]() {
618 CFrmWebView* pWeb = CurrentView();
619 if(pWeb && pWeb->page())
620 pWeb->page()->action(QWebEnginePage::Stop)->trigger();
622 m_pStop->setEnabled(
false);
623 m_pStop->setShortcuts(QKeySequence::Cancel);
624 m_pStop->setStatusTip(m_pStop->text());
626 pMenu->addSeparator();
627 pMenu->addAction(m_pAddPage);
628 m_pAddPageIncognito = pMenu->addAction(
629 QIcon::fromTheme(
"add"), tr(
"Add incognito tab"),
631 CreateWindow(QWebEnginePage::WebBrowserTab,
true);
632 if(!m_pPara->GetTabUrl().isEmpty()) {
633 m_pUrlLineEdit->setText(m_pPara->GetTabUrl());
637 m_pAddPageIncognito->setStatusTip(m_pAddPageIncognito->text());
638 m_pAddWindow = pMenu->addAction(
639 QIcon::fromTheme(
"add"), tr(
"Add window"),
641 CreateWindow(QWebEnginePage::WebBrowserWindow);
643 m_pAddWindow->setVisible(
false);
644 m_pAddWindow->setStatusTip(m_pAddWindow->text());
645 m_pAddWindowIncognito = pMenu->addAction(
646 QIcon::fromTheme(
"add"), tr(
"Add Incognito Window"),
648 CreateWindow(QWebEnginePage::WebBrowserWindow,
true);
650 m_pAddWindowIncognito->setVisible(
false);
651 m_pAddWindowIncognito->setStatusTip(m_pAddWindowIncognito->text());
653 pMenu->addSeparator();
654 m_pFind = pMenu->addAction(
655 QIcon::fromTheme(
"edit-find"), tr(
"&Find"),
this,
657 CFrmWebView* pWeb = CurrentView();
660 if(pWeb->selectedText().isEmpty()) {
661 if(QApplication::clipboard()
662 && !QApplication::clipboard()->text().isEmpty())
663 m_szFindText = QApplication::clipboard()->text();
665 m_szFindText = pWeb->selectedText();
667 QString search = QInputDialog::getText(
669 tr(
"Find:"), QLineEdit::Normal,
671 if (ok && !search.isEmpty()) {
672 m_szFindText = search;
673#if QT_VERSION >= QT_VERSION_CHECK(6, 0, 0)
674 pWeb->findText(m_szFindText, QWebEnginePage::FindFlags(),
675 [&](
const QWebEngineFindTextResult& result){
676 if (result.numberOfMatches() == 0) {
677 emit sigInformation(tr(
"\"%1\" not found.").arg(m_szFindText));
679 emit sigInformation(tr(
"\"%1\" found: %2/%3").arg(m_szFindText, QString::number(result.activeMatch()), QString::number(result.numberOfMatches())));
683 pWeb->findText(m_szFindText, QWebEnginePage::FindFlags(), [
this](
bool found) {
685 emit sigInformation(tr(
"\"%1\" not found.").arg(m_szFindText));
691 m_pFind->setShortcuts(QKeySequence::Find);
692 m_pFind->setStatusTip(m_pFind->text());
694 m_pFindNext = pMenu->addAction(
695 QIcon::fromTheme(
"go-next"), tr(
"Find &Next"),
this,
697 CFrmWebView* pWeb = CurrentView();
698 if(pWeb && !m_szFindText.isEmpty()) {
699 pWeb->findText(m_szFindText);
702 m_pFindNext->setShortcuts(QKeySequence::FindNext);
703 m_pFindNext->setText(m_pFindNext->text());
705 m_pFindPrevious = pMenu->addAction(
706 QIcon::fromTheme(
"go-previous"), tr(
"Find &Previous"),
this,
708 CFrmWebView* pWeb = CurrentView();
709 if(pWeb && !m_szFindText.isEmpty()) {
710 pWeb->findText(m_szFindText, QWebEnginePage::FindBackward);
713 m_pFindPrevious->setShortcuts(QKeySequence::FindPrevious);
714 m_pFindPrevious->setStatusTip(m_pFindPrevious->text());
716 pMenu->addSeparator();
717 m_pZoomOriginal = pMenu->addAction(
718 QIcon::fromTheme(
"zoom-original"), tr(
"Original"));
719 m_pZoomOriginal->setShortcut(QKeySequence(Qt::CTRL | Qt::Key_0));
720 m_pZoomOriginal->setStatusTip(tr(
"Original"));
721 m_pZoomOriginal->setToolTip(tr(
"Original"));
722 check = connect(m_pZoomOriginal, &QAction::triggered,
this,
724 CFrmWebView* pWeb = CurrentView();
726 pWeb->setZoomFactor(1.0);
729 m_pZoomIn = pMenu->addAction(QIcon::fromTheme(
"zoom-in"), tr(
"Zoom in"));
730 m_pZoomIn->setShortcuts(QKeySequence::ZoomIn);
731 m_pZoomIn->setStatusTip(tr(
"Zoom in"));
732 m_pZoomIn->setToolTip(tr(
"Zoom in"));
734 m_pZoomIn, &QAction::triggered,
this,
736 CFrmWebView* pWeb = CurrentView();
738 pWeb->setZoomFactor(pWeb->zoomFactor() + 0.1);
741 m_pZoomOut = pMenu->addAction(
742 QIcon::fromTheme(
"zoom-out"), tr(
"Zoom out"));
743 m_pZoomOut->setShortcuts(QKeySequence::ZoomOut);
744 m_pZoomOut->setStatusTip(tr(
"Zoom out"));
745 m_pZoomOut->setToolTip(tr(
"Zoom out"));
747 m_pZoomOut, &QAction::triggered,
this,
749 CFrmWebView* pWeb = CurrentView();
751 pWeb->setZoomFactor(pWeb->zoomFactor() - 0.1);
755 pMenu->addSeparator();
756#if QT_VERSION >= QT_VERSION_CHECK(6, 2, 0)
757 m_pPrint = pMenu->addAction(
758 QIcon::fromTheme(
"document-print"), tr(
"Print"),
759 this, &CFrmWebBrowser::slotPrint);
760 m_pPrint->setVisible(
false);
761 m_pPrint->setShortcuts(QKeySequence::Print);
762 m_pPrintToPdf = pMenu->addAction(
763 QIcon::fromTheme(
"document-print"), tr(
"Print to PDF"),
764 this, &CFrmWebBrowser::slotPrintToPdf);
767 pMenu->addAction(m_pDownload);
769 m_pInspector = pMenu->addAction(QIcon::fromTheme(
"tools"), tr(
"Inspector"));
770 check = connect(m_pInspector, &QAction::toggled,
771 this, &CFrmWebBrowser::slotInspector);
773 m_pInspector->setStatusTip(tr(
"Inspector"));
774 m_pInspector->setCheckable(
true);
775 m_pInspector->setEnabled(
false);
776 m_pInspector->setShortcuts({
777 QKeySequence(Qt::CTRL | Qt::SHIFT | Qt::Key_I),
778 QKeySequence(Qt::Key_F12)
782 pMenu->addSeparator();
783 QMenu* pMenuBookmark =
new QMenu(tr(
"Bookmark"), pMenu);
784 pMenuBookmark->setIcon(QIcon::fromTheme(
"user-bookmarks"));
785 pMenu->addMenu(pMenuBookmark);
786 pMenuBookmark->addAction(m_pAddBookmark);
787 pMenuBookmark->addAction(tr(
"Manage Bookmark "),
this, &CFrmWebBrowser::slotBookmark);
788 pMenu->addAction(tr(
"History"),
this, &CFrmWebBrowser::slotHistory);
790 pMenu->addSeparator();
791 m_pCapturePage = pMenu->addAction(
792 QIcon::fromTheme(
"screen-shot"), tr(
"Capture page"),
793 this, &CFrmWebBrowser::slotCapturePage);
794 m_pCapturePage->setStatusTip(tr(
"Capture page"));
795 m_pCaptureFulPage = pMenu->addAction(
796 QIcon::fromTheme(
"screen-shot"), tr(
"Capture full page"),
797 this, &CFrmWebBrowser::slotCaptureFullPage);
798 m_pCaptureFulPage->setStatusTip(tr(
"Capture full page"));
799 m_pRecord = pMenu->addAction(QIcon::fromTheme(
"media-record"), tr(
"Record"),
800 this, &CFrmWebBrowser::slotRecord);
801 m_pRecord->setCheckable(
true);
802 m_pRecord->setStatusTip(tr(
"Record"));
803#ifdef HAVE_QT6_RECORD
804 m_pRecord->setEnabled(
true);
806 m_pRecord->setEnabled(
false);
813int CFrmWebBrowser::Start()
817 if(m_pTab && m_pTab->count() == 0) {
819 m_pAddPage->trigger();
825int CFrmWebBrowser::Stop()
829 if(m_pRecord && m_pRecord->isChecked())
832 for(
int i = 0; i < m_pTab->count(); i++) {
841void CFrmWebBrowser::slotTabCurrentChanged(
int index)
843 if(-1 == index)
return;
844 CFrmWebView* pWeb = CurrentView();
846 setWindowTitle(pWeb->title());
847 setWindowIcon(pWeb->icon());
848 m_pUrlLineEdit->setText(pWeb->url().toString());
849 m_pProgressBar->setValue(pWeb->progress());
851 auto page = pWeb->page();
853 auto action = page->action(QWebEnginePage::Back);
854 if(action && m_pBack) {
855 m_pBack->setEnabled(action->isEnabled());
857 action = page->action(QWebEnginePage::Forward);
858 if(action && m_pForward) {
859 m_pForward->setEnabled(action->isEnabled());
861 action = page->action(QWebEnginePage::Reload);
862 if(action && m_pRefresh)
863 m_pRefresh->setEnabled(action->isEnabled());
864 if(m_pRefresh->isEnabled())
865 m_pToolBar->insertAction(m_pUrl, m_pRefresh);
867 m_pToolBar->removeAction(m_pRefresh);
868 action = page->action(QWebEnginePage::Stop);
869 if(action && m_pStop)
870 m_pStop->setEnabled(action->isEnabled());
871 if(m_pStop->isEnabled())
872 m_pToolBar->insertAction(m_pUrl, m_pStop);
874 m_pToolBar->removeAction(m_pStop);
876 m_pInspector->setChecked(CurrentView(ViewType::DevTools));
880 setWindowTitle(tr(
"Web browser"));
881 setWindowIcon(QIcon::fromTheme(
"web-browser"));
882 m_pUrlLineEdit->setText(
"");
883 m_pProgressBar->setValue(100);
886 m_pInspector->setChecked(
false);
891void CFrmWebBrowser::EnableAction(
bool enable)
894 m_pBack->setEnabled(
false);
896 m_pForward->setEnabled(
false);
898 m_pRefresh->setEnabled(enable);
900 m_pStop->setEnabled(
false);
902 m_pFind->setEnabled(enable);
904 m_pFindNext->setEnabled(enable);
906 m_pFindPrevious->setEnabled(enable);
908 m_pZoomOriginal->setEnabled(enable);
910 m_pZoomIn->setEnabled(enable);
912 m_pZoomOut->setEnabled(enable);
914 m_pInspector->setEnabled(enable);
916 m_pRecord->setEnabled(enable);
919void CFrmWebBrowser::slotTabCloseRequested(
int index)
921 qDebug(log) <<
"slotTabCloseRequested:" << index;
922 if(-1 == index || !m_pTab)
return;
923 auto pView = m_pTab->widget(index);
925 pView->deleteLater();
926 m_pTab->removeTab(index);
929void CFrmWebBrowser::slotViewCloseRequested()
931 CFrmWebView* p = qobject_cast<CFrmWebView*>(sender());
933 int index = IndexOfTab(p);
934 slotTabCloseRequested(index);
937void CFrmWebBrowser::slotReturnPressed()
939 slotUrlSelected(m_pUrlLineEdit->text());
942void CFrmWebBrowser::slotUrlSelected(
const QString &szUrl)
944 if(szUrl.isEmpty())
return;
945 QUrl url = QUrl::fromUserInput(szUrl);
946 qDebug(log) << url << szUrl << url.isValid();
947 if(szUrl.startsWith(
"@search:", Qt::CaseInsensitive)) {
949 QString keyword = szUrl.mid(8);
951 szSearch = m_pPara->GetSearchEngine();
952 url = szSearch.replace(m_pPara->GetSearchRelaceString(),
953 QUrl::toPercentEncoding(keyword));
956 emit sigInformation(url.toString());
957 CFrmWebView* pWeb = CurrentView();
959 pWeb = qobject_cast<CFrmWebView*>(CreateWindow(QWebEnginePage::WebBrowserTab));
961 if(m_pGo->isVisible())
962 m_pGo->setVisible(
false);
965void CFrmWebBrowser::slotInspector(
bool checked)
967 CFrmWebView* pWeb = CurrentView();
968 if(!pWeb || !m_pTab)
return;
969 auto dev = CurrentView(ViewType::DevTools);
970 if(pWeb && pWeb->page() && checked) {
972 auto w = m_pTab->currentWidget();
974 QSplitter *pSplitter = qobject_cast<QSplitter*>(w);
975 if(!pSplitter || 1 != pSplitter->count())
return;
976 dev = CreateWebView(pWeb->page()->profile()->isOffTheRecord());
979 pSplitter->addWidget(dev);
980 bool check = connect(pWeb, &CFrmWebView::sigDevToolsRequested,
983 m_pInspector->setChecked(
true);
986 check = connect(dev, &CFrmWebView::sigCloseRequested,
988 m_pInspector->setChecked(
false);
994 pWeb->page()->setDevToolsPage(dev->page());
999 pWeb->page()->setDevToolsPage(
nullptr);
1001 dev->setParent(
nullptr);
1007int CFrmWebBrowser::Load(QSettings &set)
1009 if(m_pPara && m_pPara->GetOpenPrevious()) {
1010 set.beginGroup(
"OpenPrevious");
1012 nCount = set.value(
"Count", 0).toInt();
1013 int nCurrent = set.value(
"Current", -1).toInt();
1014 for(
int i = 0; i < nCount; i++)
1016 QString u = set.value(
"Url/" + QString::number(i)).toString();
1017 auto pView = CreateWindow(QWebEnginePage::WebBrowserTab);
1018 pView->load(QUrl(u));
1021 history = set.value(
"History/" + QString::number(i)).toByteArray();
1022 QDataStream d(&history, QIODevice::ReadWrite);
1023 d >> *pView->history();
1025 if(-1 < nCurrent && m_pTab->count() > nCurrent)
1026 m_pTab->setCurrentIndex(nCurrent);
1032int CFrmWebBrowser::Save(QSettings &set)
1034 if(m_pPara && m_pPara->GetOpenPrevious()) {
1035 set.beginGroup(
"OpenPrevious");
1036 set.setValue(
"Count", m_pTab->count());
1037 set.setValue(
"Current", m_pTab->currentIndex());
1039 for(
int i = 0; i < m_pTab->count(); i++) {
1040 auto v = GetView(i);
1042 set.setValue(
"Url/" + QString::number(i), v->url().toString());
1044 QDataStream d(&history, QIODevice::ReadWrite);
1046 set.setValue(
"History/" + QString::number(i), history);
1055void CFrmWebBrowser::slotPrint()
1057 CFrmWebView* pWeb = CurrentView();
1059#if QT_VERSION >= QT_VERSION_CHECK(6, 2, 0)
1061 pWeb->print(&printer);
1066void CFrmWebBrowser::slotPrintFinished(
bool success)
1068 if(success && m_pPara->GetPromptPrintFinished()) {
1069 QMessageBox::information(
this, tr(
"Print finished"),
1070 tr(
"Successfully printed"));
1074void CFrmWebBrowser::slotPrintToPdf()
1076 CFrmWebView* pWeb = CurrentView();
1079 szPath += RabbitCommon::CDir::Instance()->GetDirUserData()
1080 + QDir::separator() +
"pdf";
1084 szPath += QDir::separator() + pWeb->page()->title() +
".pdf";
1085 qDebug(log) <<
"pdf:" << szPath;
1086#if QT_VERSION >= QT_VERSION_CHECK(6, 2, 0)
1087 pWeb->printToPdf(szPath);
1092void CFrmWebBrowser::slotPdfPrintingFinished(
const QString& szFile,
bool success) {
1093 if(success && m_pPara->GetPromptPrintFinished())
1094 QMessageBox::information(
this, tr(
"Print to PDF finished"),
1095 tr(
"Successfully printed to PDF.") +
"\n"
1096 + tr(
"PDF file: ") + szFile);
1097 qDebug(log) <<
"Print to PDF:" << szFile << success;
1100void CFrmWebBrowser::slotFullScreen(
bool bFullScreen)
1102 if(sender() ==
this)
1106 m_pProgressBar->hide();
1107 m_pTab->tabBar()->setVisible(
false);
1108 m_szStyleSheet = m_pTab->styleSheet();
1109 m_pTab->setStyleSheet(
"QTabWidget::pane{top:0px;left:0px;border:none;}");
1112 m_pProgressBar->show();
1113 m_pTab->tabBar()->setVisible(
true);
1114 m_pTab->setStyleSheet(m_szStyleSheet);
1115 if(CurrentView() && CurrentView()->page() && CurrentView()->page()->action(QWebEnginePage::ExitFullScreen))
1116 CurrentView()->page()->action(QWebEnginePage::ExitFullScreen)->toggle();
1118 emit sigFullScreen(bFullScreen);
1121void CFrmWebBrowser::slotCapturePage()
1123 auto pWeb = CurrentView();
1127 QPixmap pixmap = pWeb->grab();
1128 QImage image = pixmap.toImage();
1129 QString szFile = m_pPara->m_Record.GetImageFile(
true);
1130 if(szFile.isEmpty() && image.isNull())
return;
1131 if(!image.save(szFile,
"PNG"))
1134 szErr = tr(
"Fail: Save capture page to the file: ") + szFile;
1135 qCritical(log) << szErr;
1136 emit sigError(RV::FailCapturePage, szErr);
1139 szMsg = tr(
"Save capture page to the file:") + szFile;
1140 qInfo(log) << szMsg;
1141 emit sigInformation(szMsg);
1142 qDebug(log) <<
"End action:" << m_pPara->m_Record.GetEndAction();
1143 switch(m_pPara->m_Record.GetEndAction())
1145 case CParameterRecord::ENDACTION::OpenFile: {
1146 bool bRet = QDesktopServices::openUrl(QUrl::fromLocalFile(szFile));
1148 qCritical(log) <<
"Fail: Open capture page the file:" << szFile;
1151 case CParameterRecord::ENDACTION::OpenFolder: {
1152 QFileInfo fi(szFile);
1153 QDesktopServices::openUrl(QUrl::fromLocalFile(fi.absolutePath()));
1161void CFrmWebBrowser::slotCaptureFullPage()
1163 auto pWeb = CurrentView();
1165 qDebug(log) <<
"contents size:" << pWeb->page()->contentsSize();
1166 QString szFile = m_pPara->m_Record.GetImageFile(
true);
1167 CCaptureFullPage *pCapture =
new CCaptureFullPage();
1168 if(szFile.isEmpty() || !pCapture)
1170 bool check = connect(pCapture, &CCaptureFullPage::sigFinished,
1171 this, [
this, pWeb, szFile, pCapture](){
1172 pWeb->setEnabled(
true);
1173 qDebug(log) <<
"End action:" << m_pPara->m_Record.GetEndAction();
1174 QFileInfo fi(szFile);
1176 QString szErr = tr(
"Fail: capture full page");
1177 qCritical(log) << szErr;
1178 emit sigError(FailCaptureFullPage, szErr);
1180 QString szMsg = tr(
"Capture full page to") +
" " + szFile;
1181 qInfo(log) << szMsg;
1182 emit sigInformation(szMsg);
1183 switch(m_pPara->m_Record.GetEndAction())
1185 case CParameterRecord::ENDACTION::OpenFile: {
1186 bool bRet = QDesktopServices::openUrl(QUrl::fromLocalFile(szFile));
1188 qCritical(log) <<
"Fail: Open capture page the file:" << szFile;
1191 case CParameterRecord::ENDACTION::OpenFolder: {
1192 QFileInfo fi(szFile);
1193 QDesktopServices::openUrl(QUrl::fromLocalFile(fi.absolutePath()));
1199 pCapture->deleteLater();
1203 pWeb->setEnabled(
false);
1204 pCapture->Start(pWeb, pWeb->url(), szFile);
1206 emit sigInformation(tr(
"Start capture full page"));
1209void CFrmWebBrowser::slotRecord()
1211 if(m_pRecord->isChecked()) {
1212 m_pRecord->setText(tr(
"Stop record"));
1213 m_pRecord->setIcon(QIcon::fromTheme(
"media-stop"));
1215 Q_ASSERT(!m_pMultimediaRecord);
1218 m_pMultimediaRecord =
new CMultimediaRecordThread(m_pPara);
1219 if(m_pMultimediaRecord) {
1220 connect(m_pMultimediaRecord, &CMultimediaRecordThread::finished,
1222 m_pMultimediaRecord =
nullptr;
1223 if(m_pRecord->isChecked()) {
1224 m_pRecord->activate(QAction::Trigger);
1225 emit sigError(RV::FailRecordPage, tr(
"Fail record web page"));
1228 m_pMultimediaRecord->start();
1232 qreal rate = m_pPara->m_Record.GetVideoFrameRate();
1235 m_tmRecord.start(qreal(1000) / rate);
1236 emit sigInformation(tr(
"Start record web page"));
1238 m_pRecord->setIcon(QIcon::fromTheme(
"media-record"));
1239 m_pRecord->setText(tr(
"Record"));
1241 if(m_pMultimediaRecord) {
1242 QMetaObject::invokeMethod(m_pMultimediaRecord,
1244 Qt::AutoConnection);
1245 m_pMultimediaRecord =
nullptr;
1246 emit sigInformation(tr(
"Record web page is stopped"));
1249 m_pRecord->setStatusTip(m_pRecord->text());
1252void CFrmWebBrowser::slotRecordTimeout()
1255 if(!m_pMultimediaRecord)
return;
1256 auto pWeb = CurrentView();
1258 QPixmap pixmap = pWeb->grab();
1259 QImage image = pixmap.toImage();
1260 if(image.isNull())
return;
1261 QMetaObject::invokeMethod(m_pMultimediaRecord,
1262 "slotUpdateVideoFrame",
1264 Q_ARG(QImage, image));
1267void CFrmWebBrowser::slotAddBookmark()
1269 auto pView = CurrentView();
1272 QUrl url = pView->url();
1274 url = m_pUrlLineEdit->text();
1275 CFrmAddBookmark* pAdd =
new CFrmAddBookmark(
1276 pView->title(), url, pView->favIcon(),
1278 bool check = connect(
this, &CFrmWebBrowser::destroyed, pAdd, &CFrmAddBookmark::close);
1280 RC_SHOW_WINDOW(pAdd);
1283void CFrmWebBrowser::slotBookmark()
1285 CFrmBookmark* pBookmark =
new CFrmBookmark(m_pPara);
1286 if(!pBookmark)
return;
1287 pBookmark->setAttribute(Qt::WA_DeleteOnClose);
1288 connect(
this, &CFrmWebBrowser::destroyed, pBookmark, &CFrmBookmark::close);
1289 connect(pBookmark, &CFrmBookmark::openUrlRequested,
this, [&](
const QString& url) {
1290 CFrmWebView* pWeb = CurrentView();
1292 pWeb = qobject_cast<CFrmWebView*>(CreateWindow(QWebEnginePage::WebBrowserTab));
1297 RC_SHOW_WINDOW(pBookmark);
1300void CFrmWebBrowser::slotHistory()
1302 CFrmHistory* pHistory =
new CFrmHistory(m_pPara);
1303 if(!pHistory)
return;
1304 pHistory->setAttribute(Qt::WA_DeleteOnClose);
1305 connect(
this, &CFrmWebBrowser::destroyed, pHistory, &CFrmHistory::close);
1306 connect(pHistory, &CFrmHistory::sigOpenUrl,
this, [&](
const QString& url) {
1307 CFrmWebView* pWeb = CurrentView();
1309 pWeb = qobject_cast<CFrmWebView*>(CreateWindow(QWebEnginePage::WebBrowserTab));
1314 connect(pHistory, &CFrmHistory::sigOpenUrlInNewTab,
1315 this, [&](
const QString& url) {
1316 auto pWeb = qobject_cast<CFrmWebView*>(CreateWindow(QWebEnginePage::WebBrowserTab));
1320 RC_SHOW_WINDOW(pHistory);
void sigUpdateTitle()
Title or icon changed.