Rabbit Remote Control 0.1.0-bate14
Loading...
Searching...
No Matches
FrmWebBrowser.cpp
1// Author: Kang Lin <kl222@126.com>
2
3#include <QPainter>
4#include <QTabBar>
5#include <QMessageBox>
6#include <QMenu>
7#include <QFile>
8#include <QDir>
9#include <QPrinter>
10#include <QInputDialog>
11#include <QSplitter>
12#include <QVBoxLayout>
13#include <QWebEngineProfile>
14#include <QWebEngineHistory>
15#include <QWebEngineSettings>
16#include <QWebEngineFindTextResult>
17#include <QRegularExpression>
18#include <QWebEngineCookieStore>
19#include <QStandardPaths>
20#include <QClipboard>
21#include <QApplication>
22#include <QDesktopServices>
23#if QT_VERSION >= QT_VERSION_CHECK(6, 9, 0)
24 #include <QWebEngineProfileBuilder>
25#endif
26#if QT_VERSION >= QT_VERSION_CHECK(6, 10, 0)
27 #include <QWebEngineExtensionManager>
28#endif
29#include <QLoggingCategory>
30
31#include "RabbitCommonDir.h"
32#include "RabbitCommonTools.h"
33#include "FrmPopup.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"
44
45static Q_LOGGING_CATEGORY(log, "WebBrowser.Browser")
46CFrmWebBrowser::CFrmWebBrowser(CParameterWebBrowser *pPara, bool bMenuBar, QWidget *parent)
47 : QWidget{parent}
48 , m_pPara(pPara)
49 , m_pMenuBar(nullptr)
50 , m_pToolBar(nullptr)
51 , m_pBack(nullptr)
52 , m_pForward(nullptr)
53 , m_pRefresh(nullptr)
54 , m_pStop(nullptr)
55 , m_pAddBookmark(nullptr)
56 , m_pFind(nullptr)
57 , m_pFindNext(nullptr)
58 , m_pFindPrevious(nullptr)
59 , m_pZoomOriginal(nullptr)
60 , m_pZoomIn(nullptr)
61 , m_pZoomOut(nullptr)
62 , m_pFavAction(nullptr)
63 , m_pGo(nullptr)
64 , m_pAddPage(nullptr)
65 , m_pAddPageIncognito(nullptr)
66 , m_pAddWindow(nullptr)
67 , m_pPrint(nullptr)
68 , m_pPrintToPdf(nullptr)
69 , m_pAddWindowIncognito(nullptr)
70 , m_pDownload(nullptr)
71 , m_pInspector(nullptr)
72 , m_pUrl(nullptr)
73 , m_pUrlLineEdit(nullptr)
74 , m_pProgressBar(nullptr)
75 , m_pTab(nullptr)
76 , m_DownloadManager(pPara)
77 , m_pCapturePage(nullptr)
78 , m_pCaptureFulPage(nullptr)
79 , m_pRecord(nullptr)
80 , m_pMultimediaRecord(nullptr)
81{
82 qDebug(log) << Q_FUNC_INFO;
83 bool check = false;
84
85 setWindowIcon(QIcon::fromTheme("web-browser"));
86
87 QVBoxLayout* pLayout = new QVBoxLayout(this);
88 if(!pLayout) {
89 return;
90 }
91 pLayout->setSpacing(0);
92 pLayout->setContentsMargins(0, 0, 0, 0);
93 setLayout(pLayout);
94
95 m_pToolBar = new QToolBar(this);
96 if(m_pToolBar) {
97 pLayout->addWidget(m_pToolBar);
98 }
99
100 m_pBack = m_pToolBar->addAction(
101 QIcon::fromTheme("go-previous"), tr("Back"),
102 this, [&](){
103 CFrmWebView* pWeb = CurrentView();
104 if(pWeb && pWeb->page())
105 pWeb->page()->action(QWebEnginePage::Back)->trigger();
106 });
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"),
112 this, [&](){
113 CFrmWebView* pWeb = CurrentView();
114 if(pWeb && pWeb->page())
115 pWeb->page()->action(QWebEnginePage::Forward)->trigger();
116 });
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"),
122 this, [&](){
123 CFrmWebView* pWeb = CurrentView();
124 if(pWeb && pWeb->page())
125 pWeb->page()->action(QWebEnginePage::Reload)->trigger();
126 });
127 m_pRefresh->setShortcuts(QKeySequence::Refresh);
128 m_pRefresh->setStatusTip(m_pRefresh->text());
129
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);
138 Q_ASSERT(check);
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());
144 if(pLineEdit) {
145 if(text.isEmpty()) {
146 if(m_pGo->isVisible())
147 m_pGo->setVisible(false);
148 } else {
149 if(!m_pGo->isVisible())
150 m_pGo->setVisible(true);
151 }
152 }
153 });
154 Q_ASSERT(check);
155 // 创建地址栏自动完成器
156 auto pAddressCompleter = new CAddressCompleter(&m_pPara->m_HistoryDatabase, this);
157 pAddressCompleter->attachToLineEdit(m_pUrlLineEdit);
158 if(m_pPara)
159 pAddressCompleter->setMaxVisibleItems(m_pPara->GetAddCompleterLines());
160 check = connect(pAddressCompleter, &CAddressCompleter::urlSelected,
161 this, &CFrmWebBrowser::slotUrlSelected);
162 Q_ASSERT(check);
163 check = connect(pAddressCompleter, &CAddressCompleter::searchRequested,
164 this, [&](const QString& keyword) {
165 qDebug(log) << "CAddressCompleter::searchRequested keyword:" << keyword;
166 QString szSearch;
167 QString szUrl;
168 if(m_pPara) {
169 szSearch = m_pPara->GetSearchEngine();
170 szUrl = szSearch.replace(m_pPara->GetSearchRelaceString(),
171 QUrl::toPercentEncoding(keyword));
172 if(!szUrl.isEmpty())
173 slotUrlSelected(szUrl);
174 }
175 });
176 Q_ASSERT(check);
177 check = connect(pAddressCompleter, &CAddressCompleter::sigCommand,
178 this, [&](const QString& cmd) {
179 if(cmd.startsWith("@setting")) {
180 CDlgSettings dlg(GetProfile(), m_pPara);
181 RC_SHOW_WINDOW(&dlg);
182 } else if(cmd.startsWith("@history")) {
183 slotHistory();
184 } else if(cmd.startsWith("@bookmark")) {
185 slotBookmark();
186 }
187 });
188 Q_ASSERT(check);
189
190 m_pAddBookmark = m_pToolBar->addAction(
191 QIcon::fromTheme("user-bookmarks"),
192 tr("Add bookmark"), this, SLOT(slotAddBookmark()));
193
194 m_pAddPage = m_pToolBar->addAction(QIcon::fromTheme("add"), tr("Add tab page"),
195 this, [&](){
196 CreateWindow(QWebEnginePage::WebBrowserTab);
197 if(!m_pPara->GetTabUrl().isEmpty()) {
198 m_pUrlLineEdit->setText(m_pPara->GetTabUrl());
199 slotReturnPressed();
200 }
201 });
202 m_pAddPage->setStatusTip(m_pAddPage->text());
203 m_pAddPage->setShortcuts(QKeySequence::AddTab);
204 Q_ASSERT(check);
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){
212 if(checked)
213 m_DownloadManager.show();
214 else
215 m_DownloadManager.hide();
216 });
217 Q_ASSERT(check);
218 check = connect(&m_DownloadManager, &CFrmDownloadManager::sigVisible, this,
219 [&](bool visible){
220 if(m_pDownload)
221 m_pDownload->setChecked(visible);
222 });
223 Q_ASSERT(check);
224
225 m_pProgressBar = new QProgressBar(this);
226 if(m_pProgressBar) {
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}");
232 }
233
234 m_pTab = new QTabWidget(this);
235 if(m_pTab) {
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);
241 }
242 check = connect(m_pTab, &QTabWidget::currentChanged,
243 this, &CFrmWebBrowser::slotTabCurrentChanged);
244 Q_ASSERT(check);
245 check = connect(m_pTab, &QTabWidget::tabCloseRequested,
246 this, &CFrmWebBrowser::slotTabCloseRequested);
247 Q_ASSERT(check);
248
249 m_DownloadManager.hide();
250 QWebEngineProfile::defaultProfile()->setDownloadPath(m_pPara->GetDownloadFolder());
251 check = connect(QWebEngineProfile::defaultProfile(), &QWebEngineProfile::downloadRequested,
252 &m_DownloadManager, &CFrmDownloadManager::slotDownloadRequested);
253 Q_ASSERT(check);
254 check = connect(m_pPara, &CParameterWebBrowser::sigDownloadFolderChanged,
255 this, [&](){
256 QWebEngineProfile::defaultProfile()->setDownloadPath(m_pPara->GetDownloadFolder());
257 if(m_profile)
258 m_profile->setDownloadPath(m_pPara->GetDownloadFolder());
259 });
260 Q_ASSERT(check);
261
262 InitMenu(&m_Menu);
263 if(bMenuBar)
264 {
265 m_pMenuBar = new QMenuBar(this);
266 if(m_pMenuBar) {
267 m_Menu.setTitle(tr("Operate"));
268 m_pMenuBar->addMenu(&m_Menu);
269 pLayout->setMenuBar(m_pMenuBar);
270 }
271 }
272
273 check = connect(&m_tmRecord, &QTimer::timeout, this, &CFrmWebBrowser::slotRecordTimeout);
274 Q_ASSERT(check);
275}
276
277CFrmWebBrowser::~CFrmWebBrowser()
278{
279 qDebug(log) << Q_FUNC_INFO;
280 if(m_pToolBar) {
281 m_pToolBar->deleteLater();
282 m_pToolBar = nullptr;
283 }
284 if(m_pTab) {
285 m_pTab->deleteLater();
286 m_pTab = nullptr;
287 }
288
289 if(m_pPara->GetClearCookie() && m_profile)
290 m_profile->cookieStore()->deleteAllCookies();
291 if(m_pPara->GetClearHttpCache() && m_profile)
292 m_profile->clearHttpCache();
293}
294
295QMenu* CFrmWebBrowser::GetMenu(QWidget *parent)
296{
297 if(m_Menu.actions().isEmpty())
298 return nullptr;
299 return &m_Menu;
300}
301
302QWebEngineView* CFrmWebBrowser::CreateWindow(
303 QWebEnginePage::WebWindowType type, bool offTheRecord)
304{
305 qDebug(log) << "Create window:" << type;
306
307 CFrmWebView* pView = nullptr;
308 switch (type) {
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"));
313 if(-1 < index)
314 m_pTab->setCurrentIndex(index);
315 break;
316 }
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);
324 break;
325 }
326 case QWebEnginePage::WebBrowserWindow: {
327 auto pWin = new CFrmWebBrowser(m_pPara, true);
328 if(pWin) {
329 pView = qobject_cast<CFrmWebView*>(
330 pWin->CreateWindow(QWebEnginePage::WebBrowserTab));
331 pWin->setAttribute(Qt::WA_DeleteOnClose);
332 auto pMainWin = RabbitCommon::CTools::GetMainWindow();
333 if(pMainWin)
334 pWin->resize(pMainWin->frameGeometry().width(),
335 pMainWin->frameGeometry().height());
336 pWin->show();
337 }
338 break;
339 }
340 case QWebEnginePage::WebDialog: {
341 // Test: Resource\html\TestQWebEnginePageWebDialog.html
342 auto popup = new CFrmPopup(GetProfile(offTheRecord), this);
343 pView = popup->GetView();
344 }
345 }
346
347 return pView;
348}
349
350void CFrmWebBrowser::SetConnect(CFrmWebView* pWeb)
351{
352 bool check = false;
353 if(!pWeb) return;
354 check = connect(pWeb, &CFrmWebView::sigDevToolsRequested,
355 this, [&](){
356 if(m_pInspector)
357 m_pInspector->setChecked(true);
358 });
359 Q_ASSERT(check);
360 check = connect(pWeb, &CFrmWebView::sigWebActionEnabledChanged,
361 this, [this, pWeb](QWebEnginePage::WebAction webAction, bool enabled){
362 if(!IsCurrentView(pWeb)) return;
363 switch(webAction){
364 case QWebEnginePage::WebAction::Back:
365 m_pBack->setEnabled(enabled);
366 break;
367 case QWebEnginePage::WebAction::Forward:
368 m_pForward->setEnabled(enabled);
369 break;
370 case QWebEnginePage::WebAction::Reload: {
371 m_pRefresh->setEnabled(enabled);
372 if(m_pRefresh->isEnabled())
373 m_pToolBar->insertAction(m_pUrl, m_pRefresh);
374 else
375 m_pToolBar->removeAction(m_pRefresh);
376 break;
377 }
378 case QWebEnginePage::WebAction::Stop: {
379 m_pStop->setEnabled(enabled);
380 if(m_pStop->isEnabled())
381 m_pToolBar->insertAction(m_pUrl, m_pStop);
382 else
383 m_pToolBar->removeAction(m_pStop);
384 break;
385 }
386 default:
387 break;
388 }
389 });
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());
395 if(m_pPara) {
396 m_pPara->m_HistoryDatabase.addHistoryEntry(url.toString());
397 }
398 });
399 Q_ASSERT(check);
400 check = connect(pWeb, &CFrmWebView::titleChanged,
401 this, [&](const QString &title) {
402 CFrmWebView* pWeb = qobject_cast<CFrmWebView*>(sender());
403 int index = IndexOfTab(pWeb);
404 if(-1 < index) {
405 if(m_pTab)
406 m_pTab->setTabText(index, title);
407 setWindowTitle(title);
408 emit sigUpdateTitle();
409 }
410 if(m_pPara) {
411 m_pPara->m_HistoryDatabase.updateHistoryEntry(pWeb->url().toString(), title);
412 }
413 });
414 Q_ASSERT(check);
415 check = connect(pWeb, &CFrmWebView::favIconChanged,
416 this, [&](const QIcon &icon){
417 CFrmWebView* pWeb = qobject_cast<CFrmWebView*>(sender());
418 int index = IndexOfTab(pWeb);
419 if(-1 < index) {
420 if(m_pTab)
421 m_pTab->setTabIcon(index, icon);
422 m_pFavAction->setIcon(icon);
423 setWindowIcon(icon);
424 emit sigUpdateTitle();
425 }
426 if(m_pPara) {
427 m_pPara->m_HistoryDatabase.updateHistoryEntry(pWeb->url().toString(), QString(), icon);
428 }
429 });
430 Q_ASSERT(check);
431 check = connect(pWeb, &CFrmWebView::sigLinkHovered,
432 this, &CFrmWebBrowser::sigInformation);
433 Q_ASSERT(check);
434 check = connect(pWeb, &CFrmWebView::sigCloseRequested,
435 this, &CFrmWebBrowser::slotViewCloseRequested);
436 Q_ASSERT(check);
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);
442 });
443 Q_ASSERT(check);
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);
448 Q_ASSERT(check);
449 check = connect(pWeb, &CFrmWebView::pdfPrintingFinished,
450 this, &CFrmWebBrowser::slotPdfPrintingFinished);
451 Q_ASSERT(check);
452#endif
453}
454
455QWebEngineProfile* CFrmWebBrowser::GetProfile(bool offTheRecord)
456{
457 if(offTheRecord)
458 return QWebEngineProfile::defaultProfile();
459 if(m_profile)
460 return m_profile.get();
461
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));
471#else
472 name = set.value("Profile/Name", name).toString();
473 m_profile.reset(new QWebEngineProfile(name));
474#endif
475 if(!m_profile)
476 return QWebEngineProfile::defaultProfile();
477
478 set.setValue("Profile/Name", name);
479
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);
486#endif
487#if QT_VERSION >= QT_VERSION_CHECK(5, 7, 0)
488 m_profile->settings()->setAttribute(QWebEngineSettings::ScreenCaptureEnabled, true);
489#endif
490#if QT_VERSION >= QT_VERSION_CHECK(5, 8, 0)
491 m_profile->settings()->setAttribute(QWebEngineSettings::AllowRunningInsecureContent, true);
492#endif
493#if QT_VERSION > QT_VERSION_CHECK(6, 0, 0)
494 m_profile->settings()->setAttribute(QWebEngineSettings::PlaybackRequiresUserGesture, false);
495#endif
496 m_profile->setDownloadPath(m_pPara->GetDownloadFolder());
497 bool check = connect(m_profile.get(), &QWebEngineProfile::downloadRequested,
498 &m_DownloadManager, &CFrmDownloadManager::slotDownloadRequested);
499 Q_ASSERT(check);
500 //m_profile->setPersistentCookiesPolicy(QWebEngineProfile::ForcePersistentCookies);
501 //m_profile->setPersistentStoragePath(m_profile->cachePath() + QDir::separator() + "Persistent");
502 //m_profile->setHttpCacheMaximumSize(50);
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()
512#endif
513#if QT_VERSION > QT_VERSION_CHECK(6, 8, 0)
514 //<< "AllPermissions:" << m_profile->listAllPermissions()
515 << "persistentPermissionsPolicy:" << m_profile->persistentPermissionsPolicy()
516#endif
517 << "persistentCookiesPolicy:" << m_profile->persistentCookiesPolicy()
518 << "httpCacheMaximumSize:" << m_profile->httpCacheMaximumSize()
519 ;
520 return m_profile.get();
521}
522
523CFrmWebView *CFrmWebBrowser::CreateWebView(bool offTheRecord)
524{
525 auto pView = new CFrmWebView(this);
526 if(pView) {
527 auto profile = GetProfile(offTheRecord);
528 CProtocolManager manager;
529 manager.registerAllProcotol(profile);
530// #if QT_VERSION >= QT_VERSION_CHECK(6, 8, 0)
531// profile->setPersistentPermissionsPolicy(QWebEngineProfile::PersistentPermissionsPolicy::AskEveryTime);
532// #endif
533 auto page = new QWebEnginePage(profile, pView);
534 pView->setPage(page);
535 }
536 return pView;
537}
538
539QWidget* CFrmWebBrowser::CreateTab(CFrmWebView **view, bool offTheRecord)
540{
541 QSplitter *pSplitter = new QSplitter(Qt::Vertical, this);
542 if(pSplitter) {
543 pSplitter->setSizePolicy(QSizePolicy::Expanding, QSizePolicy::Expanding);
544 //pSplitter->setContentsMargins(0, 0, 0, 0);
545 CFrmWebView* pWeb = nullptr;
546 if(view) {
547 if(*view) {
548 pWeb = *view;
549 } else {
550 pWeb = CreateWebView(offTheRecord);
551 *view = pWeb;
552 }
553 } else {
554 pWeb = CreateWebView(offTheRecord);
555 }
556 if(pWeb) {
557 pSplitter->addWidget(pWeb);
558 SetConnect(pWeb);
559 }
560 }
561 return pSplitter;
562}
563
564CFrmWebView *CFrmWebBrowser::CurrentView(ViewType type)
565{
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));
574}
575
576CFrmWebView* CFrmWebBrowser::GetView(int index, ViewType type)
577{
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;
583 int idx = (int)type;
584 if(0 > idx && pSplitter->count() <= idx) return nullptr;
585 return qobject_cast<CFrmWebView*>(pSplitter->widget(idx));
586}
587
588bool CFrmWebBrowser::IsCurrentView(CFrmWebView *pView)
589{
590 if(!m_pTab) return false;
591 auto w = m_pTab->currentWidget();
592 if(!w) return false;
593 QSplitter *pSplitter = qobject_cast<QSplitter*>(w);
594 if(!pSplitter) return false;
595 return -1 != pSplitter->indexOf(pView);
596}
597
598int CFrmWebBrowser::IndexOfTab(CFrmWebView *pView)
599{
600 int nRet = -1;
601 if(!pView) return nRet;
602 QWidget* p = qobject_cast<QWidget*>(pView->parent());
603 if(!p) return nRet;
604 if(m_pTab)
605 nRet = m_pTab->indexOf(p);
606 return nRet;
607}
608
609int CFrmWebBrowser::InitMenu(QMenu *pMenu)
610{
611 bool check = false;
612 if(!pMenu) return 0;
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();
621 });
622 m_pStop->setEnabled(false);
623 m_pStop->setShortcuts(QKeySequence::Cancel);
624 m_pStop->setStatusTip(m_pStop->text());
625
626 pMenu->addSeparator();
627 pMenu->addAction(m_pAddPage);
628 m_pAddPageIncognito = pMenu->addAction(
629 QIcon::fromTheme("add"), tr("Add incognito tab"),
630 this, [&]() {
631 CreateWindow(QWebEnginePage::WebBrowserTab, true);
632 if(!m_pPara->GetTabUrl().isEmpty()) {
633 m_pUrlLineEdit->setText(m_pPara->GetTabUrl());
634 slotReturnPressed();
635 }
636 });
637 m_pAddPageIncognito->setStatusTip(m_pAddPageIncognito->text());
638 m_pAddWindow = pMenu->addAction(
639 QIcon::fromTheme("add"), tr("Add window"),
640 this, [&]() {
641 CreateWindow(QWebEnginePage::WebBrowserWindow);
642 });
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"),
647 this, [&]() {
648 CreateWindow(QWebEnginePage::WebBrowserWindow, true);
649 });
650 m_pAddWindowIncognito->setVisible(false);
651 m_pAddWindowIncognito->setStatusTip(m_pAddWindowIncognito->text());
652
653 pMenu->addSeparator();
654 m_pFind = pMenu->addAction(
655 QIcon::fromTheme("edit-find"), tr("&Find"), this,
656 [&]() {
657 CFrmWebView* pWeb = CurrentView();
658 if(pWeb) {
659 bool ok = false;
660 if(pWeb->selectedText().isEmpty()) {
661 if(QApplication::clipboard()
662 && !QApplication::clipboard()->text().isEmpty())
663 m_szFindText = QApplication::clipboard()->text();
664 } else {
665 m_szFindText = pWeb->selectedText();
666 }
667 QString search = QInputDialog::getText(
668 this, tr("Find"),
669 tr("Find:"), QLineEdit::Normal,
670 m_szFindText, &ok);
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));
678 } else {
679 emit sigInformation(tr("\"%1\" found: %2/%3").arg(m_szFindText, QString::number(result.activeMatch()), QString::number(result.numberOfMatches())));
680 }
681 });
682#else
683 pWeb->findText(m_szFindText, QWebEnginePage::FindFlags(), [this](bool found) {
684 if (!found)
685 emit sigInformation(tr("\"%1\" not found.").arg(m_szFindText));
686 });
687#endif
688 }
689 }
690 });
691 m_pFind->setShortcuts(QKeySequence::Find);
692 m_pFind->setStatusTip(m_pFind->text());
693
694 m_pFindNext = pMenu->addAction(
695 QIcon::fromTheme("go-next"), tr("Find &Next"), this,
696 [this]() {
697 CFrmWebView* pWeb = CurrentView();
698 if(pWeb && !m_szFindText.isEmpty()) {
699 pWeb->findText(m_szFindText);
700 }
701 });
702 m_pFindNext->setShortcuts(QKeySequence::FindNext);
703 m_pFindNext->setText(m_pFindNext->text());
704
705 m_pFindPrevious = pMenu->addAction(
706 QIcon::fromTheme("go-previous"), tr("Find &Previous"), this,
707 [&]() {
708 CFrmWebView* pWeb = CurrentView();
709 if(pWeb && !m_szFindText.isEmpty()) {
710 pWeb->findText(m_szFindText, QWebEnginePage::FindBackward);
711 }
712 });
713 m_pFindPrevious->setShortcuts(QKeySequence::FindPrevious);
714 m_pFindPrevious->setStatusTip(m_pFindPrevious->text());
715
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,
723 [&](){
724 CFrmWebView* pWeb = CurrentView();
725 if(pWeb)
726 pWeb->setZoomFactor(1.0);
727 });
728 Q_ASSERT(check);
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"));
733 check = connect(
734 m_pZoomIn, &QAction::triggered, this,
735 [&](){
736 CFrmWebView* pWeb = CurrentView();
737 if(pWeb)
738 pWeb->setZoomFactor(pWeb->zoomFactor() + 0.1);
739 });
740 Q_ASSERT(check);
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"));
746 check = connect(
747 m_pZoomOut, &QAction::triggered, this,
748 [&](){
749 CFrmWebView* pWeb = CurrentView();
750 if(pWeb)
751 pWeb->setZoomFactor(pWeb->zoomFactor() - 0.1);
752 });
753 Q_ASSERT(check);
754
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);
765#endif
766
767 pMenu->addAction(m_pDownload);
768 if(!m_pInspector) {
769 m_pInspector = pMenu->addAction(QIcon::fromTheme("tools"), tr("Inspector"));
770 check = connect(m_pInspector, &QAction::toggled,
771 this, &CFrmWebBrowser::slotInspector);
772 Q_ASSERT(check);
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)
779 });
780 }
781
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);
789
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);
805#else
806 m_pRecord->setEnabled(false);
807#endif
808
809 EnableAction(false);
810 return 0;
811}
812
813int CFrmWebBrowser::Start()
814{
815 int nRet = 0;
816
817 if(m_pTab && m_pTab->count() == 0) {
818 // Add new web view
819 m_pAddPage->trigger();
820 }
821
822 return nRet;
823}
824
825int CFrmWebBrowser::Stop()
826{
827 int nRet = 0;
828
829 if(m_pRecord && m_pRecord->isChecked())
830 slotRecord();
831 if(m_pTab) {
832 for(int i = 0; i < m_pTab->count(); i++) {
833 auto v = GetView(i);
834 if(!v) continue;
835 v->stop();
836 }
837 }
838 return nRet;
839}
840
841void CFrmWebBrowser::slotTabCurrentChanged(int index)
842{
843 if(-1 == index) return;
844 CFrmWebView* pWeb = CurrentView();
845 if(pWeb) {
846 setWindowTitle(pWeb->title());
847 setWindowIcon(pWeb->icon());
848 m_pUrlLineEdit->setText(pWeb->url().toString());
849 m_pProgressBar->setValue(pWeb->progress());
850 EnableAction(true);
851 auto page = pWeb->page();
852 if(page) {
853 auto action = page->action(QWebEnginePage::Back);
854 if(action && m_pBack) {
855 m_pBack->setEnabled(action->isEnabled());
856 }
857 action = page->action(QWebEnginePage::Forward);
858 if(action && m_pForward) {
859 m_pForward->setEnabled(action->isEnabled());
860 }
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);
866 else
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);
873 else
874 m_pToolBar->removeAction(m_pStop);
875 if(m_pInspector) {
876 m_pInspector->setChecked(CurrentView(ViewType::DevTools));
877 }
878 }
879 } else {
880 setWindowTitle(tr("Web browser"));
881 setWindowIcon(QIcon::fromTheme("web-browser"));
882 m_pUrlLineEdit->setText("");
883 m_pProgressBar->setValue(100);
884 EnableAction(false);
885 if(m_pInspector)
886 m_pInspector->setChecked(false);
887 }
888 emit sigUpdateTitle();
889}
890
891void CFrmWebBrowser::EnableAction(bool enable)
892{
893 if(m_pBack)
894 m_pBack->setEnabled(false);
895 if(m_pForward)
896 m_pForward->setEnabled(false);
897 if(m_pRefresh)
898 m_pRefresh->setEnabled(enable);
899 if(m_pStop)
900 m_pStop->setEnabled(false);
901 if(m_pFind)
902 m_pFind->setEnabled(enable);
903 if(m_pFindNext)
904 m_pFindNext->setEnabled(enable);
905 if(m_pFindPrevious)
906 m_pFindPrevious->setEnabled(enable);
907 if(m_pZoomOriginal)
908 m_pZoomOriginal->setEnabled(enable);
909 if(m_pZoomIn)
910 m_pZoomIn->setEnabled(enable);
911 if(m_pZoomOut)
912 m_pZoomOut->setEnabled(enable);
913 if(m_pInspector)
914 m_pInspector->setEnabled(enable);
915 if(m_pRecord)
916 m_pRecord->setEnabled(enable);
917}
918
919void CFrmWebBrowser::slotTabCloseRequested(int index)
920{
921 qDebug(log) << "slotTabCloseRequested:" << index;
922 if(-1 == index || !m_pTab) return;
923 auto pView = m_pTab->widget(index);
924 if(pView)
925 pView->deleteLater();
926 m_pTab->removeTab(index);
927}
928
929void CFrmWebBrowser::slotViewCloseRequested()
930{
931 CFrmWebView* p = qobject_cast<CFrmWebView*>(sender());
932 if(!p) return;
933 int index = IndexOfTab(p);
934 slotTabCloseRequested(index);
935}
936
937void CFrmWebBrowser::slotReturnPressed()
938{
939 slotUrlSelected(m_pUrlLineEdit->text());
940}
941
942void CFrmWebBrowser::slotUrlSelected(const QString &szUrl)
943{
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)) {
948 QString szSearch;
949 QString keyword = szUrl.mid(8);
950 if(m_pPara) {
951 szSearch = m_pPara->GetSearchEngine();
952 url = szSearch.replace(m_pPara->GetSearchRelaceString(),
953 QUrl::toPercentEncoding(keyword));
954 }
955 }
956 emit sigInformation(url.toString());
957 CFrmWebView* pWeb = CurrentView();
958 if(!pWeb)
959 pWeb = qobject_cast<CFrmWebView*>(CreateWindow(QWebEnginePage::WebBrowserTab));
960 pWeb->load(url);
961 if(m_pGo->isVisible())
962 m_pGo->setVisible(false);
963}
964
965void CFrmWebBrowser::slotInspector(bool checked)
966{
967 CFrmWebView* pWeb = CurrentView();
968 if(!pWeb || !m_pTab) return;
969 auto dev = CurrentView(ViewType::DevTools);
970 if(pWeb && pWeb->page() && checked) {
971 if(!dev) {
972 auto w = m_pTab->currentWidget();
973 if(!w) return;
974 QSplitter *pSplitter = qobject_cast<QSplitter*>(w);
975 if(!pSplitter || 1 != pSplitter->count()) return;
976 dev = CreateWebView(pWeb->page()->profile()->isOffTheRecord());
977 if(dev) {
978 dev->show();
979 pSplitter->addWidget(dev);
980 bool check = connect(pWeb, &CFrmWebView::sigDevToolsRequested,
981 this, [&](){
982 if(m_pInspector)
983 m_pInspector->setChecked(true);
984 });
985 Q_ASSERT(check);
986 check = connect(dev, &CFrmWebView::sigCloseRequested,
987 this, [this]() {
988 m_pInspector->setChecked(false);
989 });
990 Q_ASSERT(check);
991 }
992 }
993 if(dev) {
994 pWeb->page()->setDevToolsPage(dev->page());
995 if(dev->isHidden())
996 dev->show();
997 }
998 } else {
999 pWeb->page()->setDevToolsPage(nullptr);
1000 if(dev) {
1001 dev->setParent(nullptr);
1002 dev->deleteLater();
1003 }
1004 }
1005}
1006
1007int CFrmWebBrowser::Load(QSettings &set)
1008{
1009 if(m_pPara && m_pPara->GetOpenPrevious()) {
1010 set.beginGroup("OpenPrevious");
1011 int nCount = 0;
1012 nCount = set.value("Count", 0).toInt();
1013 int nCurrent = set.value("Current", -1).toInt();
1014 for(int i = 0; i < nCount; i++)
1015 {
1016 QString u = set.value("Url/" + QString::number(i)).toString();
1017 auto pView = CreateWindow(QWebEnginePage::WebBrowserTab);
1018 pView->load(QUrl(u));
1019
1020 QByteArray history;
1021 history = set.value("History/" + QString::number(i)).toByteArray();
1022 QDataStream d(&history, QIODevice::ReadWrite);
1023 d >> *pView->history();
1024 }
1025 if(-1 < nCurrent && m_pTab->count() > nCurrent)
1026 m_pTab->setCurrentIndex(nCurrent);
1027 set.endGroup();
1028 }
1029 return 0;
1030}
1031
1032int CFrmWebBrowser::Save(QSettings &set)
1033{
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());
1038
1039 for(int i = 0; i < m_pTab->count(); i++) {
1040 auto v = GetView(i);
1041 if(v) {
1042 set.setValue("Url/" + QString::number(i), v->url().toString());
1043 QByteArray history;
1044 QDataStream d(&history, QIODevice::ReadWrite);
1045 d << *v->history();
1046 set.setValue("History/" + QString::number(i), history);
1047 }
1048 }
1049
1050 set.endGroup();
1051 }
1052 return 0;
1053}
1054
1055void CFrmWebBrowser::slotPrint()
1056{
1057 CFrmWebView* pWeb = CurrentView();
1058 if(pWeb) {
1059#if QT_VERSION >= QT_VERSION_CHECK(6, 2, 0)
1060 QPrinter printer;
1061 pWeb->print(&printer);
1062#endif
1063 }
1064}
1065
1066void CFrmWebBrowser::slotPrintFinished(bool success)
1067{
1068 if(success && m_pPara->GetPromptPrintFinished()) {
1069 QMessageBox::information(this, tr("Print finished"),
1070 tr("Successfully printed"));
1071 }
1072}
1073
1074void CFrmWebBrowser::slotPrintToPdf()
1075{
1076 CFrmWebView* pWeb = CurrentView();
1077 if(pWeb) {
1078 QString szPath;
1079 szPath += RabbitCommon::CDir::Instance()->GetDirUserData()
1080 + QDir::separator() + "pdf";
1081 QDir d(szPath);
1082 if(!d.exists())
1083 d.mkpath(szPath);
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);
1088#endif
1089 }
1090}
1091
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;
1098}
1099
1100void CFrmWebBrowser::slotFullScreen(bool bFullScreen)
1101{
1102 if(sender() == this)
1103 return;
1104 if(bFullScreen) {
1105 m_pToolBar->hide();
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;}");
1110 } else {
1111 m_pToolBar->show();
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();
1117 }
1118 emit sigFullScreen(bFullScreen);
1119}
1120
1121void CFrmWebBrowser::slotCapturePage()
1122{
1123 auto pWeb = CurrentView();
1124 if(!pWeb) return;
1125
1126 QString szMsg;
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"))
1132 {
1133 QString szErr;
1134 szErr = tr("Fail: Save capture page to the file: ") + szFile;
1135 qCritical(log) << szErr;
1136 emit sigError(RV::FailCapturePage, szErr);
1137 return;
1138 }
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())
1144 {
1145 case CParameterRecord::ENDACTION::OpenFile: {
1146 bool bRet = QDesktopServices::openUrl(QUrl::fromLocalFile(szFile));
1147 if(!bRet)
1148 qCritical(log) << "Fail: Open capture page the file:" << szFile;
1149 break;
1150 }
1151 case CParameterRecord::ENDACTION::OpenFolder: {
1152 QFileInfo fi(szFile);
1153 QDesktopServices::openUrl(QUrl::fromLocalFile(fi.absolutePath()));
1154 break;
1155 }
1156 default:
1157 break;
1158 }
1159}
1160
1161void CFrmWebBrowser::slotCaptureFullPage()
1162{
1163 auto pWeb = CurrentView();
1164 if(!pWeb) return;
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)
1169 return;
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);
1175 if(!fi.exists()) {
1176 QString szErr = tr("Fail: capture full page");
1177 qCritical(log) << szErr;
1178 emit sigError(FailCaptureFullPage, szErr);
1179 } else {
1180 QString szMsg = tr("Capture full page to") + " " + szFile;
1181 qInfo(log) << szMsg;
1182 emit sigInformation(szMsg);
1183 switch(m_pPara->m_Record.GetEndAction())
1184 {
1185 case CParameterRecord::ENDACTION::OpenFile: {
1186 bool bRet = QDesktopServices::openUrl(QUrl::fromLocalFile(szFile));
1187 if(!bRet)
1188 qCritical(log) << "Fail: Open capture page the file:" << szFile;
1189 break;
1190 }
1191 case CParameterRecord::ENDACTION::OpenFolder: {
1192 QFileInfo fi(szFile);
1193 QDesktopServices::openUrl(QUrl::fromLocalFile(fi.absolutePath()));
1194 break;
1195 }
1196 default:
1197 break;
1198 }
1199 pCapture->deleteLater();
1200 }
1201 });
1202 Q_ASSERT(check);
1203 pWeb->setEnabled(false);
1204 pCapture->Start(pWeb, pWeb->url(), szFile);
1205
1206 emit sigInformation(tr("Start capture full page"));
1207}
1208
1209void CFrmWebBrowser::slotRecord()
1210{
1211 if(m_pRecord->isChecked()) {
1212 m_pRecord->setText(tr("Stop record"));
1213 m_pRecord->setIcon(QIcon::fromTheme("media-stop"));
1214
1215 Q_ASSERT(!m_pMultimediaRecord);
1216 // Note: It automatically releases memory when exiting.
1217 // See: CMultimediaRecordThread::CMultimediaRecordThread()
1218 m_pMultimediaRecord = new CMultimediaRecordThread(m_pPara);
1219 if(m_pMultimediaRecord) {
1220 connect(m_pMultimediaRecord, &CMultimediaRecordThread::finished,
1221 this, [this]() {
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"));
1226 }
1227 });
1228 m_pMultimediaRecord->start();
1229 }
1230
1231 // modify interval
1232 qreal rate = m_pPara->m_Record.GetVideoFrameRate();
1233 if(rate <= 0)
1234 rate = 24;
1235 m_tmRecord.start(qreal(1000) / rate);
1236 emit sigInformation(tr("Start record web page"));
1237 } else {
1238 m_pRecord->setIcon(QIcon::fromTheme("media-record"));
1239 m_pRecord->setText(tr("Record"));
1240 m_tmRecord.stop();
1241 if(m_pMultimediaRecord) {
1242 QMetaObject::invokeMethod(m_pMultimediaRecord,
1243 "slotQuit",
1244 Qt::AutoConnection);
1245 m_pMultimediaRecord = nullptr;
1246 emit sigInformation(tr("Record web page is stopped"));
1247 }
1248 }
1249 m_pRecord->setStatusTip(m_pRecord->text());
1250}
1251
1252void CFrmWebBrowser::slotRecordTimeout()
1253{
1254 //qDebug(log) << Q_FUNC_INFO;
1255 if(!m_pMultimediaRecord) return;
1256 auto pWeb = CurrentView();
1257 if(!pWeb) return;
1258 QPixmap pixmap = pWeb->grab();
1259 QImage image = pixmap.toImage();
1260 if(image.isNull()) return;
1261 QMetaObject::invokeMethod(m_pMultimediaRecord,
1262 "slotUpdateVideoFrame",
1263 Qt::AutoConnection,
1264 Q_ARG(QImage, image));
1265}
1266
1267void CFrmWebBrowser::slotAddBookmark()
1268{
1269 auto pView = CurrentView();
1270 if(!pView) return;
1271
1272 QUrl url = pView->url();
1273 if(url.isEmpty())
1274 url = m_pUrlLineEdit->text();
1275 CFrmAddBookmark* pAdd = new CFrmAddBookmark(
1276 pView->title(), url, pView->favIcon(),
1277 m_pPara);
1278 bool check = connect(this, &CFrmWebBrowser::destroyed, pAdd, &CFrmAddBookmark::close);
1279 Q_ASSERT(check);
1280 RC_SHOW_WINDOW(pAdd);
1281}
1282
1283void CFrmWebBrowser::slotBookmark()
1284{
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();
1291 if(!pWeb) {
1292 pWeb = qobject_cast<CFrmWebView*>(CreateWindow(QWebEnginePage::WebBrowserTab));
1293 }
1294 if(pWeb)
1295 pWeb->load(url);
1296 });
1297 RC_SHOW_WINDOW(pBookmark);
1298}
1299
1300void CFrmWebBrowser::slotHistory()
1301{
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();
1308 if(!pWeb) {
1309 pWeb = qobject_cast<CFrmWebView*>(CreateWindow(QWebEnginePage::WebBrowserTab));
1310 }
1311 if(pWeb)
1312 pWeb->load(url);
1313 });
1314 connect(pHistory, &CFrmHistory::sigOpenUrlInNewTab,
1315 this, [&](const QString& url) {
1316 auto pWeb = qobject_cast<CFrmWebView*>(CreateWindow(QWebEnginePage::WebBrowserTab));
1317 if(pWeb)
1318 pWeb->load(url);
1319 });
1320 RC_SHOW_WINDOW(pHistory);
1321}
void sigUpdateTitle()
Title or icon changed.