Rabbit Remote Control 0.1.0-bate5
Loading...
Searching...
No Matches
FrmWebBrowser.cpp
1// Author: Kang Lin <kl222@126.com>
2
3#include <QTabBar>
4#include <QMessageBox>
5#include <QMenu>
6#include <QFile>
7#include <QDir>
8#include <QPrinter>
9#include <QInputDialog>
10#include <QSplitter>
11#include <QVBoxLayout>
12#include <QWebEngineProfile>
13#include <QWebEngineHistory>
14#include <QWebEngineSettings>
15#include <QWebEngineFindTextResult>
16#include <QRegularExpression>
17#include <QWebEngineCookieStore>
18#include <QStandardPaths>
19#include <QClipboard>
20#include <QApplication>
21#if QT_VERSION >= QT_VERSION_CHECK(6, 9, 0)
22 #include <QWebEngineProfileBuilder>
23#endif
24#include <QLoggingCategory>
25#include "RabbitCommonDir.h"
26#include "RabbitCommonTools.h"
27#include "FrmWebBrowser.h"
28#include "FrmPopup.h"
29
30static Q_LOGGING_CATEGORY(log, "WebBrowser.Browser")
31CFrmWebBrowser::CFrmWebBrowser(CParameterWebBrowser *pPara, bool bMenuBar, QWidget *parent)
32 : QWidget{parent}
33 , m_pMenuBar(nullptr)
34 , m_pPara(pPara)
35 , m_pToolBar(nullptr)
36 , m_pBack(nullptr)
37 , m_pForward(nullptr)
38 , m_pRefresh(nullptr)
39 , m_pStop(nullptr)
40 , m_pFind(nullptr)
41 , m_pFindNext(nullptr)
42 , m_pFindPrevious(nullptr)
43 , m_pZoomOriginal(nullptr)
44 , m_pZoomIn(nullptr)
45 , m_pZoomOut(nullptr)
46 , m_pFavAction(nullptr)
47 , m_pGo(nullptr)
48 , m_pAddPage(nullptr)
49 , m_pAddPageIncognito(nullptr)
50 , m_pAddWindow(nullptr)
51 , m_pPrint(nullptr)
52 , m_pPrintToPdf(nullptr)
53 , m_pAddWindowIncognito(nullptr)
54 , m_pDownload(nullptr)
55 , m_pInspector(nullptr)
56 , m_pUrl(nullptr)
57 , m_pUrlLineEdit(nullptr)
58 , m_pProgressBar(nullptr)
59 , m_pTab(nullptr)
60 , m_DownloadManager(pPara)
61{
62 qDebug(log) << Q_FUNC_INFO;
63 bool check = false;
64
65 setWindowIcon(QIcon::fromTheme("web-browser"));
66
67 QVBoxLayout* pLayout = new QVBoxLayout(this);
68 if(!pLayout) {
69 return;
70 }
71 pLayout->setSpacing(0);
72 pLayout->setContentsMargins(0, 0, 0, 0);
73 setLayout(pLayout);
74
75 m_pToolBar = new QToolBar(this);
76 if(m_pToolBar) {
77 pLayout->addWidget(m_pToolBar);
78 }
79
80 m_pBack = m_pToolBar->addAction(
81 QIcon::fromTheme("go-previous"), tr("Back"),
82 this, [&](){
83 CFrmWebView* pWeb = CurrentView();
84 if(pWeb && pWeb->page())
85 pWeb->page()->action(QWebEnginePage::Back)->trigger();
86 });
87 m_pBack->setEnabled(false);
88 m_pBack->setShortcuts(QKeySequence::Back);
89 m_pBack->setStatusTip(m_pBack->text());
90 m_pForward = m_pToolBar->addAction(
91 QIcon::fromTheme("go-next"), tr("Forward"),
92 this, [&](){
93 CFrmWebView* pWeb = CurrentView();
94 if(pWeb && pWeb->page())
95 pWeb->page()->action(QWebEnginePage::Forward)->trigger();
96 });
97 m_pForward->setEnabled(false);
98 m_pForward->setShortcuts(QKeySequence::Forward);
99 m_pForward->setStatusTip(m_pForward->text());
100 m_pRefresh = m_pToolBar->addAction(
101 QIcon::fromTheme("view-refresh"), tr("Refresh"),
102 this, [&](){
103 CFrmWebView* pWeb = CurrentView();
104 if(pWeb && pWeb->page())
105 pWeb->page()->action(QWebEnginePage::Reload)->trigger();
106 });
107 m_pRefresh->setShortcuts(QKeySequence::Refresh);
108 m_pRefresh->setStatusTip(m_pRefresh->text());
109
110 m_pUrlLineEdit = new QLineEdit(this);
111 m_pFavAction = new QAction(m_pUrlLineEdit);
112 m_pUrlLineEdit->addAction(m_pFavAction, QLineEdit::LeadingPosition);
113 m_pUrlLineEdit->setClearButtonEnabled(true);
114 m_pUrl = m_pToolBar->addWidget(m_pUrlLineEdit);
115 check = connect(m_pUrlLineEdit, &QLineEdit::returnPressed,
116 this, &CFrmWebBrowser::slotReturnPressed);
117 Q_ASSERT(check);
118 check = connect(m_pUrlLineEdit, &QLineEdit::editingFinished,
119 this, &CFrmWebBrowser::slotReturnPressed);
120 Q_ASSERT(check);
121 m_pGo = new QAction(QIcon::fromTheme("go-next"), tr("go"), m_pUrlLineEdit);
122 m_pGo->setStatusTip(m_pGo->text());
123 check = connect(m_pGo, &QAction::triggered, this, &CFrmWebBrowser::slotReturnPressed);
124 Q_ASSERT(check);
125 m_pUrlLineEdit->addAction(m_pGo, QLineEdit::TrailingPosition);
126 m_pGo->setVisible(false);
127 check = connect(m_pUrlLineEdit, &QLineEdit::textEdited,
128 this, [&](const QString &text){
129 QLineEdit* pLineEdit = qobject_cast<QLineEdit*>(sender());
130 if(pLineEdit) {
131 if(text.isEmpty()) {
132 if(m_pGo->isVisible())
133 m_pGo->setVisible(false);
134 } else {
135 if(!m_pGo->isVisible())
136 m_pGo->setVisible(true);
137 }
138 }
139 });
140 Q_ASSERT(check);
141
142 m_pAddPage = m_pToolBar->addAction(QIcon::fromTheme("add"), tr("Add tab page"),
143 this, [&](){
144 CreateWindow(QWebEnginePage::WebBrowserTab);
145 if(!m_pPara->GetTabUrl().isEmpty()) {
146 m_pUrlLineEdit->setText(m_pPara->GetTabUrl());
147 slotReturnPressed();
148 }
149 });
150 m_pAddPage->setStatusTip(m_pAddPage->text());
151 m_pAddPage->setShortcuts(QKeySequence::AddTab);
152 Q_ASSERT(check);
153 m_pDownload = m_pToolBar->addAction(
154 QIcon::fromTheme("emblem-downloads"), tr("Download Manager"));
155 m_pDownload->setCheckable(true);
156 m_pDownload->setStatusTip(m_pDownload->text());
157 m_pDownload->setShortcut(QKeySequence(Qt::CTRL | Qt::Key_D));
158 check = connect(m_pDownload, &QAction::toggled,
159 this, [&](bool checked){
160 if(checked)
161 m_DownloadManager.show();
162 else
163 m_DownloadManager.hide();
164 });
165 Q_ASSERT(check);
166 check = connect(&m_DownloadManager, &CFrmDownloadManager::sigVisible, this,
167 [&](bool visible){
168 if(m_pDownload)
169 m_pDownload->setChecked(visible);
170 });
171 Q_ASSERT(check);
172
173 m_pProgressBar = new QProgressBar(this);
174 if(m_pProgressBar) {
175 pLayout->addWidget(m_pProgressBar);
176 m_pProgressBar->setMaximumHeight(1);
177 m_pProgressBar->setTextVisible(false);
178 m_pProgressBar->show();
179 m_pProgressBar->setStyleSheet("QProgressBar {border: 0px} QProgressBar::chunk {background-color: #da4453}");
180 }
181
182 m_pTab = new QTabWidget(this);
183 if(m_pTab) {
184 m_pTab->setTabsClosable(true);
185 m_pTab->setUsesScrollButtons(true);
186 m_pTab->setMovable(true);
187 m_pTab->setElideMode(Qt::TextElideMode::ElideRight);
188 pLayout->addWidget(m_pTab);
189 }
190 check = connect(m_pTab, &QTabWidget::currentChanged,
191 this, &CFrmWebBrowser::slotTabCurrentChanged);
192 Q_ASSERT(check);
193 check = connect(m_pTab, &QTabWidget::tabCloseRequested,
194 this, &CFrmWebBrowser::slotTabCloseRequested);
195 Q_ASSERT(check);
196
197 m_DownloadManager.hide();
198 QWebEngineProfile::defaultProfile()->setDownloadPath(m_pPara->GetDownloadFolder());
199 check = connect(QWebEngineProfile::defaultProfile(), &QWebEngineProfile::downloadRequested,
200 &m_DownloadManager, &CFrmDownloadManager::slotDownloadRequested);
201 Q_ASSERT(check);
202 check = connect(m_pPara, &CParameterWebBrowser::sigDownloadFolderChanged,
203 this, [&](){
204 QWebEngineProfile::defaultProfile()->setDownloadPath(m_pPara->GetDownloadFolder());
205 if(m_profile)
206 m_profile->setDownloadPath(m_pPara->GetDownloadFolder());
207 });
208 Q_ASSERT(check);
209
210 InitMenu(&m_Menu);
211 if(bMenuBar)
212 {
213 m_pMenuBar = new QMenuBar(this);
214 if(m_pMenuBar) {
215 m_Menu.setTitle(tr("Operate"));
216 m_pMenuBar->addMenu(&m_Menu);
217 pLayout->setMenuBar(m_pMenuBar);
218 }
219 }
220}
221
222CFrmWebBrowser::~CFrmWebBrowser()
223{
224 qDebug(log) << Q_FUNC_INFO;
225 if(m_pToolBar) {
226 m_pToolBar->deleteLater();
227 m_pToolBar = nullptr;
228 }
229 if(m_pTab) {
230 m_pTab->deleteLater();
231 m_pTab = nullptr;
232 }
233
234 if(m_pPara->GetClearCookie() && m_profile)
235 m_profile->cookieStore()->deleteAllCookies();
236 if(m_pPara->GetClearHttpCache() && m_profile)
237 m_profile->clearHttpCache();
238}
239
240QMenu* CFrmWebBrowser::GetMenu(QWidget *parent)
241{
242 if(m_Menu.actions().isEmpty())
243 return nullptr;
244 return &m_Menu;
245}
246
247QWebEngineView* CFrmWebBrowser::CreateWindow(
248 QWebEnginePage::WebWindowType type, bool offTheRecord)
249{
250 qDebug(log) << "Create window:" << type;
251
252 CFrmWebView* pView = nullptr;
253 switch (type) {
254 case QWebEnginePage::WebBrowserTab: {
255 auto pTab = CreateTab(&pView, offTheRecord);
256 int index = m_pTab->addTab(pTab, pView->favIcon(), tr("New page"));
257 if(-1 < index)
258 m_pTab->setCurrentIndex(index);
259 break;
260 }
261 case QWebEnginePage::WebBrowserBackgroundTab: {
262 auto pTab = CreateTab(&pView, offTheRecord);
263 int index = m_pTab->currentIndex();
264 m_pTab->addTab(pTab, pView->favIcon(), tr("New page"));
265 if(-1 < index && index != m_pTab->currentIndex())
266 m_pTab->setCurrentIndex(index);
267 break;
268 }
269 case QWebEnginePage::WebBrowserWindow: {
270 auto pWin = new CFrmWebBrowser(m_pPara, true);
271 if(pWin) {
272 pView = qobject_cast<CFrmWebView*>(
273 pWin->CreateWindow(QWebEnginePage::WebBrowserTab));
274 pWin->setAttribute(Qt::WA_DeleteOnClose);
275 auto pMainWin = RabbitCommon::CTools::GetMainWindow();
276 if(pMainWin)
277 pWin->resize(pMainWin->frameGeometry().width(),
278 pMainWin->frameGeometry().height());
279 pWin->show();
280 }
281 break;
282 }
283 case QWebEnginePage::WebDialog: {
284 // Test: Resource\html\TestQWebEnginePageWebDialog.html
285 auto popup = new CFrmPopup(GetProfile(offTheRecord), this);
286 pView = popup->GetView();
287 }
288 }
289
290 return pView;
291}
292
293void CFrmWebBrowser::SetConnect(CFrmWebView* pWeb)
294{
295 bool check = false;
296 if(!pWeb) return;
297 check = connect(pWeb, &CFrmWebView::sigDevToolsRequested,
298 this, [&](){
299 if(m_pInspector)
300 m_pInspector->setChecked(true);
301 });
302 Q_ASSERT(check);
303 check = connect(pWeb, &CFrmWebView::sigWebActionEnabledChanged,
304 this, [this, pWeb](QWebEnginePage::WebAction webAction, bool enabled){
305 if(!IsCurrentView(pWeb)) return;
306 switch(webAction){
307 case QWebEnginePage::WebAction::Back:
308 m_pBack->setEnabled(enabled);
309 break;
310 case QWebEnginePage::WebAction::Forward:
311 m_pForward->setEnabled(enabled);
312 break;
313 case QWebEnginePage::WebAction::Reload: {
314 m_pRefresh->setEnabled(enabled);
315 if(m_pRefresh->isEnabled())
316 m_pToolBar->insertAction(m_pUrl, m_pRefresh);
317 else
318 m_pToolBar->removeAction(m_pRefresh);
319 break;
320 }
321 case QWebEnginePage::WebAction::Stop: {
322 m_pStop->setEnabled(enabled);
323 if(m_pStop->isEnabled())
324 m_pToolBar->insertAction(m_pUrl, m_pStop);
325 else
326 m_pToolBar->removeAction(m_pStop);
327 break;
328 }
329 default:
330 break;
331 }
332 });
333 check = connect(pWeb, &QWebEngineView::urlChanged,
334 this, [&](const QUrl &url){
335 CFrmWebView* pWeb = qobject_cast<CFrmWebView*>(sender());
336 if(IsCurrentView(pWeb))
337 m_pUrlLineEdit->setText(url.toString());
338 });
339 Q_ASSERT(check);
340 check = connect(pWeb, &CFrmWebView::titleChanged,
341 this, [&](const QString &title) {
342 CFrmWebView* pWeb = qobject_cast<CFrmWebView*>(sender());
343 int index = IndexOfTab(pWeb);
344 if(-1 < index) {
345 m_pTab->setTabText(index, title);
346 setWindowTitle(title);
347 emit sigUpdateTitle();
348 }
349 });
350 Q_ASSERT(check);
351 check = connect(pWeb, &CFrmWebView::favIconChanged,
352 this, [&](const QIcon &icon){
353 CFrmWebView* pWeb = qobject_cast<CFrmWebView*>(sender());
354 int index = IndexOfTab(pWeb);
355 if(-1 < index) {
356 m_pTab->setTabIcon(index, icon);
357 setWindowIcon(icon);
358 emit sigUpdateTitle();
359 }
360 });
361 Q_ASSERT(check);
362 check = connect(pWeb, &CFrmWebView::sigLinkHovered,
363 this, &CFrmWebBrowser::sigInformation);
364 Q_ASSERT(check);
365 check = connect(pWeb, &CFrmWebView::sigCloseRequested,
366 this, &CFrmWebBrowser::slotViewCloseRequested);
367 Q_ASSERT(check);
368 check = connect(pWeb, &CFrmWebView::loadProgress,
369 this, [&](int progress){
370 CFrmWebView* pWeb = qobject_cast<CFrmWebView*>(sender());
371 if(IsCurrentView(pWeb))
372 m_pProgressBar->setValue(progress);
373 });
374 Q_ASSERT(check);
375 m_pProgressBar->setValue(pWeb->progress());
376#if QT_VERSION >= QT_VERSION_CHECK(6, 2, 0)
377 check = connect(pWeb, &CFrmWebView::printFinished,
378 this, &CFrmWebBrowser::slotPrintFinished);
379 Q_ASSERT(check);
380 check = connect(pWeb, &CFrmWebView::pdfPrintingFinished,
381 this, &CFrmWebBrowser::slotPdfPrintingFinished);
382 Q_ASSERT(check);
383#endif
384}
385
386QWebEngineProfile* CFrmWebBrowser::GetProfile(bool offTheRecord)
387{
388 if(offTheRecord)
389 return QWebEngineProfile::defaultProfile();
390 if(m_profile)
391 return m_profile.get();
392
393 QSettings set(RabbitCommon::CDir::Instance()->GetDirUserData()
394 + QDir::separator() + "WebBrowser.ini",
395 QSettings::IniFormat);
396 QString name = "io.github.KangLin.RabbitRemoteControl";
397#if QT_VERSION >= QT_VERSION_CHECK(6, 9, 0)
398 name += QLatin1StringView(qWebEngineChromiumVersion());
399 name = set.value("Profile/Name", name).toString();
400 QWebEngineProfileBuilder profileBuilder;
401 m_profile.reset(profileBuilder.createProfile(name));
402#else
403 name = set.value("Profile/Name", name).toString();
404 m_profile.reset(new QWebEngineProfile(name));
405#endif
406 if(!m_profile)
407 return QWebEngineProfile::defaultProfile();
408
409 set.setValue("Profile/Name", name);
410
411 m_profile->settings()->setAttribute(QWebEngineSettings::PluginsEnabled, true);
412 m_profile->settings()->setAttribute(QWebEngineSettings::DnsPrefetchEnabled, true);
413 m_profile->settings()->setAttribute(QWebEngineSettings::LocalContentCanAccessRemoteUrls, true);
414 m_profile->settings()->setAttribute(QWebEngineSettings::LocalContentCanAccessFileUrls, false);
415#if QT_VERSION >= QT_VERSION_CHECK(5, 6, 0)
416 m_profile->settings()->setAttribute(QWebEngineSettings::FullScreenSupportEnabled, true);
417#endif
418#if QT_VERSION >= QT_VERSION_CHECK(5, 7, 0)
419 m_profile->settings()->setAttribute(QWebEngineSettings::ScreenCaptureEnabled, true);
420#endif
421#if QT_VERSION >= QT_VERSION_CHECK(5, 8, 0)
422 m_profile->settings()->setAttribute(QWebEngineSettings::AllowRunningInsecureContent, true);
423#endif
424#if QT_VERSION > QT_VERSION_CHECK(6, 0, 0)
425 m_profile->settings()->setAttribute(QWebEngineSettings::PlaybackRequiresUserGesture, false);
426#endif
427 m_profile->setDownloadPath(m_pPara->GetDownloadFolder());
428 bool check = connect(m_profile.get(), &QWebEngineProfile::downloadRequested,
429 &m_DownloadManager, &CFrmDownloadManager::slotDownloadRequested);
430 Q_ASSERT(check);
431 qDebug(log) << "User agent:" << m_profile->httpUserAgent()
432 << "Persistent path:" << m_profile->persistentStoragePath()
433 << "Cache path:" << m_profile->cachePath()
434 << "Storage name:" << m_profile->storageName()
435 << "Cookie:" << m_profile->cookieStore()
436 << "Is off the Record:" << m_profile->isOffTheRecord()
437 << "Download:" << m_profile->downloadPath();
438 return m_profile.get();
439}
440
441CFrmWebView *CFrmWebBrowser::CreateWebView(bool offTheRecord)
442{
443 auto pView = new CFrmWebView(this);
444 if(pView) {
445 auto profile = GetProfile(offTheRecord);
446// #if QT_VERSION >= QT_VERSION_CHECK(6, 8, 0)
447// profile->setPersistentPermissionsPolicy(QWebEngineProfile::PersistentPermissionsPolicy::AskEveryTime);
448// #endif
449 auto page = new QWebEnginePage(profile, pView);
450 pView->setPage(page);
451 }
452 return pView;
453}
454
455QWidget* CFrmWebBrowser::CreateTab(CFrmWebView **view, bool offTheRecord)
456{
457 QSplitter *pSplitter = new QSplitter(Qt::Vertical, this);
458 if(pSplitter) {
459 pSplitter->setSizePolicy(QSizePolicy::Expanding, QSizePolicy::Expanding);
460 //pSplitter->setContentsMargins(0, 0, 0, 0);
461 CFrmWebView* pWeb = nullptr;
462 if(view) {
463 if(*view) {
464 pWeb = *view;
465 } else {
466 pWeb = CreateWebView(offTheRecord);
467 *view = pWeb;
468 }
469 } else {
470 pWeb = CreateWebView(offTheRecord);
471 }
472 if(pWeb) {
473 pSplitter->addWidget(pWeb);
474 SetConnect(pWeb);
475 }
476 }
477 return pSplitter;
478}
479
480CFrmWebView *CFrmWebBrowser::CurrentView(ViewType type)
481{
482 auto w = m_pTab->currentWidget();
483 if(!w) return nullptr;
484 QSplitter *pSplitter = qobject_cast<QSplitter*>(w);
485 if(!pSplitter) return nullptr;
486 int index = (int)type;
487 if(0 > index && pSplitter->count() <= index) return nullptr;
488 return qobject_cast<CFrmWebView*>(pSplitter->widget(index));
489}
490
491CFrmWebView* CFrmWebBrowser::GetView(int index, ViewType type)
492{
493 if(0 > index || m_pTab->count() <= index) return nullptr;
494 auto w = m_pTab->widget(index);
495 if(!w) return nullptr;
496 QSplitter *pSplitter = qobject_cast<QSplitter*>(w);
497 if(!pSplitter) return nullptr;
498 int idx = (int)type;
499 if(0 > idx && pSplitter->count() <= idx) return nullptr;
500 return qobject_cast<CFrmWebView*>(pSplitter->widget(idx));
501}
502
503bool CFrmWebBrowser::IsCurrentView(CFrmWebView *pView)
504{
505 auto w = m_pTab->currentWidget();
506 if(!w) return false;
507 QSplitter *pSplitter = qobject_cast<QSplitter*>(w);
508 if(!pSplitter) return false;
509 return -1 != pSplitter->indexOf(pView);
510}
511
512int CFrmWebBrowser::IndexOfTab(CFrmWebView *pView)
513{
514 int nRet = -1;
515 if(!pView) return nRet;
516 QWidget* p = qobject_cast<QWidget*>(pView->parent());
517 if(!p) return nRet;
518 nRet = m_pTab->indexOf(p);
519 return nRet;
520}
521
522int CFrmWebBrowser::InitMenu(QMenu *pMenu)
523{
524 bool check = false;
525 if(!pMenu) return 0;
526 pMenu->addAction(m_pBack);
527 pMenu->addAction(m_pForward);
528 pMenu->addAction(m_pRefresh);
529 m_pStop = pMenu->addAction(
530 QIcon::fromTheme("media-playback-stop"), tr("Stop"), this, [&](){
531 CFrmWebView* pWeb = CurrentView();
532 if(pWeb && pWeb->page())
533 pWeb->page()->action(QWebEnginePage::Stop)->trigger();
534 });
535 m_pStop->setEnabled(false);
536 m_pStop->setShortcuts(QKeySequence::Cancel);
537 m_pStop->setStatusTip(m_pStop->text());
538
539 pMenu->addSeparator();
540 pMenu->addAction(m_pAddPage);
541 m_pAddPageIncognito = pMenu->addAction(
542 QIcon::fromTheme("add"), tr("Add incognito tab"),
543 this, [&](){
544 CreateWindow(QWebEnginePage::WebBrowserTab, true);
545 if(!m_pPara->GetTabUrl().isEmpty()) {
546 m_pUrlLineEdit->setText(m_pPara->GetTabUrl());
547 slotReturnPressed();
548 }
549 });
550 m_pAddPageIncognito->setStatusTip(m_pAddPageIncognito->text());
551 m_pAddWindow = pMenu->addAction(
552 QIcon::fromTheme("add"), tr("Add window"),
553 this, [&](){
554 CreateWindow(QWebEnginePage::WebBrowserWindow);
555 });
556 m_pAddWindow->setVisible(false);
557 m_pAddWindow->setStatusTip(m_pAddWindow->text());
558 m_pAddWindowIncognito = pMenu->addAction(
559 QIcon::fromTheme("add"), tr("Add Incognito Window"),
560 this, [&](){
561 CreateWindow(QWebEnginePage::WebBrowserWindow, true);
562 });
563 m_pAddWindowIncognito->setVisible(false);
564 m_pAddWindowIncognito->setStatusTip(m_pAddWindowIncognito->text());
565
566 pMenu->addSeparator();
567 m_pFind = pMenu->addAction(
568 QIcon::fromTheme("edit-find"), tr("&Find"), this,
569 [&](){
570 CFrmWebView* pWeb = CurrentView();
571 if(pWeb) {
572 bool ok = false;
573 if(pWeb->selectedText().isEmpty()) {
574 if(QApplication::clipboard()
575 && !QApplication::clipboard()->text().isEmpty())
576 m_szFindText = QApplication::clipboard()->text();
577 } else {
578 m_szFindText = pWeb->selectedText();
579 }
580 QString search = QInputDialog::getText(
581 this, tr("Find"),
582 tr("Find:"), QLineEdit::Normal,
583 m_szFindText, &ok);
584 if (ok && !search.isEmpty()) {
585 m_szFindText = search;
586#if QT_VERSION >= QT_VERSION_CHECK(6, 0, 0)
587 pWeb->findText(m_szFindText, QWebEnginePage::FindFlags(),
588 [&](const QWebEngineFindTextResult& result){
589 if (result.numberOfMatches() == 0) {
590 emit sigInformation(tr("\"%1\" not found.").arg(m_szFindText));
591 } else {
592 emit sigInformation(tr("\"%1\" found: %2/%3").arg(m_szFindText, QString::number(result.activeMatch()), QString::number(result.numberOfMatches())));
593 }
594 });
595#else
596 pWeb->findText(m_szFindText, QWebEnginePage::FindFlags(), [this](bool found) {
597 if (!found)
598 emit sigInformation(tr("\"%1\" not found.").arg(m_szFindText));
599 });
600#endif
601 }
602 }
603 });
604 m_pFind->setShortcuts(QKeySequence::Find);
605 m_pFind->setStatusTip(m_pFind->text());
606
607 m_pFindNext = pMenu->addAction(
608 QIcon::fromTheme("go-next"), tr("Find &Next"), this,
609 [this]() {
610 CFrmWebView* pWeb = CurrentView();
611 if(pWeb && !m_szFindText.isEmpty()) {
612 pWeb->findText(m_szFindText);
613 }
614 });
615 m_pFindNext->setShortcuts(QKeySequence::FindNext);
616 m_pFindNext->setText(m_pFindNext->text());
617
618 m_pFindPrevious = pMenu->addAction(
619 QIcon::fromTheme("go-previous"), tr("Find &Previous"), this,
620 [&]() {
621 CFrmWebView* pWeb = CurrentView();
622 if(pWeb && !m_szFindText.isEmpty()) {
623 pWeb->findText(m_szFindText, QWebEnginePage::FindBackward);
624 }
625 });
626 m_pFindPrevious->setShortcuts(QKeySequence::FindPrevious);
627 m_pFindPrevious->setStatusTip(m_pFindPrevious->text());
628
629 pMenu->addSeparator();
630 m_pZoomOriginal = pMenu->addAction(
631 QIcon::fromTheme("zoom-original"), tr("Original"));
632 m_pZoomOriginal->setShortcut(QKeySequence(Qt::CTRL | Qt::Key_0));
633 m_pZoomOriginal->setStatusTip(tr("Original"));
634 m_pZoomOriginal->setToolTip(tr("Original"));
635 check = connect(m_pZoomOriginal, &QAction::triggered, this,
636 [&](){
637 CFrmWebView* pWeb = CurrentView();
638 if(pWeb)
639 pWeb->setZoomFactor(1.0);
640 });
641 Q_ASSERT(check);
642 m_pZoomIn = pMenu->addAction(QIcon::fromTheme("zoom-in"), tr("Zoom in"));
643 m_pZoomIn->setShortcuts(QKeySequence::ZoomIn);
644 m_pZoomIn->setStatusTip(tr("Zoom in"));
645 m_pZoomIn->setToolTip(tr("Zoom in"));
646 check = connect(
647 m_pZoomIn, &QAction::triggered, this,
648 [&](){
649 CFrmWebView* pWeb = CurrentView();
650 if(pWeb)
651 pWeb->setZoomFactor(pWeb->zoomFactor() + 0.1);
652 });
653 Q_ASSERT(check);
654 m_pZoomOut = pMenu->addAction(
655 QIcon::fromTheme("zoom-out"), tr("Zoom out"));
656 m_pZoomOut->setShortcuts(QKeySequence::ZoomOut);
657 m_pZoomOut->setStatusTip(tr("Zoom out"));
658 m_pZoomOut->setToolTip(tr("Zoom out"));
659 check = connect(
660 m_pZoomOut, &QAction::triggered, this,
661 [&](){
662 CFrmWebView* pWeb = CurrentView();
663 if(pWeb)
664 pWeb->setZoomFactor(pWeb->zoomFactor() - 0.1);
665 });
666 Q_ASSERT(check);
667
668 pMenu->addSeparator();
669#if QT_VERSION >= QT_VERSION_CHECK(6, 2, 0)
670 m_pPrint = pMenu->addAction(
671 QIcon::fromTheme("document-print"), tr("Print"),
672 this, &CFrmWebBrowser::slotPrint);
673 m_pPrint->setVisible(false);
674 m_pPrint->setShortcuts(QKeySequence::Print);
675 m_pPrintToPdf = pMenu->addAction(
676 QIcon::fromTheme("document-print"), tr("Print to PDF"),
677 this, &CFrmWebBrowser::slotPrintToPdf);
678#endif
679
680 pMenu->addAction(m_pDownload);
681 if(!m_pInspector) {
682 m_pInspector = pMenu->addAction(QIcon::fromTheme("tools"), tr("Inspector"));
683 check = connect(m_pInspector, &QAction::toggled,
684 this, &CFrmWebBrowser::slotInspector);
685 Q_ASSERT(check);
686 m_pInspector->setCheckable(true);
687 m_pInspector->setEnabled(false);
688 m_pInspector->setShortcuts({
689 QKeySequence(Qt::CTRL | Qt::SHIFT | Qt::Key_I),
690 QKeySequence(Qt::Key_F12)
691 });
692 }
693
694 EnableAction(false);
695 return 0;
696}
697
698int CFrmWebBrowser::Start()
699{
700 int nRet = 0;
701 if(m_pTab->count() == 0) {
702 // Add new web view
703 m_pAddPage->trigger();
704 }
705 return nRet;
706}
707
708int CFrmWebBrowser::Stop()
709{
710 int nRet = 0;
711
712 for(int i = 0; i < m_pTab->count(); i++) {
713 auto v = GetView(i);
714 if(!v) continue;
715 v->stop();
716 }
717
718 return nRet;
719}
720
721void CFrmWebBrowser::slotTabCurrentChanged(int index)
722{
723 if(-1 == index) return;
724 CFrmWebView* pWeb = CurrentView();
725 if(pWeb) {
726 setWindowTitle(pWeb->title());
727 setWindowIcon(pWeb->icon());
728 m_pUrlLineEdit->setText(pWeb->url().toString());
729 m_pProgressBar->setValue(pWeb->progress());
730 EnableAction(true);
731 auto page = pWeb->page();
732 if(page) {
733 auto action = page->action(QWebEnginePage::Back);
734 if(action && m_pBack) {
735 m_pBack->setEnabled(action->isEnabled());
736 }
737 action = page->action(QWebEnginePage::Forward);
738 if(action && m_pForward) {
739 m_pForward->setEnabled(action->isEnabled());
740 }
741 action = page->action(QWebEnginePage::Reload);
742 if(action && m_pRefresh)
743 m_pRefresh->setEnabled(action->isEnabled());
744 if(m_pRefresh->isEnabled())
745 m_pToolBar->insertAction(m_pUrl, m_pRefresh);
746 else
747 m_pToolBar->removeAction(m_pRefresh);
748 action = page->action(QWebEnginePage::Stop);
749 if(action && m_pStop)
750 m_pStop->setEnabled(action->isEnabled());
751 if(m_pStop->isEnabled())
752 m_pToolBar->insertAction(m_pUrl, m_pStop);
753 else
754 m_pToolBar->removeAction(m_pStop);
755 if(m_pInspector) {
756 m_pInspector->setChecked(CurrentView(ViewType::DevTools));
757 }
758 }
759 } else {
760 setWindowTitle(tr("Web browser"));
761 setWindowIcon(QIcon::fromTheme("web-browser"));
762 m_pUrlLineEdit->setText("");
763 m_pProgressBar->setValue(100);
764 EnableAction(false);
765 if(m_pInspector)
766 m_pInspector->setChecked(false);
767 }
768 emit sigUpdateTitle();
769}
770
771void CFrmWebBrowser::EnableAction(bool enable)
772{
773 if(m_pBack)
774 m_pBack->setEnabled(false);
775 if(m_pForward)
776 m_pForward->setEnabled(false);
777 if(m_pRefresh)
778 m_pRefresh->setEnabled(enable);
779 if(m_pStop)
780 m_pStop->setEnabled(false);
781 if(m_pFind)
782 m_pFind->setEnabled(enable);
783 if(m_pFindNext)
784 m_pFindNext->setEnabled(enable);
785 if(m_pFindPrevious)
786 m_pFindPrevious->setEnabled(enable);
787 if(m_pZoomOriginal)
788 m_pZoomOriginal->setEnabled(enable);
789 if(m_pZoomIn)
790 m_pZoomIn->setEnabled(enable);
791 if(m_pZoomOut)
792 m_pZoomOut->setEnabled(enable);
793 if(m_pInspector)
794 m_pInspector->setEnabled(enable);
795}
796
797void CFrmWebBrowser::slotTabCloseRequested(int index)
798{
799 qDebug(log) << "slotTabCloseRequested:" << index;
800 if(-1 == index) return;
801 auto pView = m_pTab->widget(index);
802 if(pView)
803 pView->deleteLater();
804 m_pTab->removeTab(index);
805}
806
807void CFrmWebBrowser::slotViewCloseRequested()
808{
809 CFrmWebView* p = qobject_cast<CFrmWebView*>(sender());
810 if(!p) return;
811 int index = IndexOfTab(p);
812 slotTabCloseRequested(index);
813}
814
815void CFrmWebBrowser::slotReturnPressed()
816{
817 QUrl u = QUrl::fromUserInput(m_pUrlLineEdit->text());
818 qDebug(log) << u << m_pUrlLineEdit->text();
819 if(u.isEmpty()) {
820 QString szSearch;
821 if(m_pPara) {
822 szSearch = m_pPara->GetSearchEngine();
823 u = szSearch.replace(m_pPara->GetSearchRelaceString(),
824 QUrl::toPercentEncoding(m_pUrlLineEdit->text()));
825 }
826 }
827 qDebug(log) << u << m_pUrlLineEdit->text();
828 emit sigInformation(u.toString());
829 CFrmWebView* pWeb = CurrentView();
830 if(!pWeb)
831 pWeb = qobject_cast<CFrmWebView*>(CreateWindow(QWebEnginePage::WebBrowserTab));
832 pWeb->load(u);
833 if(m_pGo->isVisible())
834 m_pGo->setVisible(false);
835}
836
837void CFrmWebBrowser::slotInspector(bool checked)
838{
839 CFrmWebView* pWeb = CurrentView();
840 auto dev = CurrentView(ViewType::DevTools);
841 if(pWeb && pWeb->page() && checked) {
842 if(!dev) {
843 auto w = m_pTab->currentWidget();
844 if(!w) return;
845 QSplitter *pSplitter = qobject_cast<QSplitter*>(w);
846 if(!pSplitter || 1 != pSplitter->count()) return;
847 dev = CreateWebView(pWeb->page()->profile()->isOffTheRecord());
848 if(dev) {
849 dev->show();
850 pSplitter->addWidget(dev);
851 bool check = connect(pWeb, &CFrmWebView::sigDevToolsRequested,
852 this, [&](){
853 if(m_pInspector)
854 m_pInspector->setChecked(true);
855 });
856 Q_ASSERT(check);
857 check = connect(dev, &CFrmWebView::sigCloseRequested,
858 this, [this]() {
859 m_pInspector->setChecked(false);
860 });
861 Q_ASSERT(check);
862 }
863 }
864 if(dev) {
865 pWeb->page()->setDevToolsPage(dev->page());
866 if(dev->isHidden())
867 dev->show();
868 }
869 } else {
870 pWeb->page()->setDevToolsPage(nullptr);
871 if(dev) {
872 dev->setParent(nullptr);
873 dev->deleteLater();
874 }
875 }
876}
877
878int CFrmWebBrowser::Load(QSettings &set)
879{
880 if(m_pPara && m_pPara->GetOpenPrevious()) {
881 set.beginGroup("OpenPrevious");
882 int nCount = 0;
883 nCount = set.value("Count", 0).toInt();
884 int nCurrent = set.value("Current", -1).toInt();
885 for(int i = 0; i < nCount; i++)
886 {
887 QString u = set.value("Url/" + QString::number(i)).toString();
888 auto pView = CreateWindow(QWebEnginePage::WebBrowserTab);
889 pView->load(QUrl(u));
890
891 QByteArray history;
892 history = set.value("History/" + QString::number(i)).toByteArray();
893 QDataStream d(&history, QIODevice::ReadWrite);
894 d >> *pView->history();
895 }
896 if(-1 < nCurrent && m_pTab->count() > nCurrent)
897 m_pTab->setCurrentIndex(nCurrent);
898 set.endGroup();
899 }
900 return 0;
901}
902
903int CFrmWebBrowser::Save(QSettings &set)
904{
905 if(m_pPara && m_pPara->GetOpenPrevious()) {
906 set.beginGroup("OpenPrevious");
907 set.setValue("Count", m_pTab->count());
908 set.setValue("Current", m_pTab->currentIndex());
909
910 for(int i = 0; i < m_pTab->count(); i++) {
911 auto v = GetView(i);
912 if(v) {
913 set.setValue("Url/" + QString::number(i), v->url().toString());
914 QByteArray history;
915 QDataStream d(&history, QIODevice::ReadWrite);
916 d << *v->history();
917 set.setValue("History/" + QString::number(i), history);
918 }
919 }
920
921 set.endGroup();
922 }
923 return 0;
924}
925
926void CFrmWebBrowser::slotPrint()
927{
928 CFrmWebView* pWeb = CurrentView();
929 if(pWeb) {
930#if QT_VERSION >= QT_VERSION_CHECK(6, 2, 0)
931 QPrinter printer;
932 pWeb->print(&printer);
933#endif
934 }
935}
936
937void CFrmWebBrowser::slotPrintFinished(bool success)
938{
939 if(success && m_pPara->GetPromptPrintFinished()) {
940 QMessageBox::information(this, tr("Print finished"),
941 tr("Successfully printed"));
942 }
943}
944
945void CFrmWebBrowser::slotPrintToPdf()
946{
947 CFrmWebView* pWeb = CurrentView();
948 if(pWeb) {
949 QString szPath;
950 szPath += RabbitCommon::CDir::Instance()->GetDirUserData()
951 + QDir::separator() + "pdf";
952 QDir d(szPath);
953 if(!d.exists())
954 d.mkpath(szPath);
955 szPath += QDir::separator() + pWeb->page()->title() + ".pdf";
956 qDebug(log) << "pdf:" << szPath;
957#if QT_VERSION >= QT_VERSION_CHECK(6, 2, 0)
958 pWeb->printToPdf(szPath);
959#endif
960 }
961}
962
963void CFrmWebBrowser::slotPdfPrintingFinished(const QString& szFile, bool success) {
964 if(success && m_pPara->GetPromptPrintFinished())
965 QMessageBox::information(this, tr("Print to PDF finished"),
966 tr("Successfully printed to PDF.") + "\n"
967 + tr("PDF file: ") + szFile);
968 qDebug(log) << "Print to PDF:" << szFile << success;
969}
970
971void CFrmWebBrowser::slotFullScreen(bool bFullScreen)
972{
973 if(sender() == this)
974 return;
975 if(bFullScreen) {
976 m_pToolBar->hide();
977 m_pProgressBar->hide();
978 m_pTab->tabBar()->setVisible(false);
979 m_szStyleSheet = m_pTab->styleSheet();
980 m_pTab->setStyleSheet("QTabWidget::pane{top:0px;left:0px;border:none;}");
981 } else {
982 m_pToolBar->show();
983 m_pProgressBar->show();
984 m_pTab->tabBar()->setVisible(true);
985 m_pTab->setStyleSheet(m_szStyleSheet);
986 if(CurrentView() && CurrentView()->page() && CurrentView()->page()->action(QWebEnginePage::ExitFullScreen))
987 CurrentView()->page()->action(QWebEnginePage::ExitFullScreen)->toggle();
988 }
989 emit sigFullScreen(bFullScreen);
990}
void sigUpdateTitle()
Title or icon changed.