Skip to content

Commit bb11ca6

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

17 files changed

Lines changed: 1209 additions & 18 deletions

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

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 <kl222@126.com>
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)