12#include <QInputDialog>
15#include <QWebEngineProfile>
16#include <QWebEngineHistory>
17#include <QWebEngineSettings>
18#include <QWebEngineFindTextResult>
19#include <QRegularExpression>
20#include <QWebEngineCookieStore>
21#include <QStandardPaths>
23#include <QApplication>
24#include <QDesktopServices>
25#if QT_VERSION >= QT_VERSION_CHECK(6, 9, 0)
26 #include <QWebEngineProfileBuilder>
28#if QT_VERSION >= QT_VERSION_CHECK(6, 10, 0)
29 #include <QWebEngineExtensionManager>
31#include <QLoggingCategory>
33#include "RabbitCommonDir.h"
34#include "RabbitCommonTools.h"
36#include "CaptureFullPage.h"
37#include "FrmHistory.h"
38#include "AddressCompleter.h"
39#include "AutoCompleteLineEdit.h"
40#include "FrmBookmark.h"
41#include "FrmAddBookmark.h"
42#include "DlgSettings.h"
43#include "ParameterGlobal.h"
44#include "ProtocolManager.h"
45#include "FrmWebBrowser.h"
47static Q_LOGGING_CATEGORY(log,
"WebBrowser.Browser")
49 bool bMenuBar, QWidget *parent)
58 , m_pAddBookmark(
nullptr)
60 , m_pFindNext(
nullptr)
61 , m_pFindPrevious(
nullptr)
62 , m_pZoomOriginal(
nullptr)
65 , m_pFavAction(
nullptr)
68 , m_pAddPageIncognito(
nullptr)
69 , m_pAddWindow(
nullptr)
71 , m_pPrintToPdf(
nullptr)
72 , m_pAddWindowIncognito(
nullptr)
73 , m_pDownload(
nullptr)
74 , m_pInspector(
nullptr)
76 , m_pUrlLineEdit(
nullptr)
77 , m_pProgressBar(
nullptr)
79 , m_DownloadManager(pPara)
80 , m_pCapturePage(
nullptr)
81 , m_pCaptureFulPage(
nullptr)
83 , m_pMultimediaRecord(
nullptr)
85 qDebug(log) << Q_FUNC_INFO;
88 setWindowIcon(QIcon::fromTheme(
"web-browser"));
90 QVBoxLayout* pLayout =
new QVBoxLayout(
this);
94 pLayout->setSpacing(0);
95 pLayout->setContentsMargins(0, 0, 0, 0);
98 m_pToolBar =
new QToolBar(
this);
100 pLayout->addWidget(m_pToolBar);
103 m_pBack = m_pToolBar->addAction(
104 QIcon::fromTheme(
"go-previous"), tr(
"Back"),
107 if(pWeb && pWeb->page())
108 pWeb->page()->action(QWebEnginePage::Back)->trigger();
110 m_pBack->setEnabled(
false);
111 m_pBack->setShortcuts(QKeySequence::Back);
112 m_pBack->setStatusTip(m_pBack->text());
113 m_pForward = m_pToolBar->addAction(
114 QIcon::fromTheme(
"go-next"), tr(
"Forward"),
117 if(pWeb && pWeb->page())
118 pWeb->page()->action(QWebEnginePage::Forward)->trigger();
120 m_pForward->setEnabled(
false);
121 m_pForward->setShortcuts(QKeySequence::Forward);
122 m_pForward->setStatusTip(m_pForward->text());
123 m_pRefresh = m_pToolBar->addAction(
124 QIcon::fromTheme(
"view-refresh"), tr(
"Refresh"),
127 if(pWeb && pWeb->page())
128 pWeb->page()->action(QWebEnginePage::Reload)->trigger();
130 m_pRefresh->setShortcuts(QKeySequence::Refresh);
131 m_pRefresh->setStatusTip(m_pRefresh->text());
133 m_pUrlLineEdit =
new QLineEdit(
this);
134 m_pFavAction =
new QAction(m_pUrlLineEdit);
135 m_pUrlLineEdit->addAction(m_pFavAction, QLineEdit::LeadingPosition);
136 m_pUrlLineEdit->setClearButtonEnabled(
true);
137 m_pUrl = m_pToolBar->addWidget(m_pUrlLineEdit);
138 m_pGo =
new QAction(QIcon::fromTheme(
"go-next"), tr(
"go"), m_pUrlLineEdit);
139 m_pGo->setStatusTip(m_pGo->text());
140 check = connect(m_pGo, &QAction::triggered,
this, &CFrmWebBrowser::slotReturnPressed);
142 m_pUrlLineEdit->addAction(m_pGo, QLineEdit::TrailingPosition);
143 m_pGo->setVisible(
false);
144 check = connect(m_pUrlLineEdit, &QLineEdit::textEdited,
145 this, [&](
const QString &text){
146 QLineEdit* pLineEdit = qobject_cast<QLineEdit*>(sender());
149 if(m_pGo->isVisible())
150 m_pGo->setVisible(
false);
152 if(!m_pGo->isVisible())
153 m_pGo->setVisible(
true);
159 auto pAddressCompleter =
new CAddressCompleter(&m_pPara->m_HistoryDatabase,
this);
160 pAddressCompleter->attachToLineEdit(m_pUrlLineEdit);
162 pAddressCompleter->setMaxVisibleItems(m_pPara->GetAddCompleterLines());
163 check = connect(pAddressCompleter, &CAddressCompleter::urlSelected,
164 this, &CFrmWebBrowser::slotUrlSelected);
166 check = connect(pAddressCompleter, &CAddressCompleter::searchRequested,
167 this, [&](
const QString& keyword) {
168 qDebug(log) <<
"CAddressCompleter::searchRequested keyword:" << keyword;
172 szSearch = m_pPara->GetSearchEngine();
173 szUrl = szSearch.replace(m_pPara->GetSearchRelaceString(),
174 QUrl::toPercentEncoding(keyword));
176 slotUrlSelected(szUrl);
180 check = connect(pAddressCompleter, &CAddressCompleter::sigCommand,
181 this, [&](
const QString& cmd) {
182 if(cmd.startsWith(
"@setting")) {
184 RC_SHOW_WINDOW(&dlg);
185 }
else if(cmd.startsWith(
"@history")) {
187 }
else if(cmd.startsWith(
"@bookmark")) {
193 m_pAddBookmark = m_pToolBar->addAction(
194 QIcon::fromTheme(
"user-bookmarks"),
195 tr(
"Add bookmark"),
this, SLOT(slotAddBookmark()));
197 m_pAddPage = m_pToolBar->addAction(QIcon::fromTheme(
"add"), tr(
"Add tab page"),
199 CreateWindow(QWebEnginePage::WebBrowserTab);
200 if(!m_pPara->GetTabUrl().isEmpty()) {
201 m_pUrlLineEdit->setText(m_pPara->GetTabUrl());
205 m_pAddPage->setStatusTip(m_pAddPage->text());
206 m_pAddPage->setShortcuts(QKeySequence::AddTab);
208 m_pDownload = m_pToolBar->addAction(
209 QIcon::fromTheme(
"emblem-downloads"), tr(
"Download Manager"));
210 m_pDownload->setCheckable(
true);
211 m_pDownload->setStatusTip(m_pDownload->text());
212 m_pDownload->setShortcut(QKeySequence(Qt::CTRL | Qt::Key_D));
213 check = connect(m_pDownload, &QAction::toggled,
214 this, [&](
bool checked){
216 m_DownloadManager.show();
218 m_DownloadManager.hide();
221 check = connect(&m_DownloadManager, &CFrmDownloadManager::sigVisible,
this,
224 m_pDownload->setChecked(visible);
228 m_pProgressBar =
new QProgressBar(
this);
230 pLayout->addWidget(m_pProgressBar);
231 m_pProgressBar->setMaximumHeight(1);
232 m_pProgressBar->setTextVisible(
false);
233 m_pProgressBar->show();
234 m_pProgressBar->setStyleSheet(
"QProgressBar {border: 0px} QProgressBar::chunk {background-color: #da4453}");
237 m_pTab =
new QTabWidget(
this);
239 m_pTab->setTabsClosable(
true);
240 m_pTab->setUsesScrollButtons(
true);
241 m_pTab->setMovable(
true);
242 m_pTab->setElideMode(Qt::TextElideMode::ElideRight);
243 pLayout->addWidget(m_pTab);
245 check = connect(m_pTab, &QTabWidget::currentChanged,
246 this, &CFrmWebBrowser::slotTabCurrentChanged);
248 check = connect(m_pTab, &QTabWidget::tabCloseRequested,
249 this, &CFrmWebBrowser::slotTabCloseRequested);
252 m_DownloadManager.hide();
253 QWebEngineProfile::defaultProfile()->setDownloadPath(m_pPara->GetDownloadFolder());
254 check = connect(QWebEngineProfile::defaultProfile(), &QWebEngineProfile::downloadRequested,
255 &m_DownloadManager, &CFrmDownloadManager::slotDownloadRequested);
257 check = connect(m_pPara, &CParameterWebBrowser::sigDownloadFolderChanged,
259 QWebEngineProfile::defaultProfile()->setDownloadPath(m_pPara->GetDownloadFolder());
261 m_profile->setDownloadPath(m_pPara->GetDownloadFolder());
268 m_pMenuBar =
new QMenuBar(
this);
270 m_Menu.setTitle(tr(
"Operate"));
271 m_pMenuBar->addMenu(&m_Menu);
272 pLayout->setMenuBar(m_pMenuBar);
276 check = connect(&m_tmRecord, &QTimer::timeout,
this, &CFrmWebBrowser::slotRecordTimeout);
280CFrmWebBrowser::~CFrmWebBrowser()
282 qDebug(log) << Q_FUNC_INFO;
284 m_pToolBar->deleteLater();
285 m_pToolBar =
nullptr;
288 m_pTab->deleteLater();
292 if(m_pPara->GetClearCookie() && m_profile)
293 m_profile->cookieStore()->deleteAllCookies();
294 if(m_pPara->GetClearHttpCache() && m_profile)
295 m_profile->clearHttpCache();
298QMenu* CFrmWebBrowser::GetMenu(QWidget *parent)
300 if(m_Menu.actions().isEmpty())
305QWebEngineView* CFrmWebBrowser::CreateWindow(
306 QWebEnginePage::WebWindowType type,
bool offTheRecord)
308 qDebug(log) <<
"Create window:" << type;
310 CFrmWebView* pView =
nullptr;
312 case QWebEnginePage::WebBrowserTab: {
313 auto pTab = CreateTab(&pView, offTheRecord);
314 if(!pTab || !m_pTab)
break;
315 int index = m_pTab->addTab(pTab, pView->favIcon(), tr(
"New page"));
317 m_pTab->setCurrentIndex(index);
320 case QWebEnginePage::WebBrowserBackgroundTab: {
321 auto pTab = CreateTab(&pView, offTheRecord);
322 if(!pTab || !m_pTab)
break;
323 int index = m_pTab->currentIndex();
324 m_pTab->addTab(pTab, pView->favIcon(), tr(
"New page"));
325 if(-1 < index && index != m_pTab->currentIndex())
326 m_pTab->setCurrentIndex(index);
329 case QWebEnginePage::WebBrowserWindow: {
330 auto pWin =
new CFrmWebBrowser(m_pPara,
true);
332 pView = qobject_cast<CFrmWebView*>(
333 pWin->CreateWindow(QWebEnginePage::WebBrowserTab));
334 pWin->setAttribute(Qt::WA_DeleteOnClose);
335 auto pMainWin = RabbitCommon::CTools::GetMainWindow();
337 pWin->resize(pMainWin->frameGeometry().width(),
338 pMainWin->frameGeometry().height());
343 case QWebEnginePage::WebDialog: {
345 auto popup =
new CFrmPopup(GetProfile(offTheRecord),
this);
346 pView = popup->GetView();
357 check = connect(pWeb, &CFrmWebView::sigDevToolsRequested,
360 m_pInspector->setChecked(
true);
363 check = connect(pWeb, &CFrmWebView::sigWebActionEnabledChanged,
364 this, [
this, pWeb](QWebEnginePage::WebAction webAction,
bool enabled){
365 if(!IsCurrentView(pWeb))
return;
367 case QWebEnginePage::WebAction::Back:
368 m_pBack->setEnabled(enabled);
370 case QWebEnginePage::WebAction::Forward:
371 m_pForward->setEnabled(enabled);
373 case QWebEnginePage::WebAction::Reload: {
374 m_pRefresh->setEnabled(enabled);
375 if(m_pRefresh->isEnabled())
376 m_pToolBar->insertAction(m_pUrl, m_pRefresh);
378 m_pToolBar->removeAction(m_pRefresh);
381 case QWebEnginePage::WebAction::Stop: {
382 m_pStop->setEnabled(enabled);
383 if(m_pStop->isEnabled())
384 m_pToolBar->insertAction(m_pUrl, m_pStop);
386 m_pToolBar->removeAction(m_pStop);
393 check = connect(pWeb, &QWebEngineView::urlChanged,
394 this, [&](
const QUrl &url) {
395 CFrmWebView* pWeb = qobject_cast<CFrmWebView*>(sender());
396 if(IsCurrentView(pWeb))
397 m_pUrlLineEdit->setText(url.toString());
399 m_pPara->m_HistoryDatabase.addHistoryEntry(url.toString());
403 check = connect(pWeb, &CFrmWebView::titleChanged,
404 this, [&](
const QString &title) {
405 CFrmWebView* pWeb = qobject_cast<CFrmWebView*>(sender());
406 int index = IndexOfTab(pWeb);
409 m_pTab->setTabText(index, title);
410 setWindowTitle(title);
414 m_pPara->m_HistoryDatabase.updateHistoryEntry(pWeb->url().toString(), title);
418 check = connect(pWeb, &CFrmWebView::favIconChanged,
419 this, [&](
const QIcon &icon){
420 CFrmWebView* pWeb = qobject_cast<CFrmWebView*>(sender());
421 int index = IndexOfTab(pWeb);
424 m_pTab->setTabIcon(index, icon);
425 m_pFavAction->setIcon(icon);
430 m_pPara->m_HistoryDatabase.updateHistoryEntry(pWeb->url().toString(), QString(), icon);
434 check = connect(pWeb, &CFrmWebView::sigLinkHovered,
435 this, &CFrmWebBrowser::sigInformation);
437 check = connect(pWeb, &CFrmWebView::sigCloseRequested,
438 this, &CFrmWebBrowser::slotViewCloseRequested);
440 check = connect(pWeb, &CFrmWebView::loadProgress,
441 this, [&](
int progress){
442 CFrmWebView* pWeb = qobject_cast<CFrmWebView*>(sender());
443 if(IsCurrentView(pWeb))
444 m_pProgressBar->setValue(progress);
447 m_pProgressBar->setValue(pWeb->progress());
448#if QT_VERSION >= QT_VERSION_CHECK(6, 2, 0)
449 check = connect(pWeb, &CFrmWebView::printFinished,
450 this, &CFrmWebBrowser::slotPrintFinished);
452 check = connect(pWeb, &CFrmWebView::pdfPrintingFinished,
453 this, &CFrmWebBrowser::slotPdfPrintingFinished);
458QWebEngineProfile* CFrmWebBrowser::GetProfile(
bool offTheRecord)
461 return QWebEngineProfile::defaultProfile();
463 return m_profile.get();
465 QSettings set(RabbitCommon::CDir::Instance()->GetDirUserConfig()
466 + QDir::separator() +
"WebBrowser.ini",
467 QSettings::IniFormat);
468 QString name =
"io.github.KangLin.RabbitRemoteControl";
469#if QT_VERSION >= QT_VERSION_CHECK(6, 9, 0)
470 name +=
"_" + QLatin1StringView(qWebEngineChromiumVersion());
471 name = set.value(
"Profile/Name", name).toString();
472 QWebEngineProfileBuilder profileBuilder;
473 m_profile.reset(profileBuilder.createProfile(name));
475 name = set.value(
"Profile/Name", name).toString();
476 m_profile.reset(
new QWebEngineProfile(name));
479 return QWebEngineProfile::defaultProfile();
481 set.setValue(
"Profile/Name", name);
483 m_profile->settings()->setAttribute(QWebEngineSettings::PluginsEnabled,
true);
484 m_profile->settings()->setAttribute(QWebEngineSettings::DnsPrefetchEnabled,
true);
485 m_profile->settings()->setAttribute(QWebEngineSettings::LocalContentCanAccessRemoteUrls,
true);
486 m_profile->settings()->setAttribute(QWebEngineSettings::LocalContentCanAccessFileUrls,
false);
487#if QT_VERSION >= QT_VERSION_CHECK(5, 6, 0)
488 m_profile->settings()->setAttribute(QWebEngineSettings::FullScreenSupportEnabled,
true);
490#if QT_VERSION >= QT_VERSION_CHECK(5, 7, 0)
491 m_profile->settings()->setAttribute(QWebEngineSettings::ScreenCaptureEnabled,
true);
493#if QT_VERSION >= QT_VERSION_CHECK(5, 8, 0)
494 m_profile->settings()->setAttribute(QWebEngineSettings::AllowRunningInsecureContent,
true);
496#if QT_VERSION > QT_VERSION_CHECK(6, 0, 0)
497 m_profile->settings()->setAttribute(QWebEngineSettings::PlaybackRequiresUserGesture,
false);
499 m_profile->setDownloadPath(m_pPara->GetDownloadFolder());
500 bool check = connect(m_profile.get(), &QWebEngineProfile::downloadRequested,
501 &m_DownloadManager, &CFrmDownloadManager::slotDownloadRequested);
506 qDebug(log) <<
"User agent:" << m_profile->httpUserAgent()
507 <<
"Persistent path:" << m_profile->persistentStoragePath()
508 <<
"Cache path:" << m_profile->cachePath()
509 <<
"Storage name:" << m_profile->storageName()
510 <<
"Cookie:" << m_profile->cookieStore()
511 <<
"Is off the Record:" << m_profile->isOffTheRecord()
512 <<
"Download:" << m_profile->downloadPath()
513#if QT_VERSION > QT_VERSION_CHECK(6, 10, 0) && defined(HAVE_EXTENSION)
514 <<
"Extension path:" << m_profile->extensionManager()->installPath()
516#if QT_VERSION > QT_VERSION_CHECK(6, 8, 0)
518 <<
"persistentPermissionsPolicy:" << m_profile->persistentPermissionsPolicy()
520 <<
"persistentCookiesPolicy:" << m_profile->persistentCookiesPolicy()
521 <<
"httpCacheMaximumSize:" << m_profile->httpCacheMaximumSize()
523 return m_profile.get();
526CFrmWebView *CFrmWebBrowser::CreateWebView(
bool offTheRecord)
528 auto pView =
new CFrmWebView(
this);
530 auto profile = GetProfile(offTheRecord);
531 CProtocolManager manager;
532 manager.registerAllProcotol(profile);
536 auto page =
new QWebEnginePage(profile, pView);
537 pView->setPage(page);
542QWidget* CFrmWebBrowser::CreateTab(
CFrmWebView **view,
bool offTheRecord)
544 QSplitter *pSplitter =
new QSplitter(Qt::Vertical,
this);
546 pSplitter->setSizePolicy(QSizePolicy::Expanding, QSizePolicy::Expanding);
548 CFrmWebView* pWeb =
nullptr;
553 pWeb = CreateWebView(offTheRecord);
557 pWeb = CreateWebView(offTheRecord);
560 pSplitter->addWidget(pWeb);
567CFrmWebView *CFrmWebBrowser::CurrentView(ViewType type)
569 if(!m_pTab)
return nullptr;
570 auto w = m_pTab->currentWidget();
571 if(!w)
return nullptr;
572 QSplitter *pSplitter = qobject_cast<QSplitter*>(w);
573 if(!pSplitter)
return nullptr;
574 int index = (int)type;
575 if(0 > index && pSplitter->count() <= index)
return nullptr;
576 return qobject_cast<CFrmWebView*>(pSplitter->widget(index));
579CFrmWebView* CFrmWebBrowser::GetView(
int index, ViewType type)
581 if(0 > index || !m_pTab || m_pTab->count() <= index)
return nullptr;
582 auto w = m_pTab->widget(index);
583 if(!w)
return nullptr;
584 QSplitter *pSplitter = qobject_cast<QSplitter*>(w);
585 if(!pSplitter)
return nullptr;
587 if(0 > idx && pSplitter->count() <= idx)
return nullptr;
588 return qobject_cast<CFrmWebView*>(pSplitter->widget(idx));
591bool CFrmWebBrowser::IsCurrentView(
CFrmWebView *pView)
593 if(!m_pTab)
return false;
594 auto w = m_pTab->currentWidget();
596 QSplitter *pSplitter = qobject_cast<QSplitter*>(w);
597 if(!pSplitter)
return false;
598 return -1 != pSplitter->indexOf(pView);
604 if(!pView)
return nRet;
605 QWidget* p = qobject_cast<QWidget*>(pView->parent());
608 nRet = m_pTab->indexOf(p);
612int CFrmWebBrowser::InitMenu(QMenu *pMenu)
616 pMenu->addAction(m_pBack);
617 pMenu->addAction(m_pForward);
618 pMenu->addAction(m_pRefresh);
619 m_pStop = pMenu->addAction(
620 QIcon::fromTheme(
"media-playback-stop"), tr(
"Stop"),
this, [&]() {
621 CFrmWebView* pWeb = CurrentView();
622 if(pWeb && pWeb->page())
623 pWeb->page()->action(QWebEnginePage::Stop)->trigger();
625 m_pStop->setEnabled(
false);
626 m_pStop->setShortcuts(QKeySequence::Cancel);
627 m_pStop->setStatusTip(m_pStop->text());
629 pMenu->addSeparator();
630 pMenu->addAction(m_pAddPage);
631 m_pAddPageIncognito = pMenu->addAction(
632 QIcon::fromTheme(
"add"), tr(
"Add incognito tab"),
634 CreateWindow(QWebEnginePage::WebBrowserTab,
true);
635 if(!m_pPara->GetTabUrl().isEmpty()) {
636 m_pUrlLineEdit->setText(m_pPara->GetTabUrl());
640 m_pAddPageIncognito->setStatusTip(m_pAddPageIncognito->text());
641 m_pAddWindow = pMenu->addAction(
642 QIcon::fromTheme(
"add"), tr(
"Add window"),
644 CreateWindow(QWebEnginePage::WebBrowserWindow);
646 m_pAddWindow->setVisible(
false);
647 m_pAddWindow->setStatusTip(m_pAddWindow->text());
648 m_pAddWindowIncognito = pMenu->addAction(
649 QIcon::fromTheme(
"add"), tr(
"Add Incognito Window"),
651 CreateWindow(QWebEnginePage::WebBrowserWindow,
true);
653 m_pAddWindowIncognito->setVisible(
false);
654 m_pAddWindowIncognito->setStatusTip(m_pAddWindowIncognito->text());
656 pMenu->addSeparator();
657 m_pFind = pMenu->addAction(
658 QIcon::fromTheme(
"edit-find"), tr(
"&Find"),
this,
660 CFrmWebView* pWeb = CurrentView();
663 if(pWeb->selectedText().isEmpty()) {
664 if(QApplication::clipboard()
665 && !QApplication::clipboard()->text().isEmpty())
666 m_szFindText = QApplication::clipboard()->text();
668 m_szFindText = pWeb->selectedText();
670 QString search = QInputDialog::getText(
672 tr(
"Find:"), QLineEdit::Normal,
674 if (ok && !search.isEmpty()) {
675 m_szFindText = search;
676#if QT_VERSION >= QT_VERSION_CHECK(6, 0, 0)
677 pWeb->findText(m_szFindText, QWebEnginePage::FindFlags(),
678 [&](
const QWebEngineFindTextResult& result){
679 if (result.numberOfMatches() == 0) {
680 emit sigInformation(tr(
"\"%1\" not found.").arg(m_szFindText));
682 emit sigInformation(tr(
"\"%1\" found: %2/%3").arg(m_szFindText, QString::number(result.activeMatch()), QString::number(result.numberOfMatches())));
686 pWeb->findText(m_szFindText, QWebEnginePage::FindFlags(), [
this](
bool found) {
688 emit sigInformation(tr(
"\"%1\" not found.").arg(m_szFindText));
694 m_pFind->setShortcuts(QKeySequence::Find);
695 m_pFind->setStatusTip(m_pFind->text());
697 m_pFindNext = pMenu->addAction(
698 QIcon::fromTheme(
"go-next"), tr(
"Find &Next"),
this,
700 CFrmWebView* pWeb = CurrentView();
701 if(pWeb && !m_szFindText.isEmpty()) {
702 pWeb->findText(m_szFindText);
705 m_pFindNext->setShortcuts(QKeySequence::FindNext);
706 m_pFindNext->setText(m_pFindNext->text());
708 m_pFindPrevious = pMenu->addAction(
709 QIcon::fromTheme(
"go-previous"), tr(
"Find &Previous"),
this,
711 CFrmWebView* pWeb = CurrentView();
712 if(pWeb && !m_szFindText.isEmpty()) {
713 pWeb->findText(m_szFindText, QWebEnginePage::FindBackward);
716 m_pFindPrevious->setShortcuts(QKeySequence::FindPrevious);
717 m_pFindPrevious->setStatusTip(m_pFindPrevious->text());
719 pMenu->addSeparator();
720 m_pZoomOriginal = pMenu->addAction(
721 QIcon::fromTheme(
"zoom-original"), tr(
"Original"));
722 m_pZoomOriginal->setShortcut(QKeySequence(Qt::CTRL | Qt::Key_0));
723 m_pZoomOriginal->setStatusTip(tr(
"Original"));
724 m_pZoomOriginal->setToolTip(tr(
"Original"));
725 check = connect(m_pZoomOriginal, &QAction::triggered,
this,
727 CFrmWebView* pWeb = CurrentView();
729 pWeb->setZoomFactor(1.0);
732 m_pZoomIn = pMenu->addAction(QIcon::fromTheme(
"zoom-in"), tr(
"Zoom in"));
733 m_pZoomIn->setShortcuts(QKeySequence::ZoomIn);
734 m_pZoomIn->setStatusTip(tr(
"Zoom in"));
735 m_pZoomIn->setToolTip(tr(
"Zoom in"));
737 m_pZoomIn, &QAction::triggered,
this,
739 CFrmWebView* pWeb = CurrentView();
741 pWeb->setZoomFactor(pWeb->zoomFactor() + 0.1);
744 m_pZoomOut = pMenu->addAction(
745 QIcon::fromTheme(
"zoom-out"), tr(
"Zoom out"));
746 m_pZoomOut->setShortcuts(QKeySequence::ZoomOut);
747 m_pZoomOut->setStatusTip(tr(
"Zoom out"));
748 m_pZoomOut->setToolTip(tr(
"Zoom out"));
750 m_pZoomOut, &QAction::triggered,
this,
752 CFrmWebView* pWeb = CurrentView();
754 pWeb->setZoomFactor(pWeb->zoomFactor() - 0.1);
758 pMenu->addSeparator();
759#if QT_VERSION >= QT_VERSION_CHECK(6, 2, 0)
760 m_pPrint = pMenu->addAction(
761 QIcon::fromTheme(
"document-print"), tr(
"Print"),
762 this, &CFrmWebBrowser::slotPrint);
763 m_pPrint->setVisible(
false);
764 m_pPrint->setShortcuts(QKeySequence::Print);
765 m_pPrintToPdf = pMenu->addAction(
766 QIcon::fromTheme(
"document-print"), tr(
"Print to PDF"),
767 this, &CFrmWebBrowser::slotPrintToPdf);
770 pMenu->addAction(m_pDownload);
772 m_pInspector = pMenu->addAction(QIcon::fromTheme(
"tools"), tr(
"Inspector"));
773 check = connect(m_pInspector, &QAction::toggled,
774 this, &CFrmWebBrowser::slotInspector);
776 m_pInspector->setStatusTip(tr(
"Inspector"));
777 m_pInspector->setCheckable(
true);
778 m_pInspector->setEnabled(
false);
779 m_pInspector->setShortcuts({
780 QKeySequence(Qt::CTRL | Qt::SHIFT | Qt::Key_I),
781 QKeySequence(Qt::Key_F12)
785 pMenu->addSeparator();
786 QMenu* pMenuBookmark =
new QMenu(tr(
"Bookmark"), pMenu);
787 pMenuBookmark->setIcon(QIcon::fromTheme(
"user-bookmarks"));
788 pMenu->addMenu(pMenuBookmark);
789 pMenuBookmark->addAction(m_pAddBookmark);
790 pMenuBookmark->addAction(tr(
"Manage Bookmark "),
this, &CFrmWebBrowser::slotBookmark);
791 pMenu->addAction(tr(
"History"),
this, &CFrmWebBrowser::slotHistory);
793 pMenu->addSeparator();
794 m_pCapturePage = pMenu->addAction(
795 QIcon::fromTheme(
"screen-shot"), tr(
"Capture page"),
796 this, &CFrmWebBrowser::slotCapturePage);
797 m_pCapturePage->setStatusTip(tr(
"Capture page"));
798 m_pCaptureFulPage = pMenu->addAction(
799 QIcon::fromTheme(
"screen-shot"), tr(
"Capture full page"),
800 this, &CFrmWebBrowser::slotCaptureFullPage);
801 m_pCaptureFulPage->setStatusTip(tr(
"Capture full page"));
802 m_pRecord = pMenu->addAction(QIcon::fromTheme(
"media-record"), tr(
"Record"),
803 this, &CFrmWebBrowser::slotRecord);
804 m_pRecord->setCheckable(
true);
805 m_pRecord->setStatusTip(tr(
"Record"));
806#ifdef HAVE_QT6_RECORD
807 m_pRecord->setEnabled(
true);
809 m_pRecord->setEnabled(
false);
816int CFrmWebBrowser::Start()
820 if(m_pTab && m_pTab->count() == 0) {
822 m_pAddPage->trigger();
828int CFrmWebBrowser::Stop()
832 if(m_pRecord && m_pRecord->isChecked())
835 for(
int i = 0; i < m_pTab->count(); i++) {
844void CFrmWebBrowser::slotTabCurrentChanged(
int index)
846 if(-1 == index)
return;
847 CFrmWebView* pWeb = CurrentView();
849 setWindowTitle(pWeb->title());
850 setWindowIcon(pWeb->icon());
851 m_pUrlLineEdit->setText(pWeb->url().toString());
852 m_pProgressBar->setValue(pWeb->progress());
854 auto page = pWeb->page();
856 auto action = page->action(QWebEnginePage::Back);
857 if(action && m_pBack) {
858 m_pBack->setEnabled(action->isEnabled());
860 action = page->action(QWebEnginePage::Forward);
861 if(action && m_pForward) {
862 m_pForward->setEnabled(action->isEnabled());
864 action = page->action(QWebEnginePage::Reload);
865 if(action && m_pRefresh)
866 m_pRefresh->setEnabled(action->isEnabled());
867 if(m_pRefresh->isEnabled())
868 m_pToolBar->insertAction(m_pUrl, m_pRefresh);
870 m_pToolBar->removeAction(m_pRefresh);
871 action = page->action(QWebEnginePage::Stop);
872 if(action && m_pStop)
873 m_pStop->setEnabled(action->isEnabled());
874 if(m_pStop->isEnabled())
875 m_pToolBar->insertAction(m_pUrl, m_pStop);
877 m_pToolBar->removeAction(m_pStop);
879 m_pInspector->setChecked(CurrentView(ViewType::DevTools));
883 setWindowTitle(tr(
"Web browser"));
884 setWindowIcon(QIcon::fromTheme(
"web-browser"));
885 m_pUrlLineEdit->setText(
"");
886 m_pProgressBar->setValue(100);
889 m_pInspector->setChecked(
false);
894void CFrmWebBrowser::EnableAction(
bool enable)
897 m_pBack->setEnabled(
false);
899 m_pForward->setEnabled(
false);
901 m_pRefresh->setEnabled(enable);
903 m_pStop->setEnabled(
false);
905 m_pFind->setEnabled(enable);
907 m_pFindNext->setEnabled(enable);
909 m_pFindPrevious->setEnabled(enable);
911 m_pZoomOriginal->setEnabled(enable);
913 m_pZoomIn->setEnabled(enable);
915 m_pZoomOut->setEnabled(enable);
917 m_pInspector->setEnabled(enable);
919 m_pRecord->setEnabled(enable);
922void CFrmWebBrowser::slotTabCloseRequested(
int index)
924 qDebug(log) <<
"slotTabCloseRequested:" << index;
925 if(-1 == index || !m_pTab)
return;
926 auto pView = m_pTab->widget(index);
928 pView->deleteLater();
929 m_pTab->removeTab(index);
932void CFrmWebBrowser::slotViewCloseRequested()
934 CFrmWebView* p = qobject_cast<CFrmWebView*>(sender());
936 int index = IndexOfTab(p);
937 slotTabCloseRequested(index);
940void CFrmWebBrowser::slotReturnPressed()
942 slotUrlSelected(m_pUrlLineEdit->text());
945void CFrmWebBrowser::slotUrlSelected(
const QString &szUrl)
947 if(szUrl.isEmpty())
return;
948 QUrl url = QUrl::fromUserInput(szUrl);
949 qDebug(log) << url << szUrl << url.isValid();
950 if(szUrl.startsWith(
"@search:", Qt::CaseInsensitive)) {
952 QString keyword = szUrl.mid(8);
954 szSearch = m_pPara->GetSearchEngine();
955 url = szSearch.replace(m_pPara->GetSearchRelaceString(),
956 QUrl::toPercentEncoding(keyword));
959 emit sigInformation(url.toString());
960 CFrmWebView* pWeb = CurrentView();
962 pWeb = qobject_cast<CFrmWebView*>(CreateWindow(QWebEnginePage::WebBrowserTab));
964 if(m_pGo->isVisible())
965 m_pGo->setVisible(
false);
968void CFrmWebBrowser::slotInspector(
bool checked)
970 CFrmWebView* pWeb = CurrentView();
971 if(!pWeb || !m_pTab)
return;
972 auto dev = CurrentView(ViewType::DevTools);
973 if(pWeb && pWeb->page() && checked) {
975 auto w = m_pTab->currentWidget();
977 QSplitter *pSplitter = qobject_cast<QSplitter*>(w);
978 if(!pSplitter || 1 != pSplitter->count())
return;
979 dev = CreateWebView(pWeb->page()->profile()->isOffTheRecord());
982 pSplitter->addWidget(dev);
983 bool check = connect(pWeb, &CFrmWebView::sigDevToolsRequested,
986 m_pInspector->setChecked(
true);
989 check = connect(dev, &CFrmWebView::sigCloseRequested,
991 m_pInspector->setChecked(
false);
997 pWeb->page()->setDevToolsPage(dev->page());
1002 pWeb->page()->setDevToolsPage(
nullptr);
1004 dev->setParent(
nullptr);
1010int CFrmWebBrowser::Load(QSettings &set)
1012 if(m_pPara && m_pPara->GetOpenPrevious()) {
1013 set.beginGroup(
"OpenPrevious");
1015 nCount = set.value(
"Count", 0).toInt();
1016 int nCurrent = set.value(
"Current", -1).toInt();
1017 for(
int i = 0; i < nCount; i++)
1019 QString u = set.value(
"Url/" + QString::number(i)).toString();
1020 auto pView = CreateWindow(QWebEnginePage::WebBrowserTab);
1021 pView->load(QUrl(u));
1024 history = set.value(
"History/" + QString::number(i)).toByteArray();
1025 QDataStream d(&history, QIODevice::ReadWrite);
1026 d >> *pView->history();
1028 if(-1 < nCurrent && m_pTab->count() > nCurrent)
1029 m_pTab->setCurrentIndex(nCurrent);
1035int CFrmWebBrowser::Save(QSettings &set)
1037 if(m_pPara && m_pPara->GetOpenPrevious()) {
1038 set.beginGroup(
"OpenPrevious");
1039 set.setValue(
"Count", m_pTab->count());
1040 set.setValue(
"Current", m_pTab->currentIndex());
1042 for(
int i = 0; i < m_pTab->count(); i++) {
1043 auto v = GetView(i);
1045 set.setValue(
"Url/" + QString::number(i), v->url().toString());
1047 QDataStream d(&history, QIODevice::ReadWrite);
1049 set.setValue(
"History/" + QString::number(i), history);
1058void CFrmWebBrowser::slotPrint()
1060 CFrmWebView* pWeb = CurrentView();
1062#if QT_VERSION >= QT_VERSION_CHECK(6, 2, 0) && defined(HAVE_Printer)
1064 pWeb->print(&printer);
1069void CFrmWebBrowser::slotPrintFinished(
bool success)
1071 if(success && m_pPara->GetPromptPrintFinished()) {
1072 QMessageBox::information(
this, tr(
"Print finished"),
1073 tr(
"Successfully printed"));
1077void CFrmWebBrowser::slotPrintToPdf()
1079 CFrmWebView* pWeb = CurrentView();
1082 szPath += RabbitCommon::CDir::Instance()->GetDirUserData()
1083 + QDir::separator() +
"pdf";
1087 szPath += QDir::separator() + pWeb->page()->title() +
".pdf";
1088 qDebug(log) <<
"pdf:" << szPath;
1089#if QT_VERSION >= QT_VERSION_CHECK(6, 2, 0)
1090 pWeb->printToPdf(szPath);
1095void CFrmWebBrowser::slotPdfPrintingFinished(
const QString& szFile,
bool success) {
1096 if(success && m_pPara->GetPromptPrintFinished())
1097 QMessageBox::information(
this, tr(
"Print to PDF finished"),
1098 tr(
"Successfully printed to PDF.") +
"\n"
1099 + tr(
"PDF file: ") + szFile);
1100 qDebug(log) <<
"Print to PDF:" << szFile << success;
1103void CFrmWebBrowser::slotFullScreen(
bool bFullScreen)
1105 if(sender() ==
this)
1109 m_pProgressBar->hide();
1110 m_pTab->tabBar()->setVisible(
false);
1111 m_szStyleSheet = m_pTab->styleSheet();
1112 m_pTab->setStyleSheet(
"QTabWidget::pane{top:0px;left:0px;border:none;}");
1115 m_pProgressBar->show();
1116 m_pTab->tabBar()->setVisible(
true);
1117 m_pTab->setStyleSheet(m_szStyleSheet);
1118 if(CurrentView() && CurrentView()->page() && CurrentView()->page()->action(QWebEnginePage::ExitFullScreen))
1119 CurrentView()->page()->action(QWebEnginePage::ExitFullScreen)->toggle();
1121 emit sigFullScreen(bFullScreen);
1124void CFrmWebBrowser::slotCapturePage()
1126 auto pWeb = CurrentView();
1130 QPixmap pixmap = pWeb->grab();
1131 QImage image = pixmap.toImage();
1132 QString szFile = m_pPara->m_Record.GetImageFile(
true);
1133 if(szFile.isEmpty() && image.isNull())
return;
1134 if(!image.save(szFile,
"PNG"))
1137 szErr = tr(
"Fail: Save capture page to the file: ") + szFile;
1138 qCritical(log) << szErr;
1139 emit sigError(RV::FailCapturePage, szErr);
1142 szMsg = tr(
"Save capture page to the file:") + szFile;
1143 qInfo(log) << szMsg;
1144 emit sigInformation(szMsg);
1145 qDebug(log) <<
"End action:" << m_pPara->m_Record.GetEndAction();
1146 switch(m_pPara->m_Record.GetEndAction())
1148 case CParameterRecord::ENDACTION::OpenFile: {
1149 bool bRet = QDesktopServices::openUrl(QUrl::fromLocalFile(szFile));
1151 qCritical(log) <<
"Fail: Open capture page the file:" << szFile;
1154 case CParameterRecord::ENDACTION::OpenFolder: {
1155 QFileInfo fi(szFile);
1156 QDesktopServices::openUrl(QUrl::fromLocalFile(fi.absolutePath()));
1164void CFrmWebBrowser::slotCaptureFullPage()
1166 auto pWeb = CurrentView();
1168 qDebug(log) <<
"contents size:" << pWeb->page()->contentsSize();
1169 QString szFile = m_pPara->m_Record.GetImageFile(
true);
1170 CCaptureFullPage *pCapture =
new CCaptureFullPage();
1171 if(szFile.isEmpty() || !pCapture)
1173 bool check = connect(pCapture, &CCaptureFullPage::sigFinished,
1174 this, [
this, pWeb, szFile, pCapture](){
1175 pWeb->setEnabled(
true);
1176 qDebug(log) <<
"End action:" << m_pPara->m_Record.GetEndAction();
1177 QFileInfo fi(szFile);
1179 QString szErr = tr(
"Fail: capture full page");
1180 qCritical(log) << szErr;
1181 emit sigError(FailCaptureFullPage, szErr);
1183 QString szMsg = tr(
"Capture full page to") +
" " + szFile;
1184 qInfo(log) << szMsg;
1185 emit sigInformation(szMsg);
1186 switch(m_pPara->m_Record.GetEndAction())
1188 case CParameterRecord::ENDACTION::OpenFile: {
1189 bool bRet = QDesktopServices::openUrl(QUrl::fromLocalFile(szFile));
1191 qCritical(log) <<
"Fail: Open capture page the file:" << szFile;
1194 case CParameterRecord::ENDACTION::OpenFolder: {
1195 QFileInfo fi(szFile);
1196 QDesktopServices::openUrl(QUrl::fromLocalFile(fi.absolutePath()));
1202 pCapture->deleteLater();
1206 pWeb->setEnabled(
false);
1207 pCapture->Start(pWeb, pWeb->url(), szFile);
1209 emit sigInformation(tr(
"Start capture full page"));
1212void CFrmWebBrowser::slotRecord()
1214 if(m_pRecord->isChecked()) {
1215 m_pRecord->setText(tr(
"Stop record"));
1216 m_pRecord->setIcon(QIcon::fromTheme(
"media-stop"));
1218 Q_ASSERT(!m_pMultimediaRecord);
1221 m_pMultimediaRecord =
new CMultimediaRecordThread(m_pPara);
1222 if(m_pMultimediaRecord) {
1223 connect(m_pMultimediaRecord, &CMultimediaRecordThread::finished,
1225 m_pMultimediaRecord =
nullptr;
1226 if(m_pRecord->isChecked()) {
1227 m_pRecord->activate(QAction::Trigger);
1228 emit sigError(RV::FailRecordPage, tr(
"Fail record web page"));
1231 m_pMultimediaRecord->start();
1235 qreal rate = m_pPara->m_Record.GetVideoFrameRate();
1238 m_tmRecord.start(qreal(1000) / rate);
1239 emit sigInformation(tr(
"Start record web page"));
1241 m_pRecord->setIcon(QIcon::fromTheme(
"media-record"));
1242 m_pRecord->setText(tr(
"Record"));
1244 if(m_pMultimediaRecord) {
1245 QMetaObject::invokeMethod(m_pMultimediaRecord,
1247 Qt::AutoConnection);
1248 m_pMultimediaRecord =
nullptr;
1249 emit sigInformation(tr(
"Record web page is stopped"));
1252 m_pRecord->setStatusTip(m_pRecord->text());
1255void CFrmWebBrowser::slotRecordTimeout()
1258 if(!m_pMultimediaRecord)
return;
1259 auto pWeb = CurrentView();
1261 QPixmap pixmap = pWeb->grab();
1262 QImage image = pixmap.toImage();
1263 if(image.isNull())
return;
1264 QMetaObject::invokeMethod(m_pMultimediaRecord,
1265 "slotUpdateVideoFrame",
1267 Q_ARG(QImage, image));
1270void CFrmWebBrowser::slotAddBookmark()
1272 auto pView = CurrentView();
1275 QUrl url = pView->url();
1277 url = m_pUrlLineEdit->text();
1278 CFrmAddBookmark* pAdd =
new CFrmAddBookmark(
1279 pView->title(), url, pView->favIcon(),
1281 bool check = connect(
this, &CFrmWebBrowser::destroyed, pAdd, &CFrmAddBookmark::close);
1283 RC_SHOW_WINDOW(pAdd);
1286void CFrmWebBrowser::slotBookmark()
1288 CFrmBookmark* pBookmark =
new CFrmBookmark(m_pPara);
1289 if(!pBookmark)
return;
1290 pBookmark->setAttribute(Qt::WA_DeleteOnClose);
1291 connect(
this, &CFrmWebBrowser::destroyed, pBookmark, &CFrmBookmark::close);
1292 connect(pBookmark, &CFrmBookmark::openUrlRequested,
this, [&](
const QString& url) {
1293 CFrmWebView* pWeb = CurrentView();
1295 pWeb = qobject_cast<CFrmWebView*>(CreateWindow(QWebEnginePage::WebBrowserTab));
1300 RC_SHOW_WINDOW(pBookmark);
1303void CFrmWebBrowser::slotHistory()
1305 CFrmHistory* pHistory =
new CFrmHistory(m_pPara);
1306 if(!pHistory)
return;
1307 pHistory->setAttribute(Qt::WA_DeleteOnClose);
1308 connect(
this, &CFrmWebBrowser::destroyed, pHistory, &CFrmHistory::close);
1309 connect(pHistory, &CFrmHistory::sigOpenUrl,
this, [&](
const QString& url) {
1310 CFrmWebView* pWeb = CurrentView();
1312 pWeb = qobject_cast<CFrmWebView*>(CreateWindow(QWebEnginePage::WebBrowserTab));
1317 connect(pHistory, &CFrmHistory::sigOpenUrlInNewTab,
1318 this, [&](
const QString& url) {
1319 auto pWeb = qobject_cast<CFrmWebView*>(CreateWindow(QWebEnginePage::WebBrowserTab));
1323 RC_SHOW_WINDOW(pHistory);
void sigUpdateTitle()
Title or icon changed.