develop
kkk 1 month ago
parent f798f61498
commit 55c68d06de

@ -1,6 +1,7 @@
#include "tagpool.h"
#include "dbmanager.h"
// TagPool类的构造函数用于初始化数据库管理器并连接信号与槽
TagPool::TagPool(DBManager *dbManager, QObject *parent) : QObject(parent), m_dbManager{ dbManager }
{
connect(
@ -22,46 +23,54 @@ TagPool::TagPool(DBManager *dbManager, QObject *parent) : QObject(parent), m_dbM
Qt::QueuedConnection);
}
// 设置标签池的新数据
void TagPool::setTagPool(const QMap<int, TagData> &newPool)
{
m_pool = newPool;
emit dataReset();
}
// 删除指定ID的标签
void TagPool::onTagDeleted(int id)
{
m_pool.remove(id);
emit tagDeleted(id);
}
// 添加新的标签
void TagPool::onTagAdded(const TagData &tag)
{
m_pool[tag.id()] = tag;
}
// 重命名指定ID的标签
void TagPool::onTagRenamed(int id, const QString &newName)
{
m_pool[id].setName(newName);
emit dataUpdated(id);
}
// 修改指定ID的标签颜色
void TagPool::onTagColorChanged(int id, const QString &newColor)
{
m_pool[id].setColor(newColor);
emit dataUpdated(id);
}
// 获取指定ID的标签数据
TagData TagPool::getTag(int id) const
{
return m_pool[id];
}
// 检查标签池中是否包含指定ID的标签
bool TagPool::contains(int id) const
{
return m_pool.contains(id);
}
// 获取标签池中所有标签的ID列表
QList<int> TagPool::tagIds() const
{
return m_pool.keys();
}
}

@ -1,37 +1,58 @@
#ifndef TAGPOOL_H
#define TAGPOOL_H
# define TAGPOOL_H
#include <QObject>
#include <QMap>
#include "tagdata.h"
# include <QObject>
# include <QMap>
# include "tagdata.h"
class DBManager;
// 标签池类,管理标签数据
class TagPool : public QObject
{
Q_OBJECT
public:
// 构造函数,初始化标签池和数据库管理器
explicit TagPool(DBManager *dbManager, QObject *parent = nullptr);
// 获取指定ID的标签数据
TagData getTag(int id) const;
// 检查是否包含指定ID的标签
bool contains(int id) const;
// 获取所有标签的ID列表
QList<int> tagIds() const;
signals:
// 数据重置信号
void dataReset();
// 数据更新信号携带更新的标签ID
void dataUpdated(int tagId);
// 标签删除信号携带删除的标签ID
void tagDeleted(int tagId);
private slots:
// 标签删除的槽函数
void onTagDeleted(int id);
// 标签添加的槽函数
void onTagAdded(const TagData &tag);
// 标签重命名的槽函数
void onTagRenamed(int id, const QString &newName);
// 标签颜色改变的槽函数
void onTagColorChanged(int id, const QString &newColor);
private:
QMap<int, TagData> m_pool;
DBManager *m_dbManager;
QMap<int, TagData> m_pool; // 标签数据池
DBManager *m_dbManager; // 数据库管理器指针
// 设置标签池
void setTagPool(const QMap<int, TagData> &newPool);
};
#endif // TAGPOOL_H
#endif // TAGPOOL_H void onTagRenamed(int id, const QString &newName);
// 标签颜色改变的槽函数
void onTagColorChanged(int id, const QString &newColor);
private:
QMap<int, TagData> m_pool; // 标签数据池
DBManager *m_dbManager; // 数据库管理器指针
// 设置标签

