Skip to content

Commit 1f771df

Browse files
committed
Plugins::WebBrowser: add history
1 parent 0cfbed9 commit 1f771df

File tree

15 files changed

+1137
-18
lines changed

15 files changed

+1137
-18
lines changed

Plugins/FtpServer/ParameterFtpServer.cpp

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -8,7 +8,7 @@ CParameterFtpServer::CParameterFtpServer(QObject *parent, const QString &szPrefi
88
, m_nPort(21)
99
, m_bAnonymousLogin(true)
1010
, m_bReadOnly(true)
11-
, m_ConnectCount(-1)
11+
, m_ConnectCount(2)
1212
, m_bListenAll(true)
1313
{}
1414

Plugins/WebBrowser/CMakeLists.txt

Lines changed: 8 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -9,7 +9,7 @@ set(CMAKE_AUTORCC ON)
99
set(CMAKE_CXX_STANDARD 17)
1010
set(CMAKE_CXX_STANDARD_REQUIRED ON)
1111

12-
set(WebBrowser_QT_COMPONENTS Core Gui Widgets WebEngineWidgets WebEngineCore)
12+
set(WebBrowser_QT_COMPONENTS Core Gui Widgets WebEngineWidgets WebEngineCore Sql)
1313
find_package(Qt${QT_VERSION_MAJOR} COMPONENTS ${WebBrowser_QT_COMPONENTS})
1414
if(Qt${QT_VERSION_MAJOR}_FOUND)
1515
FOREACH(_COMPONENT ${WebBrowser_QT_COMPONENTS})
@@ -35,6 +35,9 @@ set(WebBrowser_SOURCE_FILES
3535
PasswordStore.cpp
3636
CaptureFullPage.cpp
3737
MultimediaRecord.cpp
38+
FrmHistory.cpp
39+
HistoryDatabase.cpp
40+
HistoryModel.cpp
3841
)
3942
set(WebBrowser_HEADER_FILES
4043
PluginWebBrowser.h
@@ -49,11 +52,15 @@ set(WebBrowser_HEADER_FILES
4952
PasswordStore.h
5053
CaptureFullPage.h
5154
MultimediaRecord.h
55+
FrmHistory.h
56+
HistoryDatabase.h
57+
HistoryModel.h
5258
)
5359
set(WebBrowser_UI_FILES
5460
FrmDownload.ui
5561
DlgSettings.ui
5662
DlgWebAuth.ui
63+
FrmHistory.ui
5764
Resource/Resource.qrc
5865
)
5966
if(QT_VERSION GREATER_EQUAL "6.7.0")

Plugins/WebBrowser/FrmDownloadManager.h

Lines changed: 2 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,6 @@
1-
#ifndef FRMDOWNLOADMANAGER_H
2-
#define FRMDOWNLOADMANAGER_H
1+
// Author: Kang Lin <[email protected]>
32

3+
#pragma once
44
#include <QWidget>
55
#include <QVBoxLayout>
66
#include "FrmDownload.h"
@@ -30,5 +30,3 @@ private Q_SLOTS:
3030
QVBoxLayout* m_pItems;
3131
CParameterWebBrowser* m_pPara;
3232
};
33-
34-
#endif // FRMDOWNLOADMANAGER_H

Plugins/WebBrowser/FrmHistory.cpp

Lines changed: 253 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,253 @@
1+
// Author: Kang Lin <[email protected]>
2+
3+
#include <QApplication>
4+
#include <QClipboard>
5+
#include <QMessageBox>
6+
#include <QMenu>
7+
#include <QLoggingCategory>
8+
#include "FrmHistory.h"
9+
#include "ui_FrmHistory.h"
10+
11+
static Q_LOGGING_CATEGORY(log, "WebBrowser.History")
12+
CFrmHistory::CFrmHistory(CHistoryDatabase *pDatabase, QWidget *parent)
13+
: QWidget(parent)
14+
, ui(new Ui::CFrmHistory)
15+
, m_pModelHistory(nullptr)
16+
{
17+
ui->setupUi(this);
18+
ui->treeView->hide();
19+
20+
setWindowTitle(tr("History"));
21+
22+
bool check = false;
23+
check = connect(ui->tableView, &QTableView::customContextMenuRequested,
24+
this, &CFrmHistory::slotCustomContextMenuRequested);
25+
ui->tableView->setSelectionMode(QAbstractItemView::SingleSelection);
26+
ui->tableView->setSelectionBehavior(QAbstractItemView::SelectRows);
27+
ui->tableView->setEditTriggers(QAbstractItemView::NoEditTriggers);
28+
29+
if(pDatabase) {
30+
m_pModelHistory = new CHistoryModel(pDatabase, this);
31+
if(m_pModelHistory) {
32+
ui->tableView->setModel(m_pModelHistory);
33+
}
34+
}
35+
36+
ui->tableView->resizeColumnsToContents();
37+
}
38+
39+
CFrmHistory::~CFrmHistory()
40+
{
41+
delete ui;
42+
}
43+
44+
void CFrmHistory::on_tableView_doubleClicked(const QModelIndex &index)
45+
{
46+
if(!index.isValid()) return;
47+
auto item = m_pModelHistory->getItem(index);
48+
emit sigOpenUrl(item.url);
49+
}
50+
51+
void CFrmHistory::slotCustomContextMenuRequested(const QPoint &pos)
52+
{
53+
auto index = ui->tableView->indexAt(pos);
54+
QMenu menu(this);
55+
// 添加菜单项
56+
// 只有在有效行上才显示某些菜单项
57+
if (index.isValid()) {
58+
// 获取当前行的数据
59+
QString url = ui->tableView->model()->data(
60+
index.siblingAtColumn(CHistoryModel::ColumnUrl)).toString();
61+
QString title = ui->tableView->model()->data(
62+
index.siblingAtColumn(CHistoryModel::ColumnTitle)).toString();
63+
64+
// 打开操作
65+
QAction *openAction = menu.addAction(QIcon::fromTheme("document-open"),
66+
tr("Open"));
67+
connect(openAction, &QAction::triggered, this, [this, url]() {
68+
emit sigOpenUrl(url);
69+
});
70+
71+
// 在新标签页中打开
72+
QAction *openNewTabAction = menu.addAction(
73+
QIcon::fromTheme("document-open"),
74+
tr("Open in new tab"));
75+
connect(openNewTabAction, &QAction::triggered, this, [this, url]() {
76+
emit sigOpenUrlInNewTab(url);
77+
});
78+
79+
// 复制URL
80+
QAction *copyUrlAction = menu.addAction(QIcon::fromTheme("edit-copy"),
81+
tr("Copy url"));
82+
connect(copyUrlAction, &QAction::triggered, this, [url]() {
83+
QApplication::clipboard()->setText(url);
84+
});
85+
86+
// 复制标题
87+
QAction *copyTitleAction = menu.addAction(
88+
QIcon::fromTheme("edit-copy"),
89+
tr("Copy title"));
90+
connect(copyTitleAction, &QAction::triggered, this, [title]() {
91+
QApplication::clipboard()->setText(title);
92+
});
93+
94+
menu.addSeparator();
95+
96+
// 删除操作
97+
QAction *deleteAction = menu.addAction(
98+
QIcon::fromTheme("edit-delete"), tr("Delete"));
99+
connect(deleteAction, &QAction::triggered, this, [this, index]() {
100+
onDeleteHistoryItem(index);
101+
});
102+
103+
// 删除所有类似网站
104+
QString domain = extractDomain(url);
105+
if (!domain.isEmpty()) {
106+
QAction *deleteDomainAction = menu.addAction(
107+
QIcon::fromTheme("edit-delete"),
108+
tr("Delete all urls from %1").arg(domain));
109+
connect(deleteDomainAction, &QAction::triggered, this, [this, domain]() {
110+
onDeleteHistoryByDomain(domain);
111+
});
112+
}
113+
114+
menu.addSeparator();
115+
116+
// 属性/详细信息
117+
QAction *propertiesAction = menu.addAction(
118+
QIcon::fromTheme("document-properties"), tr("Properties"));
119+
connect(propertiesAction, &QAction::triggered, this, [this, index]() {
120+
onShowHistoryProperties(index);
121+
});
122+
} else {
123+
// 在没有选中行的情况下显示的菜单项
124+
menu.addAction(tr("No item selected"))->setEnabled(false);
125+
}
126+
127+
menu.addSeparator();
128+
129+
// 总是显示的菜单项
130+
QAction *refreshAction = menu.addAction(
131+
QIcon::fromTheme("view-refresh"), tr("Refresh"));
132+
connect(refreshAction, &QAction::triggered, this, [&]() {
133+
if(m_pModelHistory)
134+
m_pModelHistory->refresh();
135+
});
136+
137+
QAction *clearAllAction = menu.addAction(
138+
QIcon::fromTheme("edit-clear"), tr("Clear all urls"));
139+
connect(clearAllAction, &QAction::triggered, this, [&]() {
140+
if(m_pModelHistory->removeRows(0, m_pModelHistory->rowCount()));
141+
});
142+
143+
// 设置菜单
144+
// QAction *settingsAction = menu.addAction(
145+
// QIcon::fromTheme("system-settings"), tr("Settings"));
146+
// connect(settingsAction, &QAction::triggered, this, &CFrmHistory::showHistorySettings);
147+
148+
// 4. 显示菜单
149+
menu.exec(ui->tableView->viewport()->mapToGlobal(pos));
150+
}
151+
152+
QString CFrmHistory::extractDomain(const QString &url)
153+
{
154+
QUrl qurl(url);
155+
if (qurl.isValid()) {
156+
QString host = qurl.host();
157+
// 移除 www. 前缀
158+
if (host.startsWith("www.")) {
159+
host = host.mid(4);
160+
}
161+
return host;
162+
}
163+
return QString();
164+
}
165+
166+
void CFrmHistory::onDeleteHistoryItem(const QModelIndex &index)
167+
{
168+
if (!index.isValid() || !m_pModelHistory) {
169+
return;
170+
}
171+
172+
QString title = ui->tableView->model()->data(
173+
index.siblingAtColumn(CHistoryModel::ColumnTitle)).toString();
174+
if(title.isEmpty()) {
175+
title = ui->tableView->model()->data(
176+
index.siblingAtColumn(CHistoryModel::ColumnUrl)).toString();
177+
}
178+
// 确认对话框
179+
QMessageBox::StandardButton reply = QMessageBox::question(
180+
this,
181+
tr("Delete the url"),
182+
tr("Are you sure you want to delete the url \"%1\"?").arg(title),
183+
QMessageBox::Yes | QMessageBox::No,
184+
QMessageBox::No
185+
);
186+
187+
if (reply == QMessageBox::Yes) {
188+
// 从模型中删除
189+
if (m_pModelHistory->removeRow(index.row())) {
190+
qDebug(log) << "History item deleted";
191+
}
192+
}
193+
}
194+
195+
void CFrmHistory::onDeleteHistoryByDomain(const QString &domain)
196+
{
197+
if (domain.isEmpty() || !m_pModelHistory) {
198+
return;
199+
}
200+
201+
// 确认对话框
202+
QMessageBox::StandardButton reply = QMessageBox::question(
203+
this,
204+
tr("Delete the url"),
205+
tr("Are you sure you want to delete all url from \"%1\"?").arg(domain),
206+
QMessageBox::Yes | QMessageBox::No,
207+
QMessageBox::No
208+
);
209+
210+
if (reply == QMessageBox::Yes) {
211+
m_pModelHistory->removeDomainItems(domain);
212+
}
213+
}
214+
215+
void CFrmHistory::onShowHistoryProperties(const QModelIndex &index)
216+
{
217+
if (!index.isValid() || !m_pModelHistory) {
218+
return;
219+
}
220+
221+
// 获取详细数据
222+
QString url = ui->tableView->model()->data(
223+
index.siblingAtColumn(CHistoryModel::ColumnUrl)).toString();
224+
QString title = ui->tableView->model()->data(
225+
index.siblingAtColumn(CHistoryModel::ColumnTitle)).toString();
226+
QString visitTime = ui->tableView->model()->data(
227+
index.siblingAtColumn(CHistoryModel::ColumnVisitTime)).toString();
228+
QString visitCount = ui->tableView->model()->data(
229+
index.siblingAtColumn(CHistoryModel::ColumnVisitCount)).toString();
230+
QString lastVisitTime = ui->tableView->model()->data(
231+
index.siblingAtColumn(CHistoryModel::ColumnLastVisitTime)).toString();
232+
233+
// 创建详细信息对话框
234+
QString details = QString(
235+
"<h3>%1</h3>"
236+
"<table border='0' cellspacing='5'>"
237+
"<tr><td><b>%2</b></td><td>%3</td></tr>"
238+
"<tr><td><b>%4</b></td><td>%5</td></tr>"
239+
"<tr><td><b>%6</b></td><td>%7</td></tr>"
240+
"<tr><td><b>%8</b></td><td>%9</td></tr>"
241+
"</table>")
242+
.arg(title.toHtmlEscaped())
243+
.arg(tr("Url:"))
244+
.arg(url.toHtmlEscaped())
245+
.arg(tr("Visit Count:"))
246+
.arg(visitCount)
247+
.arg(tr("Visit Time:"))
248+
.arg(visitTime)
249+
.arg(tr("Last Visit Time:"))
250+
.arg(lastVisitTime);
251+
252+
QMessageBox::information(this, tr("Properties"), details);
253+
}

Plugins/WebBrowser/FrmHistory.h

Lines changed: 37 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,37 @@
1+
// Author: Kang Lin <[email protected]>
2+
3+
#pragma once
4+
5+
#include <QWidget>
6+
#include "HistoryModel.h"
7+
8+
namespace Ui {
9+
class CFrmHistory;
10+
}
11+
12+
class CFrmHistory : public QWidget
13+
{
14+
Q_OBJECT
15+
16+
public:
17+
explicit CFrmHistory(CHistoryDatabase* pDatabase, QWidget *parent = nullptr);
18+
~CFrmHistory();
19+
20+
Q_SIGNALS:
21+
void sigOpenUrl(const QString& url);
22+
void sigOpenUrlInNewTab(const QString& url);
23+
24+
private slots:
25+
void on_tableView_doubleClicked(const QModelIndex &index);
26+
void slotCustomContextMenuRequested(const QPoint& pos);
27+
28+
private:
29+
QString extractDomain(const QString &url);
30+
void onDeleteHistoryItem(const QModelIndex &index);
31+
void onDeleteHistoryByDomain(const QString &domain);
32+
void onShowHistoryProperties(const QModelIndex &index);
33+
34+
private:
35+
Ui::CFrmHistory *ui;
36+
CHistoryModel* m_pModelHistory;
37+
};

Plugins/WebBrowser/FrmHistory.ui

Lines changed: 47 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,47 @@
1+
<?xml version="1.0" encoding="UTF-8"?>
2+
<ui version="4.0">
3+
<class>CFrmHistory</class>
4+
<widget class="QWidget" name="CFrmHistory">
5+
<property name="geometry">
6+
<rect>
7+
<x>0</x>
8+
<y>0</y>
9+
<width>400</width>
10+
<height>300</height>
11+
</rect>
12+
</property>
13+
<property name="windowTitle">
14+
<string>Form</string>
15+
</property>
16+
<layout class="QGridLayout" name="gridLayout">
17+
<item row="0" column="0">
18+
<widget class="QSplitter" name="splitter">
19+
<property name="orientation">
20+
<enum>Qt::Orientation::Horizontal</enum>
21+
</property>
22+
<widget class="QTreeView" name="treeView">
23+
<property name="sizePolicy">
24+
<sizepolicy hsizetype="Expanding" vsizetype="Expanding">
25+
<horstretch>1</horstretch>
26+
<verstretch>0</verstretch>
27+
</sizepolicy>
28+
</property>
29+
</widget>
30+
<widget class="QTableView" name="tableView">
31+
<property name="sizePolicy">
32+
<sizepolicy hsizetype="Expanding" vsizetype="Expanding">
33+
<horstretch>0</horstretch>
34+
<verstretch>0</verstretch>
35+
</sizepolicy>
36+
</property>
37+
<property name="contextMenuPolicy">
38+
<enum>Qt::ContextMenuPolicy::CustomContextMenu</enum>
39+
</property>
40+
</widget>
41+
</widget>
42+
</item>
43+
</layout>
44+
</widget>
45+
<resources/>
46+
<connections/>
47+
</ui>

0 commit comments

Comments
 (0)