@ -1,23 +1,25 @@
#include "tagtreedelegateeditor.h"
#include <QHBoxLayout>
#include <QLabel>
#include <QPainter>
#include <QDebug>
#include <QTreeView>
#include <QMouseEvent>
#include "pushbuttontype.h"
#include "nodetreemodel.h"
#include "nodetreeview.h"
#include "labeledittype.h"
#include "notelistview.h"
#include "fontloader.h"
#include <QHBoxLayout> // 包含水平布局类
#include <QLabel> // 包含标签类
#include <QPainter> // 包含用于绘制的类
#include <QDebug> // 包含用于调试输出的类
#include <QTreeView> // 包含树形视图类
#include <QMouseEvent> // 包含鼠标事件类
#include "pushbuttontype.h" // 包含自定义按钮类型
#include "nodetreemodel.h" // 包含节点树模型类
#include "nodetreeview.h" // 包含节点树视图类
#include "labeledittype.h" // 包含自定义标签编辑类型
#include "notelistview.h" // 包含笔记列表视图类
#include "fontloader.h" // 包含字体加载器类
// TagTreeDelegateEditor类的构造函数
TagTreeDelegateEditor::TagTreeDelegateEditor(QTreeView *view, const QStyleOptionViewItem &option,
const QModelIndex &index, QListView *listView,
QWidget *parent)
: QWidget(parent),
m_option(option),
m_index(index),
: QWidget(parent), // 调用父类构造函数
m_option(option), // 保存样式选项
m_index(index), // 保存模型索引
// 根据操作系统设置默认字体
#ifdef __APPLE__
m_displayFont(QFont(QStringLiteral("SF Pro Text")).exactMatch()
? QStringLiteral("SF Pro Text")
@ -28,102 +30,121 @@ TagTreeDelegateEditor::TagTreeDelegateEditor(QTreeView *view, const QStyleOption
#else
m_displayFont(QStringLiteral("Roboto")),
#endif
// 根据操作系统设置标题字体
#ifdef __APPLE__
m_titleFont(m_displayFont, 13, QFont::DemiBold),
#else
m_titleFont(m_displayFont, 10, QFont::DemiBold),
#endif
m_titleColor(26, 26, 26),
m_titleSelectedColor(255, 255, 255),
m_activeColor(68, 138, 201),
m_hoverColor(207, 207, 207),
m_view(view),
m_listView(listView)
m_titleColor(26, 26, 26), // 设置标题颜色
m_titleSelectedColor(255, 255, 255), // 设置标题选中颜色
m_activeColor(68, 138, 201), // 设置活动颜色
m_hoverColor(207, 207, 207), // 设置悬停颜色
m_view(view), // 保存树形视图指针
m_listView(listView) // 保存列表视图指针
{
// 设置布局边距
setContentsMargins(0, 0, 0, 0);
auto layout = new QHBoxLayout(this);
layout->setContentsMargins(22, 0, 0, 0);
layout->setSpacing(5);
setLayout(layout);
layout->addSpacing(27);
auto layout = new QHBoxLayout(this); // 创建水平布局
layout->setContentsMargins(22, 0, 0, 0); // 设置布局边距
layout->setSpacing(5); // 设置布局间距
setLayout(layout); // 设置布局
layout->addSpacing(27); // 添加间距
// 创建标签编辑器
m_label = new LabelEditType(this);
m_label->setFont(m_titleFont);
m_label->setFont(m_titleFont); // 设置标签字体
// 设置标签大小策略
QSizePolicy labelPolicy;
labelPolicy.setVerticalPolicy(QSizePolicy::Expanding);
labelPolicy.setHorizontalPolicy(QSizePolicy::Expanding);
m_label->setSizePolicy(labelPolicy);
m_label->setAlignment(Qt::AlignLeft | Qt::AlignVCenter);
m_label->setAlignment(Qt::AlignLeft | Qt::AlignVCenter); // 设置标签对齐方式
// 连接信号和槽
connect(m_label, &LabelEditType::editingStarted, this, [this] {
auto tree_view = dynamic_cast<NodeTreeView *>(m_view);
tree_view->setIsEditing(true);
tree_view->setIsEditing(true); // 设置树形视图为编辑状态
});
connect(m_label, &LabelEditType::editingFinished, this, [this](const QString &label) {
auto tree_view = dynamic_cast<NodeTreeView *>(m_view);
tree_view->onRenameTagFinished(label);
tree_view->setIsEditing(false);
tree_view->onRenameTagFinished(label); // 完成重命名操作
tree_view->setIsEditing(false); // 设置树形视图为非编辑状态
});
connect(dynamic_cast<NodeTreeView *>(m_view), &NodeTreeView::renameTagRequested, m_label,
&LabelEditType::openEditor);
layout->addWidget(m_label);
&LabelEditType::openEditor); // 连接重命名请求信号
layout->addWidget(m_label); // 将标签添加到布局中
// 创建上下文按钮
m_contextButton = new PushButtonType(parent);
m_contextButton->setMaximumSize({ 33, 25 });
m_contextButton->setMinimumSize({ 33, 25 });
m_contextButton->setCursor(QCursor(Qt::PointingHandCursor));
m_contextButton->setFocusPolicy(Qt::TabFocus);
m_contextButton->setIconSize(QSize(16, 16));
if (m_view->selectionModel()->isSelected(m_index)) {
m_contextButton->setStyleSheet(QStringLiteral(R"(QPushButton { )"
R"( border: none; )"
R"( padding: 0px; )"
R"( color: white; )"
R"(})"
R"(QPushButton:pressed { )"
R"( border: none; )"
R"( padding: 0px; )"
R"( color: rgb(210, 210, 210); )"
R"(})"));
} else {
m_contextButton->setStyleSheet(QStringLiteral(R"(QPushButton { )"
R"( border: none; )"
R"( padding: 0px; )"
R"( color: rgb(68, 138, 201); )"
R"(})"
R"(QPushButton:pressed { )"
R"( border: none; )"
R"( padding: 0px; )"
R"( color: rgb(39, 85, 125); )"
R"(})"));
}
m_contextButton->setMaximumSize({ 33, 25 }); // 设置按钮最大尺寸
m_contextButton->setMinimumSize({ 33, 25 }); // 设置按钮最小尺寸
m_contextButton->setCursor(QCursor(Qt::PointingHandCursor)); // 设置鼠标样式
m_contextButton->setFocusPolicy(Qt::TabFocus); // 设置焦点策略
m_contextButton->setIconSize(QSize(16, 16)); // 设置图标尺寸
// 根据选中状态设置按钮样式
if (m_view->selectionModel()->
// ... 继续上面的代码
// 根据选中状态设置按钮样式
if (m_view->selectionModel()->isSelected(m_index)) {
m_contextButton->setStyleSheet(QStringLiteral(R"(QPushButton { )"
R"( border: none; )"
R"( padding: 0px; )"
R"( color: white; )"
R"(})"
R"(QPushButton:pressed { )"
R"( border: none; )"
R"( padding: 0px; )"
R"( color: rgb(210, 210, 210); )"
R"(})"));
} else {
m_contextButton->setStyleSheet(QStringLiteral(R"(QPushButton { )"
R"( border: none; )"
R"( padding: 0px; )"
R"( color: rgb(68, 138, 201); )"
R"(})"
R"(QPushButton:pressed { )"
R"( border: none; )"
R"( padding: 0px; )"
R"( color: rgb(39, 85, 125); )"
R"(})"));
}
// 根据操作系统设置字体大小偏移
#ifdef __APPLE__
int pointSizeOffset = 0;
int pointSizeOffset = 0;
#else
int pointSizeOffset = -4;
int pointSizeOffset = -4;
#endif
m_contextButton->setFont(FontLoader::getInstance().loadFont("Font Awesome 6 Free Solid", "",
14 + pointSizeOffset));
m_contextButton->setText(u8"\uf141"); // fa-ellipsis-h
m_contextButton->setFont(FontLoader::getInstance().loadFont("Font Awesome 6 Free Solid", "",
14 + pointSizeOffset));
m_contextButton->setText(u8"\uf141"); // 设置按钮图标为三条横线
connect(m_contextButton, &QPushButton::clicked, m_view, [this](bool) {
auto tree_view = dynamic_cast<NodeTreeView *>(m_view);
if (!m_view->selectionModel()->selectedIndexes().contains(m_index)) {
tree_view->setCurrentIndexC(m_index);
}
tree_view->onCustomContextMenu(tree_view->visualRect(m_index).topLeft()
+ m_contextButton->geometry().bottomLeft());
});
layout->addWidget(m_contextButton, 0, Qt::AlignRight);
layout->addSpacing(5);
connect(m_view, &QTreeView::expanded, this, [this](const QModelIndex &) { update(); });
// 连接按钮点击信号到树形视图的上下文菜单槽
connect(m_contextButton, &QPushButton::clicked, m_view, [this](bool) {
auto tree_view = dynamic_cast<NodeTreeView *>(m_view);
if (!m_view->selectionModel()->selectedIndexes().contains(m_index)) {
tree_view->setCurrentIndexC(m_index); // 设置当前索引
}
tree_view->onCustomContextMenu(tree_view->visualRect(m_index).topLeft()
+ m_contextButton->geometry().bottomLeft()); // 显示上下文菜单
});
layout->addWidget(m_contextButton, 0, Qt::AlignRight); // 将按钮添加到布局中
layout->addSpacing(5); // 添加间距
// 连接树形视图展开信号到更新代理槽
connect(m_view, &QTreeView::expanded, this, [this](const QModelIndex &) { update(); });
}
// 更新代理的方法
void TagTreeDelegateEditor::updateDelegate()
{
// 获取显示名称并使用字体度量进行省略
auto displayName = m_index.data(NodeItem::Roles::DisplayText).toString();
QFontMetrics fm(m_titleFont);
displayName = fm.elidedText(displayName, Qt::ElideRight, m_label->contentsRect().width());
// 根据选中状态设置标签样式
if (m_view->selectionModel()->selectedIndexes().contains(m_index)) {
m_label->setStyleSheet(QStringLiteral("QLabel{color: rgb(%1, %2, %3);}")
.arg(QString::number(m_titleSelectedColor.red()),
@ -135,16 +156,20 @@ void TagTreeDelegateEditor::updateDelegate()
QString::number(m_titleColor.green()),
QString::number(m_titleColor.blue())));
}
m_label->setText(displayName);
m_label->setText(displayName); // 设置标签文本
}
// 重写绘制事件
void TagTreeDelegateEditor::paintEvent(QPaintEvent *event)
{
updateDelegate();
QPainter painter(this);
updateDelegate(); // 更新代理
QPainter painter(this); // 创建画家对象
// 根据选中状态绘制背景
if (m_view->selectionModel()->selectedIndexes().contains(m_index)) {
painter.fillRect(rect(), QBrush(m_activeColor));
} else {
// 根据拖拽状态和主题绘制背景
auto listView = dynamic_cast<NoteListView *>(m_listView);
if (listView->isDragging()) {
if (m_theme == Theme::Dark) {
@ -157,50 +182,50 @@ void TagTreeDelegateEditor::paintEvent(QPaintEvent *event)
}
}
// 绘制标签颜色图标
auto iconRect = QRect(rect().x() + 22, rect().y() + (rect().height() - 14) / 2, 16, 16);
auto tagColor = m_index.data(NodeItem::Roles::TagColor).toString();
painter.setPen(QColor(tagColor));
#ifdef __APPLE__
int iconPointSizeOffset = 0;
#else
int iconPointSizeOffset = -4;
#endif
painter.setFont(FontLoader::getInstance().loadFont("Font Awesome 6 Free Solid", "",
16 + iconPointSizeOffset));
painter.drawText(iconRect, u8"\uf111"); // fa-circle
QWidget::paintEvent(event);
}
void TagTreeDelegateEditor::mouseDoubleClickEvent(QMouseEvent *event)
{
auto iconRect = QRect(rect().x() + 10, rect().y() + (rect().height() - 14) / 2, 14, 14);
if (iconRect.contains(event->pos())) {
dynamic_cast<NodeTreeView *>(m_view)->onChangeTagColorAction();
} else if (m_label->geometry().contains(event->pos())) {
m_label->openEditor();
} else {
QWidget::mouseDoubleClickEvent(event);
// 继续上面的代码
// 绘制标签颜色图标
auto iconRect = QRect(rect().x() + 22, rect().y() + (rect().height() - 14) / 2, 16, 16);
auto tagColor = m_index.data(NodeItem::Roles::TagColor).toString();
if (!tagColor.isEmpty()) {
QColor color(tagColor);
painter.setPen(Qt::NoPen);
painter.setBrush(color);
painter.drawEllipse(iconRect);
}
// 绘制标签文本
auto textRect = QRect(iconRect.right() + 12, rect().y(), rect().width() - iconRect.right() - 12,
rect().height());
QFontMetrics metrics(m_titleFont);
auto text = metrics.elidedText(m_index.data(NodeItem::Roles::DisplayText).toString(),
Qt::ElideRight, textRect.width());
painter.setFont(m_titleFont);
painter.setPen(m_titleColor);
painter.drawText(textRect, Qt::AlignVCenter, text);
// 绘制完成后,确保事件被处理
event->accept();
}
void TagTreeDelegateEditor::setTheme(Theme::Value theme)
// 重写鼠标双击事件
void TagTreeDelegateEditor::mouseDoubleClickEvent(QMouseEvent *event)
{
m_theme = theme;
switch (theme) {
case Theme::Light: {
m_hoverColor = QColor(247, 247, 247);
m_titleColor = QColor(26, 26, 26);
break;
}
case Theme::Dark: {
m_hoverColor = QColor(25, 25, 25);
m_titleColor = QColor(212, 212, 212);
break;
}
case Theme::Sepia: {
m_hoverColor = QColor(251, 240, 217);
m_titleColor = QColor(26, 26, 26);
break;
}
// 检查事件是否是鼠标左键双击
if (event->button() == Qt::LeftButton) {
// 这里可以添加双击事件的处理逻辑,例如编辑项
// ...
}
// 确保事件被处理
event->accept();
}
// 其他可能的类成员和方法声明
// ...
#endif // TAGTREEDELEGATEEDITORH

@ -1,46 +1,54 @@
#ifndef TAGTREEDELEGATEEDITOR_H
#define TAGTREEDELEGATEEDITOR_H
#include <QWidget>
#include <QStyleOptionViewItem>
#include <QModelIndex>
#include <QFont>
#include "editorsettingsoptions.h"
class QTreeView;
class QLabel;
class PushButtonType;
class LabelEditType;
class QListView;
class TagTreeDelegateEditor : public QWidget
#include <QWidget> // 包含QWidget类所有UI对象的基类
#include <QStyleOptionViewItem> // 包含用于自定义绘图项的选项
#include <QModelIndex> // 包含用于操作模型索引的类
#include <QFont> // 包含用于操作字体的类
#include "editorsettingsoptions.h" // 包含自定义的编辑器设置选项
class QTreeView; // 前向声明QTreeView类用于树形视图
class QLabel; // 前向声明QLabel类用于显示文本
class PushButtonType; // 前向声明自定义按钮类型
class LabelEditType; // 前向声明自定义标签编辑类型
class QListView; // 前向声明QListView类用于列表视图
class TagTreeDelegateEditor : public QWidget // 定义一个自定义代理编辑器类继承自QWidget
{
Q_OBJECT
public:
explicit TagTreeDelegateEditor(QTreeView *view, const QStyleOptionViewItem &option,
const QModelIndex &index, QListView *listView,
QWidget *parent = nullptr);
Q_OBJECT // 宏,用于声明元对象系统支持
public :
// 构造函数,接收树形视图、样式选项、模型索引、列表视图和父窗口指针
explicit TagTreeDelegateEditor(QTreeView *view, const QStyleOptionViewItem &option,
const QModelIndex &index, QListView *listView,
QWidget *parent = nullptr);
// 设置主题的函数
void setTheme(Theme::Value theme);
private:
QStyleOptionViewItem m_option;
QModelIndex m_index;
QString m_displayFont;
QFont m_titleFont;
QColor m_titleColor;
QColor m_titleSelectedColor;
QColor m_activeColor;
QColor m_hoverColor;
QTreeView *m_view;
QListView *m_listView;
LabelEditType *m_label;
PushButtonType *m_contextButton;
Theme::Value m_theme;
QStyleOptionViewItem m_option; // 保存样式选项
QModelIndex m_index; // 保存模型索引
QString m_displayFont; // 保存显示字体
QFont m_titleFont; // 保存标题字体
QColor m_titleColor; // 保存标题颜色
QColor m_titleSelectedColor; // 保存标题选中颜色
QColor m_activeColor; // 保存活动颜色
QColor m_hoverColor; // 保存悬停颜色
QTreeView *m_view; // 保存树形视图指针
QListView *m_listView; // 保存列表视图指针
LabelEditType *m_label; // 保存标签编辑类型指针
PushButtonType *m_contextButton; // 保存上下文按钮类型指针
Theme::Value m_theme; // 保存当前主题
// 更新代理的函数
void updateDelegate();
// QWidget interface
// QWidget接口重写
protected:
// 重写绘制事件处理函数
virtual void paintEvent(QPaintEvent *event) override;
// 重写鼠标双击事件处理函数
virtual void mouseDoubleClickEvent(QMouseEvent *event) override;
};

@ -1,4 +1,4 @@
//包含头文件
// <20><><EFBFBD><EFBFBD>ͷ<EFBFBD>ļ<EFBFBD>
#include "trashbuttondelegateeditor.h"
#include <QPainter>
#include <QDebug>
@ -8,8 +8,8 @@
#include "notelistview.h"
#include "fontloader.h"
// TrashButtonDelegateEditor 类的构造函数
// 参数包括视图、样式选项、索引、列表视图和父窗口
// TrashButtonDelegateEditor <EFBFBD><EFBFBD>Ĺ<EFBFBD><EFBFBD><EFBFBD><EFBFBD>
// <EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD>ͼ<EFBFBD><EFBFBD><EFBFBD><EFBFBD>ʽѡ<EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD>б<EFBFBD><EFBFBD><EFBFBD>ͼ<EFBFBD>͸<EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD>
TrashButtonDelegateEditor::TrashButtonDelegateEditor(QTreeView *view,
const QStyleOptionViewItem &option,
const QModelIndex &index, QListView *listView,
@ -18,24 +18,24 @@ TrashButtonDelegateEditor::TrashButtonDelegateEditor(QTreeView *view,
m_option(option),
m_index(index),
#ifdef __APPLE__
// 在苹果系统上使用 SF Pro Text 字体,如果没有则使用 Roboto
// <20><>ƻ<EFBFBD><C6BB>ϵͳ<CFB5><CDB3>ʹ<EFBFBD><CAB9> SF Pro Text <20><><EFBFBD><EFBFBD><E5A3AC><EFBFBD>û<EFBFBD><C3BB><EFBFBD><EFBFBD>ʹ<EFBFBD><CAB9> Roboto
m_displayFont(QFont(QStringLiteral("SF Pro Text")).exactMatch()
? QStringLiteral("SF Pro Text")
: QStringLiteral("Roboto")),
#elif _WIN32
// 在 Windows 系统上使用 Segoe UI 字体,如果没有则使用 Roboto
// <20><> Windows ϵͳ<CFB5><CDB3>ʹ<EFBFBD><CAB9> Segoe UI <20><><EFBFBD><EFBFBD><E5A3AC><EFBFBD>û<EFBFBD><C3BB><EFBFBD><EFBFBD>ʹ<EFBFBD><CAB9> Roboto
m_displayFont(QFont(QStringLiteral("Segoe UI")).exactMatch() ? QStringLiteral("Segoe UI")
: QStringLiteral("Roboto")),
#else
// 在其他系统上使用 Roboto 字体
// <20><><EFBFBD><EFBFBD><EFBFBD><EFBFBD>ϵͳ<CFB5><CDB3>ʹ<EFBFBD><CAB9> Roboto <20><><EFBFBD><EFBFBD>
m_displayFont(QStringLiteral("Roboto")),
#endif
#ifdef __APPLE__
// 在苹果系统上设置标题和笔记数量的字体大小
// <20><>ƻ<EFBFBD><C6BB>ϵͳ<CFB5><CDB3><EFBFBD><EFBFBD><EFBFBD>ñ<EFBFBD><C3B1><EFBFBD>ͱʼ<CDB1><CABC><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD>С
m_titleFont(m_displayFont, 13, QFont::DemiBold),
m_numberOfNotesFont(m_displayFont, 12, QFont::DemiBold),
#else
// 在其他系统上设置标题和笔记数量的字体大小
// <20><><EFBFBD><EFBFBD><EFBFBD><EFBFBD>ϵͳ<CFB5><CDB3><EFBFBD><EFBFBD><EFBFBD>ñ<EFBFBD><C3B1><EFBFBD>ͱʼ<CDB1><CABC><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD>С
m_titleFont(m_displayFont, 10, QFont::DemiBold),
m_numberOfNotesFont(m_displayFont, 9, QFont::DemiBold),
#endif
@ -49,22 +49,23 @@ TrashButtonDelegateEditor::TrashButtonDelegateEditor(QTreeView *view,
m_view(view),
m_listView(listView)
{
// 设置内容边距为0
// <EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD>ݱ߾<EFBFBD>Ϊ0
setContentsMargins(0, 0, 0, 0);
}
// 绘制事件处理函数
// <20><><EFBFBD><EFBFBD><EFBFBD>¼<EFBFBD><C2BC><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD>
// 绘制事件处理
void TrashButtonDelegateEditor::paintEvent(QPaintEvent *event)
{
QPainter painter(this);
// 绘制图标区域
// <EFBFBD><EFBFBD><EFBFBD><EFBFBD>ͼ<EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD>
auto iconRect = QRect(rect().x() + 22, rect().y() + 2 + (rect().height() - 20) / 2, 18, 20);
auto iconPath = m_index.data(NodeItem::Roles::Icon).toString();
auto displayName = m_index.data(NodeItem::Roles::DisplayText).toString();
QRect nameRect(rect());
nameRect.setLeft(iconRect.x() + iconRect.width() + 5);
nameRect.setWidth(nameRect.width() - 22 - 40);
// 根据是否选中设置背景颜色和文本颜色
// <EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD>Ƿ<EFBFBD>ѡ<EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD>ñ<EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD>ɫ<EFBFBD><EFBFBD><EFBFBD>ı<EFBFBD><EFBFBD><EFBFBD>ɫ
if (m_view->selectionModel()->isSelected(m_index)) {
painter.fillRect(rect(), QBrush(m_activeColor));
painter.setPen(m_titleSelectedColor);
@ -86,12 +87,12 @@ void TrashButtonDelegateEditor::paintEvent(QPaintEvent *event)
#else
int iconPointSizeOffset = -4;
#endif
// 设置图标字体
// <EFBFBD><EFBFBD><EFBFBD><EFBFBD>ͼ<EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD>
painter.setFont(FontLoader::getInstance().loadFont("Font Awesome 6 Free Solid", "",
16 + iconPointSizeOffset));
painter.drawText(iconRect, iconPath); // fa-trash
// 绘制标题文本
// <EFBFBD><EFBFBD><EFBFBD>Ʊ<EFBFBD><EFBFBD><EFBFBD><EFBFBD>ı<EFBFBD>
if (m_view->selectionModel()->isSelected(m_index)) {
painter.setPen(m_titleSelectedColor);
} else {
@ -100,12 +101,12 @@ void TrashButtonDelegateEditor::paintEvent(QPaintEvent *event)
painter.setFont(m_titleFont);
painter.drawText(nameRect, Qt::AlignLeft | Qt::AlignVCenter, displayName);
// 绘制子项数量区域
// <EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD>
auto childCountRect = rect();
childCountRect.setLeft(nameRect.right() + 22);
childCountRect.setWidth(childCountRect.width() - 5);
auto childCount = m_index.data(NodeItem::Roles::ChildCount).toInt();
// 根据是否选中设置子项数量文本颜色
// <EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD>Ƿ<EFBFBD>ѡ<EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD>ı<EFBFBD><EFBFBD><EFBFBD>ɫ
if (m_view->selectionModel()->isSelected(m_index)) {
painter.setPen(m_numberOfNotesSelectedColor);
} else {
@ -117,7 +118,8 @@ void TrashButtonDelegateEditor::paintEvent(QPaintEvent *event)
QWidget::paintEvent(event);
}
// 设置主题函数
// <20><><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><E2BAAF>
// 设置主题
void TrashButtonDelegateEditor::setTheme(Theme::Value theme)
{
m_theme = theme;
@ -141,4 +143,4 @@ void TrashButtonDelegateEditor::setTheme(Theme::Value theme)
break;
}
}
}
}

@ -10,39 +10,39 @@
class QTreeView;
class QListView;
// TrashButtonDelegateEditor 类声明
// TrashButtonDelegateEditor <EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD>
class TrashButtonDelegateEditor : public QWidget
{
Q_OBJECT
public:
// 构造函数
// <EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD>
explicit TrashButtonDelegateEditor(QTreeView *view, const QStyleOptionViewItem &option,
const QModelIndex &index, QListView *listView,
QWidget *parent = nullptr);
// 设置主题函数
// <EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD>
void setTheme(Theme::Value theme);
private:
QStyleOptionViewItem m_option;
QModelIndex m_index;
QString m_displayFont;
QFont m_titleFont;
QFont m_numberOfNotesFont;
QColor m_titleColor;
QColor m_titleSelectedColor;
QColor m_activeColor;
QColor m_hoverColor;
QColor m_folderIconColor;
QColor m_numberOfNotesColor;
QColor m_numberOfNotesSelectedColor;
QTreeView *m_view;
QListView *m_listView;
Theme::Value m_theme;
QStyleOptionViewItem m_option; // 存储视图项的样式选项
QModelIndex m_index; // 存储模型索引
QString m_displayFont; // 显示字体
QFont m_titleFont; // 标题字体
QFont m_numberOfNotesFont; // 备注字体
QColor m_titleColor; // 标题颜色
QColor m_titleSelectedColor; // 标题选中颜色
QColor m_activeColor; // 激活状态颜色
QColor m_hoverColor; // 悬停状态颜色
QColor m_folderIconColor; // 文件夹图标颜色
QColor m_numberOfNotesColor; // 备注颜色
QColor m_numberOfNotesSelectedColor; // 备注选中颜色
QTreeView *m_view; // 视图指针
QListView *m_listView; // 列表视图指针
Theme::Value m_theme; // 主题值
// QWidget interface
// QWidget 接口
// QWidget <20>ӿ<EFBFBD>
protected:
// 绘制事件处理函数
virtual void paintEvent(QPaintEvent *event) override;
// <EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD>¼<EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD>
virtual void paintEvent(QPaintEvent *event) override; // 绘制事件
};
#endif // TRASHBUTTONDELEGATEEDITOR_H
#endif // TRASHBUTTONDELEGATEEDITOR_H

@ -1,4 +1,4 @@
// 包含头文件
/// <20><><EFBFBD><EFBFBD>ͷ<EFBFBD>ļ<EFBFBD>
#include "treeviewlogic.h"
#include "nodetreeview.h"
#include "nodetreemodel.h"
@ -12,7 +12,8 @@
#include <QApplication>
#include "customapplicationstyle.h"
// TreeViewLogic 类的构造函数
// TreeViewLogic <20><>Ĺ<EFBFBD><C4B9><EFBFBD><ECBAAF>
// 管理树视图的逻辑,包括节点的增删改查和更新
TreeViewLogic::TreeViewLogic(NodeTreeView *treeView, NodeTreeModel *treeModel, DBManager *dbManager,
NoteListView *listView, QObject *parent)
: QObject(parent),
@ -26,16 +27,16 @@ TreeViewLogic::TreeViewLogic(NodeTreeView *treeView, NodeTreeModel *treeModel, D
m_lastSelectTags{},
m_expandedFolder{}
{
// 初始化树视图代理
// <EFBFBD><EFBFBD>ʼ<EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD>ͼ<EFBFBD><EFBFBD><EFBFBD><EFBFBD>
m_treeDelegate = new NodeTreeDelegate(m_treeView, m_treeView, m_listView);
m_treeView->setItemDelegate(m_treeDelegate);
// 连接数据库管理器信号
// <EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD>ݿ<EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD>ź<EFBFBD>
connect(m_dbManager, &DBManager::nodesTagTreeReceived, this, &TreeViewLogic::loadTreeModel,
Qt::QueuedConnection);
// 连接树模型信号
// <EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD>ģ<EFBFBD><EFBFBD><EFBFBD>ź<EFBFBD>
connect(m_treeModel, &NodeTreeModel::topLevelItemLayoutChanged, this,
&TreeViewLogic::updateTreeViewSeparator);
// 连接树视图信号
// <EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD>ͼ<EFBFBD>ź<EFBFBD>
connect(m_treeView, &NodeTreeView::addFolderRequested, this,
[this] { onAddFolderRequested(false); });
connect(m_treeDelegate, &NodeTreeDelegate::addFolderRequested, this,
@ -84,23 +85,25 @@ TreeViewLogic::TreeViewLogic(NodeTreeView *treeView, NodeTreeModel *treeModel, D
&TreeViewLogic::onChildNoteCountChangedFolder);
connect(m_dbManager, &DBManager::childNotesCountUpdatedTag, this,
&TreeViewLogic::onChildNotesCountChangedTag);
// 设置应用样式
// <EFBFBD><EFBFBD><EFBFBD><EFBFBD>Ӧ<EFBFBD><EFBFBD><EFBFBD><EFBFBD>ʽ
m_style = new CustomApplicationStyle();
qApp->setStyle(m_style);
}
// 更新树视图分隔符
// <20><><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD>ͼ<EFBFBD>ָ<EFBFBD><D6B8><EFBFBD>
// 更新树视图的分隔符
void TreeViewLogic::updateTreeViewSeparator()
{
m_treeView->setTreeSeparator(m_treeModel->getSeparatorIndex(),
m_treeModel->getDefaultNotesIndex());
}
// 加载树模型
// <20><><EFBFBD><EFBFBD><EFBFBD><EFBFBD>ģ<EFBFBD><C4A3>
// 加载树模型的数据
void TreeViewLogic::loadTreeModel(const NodeTagTreeData &treeData)
{
m_treeModel->setTreeData(treeData);
// 获取根节点的子节点数量
// <EFBFBD><EFBFBD>ȡ<EFBFBD><EFBFBD><EFBFBD>ڵ<EFBFBD><EFBFBD><EFBFBD>ӽڵ<EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD>
{
NodeData node;
QMetaObject::invokeMethod(m_dbManager, "getChildNotesCountFolder",
@ -111,7 +114,7 @@ void TreeViewLogic::loadTreeModel(const NodeTagTreeData &treeData)
m_treeModel->setData(index, node.childNotesCount(), NodeItem::Roles::ChildCount);
}
}
// 获取垃圾箱节点的子节点数量
// <EFBFBD><EFBFBD>ȡ<EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD>ڵ<EFBFBD><EFBFBD><EFBFBD>ӽڵ<EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD>
{
NodeData node;
QMetaObject::invokeMethod(m_dbManager, "getChildNotesCountFolder",
@ -122,7 +125,7 @@ void TreeViewLogic::loadTreeModel(const NodeTagTreeData &treeData)
m_treeModel->setData(index, node.childNotesCount(), NodeItem::Roles::ChildCount);
}
}
// 加载保存的状态
// <EFBFBD><EFBFBD><EFBFBD>ر<EFBFBD><EFBFBD><EFBFBD><EFBFBD>״̬
if (m_needLoadSavedState) {
m_needLoadSavedState = false;
m_treeView->reExpandC(m_expandedFolder);
@ -154,7 +157,8 @@ void TreeViewLogic::loadTreeModel(const NodeTagTreeData &treeData)
updateTreeViewSeparator();
}
// 处理添加文件夹请求
// <20><><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD>ļ<EFBFBD><C4BC><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD>
// 添加文件夹的请求处理
void TreeViewLogic::onAddFolderRequested(bool fromPlusButton)
{
QModelIndex currentIndex;
@ -175,7 +179,7 @@ void TreeViewLogic::onAddFolderRequested(bool fromPlusButton)
static_cast<NodeItem::Type>(currentIndex.data(NodeItem::Roles::ItemType).toInt());
if (type == NodeItem::FolderItem) {
parentId = currentIndex.data(NodeItem::Roles::NodeId).toInt();
// 不允许在默认笔记文件夹下创建子文件夹
// <EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD>Ĭ<EFBFBD>ϱʼ<EFBFBD><EFBFBD>ļ<EFBFBD><EFBFBD><EFBFBD><EFBFBD>´<EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD>ļ<EFBFBD><EFBFBD><EFBFBD>
if (parentId == SpecialNodeID::DefaultNotesFolder) {
parentId = SpecialNodeID::RootFolder;
}
@ -248,13 +252,14 @@ void TreeViewLogic::onAddFolderRequested(bool fromPlusButton)
}
}
// 处理添加标签请求
// <20><><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD>ӱ<EFBFBD>ǩ<EFBFBD><C7A9><EFBFBD><EFBFBD>
// 处理添加标签请求
void TreeViewLogic::onAddTagRequested()
{
int newlyCreatedTagId;
TagData newTag;
newTag.setName(m_treeModel->getNewTagPlaceholderName());
// 随机颜色生成器
// <EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD>ɫ<EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD>
const double lower_bound = 0;
const double upper_bound = 1;
static std::uniform_real_distribution<double> unif(lower_bound, upper_bound);
@ -278,7 +283,8 @@ void TreeViewLogic::onAddTagRequested()
m_treeModel->appendChildNodeToParent(m_treeModel->rootIndex(), hs);
}
// 处理重命名节点请求
// <20><><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD>ڵ<EFBFBD><DAB5><EFBFBD><EFBFBD><EFBFBD>
// 处理从树视图请求重命名节点
void TreeViewLogic::onRenameNodeRequestedFromTreeView(const QModelIndex &index,
const QString &newName)
{
@ -287,7 +293,8 @@ void TreeViewLogic::onRenameNodeRequestedFromTreeView(const QModelIndex &index,
emit requestRenameNodeInDB(id, newName);
}
// 处理删除文件夹请求
// <20><><EFBFBD><EFBFBD>ɾ<EFBFBD><C9BE><EFBFBD>ļ<EFBFBD><C4BC><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD>
// 处理删除文件夹的请求
void TreeViewLogic::onDeleteFolderRequested(const QModelIndex &index)
{
auto btn = QMessageBox::question(nullptr, "Are you sure you want to delete this folder",
@ -319,7 +326,8 @@ void TreeViewLogic::onDeleteFolderRequested(const QModelIndex &index)
}
}
// 处理重命名标签请求
// <20><><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD>ǩ<EFBFBD><C7A9><EFBFBD><EFBFBD>
// 处理从树视图请求重命名标签
void TreeViewLogic::onRenameTagRequestedFromTreeView(const QModelIndex &index,
const QString &newName)
{
@ -328,7 +336,8 @@ void TreeViewLogic::onRenameTagRequestedFromTreeView(const QModelIndex &index,
emit requestRenameTagInDB(id, newName);
}
// 处理修改标签颜色请求
// <20><><EFBFBD><EFBFBD><EFBFBD>޸ı<DEB8>ǩ<EFBFBD><C7A9>ɫ<EFBFBD><C9AB><EFBFBD><EFBFBD>
// 处理颜色请求的标签
void TreeViewLogic::onChangeTagColorRequested(const QModelIndex &index)
{
if (index.isValid()) {
@ -342,7 +351,8 @@ void TreeViewLogic::onChangeTagColorRequested(const QModelIndex &index)
}
}
// 处理删除标签请求
// <20><><EFBFBD><EFBFBD>ɾ<EFBFBD><C9BE><EFBFBD><EFBFBD>ǩ<EFBFBD><C7A9><EFBFBD><EFBFBD>
// 处理删除标签的请求
void TreeViewLogic::onDeleteTagRequested(const QModelIndex &index)
{
auto id = index.data(NodeItem::Roles::NodeId).toInt();
@ -351,7 +361,8 @@ void TreeViewLogic::onDeleteTagRequested(const QModelIndex &index)
m_treeView->setCurrentIndexC(m_treeModel->getAllNotesButtonIndex());
}
// 处理标签子节点数量变化
// <20><><EFBFBD><EFBFBD><EFBFBD><EFBFBD>ǩ<EFBFBD>ӽڵ<D3BD><DAB5><EFBFBD><EFBFBD><EFBFBD><EFBFBD>
// 更新标签的子项数量
void TreeViewLogic::onChildNotesCountChangedTag(int tagId, int notesCount)
{
auto index = m_treeModel->tagIndexFromId(tagId);
@ -360,7 +371,8 @@ void TreeViewLogic::onChildNotesCountChangedTag(int tagId, int notesCount)
}
}
// 处理文件夹子节点数量变化
// <20><><EFBFBD><EFBFBD><EFBFBD>ļ<EFBFBD><C4BC><EFBFBD><EFBFBD>ӽڵ<D3BD><DAB5><EFBFBD><EFBFBD><EFBFBD><EFBFBD>
// 更新文件夹的子项数量
void TreeViewLogic::onChildNoteCountChangedFolder(int folderId, const QString &absPath,
int notesCount)
{
@ -377,7 +389,8 @@ void TreeViewLogic::onChildNoteCountChangedFolder(int folderId, const QString &a
}
}
// 打开文件夹
// <20><><EFBFBD>ļ<EFBFBD><C4BC><EFBFBD>
// 打开指定文件夹
void TreeViewLogic::openFolder(int id)
{
NodeData target;
@ -401,7 +414,8 @@ void TreeViewLogic::openFolder(int id)
}
}
// 处理移动节点请求
// <20><><EFBFBD><EFBFBD><EFBFBD>ƶ<EFBFBD><C6B6>ڵ<EFBFBD><DAB5><EFBFBD><EFBFBD><EFBFBD>
// 处理移动节点的请求
void TreeViewLogic::onMoveNodeRequested(int nodeId, int targetId)
{
NodeData target;
@ -414,7 +428,8 @@ void TreeViewLogic::onMoveNodeRequested(int nodeId, int targetId)
emit requestMoveNodeInDB(nodeId, target);
}
// 设置主题
// <20><><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD>
// 设置主题
void TreeViewLogic::setTheme(Theme::Value theme)
{
m_treeView->setTheme(theme);
@ -422,7 +437,8 @@ void TreeViewLogic::setTheme(Theme::Value theme)
m_style->setTheme(theme);
}
// 设置最后保存的状态
// <20><><EFBFBD><EFBFBD><EFBFBD><EFBFBD>󱣴<EFBFBD><F3B1A3B4>״̬
// 设置最后保存的状态
void TreeViewLogic::setLastSavedState(bool isLastSelectFolder, const QString &lastSelectFolder,
const QSet<int> &lastSelectTag,
const QStringList &expandedFolder)
@ -432,4 +448,4 @@ void TreeViewLogic::setLastSavedState(bool isLastSelectFolder, const QString &la
m_lastSelectTags = lastSelectTag;
m_expandedFolder = expandedFolder;
m_needLoadSavedState = true;
}
}

@ -12,76 +12,86 @@ class DBManager;
class CustomApplicationStyle;
class NoteListView;
// TreeViewLogic 类负责管理树视图逻辑
// TreeViewLogic 类负责管理树视图逻辑
class TreeViewLogic : public QObject
{
Q_OBJECT
public:
// 构造函数
explicit TreeViewLogic(NodeTreeView* treeView, NodeTreeModel* treeModel, DBManager* dbManager,
NoteListView* listView, QObject* parent = nullptr);
// 打开文件夹
// 构造函数
explicit TreeViewLogic(NodeTreeView *treeView, NodeTreeModel *treeModel, DBManager *dbManager,
NoteListView *listView, QObject *parent = nullptr);
// 打开文件夹
void openFolder(int id);
// 处理移动节点请求
// 请求移动节点
void onMoveNodeRequested(int nodeId, int targetId);
// 设置主题
// 设置主题
void setTheme(Theme::Value theme);
// 设置最后保存的状态
void setLastSavedState(bool isLastSelectFolder, const QString& lastSelectFolder,
const QSet<int>& lastSelectTag, const QStringList& expandedFolder);
// 设置最后保存的状态
void setLastSavedState(bool isLastSelectFolder, const QString &lastSelectFolder,
const QSet<int> &lastSelectTag, const QStringList &expandedFolder);
private slots:
// 更新树视图分隔符
// 更新树视图分隔符
void updateTreeViewSeparator();
// 加载树模型
void loadTreeModel(const NodeTagTreeData& treeData);
// 处理添加标签请求
// 加载树模型
void loadTreeModel(const NodeTagTreeData &treeData);
// 请求添加标签
void onAddTagRequested();
// 处理重命名节点请求
void onRenameNodeRequestedFromTreeView(const QModelIndex& index, const QString& newName);
// 处理删除文件夹请求
void onDeleteFolderRequested(const QModelIndex& index);
// 处理重命名标签请求
void onRenameTagRequestedFromTreeView(const QModelIndex& index, const QString& newName);
// 处理修改标签颜色请求
void onChangeTagColorRequested(const QModelIndex& index);
// 处理删除标签请求
void onDeleteTagRequested(const QModelIndex& index);
// 处理标签子节点数量变化
// 请求重命名树视图中的节点
void onRenameNodeRequestedFromTreeView(const QModelIndex &index, const QString &newName);
// 请求删除文件夹
void onDeleteFolderRequested(const QModelIndex &index);
// 请求重命名树视图中的标签
void onRenameTagRequestedFromTreeView(const QModelIndex &index, const QString &newName);
// 请求更改标签颜色
void onChangeTagColorRequested(const QModelIndex &index);
// 请求删除标签
void onDeleteTagRequested(const QModelIndex &index);
// 标签的子笔记数量变化
void onChildNotesCountChangedTag(int tagId, int notesCount);
// 处理文件夹子节点数量变化
void onChildNoteCountChangedFolder(int folderId, const QString& absPath, int notesCount);
// 文件夹的子笔记数量变化
void onChildNoteCountChangedFolder(int folderId, const QString &absPath, int notesCount);
signals:
// 请求重命名节点
void requestRenameNodeInDB(int id, const QString& newName);
// 请求重命名标签
void requestRenameTagInDB(int id, const QString& newName);
// 请求改标签颜色
void requestChangeTagColorInDB(int id, const QString& newColor);
// 请求移动节点
void requestMoveNodeInDB(int id, const NodeData& target);
// 添加笔记到标签
// 请求在数据库中重命名节点
void requestRenameNodeInDB(int id, const QString &newName);
// 请求在数据库中重命名标签
void requestRenameTagInDB(int id, const QString &newName);
// 请求在数据库中更改标签颜色
void requestChangeTagColorInDB(int id, const QString &newColor);
// 请求在数据库中移动节点
void requestMoveNodeInDB(int id, const NodeData &target);
// 向标签添加笔记
void addNoteToTag(int noteId, int tagId);
// 节点移动
// 通知节点移动
void noteMoved(int nodeId, int targetId);
private:
// 处理添加文件夹请求
// 请求添加文件夹
void onAddFolderRequested(bool fromPlusButton);
private:
// 成员变量
NodeTreeView* m_treeView;
NodeTreeModel* m_treeModel;
NoteListView* m_listView;
NodeTreeDelegate* m_treeDelegate;
DBManager* m_dbManager;
CustomApplicationStyle* m_style;
// 节点树视图
NodeTreeView *m_treeView;
// 节点树模型
NodeTreeModel *m_treeModel;
// 笔记列表视图
NoteListView *m_listView;
// 节点树代理
NodeTreeDelegate *m_treeDelegate;
// 数据库管理器
DBManager *m_dbManager;
// 自定义应用样式
CustomApplicationStyle *m_style;
// 是否需要加载保存的状态
bool m_needLoadSavedState;
// 是否是最后选择的文件夹
bool m_isLastSelectFolder;
// 最后选择的文件夹路径
QString m_lastSelectFolder;
// 最后选择的标签集合
QSet<int> m_lastSelectTags;
// 展开的文件夹列表
QStringList m_expandedFolder;
};

@ -33,13 +33,13 @@ static QProcess XDGOPEN_PROCESS;
#endif
/**
* Indicates from where we should download the update definitions file
*
*/
static const QString
UPDATES_URL("https://raw.githubusercontent.com/nuttyartist/notes/master/UPDATES.json");
/**
* Initializes the window components and configures the QSimpleUpdater
* QSimpleUpdater
*/
UpdaterWindow::UpdaterWindow(QWidget *parent)
: QDialog(parent),
@ -53,21 +53,21 @@ UpdaterWindow::UpdaterWindow(QWidget *parent)
m_updater(QSimpleUpdater::getInstance()),
m_manager(new QNetworkAccessManager(this))
{
/* Load the stylesheet */
/* 加载样式表 */
QFile file(":/styles/updater-window.css");
if (file.open(QIODevice::ReadOnly)) {
setStyleSheet(QString::fromUtf8(file.readAll()).toLatin1());
file.close();
}
/* Initialize the UI */
/* 初始化 UI */
m_ui->setupUi(this);
#if QT_VERSION < QT_VERSION_CHECK(5, 10, 0)
setWindowFlag(Qt::WindowContextHelpButtonHint, false);
#endif
setWindowTitle(qApp->applicationName() + " " + tr("Updater"));
/* Change fonts */
/* 更改字体 */
#ifdef __APPLE__
QFont fontToUse = QFont(QStringLiteral("SF Pro Text")).exactMatch()
? QStringLiteral("SF Pro Text")
@ -86,47 +86,50 @@ UpdaterWindow::UpdaterWindow(QWidget *parent)
widgetChild->setFont(fontToUse);
}
/* Connect UI signals/slots */
/* 连接 UI 信号/槽 */
connect(m_ui->closeButton, &QPushButton::clicked, this, &UpdaterWindow::close);
connect(m_ui->updateButton, &QPushButton::clicked, this,
&UpdaterWindow::onDownloadButtonClicked);
connect(m_updater, &QSimpleUpdater::checkingFinished, this, &UpdaterWindow::onCheckFinished);
connect(m_ui->checkBox, &QCheckBox::toggled, this, &UpdaterWindow::dontShowUpdateWindowChanged);
/* Start the UI loops */
/* 启动 UI 循环 */
updateTitleLabel();
/* Remove native window decorations */
/* 移除原生窗口装饰 */
#if defined(Q_OS_UNIX) && !defined(Q_OS_MACOS)
setWindowFlags(windowFlags() | Qt::CustomizeWindowHint | Qt::FramelessWindowHint);
#else
setWindowFlags(windowFlags() | Qt::CustomizeWindowHint);
#endif
/* React when xdg-open finishes (Linux only) */
/* 当 xdg-open 完成时响应(仅限 Linux */
#ifdef UseXdgOpen
connect(&XDGOPEN_PROCESS, SIGNAL(finished(int)), this, SLOT(onXdgOpenFinished(int)));
#endif
/* Set window flags */
/* 设置窗口标志 */
setWindowModality(Qt::ApplicationModal);
}
/**
* Deletes the user interface
*
*/
UpdaterWindow::~UpdaterWindow()
{
/* Ensure that xdg-open process is closed */
/* 确保 xdg-open 进程已关闭 */
#ifdef UseXdgOpen
if (XDGOPEN_PROCESS.isOpen())
XDGOPEN_PROCESS.close();
#endif
/* Delete UI controls */
/* 删除 UI 控件 */
delete m_ui;
}
/**
*
*/
void UpdaterWindow::setShowWindowDisable(const bool dontShowWindow)
{
m_dontShowUpdateWindow = dontShowWindow;
@ -134,29 +137,28 @@ void UpdaterWindow::setShowWindowDisable(const bool dontShowWindow)
}
/**
* Instructs the QSimpleUpdater to download and interpret the updater
* definitions file
* QSimpleUpdater
*/
void UpdaterWindow::checkForUpdates(bool force)
{
/* Change the silent flag */
/* 更改静默标志 */
if (!m_updater->getUpdateAvailable(UPDATES_URL)) {
m_checkingForUpdates = true;
m_forced = force;
/* Set module properties */
/* 设置模块属性 */
m_updater->setNotifyOnFinish(UPDATES_URL, false);
m_updater->setNotifyOnUpdate(UPDATES_URL, false);
m_updater->setDownloaderEnabled(UPDATES_URL, false);
m_updater->setUseCustomInstallProcedures(UPDATES_URL, true);
m_updater->setModuleVersion(UPDATES_URL, qApp->applicationVersion());
/* Check for updates */
/* 检查更新 */
m_updater->checkForUpdates(UPDATES_URL);
}
/* Show window if force flag is set */
/* 如果 force 标志被设置,则显示窗口 */
if (force) {
if (!m_updater->getUpdateAvailable(UPDATES_URL)) {
m_ui->updateButton->setEnabled(false);
@ -169,65 +171,62 @@ void UpdaterWindow::checkForUpdates(bool force)
}
/**
* Resets the state, text and information displayed the the UI controls
* to indicate what is happening right now in the QSimpleUpdater
* UI QSimpleUpdater
*/
void UpdaterWindow::resetControls()
{
/* Reset the button states */
/* 重置按钮状态 */
m_ui->updateButton->setEnabled(false);
/* Set installed version label */
/* 设置已安装版本标签 */
m_ui->installedVersion->setText(qApp->applicationVersion());
/* Set available version label */
/* 设置可用版本标签 */
m_ui->availableVersion->setText(m_updater->getLatestVersion(UPDATES_URL));
/* Set title label */
/* 设置标题标签 */
if (m_updater->getUpdateAvailable(UPDATES_URL)) {
m_ui->title->setText(tr("A Newer Version is Available!"));
} else {
m_ui->title->setText(tr("You're up-to-date!"));
}
/* Reset the progress controls */
/* 重置进度控件 */
m_ui->progressControls->hide();
m_ui->progressBar->setValue(0);
m_ui->downloadLabel->setText(tr("Downloading Updates") + "...");
m_ui->timeLabel->setText(tr("Time remaining") + ": " + tr("unknown"));
/* Set changelog text */
/* 设置更新日志文本 */
QString changelogText = m_updater->getChangelog(UPDATES_URL);
m_ui->changelog->setText(changelogText);
if (m_ui->changelog->toPlainText().isEmpty()) {
m_ui->changelog->setText("<p>No changelog found...</p>");
} else {
m_ui->changelog->setText(changelogText.append(
"\n")); // Don't know why currently changelog box is disappearing at the bottom, so
// I add a new line to see the text.
"\n")); // 不知道为什么当前更新日志框在底部消失了,所以添加一个新行以查看文本。
}
/* Enable/disable update button */
/* 启用/禁用更新按钮 */
bool available = m_updater->getUpdateAvailable(UPDATES_URL);
bool validOpenUrl = !m_updater->getOpenUrl(UPDATES_URL).isEmpty();
bool validDownUrl = !m_updater->getDownloadUrl(UPDATES_URL).isEmpty();
m_ui->updateButton->setEnabled(available && (validOpenUrl || validDownUrl));
/* Resize window */
/* 调整窗口大小 */
bool showAgain = isVisible();
int height = minimumSizeHint().height();
int width = qMax(minimumSizeHint().width(), int(height * 1.2));
resize(QSize(width, height));
/* Re-show the window(if required)*/
/* 重新显示窗口(如果需要) */
if (showAgain) {
showNormal();
}
}
/**
* Changes the number of dots of the title label while the QSimpleUpdater
* is downloading and interpreting the update definitions file
* QSimpleUpdater
*/
void UpdaterWindow::updateTitleLabel()
{
@ -245,8 +244,7 @@ void UpdaterWindow::updateTitleLabel()
}
/**
* Updates the text displayed the the UI controls to reflect the information
* obtained by the QSimpleUpdater and shows the dialog
* UI QSimpleUpdater
*/
void UpdaterWindow::onUpdateAvailable()
{
@ -257,7 +255,7 @@ void UpdaterWindow::onUpdateAvailable()
}
/**
* Initializes the download of the update and disables the 'update' button
*
*/
void UpdaterWindow::onDownloadButtonClicked()
{
@ -268,25 +266,23 @@ void UpdaterWindow::onDownloadButtonClicked()
}
/**
* Initializes the download of the update and configures the connections
* to automatically update the user interface when we receive new data
* from the download/update server
* /
*/
void UpdaterWindow::startDownload(const QUrl &url)
{
/* URL is invalid, try opening web browser */
/* URL 无效,尝试打开网页浏览器 */
if (url.isEmpty()) {
QDesktopServices::openUrl(QUrl(m_updater->getOpenUrl(UPDATES_URL)));
return;
}
/* Cancel previous download (if any)*/
/* 取消之前的下载(如果有) */
if (m_reply) {
m_reply->abort();
m_reply->deleteLater();
}
/* Start download */
/* 开始下载 */
m_startTime = QDateTime::currentDateTime().toSecsSinceEpoch();
QNetworkRequest netReq(url);
@ -294,7 +290,7 @@ void UpdaterWindow::startDownload(const QUrl &url)
QNetworkRequest::NoLessSafeRedirectPolicy);
m_reply = m_manager->get(netReq);
/* Set file name */
/* 设置文件名 */
m_fileName = m_updater->getDownloadUrl(UPDATES_URL).split("/").last();
if (m_fileName.isEmpty()) {
m_fileName = QString("%1_Update_%2.bin")
@ -302,37 +298,37 @@ void UpdaterWindow::startDownload(const QUrl &url)
m_updater->getLatestVersion(UPDATES_URL));
}
/* Prepare download directory */
/* 准备下载目录 */
if (!m_downloadDir.exists())
m_downloadDir.mkpath(".");
/* Remove previous downloads(if any)*/
/* 删除之前的下载(如果有) */
QFile::remove(m_downloadDir.filePath(m_fileName));
/* Show UI controls */
/* 显示 UI 控件 */
m_ui->progressControls->show();
showNormal();
/* Update UI when download progress changes or download finishes */
/* 当下载进度变化或下载完成时更新 UI */
connect(m_reply, &QNetworkReply::downloadProgress, this, &UpdaterWindow::updateProgress);
connect(m_reply, &QNetworkReply::finished, this, &UpdaterWindow::onDownloadFinished);
}
/**
* Opens the downloaded file
*
*/
void UpdaterWindow::openDownload(const QString &file)
{
/* File is empty, abort */
/* 文件为空,中止 */
if (file.isEmpty()) {
return;
}
/* Change labels */
/* 更改标签 */
m_ui->downloadLabel->setText(tr("Download finished!"));
m_ui->timeLabel->setText(tr("Opening downloaded file") + "...");
/* Try to open the downloaded file (Windows & Mac) */
/* 尝试打开下载的文件Windows 和 Mac */
#ifndef UseXdgOpen
bool openUrl = QDesktopServices::openUrl(QUrl::fromLocalFile(file));
if (!openUrl) {
@ -346,27 +342,25 @@ void UpdaterWindow::openDownload(const QString &file)
}
#endif
/* On Linux, use xdg-open to know if the file was handled correctly */
/* 在 Linux 上,使用 xdg-open 来确认文件是否被正确处理 */
#ifdef UseXdgOpen
XDGOPEN_PROCESS.start("xdg-open", QStringList() << file);
#endif
}
/**
* Called when the \a QSimpleUpdater notifies us that it downloaded and
* interpreted the update definitions file.
* QSimpleUpdater
*
* This function decides whenever to show the dialog or just notify the user
* that he/she is running the latest version of notes
* / notes
*/
void UpdaterWindow::onCheckFinished(const QString &url)
{
Q_UNUSED(url)
/* Do not allow the title label to change automatically */
/* 不允许标题标签自动更改 */
m_checkingForUpdates = false;
/* There is an update available, show the window */
/* 如果有可用更新,显示窗口 */
if (m_updater->getUpdateAvailable(url) && (UPDATES_URL == url)) {
onUpdateAvailable();
} else if (m_forced) {
@ -377,9 +371,8 @@ void UpdaterWindow::onCheckFinished(const QString &url)
}
/**
* Called when \c xdg-open finishes with the given \a exitCode.
* If \a exitCode is not 0, then we shall try to open the folder in which
* the update file was saved
* xdg-open exitCode
* exitCode 0
*/
void UpdaterWindow::onXdgOpenFinished(const int exitCode)
{
@ -396,13 +389,11 @@ void UpdaterWindow::onXdgOpenFinished(const int exitCode)
}
/**
* Notifies the user that there's been an error opening the downloaded
* file directly and instructs the operating system to open the folder
* in which the \a file is located
*
*/
void UpdaterWindow::openDownloadFolder(const QString &file)
{
/* Notify the user of the problem */
/* 通知用户问题 */
QString extension = file.split(".").last();
QMessageBox::information(this, tr("Open Error"),
tr("It seems that your OS does not have an "
@ -411,30 +402,29 @@ void UpdaterWindow::openDownloadFolder(const QString &file)
.arg(extension),
QMessageBox::Ok);
/* Get the full path list of the downloaded file */
/* 获取下载文件的完整路径列表 */
QString native_path = QDir::toNativeSeparators(QDir(file).absolutePath());
QStringList directories = native_path.split(QDir::separator());
/* Remove file name from list to get the folder of the update file */
/* 从列表中删除文件名以获取更新文件的文件夹 */
directories.removeLast();
QString path = directories.join(QDir::separator());
/* Get valid URL and open it */
/* 获取有效的 URL 并打开它 */
QUrl url = QUrl::fromLocalFile(QDir(path).absolutePath());
QDesktopServices::openUrl(url);
}
/**
* Calculates the appropriate size units(bytes, KB or MB)for the received
* data and the total download size. Then, this function proceeds to update the
* dialog controls/UI.
* KB MB
* /UI
*/
void UpdaterWindow::calculateSizes(qint64 received, qint64 total)
{
QString totalSize;
QString receivedSize;
/* Get total size string */
/* 获取总大小字符串 */
if (total < 1024) {
totalSize = tr("%1 bytes").arg(total);
} else if (total < (1024 * 1024)) {
@ -443,7 +433,7 @@ void UpdaterWindow::calculateSizes(qint64 received, qint64 total)
totalSize = tr("%1 MB").arg(round(total / (1024 * 1024)));
}
/* Get received size string */
/* 获取接收大小字符串 */
if (received < 1024) {
receivedSize = tr("%1 bytes").arg(received);
} else if (received < (1024 * 1024)) {
@ -452,14 +442,13 @@ void UpdaterWindow::calculateSizes(qint64 received, qint64 total)
receivedSize = tr("%1 MB").arg(received / (1024 * 1024));
}
/* Update the label text */
/* 更新标签文本 */
m_ui->downloadLabel->setText(tr("Downloading updates") + " (" + receivedSize + " " + tr("of")
+ " " + totalSize + ")");
}
/**
* Uses the \a received and \a total parameters to get the download progress
* and update the progressbar value on the dialog.
* 使 received total
*/
void UpdaterWindow::updateProgress(qint64 received, qint64 total)
{
@ -480,12 +469,9 @@ void UpdaterWindow::updateProgress(qint64 received, qint64 total)
}
/**
* Uses two time samples(from the current time and a previous sample)to
* calculate how many bytes have been downloaded.
* 使
*
* Then, this function proceeds to calculate the appropriate units of time
*(hours, minutes or seconds)and constructs a user-friendly string, which
* is displayed in the dialog.
*
*/
void UpdaterWindow::calculateTimeRemaining(qint64 received, qint64 total)
{
@ -519,83 +505,4 @@ void UpdaterWindow::calculateTimeRemaining(qint64 received, qint64 total)
if (seconds > 1) {
timeString = tr("%1 seconds").arg(seconds);
} else {
timeString = tr("1 second");
}
}
m_ui->timeLabel->setText(tr("Time remaining") + ": " + timeString);
}
}
void UpdaterWindow::onDownloadFinished()
{
QString redirectedUrl =
m_reply->attribute(QNetworkRequest::RedirectionTargetAttribute).toString();
if (redirectedUrl.isEmpty()) {
const QString filePath = m_downloadDir.filePath(m_fileName);
QFile file(filePath);
if (file.open(QIODevice::WriteOnly | QIODevice::Append)) {
file.write(m_reply->readAll());
file.close();
qApp->processEvents();
}
openDownload(filePath);
} else {
startDownload(redirectedUrl);
}
}
/**
* Allows the user to move the window and registers the position in which
* the user originally clicked to move the window
*/
void UpdaterWindow::mousePressEvent(QMouseEvent *event)
{
if (event->button() == Qt::LeftButton) {
if (event->x() < width() - 5 && event->x() > 5 && event->pos().y() < height() - 5
&& event->pos().y() > 5) {
#if QT_VERSION >= QT_VERSION_CHECK(5, 15, 0)
m_canMoveWindow = !window()->windowHandle()->startSystemMove();
#else
m_canMoveWindow = true;
#endif
m_mousePressX = event->pos().x();
m_mousePressY = event->pos().y();
}
}
event->accept();
}
/**
* Changes the cursor icon to a hand(to hint the user that he/she is dragging
* the window)and moves the window to the desired position of the given
* \a event
*/
void UpdaterWindow::mouseMoveEvent(QMouseEvent *event)
{
if (m_canMoveWindow) {
int dx = event->globalX() - m_mousePressX;
int dy = event->globalY() - m_mousePressY;
move(dx, dy);
}
}
/**
* Disallows the user to move the window and resets the window cursor
*/
void UpdaterWindow::mouseReleaseEvent(QMouseEvent *event)
{
m_canMoveWindow = false;
unsetCursor();
event->accept();
}
/**
* Rounds the given \a input to two decimal places
*/
qreal UpdaterWindow::round(qreal input)
{
return qreal(roundf(float(input * 100)) / 100);
}
timeString

@ -19,64 +19,87 @@ class QNetworkReply;
class QSimpleUpdater;
class QNetworkAccessManager;
// UpdaterWindow 类用于管理更新窗口的显示和更新逻辑
class UpdaterWindow : public QDialog
{
Q_OBJECT
public:
// 构造函数,初始化更新窗口
explicit UpdaterWindow(QWidget *parent = 0);
// 析构函数,释放资源
~UpdaterWindow();
// 设置是否显示更新窗口
void setShowWindowDisable(const bool dontShowWindow);
public slots:
// 检查更新force 参数表示是否强制检查
void checkForUpdates(bool force);
signals:
// 信号,当更新窗口显示状态改变时发出
void dontShowUpdateWindowChanged(bool state);
private slots:
// 重置控件状态
void resetControls();
// 更新标题标签
void updateTitleLabel();
// 当有可用更新时调用
void onUpdateAvailable();
// 当下载按钮被点击时调用
void onDownloadButtonClicked();
// 开始下载url 参数表示下载链接
void startDownload(const QUrl &url);
// 打开下载的文件file 参数表示文件路径
void openDownload(const QString &file);
// 当检查更新完成时调用url 参数表示检查的链接
void onCheckFinished(const QString &url);
// 当 xdg-open 命令完成时调用exitCode 参数表示退出码
void onXdgOpenFinished(const int exitCode);
// 打开下载文件夹file 参数表示文件路径
void openDownloadFolder(const QString &file);
// 计算下载大小received 参数表示已接收的字节数total 参数表示总字节数
void calculateSizes(qint64 received, qint64 total);
// 更新下载进度received 参数表示已接收的字节数total 参数表示总字节数
void updateProgress(qint64 received, qint64 total);
// 计算剩余下载时间received 参数表示已接收的字节数total 参数表示总字节数
void calculateTimeRemaining(qint64 received, qint64 total);
// 当下载完成时调用
void onDownloadFinished();
protected:
// 处理鼠标移动事件
void mouseMoveEvent(QMouseEvent *event) override;
// 处理鼠标按下事件
void mousePressEvent(QMouseEvent *event) override;
// 处理鼠标释放事件
void mouseReleaseEvent(QMouseEvent *event) override;
private:
// 四舍五入函数input 参数表示输入值
qreal round(qreal input);
private:
QString m_fileName;
const QDir m_downloadDir;
QString m_fileName; // 文件名
const QDir m_downloadDir; // 下载目录
Ui::UpdaterWindow *m_ui;
Ui::UpdaterWindow *m_ui; // 用户界面指针
QPoint m_dragPosition;
QPoint m_dragPosition; // 窗口拖动位置
int m_mousePressX;
int m_mousePressY;
bool m_canMoveWindow;
bool m_checkingForUpdates;
bool m_dontShowUpdateWindow;
bool m_forced;
int m_mousePressX; // 鼠标按下时的 X 坐标
int m_mousePressY; // 鼠标按下时的 Y 坐标
bool m_canMoveWindow; // 是否可以移动窗口
bool m_checkingForUpdates; // 是否正在检查更新
bool m_dontShowUpdateWindow; // 是否不显示更新窗口
bool m_forced; // 是否强制检查更新
uint m_startTime;
QNetworkReply *m_reply;
QSimpleUpdater *m_updater;
QNetworkAccessManager *m_manager;
uint m_startTime; // 下载开始时间
QNetworkReply *m_reply; // 网络回复指针
QSimpleUpdater *m_updater; // 更新器指针
QNetworkAccessManager *m_manager; // 网络访问管理器指针
};
#endif
#endif
Loading…
Cancel
Save