From 8dfcda0e5147e77d57a93760560b84b15420eaaf Mon Sep 17 00:00:00 2001 From: Le Tan Date: Sun, 14 Jan 2018 21:33:48 +0800 Subject: [PATCH] add Cart to collect notes for further processing --- src/resources/icons/cart.svg | 14 ++ src/resources/icons/clear_cart.svg | 10 + src/resources/icons/delete_cart_item.svg | 10 + .../themes/v_moonlight/v_moonlight.palette | 2 +- src/resources/themes/v_pure/v_pure.css | 6 +- src/resources/themes/v_white/v_white.css | 6 +- src/src.pro | 6 +- src/vcart.cpp | 193 ++++++++++++++++++ src/vcart.h | 57 ++++++ src/veditwindow.cpp | 34 ++- src/veditwindow.h | 3 + src/vfilelist.cpp | 32 ++- src/vfilelist.h | 7 + src/vmainwindow.cpp | 7 + src/vmainwindow.h | 11 + src/vnote.qrc | 3 + src/vsnippetlist.cpp | 1 - 17 files changed, 383 insertions(+), 19 deletions(-) create mode 100644 src/resources/icons/cart.svg create mode 100644 src/resources/icons/clear_cart.svg create mode 100644 src/resources/icons/delete_cart_item.svg create mode 100644 src/vcart.cpp create mode 100644 src/vcart.h diff --git a/src/resources/icons/cart.svg b/src/resources/icons/cart.svg new file mode 100644 index 00000000..9b28db7f --- /dev/null +++ b/src/resources/icons/cart.svg @@ -0,0 +1,14 @@ + + + + + + + + diff --git a/src/resources/icons/clear_cart.svg b/src/resources/icons/clear_cart.svg new file mode 100644 index 00000000..59af5e14 --- /dev/null +++ b/src/resources/icons/clear_cart.svg @@ -0,0 +1,10 @@ + + + + + + diff --git a/src/resources/icons/delete_cart_item.svg b/src/resources/icons/delete_cart_item.svg new file mode 100644 index 00000000..382a85ce --- /dev/null +++ b/src/resources/icons/delete_cart_item.svg @@ -0,0 +1,10 @@ + + + + + + diff --git a/src/resources/themes/v_moonlight/v_moonlight.palette b/src/resources/themes/v_moonlight/v_moonlight.palette index 2b23fc15..585fa600 100644 --- a/src/resources/themes/v_moonlight/v_moonlight.palette +++ b/src/resources/themes/v_moonlight/v_moonlight.palette @@ -11,7 +11,7 @@ codeblock_css_file=v_moonlight_codeblock.css ; without background. You could just specify the foreground colors mapping here. ; It is useful for dark mode theme. '#aabbcc' or 'red' formats are supported. ; col1:col1_new,col2:col2_new -css_color_mapping=#abb2bf:#363636,#282c34:#f5f5f5,#61afef:#0099ff,#98c379:#8e24aa,#2c313a:#e0e0e0,#5c6370:#666666,#373e47:#999999,#6c6c6c:#444444,#c678dd:#0000ee,#e06c75:#880000,#56b6c2:#af00d7,#e6c07b:#008700,#d19a66:#bc6060,#61aeee:#bc6060 +css_color_mapping=#abb2bf:#222222,#282c34:#f5f5f5,#61afef:#0099ff,#98c379:#8e24aa,#2c313a:#e0e0e0,#5c6370:#666666,#373e47:#999999,#6c6c6c:#444444,#c678dd:#0000ee,#e06c75:#880000,#56b6c2:#af00d7,#e6c07b:#008700,#d19a66:#bc6060,#61aeee:#bc6060 [phony] ; Abstract color attributes. diff --git a/src/resources/themes/v_pure/v_pure.css b/src/resources/themes/v_pure/v_pure.css index 4d2d2e06..b2f6a9e5 100644 --- a/src/resources/themes/v_pure/v_pure.css +++ b/src/resources/themes/v_pure/v_pure.css @@ -1,14 +1,14 @@ body { margin: 0 auto; font-family: Helvetica, sans-serif, Tahoma, Arial, Verdana, Geneva, Georgia, Palatino, "Times New Roman", "Hiragino Sans GB", "冬青黑体", "Microsoft YaHei", "微软雅黑", "Microsoft YaHei UI", "WenQuanYi Micro Hei", "文泉驿雅黑", Dengxian, "等线体", STXihei, "华文细黑", "Liberation Sans", "Droid Sans", NSimSun, "新宋体", SimSun, "宋体"; - color: #363636; + color: #222222; line-height: 1; padding: 15px; background: #F5F5F5; } h1, h2, h3, h4, h5, h6 { - color: #363636; + color: #222222; font-weight: bold; margin-top: 20px; margin-bottom: 10px; @@ -93,7 +93,7 @@ pre code { display: block; overflow-x: auto; padding: 0.5em; - color: #363636; + color: #222222; background-color: #E0E0E0; line-height: 1.5; } diff --git a/src/resources/themes/v_white/v_white.css b/src/resources/themes/v_white/v_white.css index 37d0d9eb..d7219aca 100644 --- a/src/resources/themes/v_white/v_white.css +++ b/src/resources/themes/v_white/v_white.css @@ -1,13 +1,13 @@ body { margin: 0 auto; font-family: Helvetica, sans-serif, Tahoma, Arial, Verdana, Geneva, Georgia, Palatino, "Times New Roman", "Hiragino Sans GB", "冬青黑体", "Microsoft YaHei", "微软雅黑", "Microsoft YaHei UI", "WenQuanYi Micro Hei", "文泉驿雅黑", Dengxian, "等线体", STXihei, "华文细黑", "Liberation Sans", "Droid Sans", NSimSun, "新宋体", SimSun, "宋体"; - color: #363636; + color: #222222; line-height: 1; padding: 15px; } h1, h2, h3, h4, h5, h6 { - color: #363636; + color: #222222; font-weight: bold; margin-top: 20px; margin-bottom: 10px; @@ -92,7 +92,7 @@ pre code { display: block; overflow-x: auto; padding: 0.5em; - color: #363636; + color: #222222; background-color: #E0E0E0; line-height: 1.5; } diff --git a/src/src.pro b/src/src.pro index a78f687d..859c5d59 100644 --- a/src/src.pro +++ b/src/src.pro @@ -106,7 +106,8 @@ SOURCES += main.cpp\ dialog/vcopytextashtmldialog.cpp \ vwaitingwidget.cpp \ utils/vwebutils.cpp \ - vlineedit.cpp + vlineedit.cpp \ + vcart.cpp HEADERS += vmainwindow.h \ vdirectorytree.h \ @@ -199,7 +200,8 @@ HEADERS += vmainwindow.h \ dialog/vcopytextashtmldialog.h \ vwaitingwidget.h \ utils/vwebutils.h \ - vlineedit.h + vlineedit.h \ + vcart.h RESOURCES += \ vnote.qrc \ diff --git a/src/vcart.cpp b/src/vcart.cpp new file mode 100644 index 00000000..ac1ffadb --- /dev/null +++ b/src/vcart.cpp @@ -0,0 +1,193 @@ +#include "vcart.h" + +#include + +#include "utils/viconutils.h" +#include "utils/vutils.h" +#include "vmainwindow.h" +#include "vnote.h" +#include "vnotefile.h" + +extern VMainWindow *g_mainWin; + +extern VNote *g_vnote; + +VCart::VCart(QWidget *p_parent) + : QWidget(p_parent) +{ + setupUI(); + + initActions(); +} + +void VCart::setupUI() +{ + m_clearBtn = new QPushButton(VIconUtils::buttonDangerIcon(":/resources/icons/clear_cart.svg"), ""); + m_clearBtn->setToolTip(tr("Clear")); + m_clearBtn->setProperty("FlatBtn", true); + connect(m_clearBtn, &QPushButton::clicked, + this, [this]() { + if (m_itemList->count() > 0) { + int ret = VUtils::showMessage(QMessageBox::Warning, + tr("Warning"), + tr("Are you sure to clear Cart?"), + "", + QMessageBox::Ok | QMessageBox::Cancel, + QMessageBox::Ok, + g_mainWin, + MessageBoxType::Danger); + if (ret == QMessageBox::Ok) { + m_itemList->clear(); + } + } + }); + + m_numLabel = new QLabel(); + + QHBoxLayout *btnLayout = new QHBoxLayout; + btnLayout->addWidget(m_clearBtn); + btnLayout->addStretch(); + btnLayout->addWidget(m_numLabel); + btnLayout->setContentsMargins(0, 0, 3, 0); + + m_itemList = new QListWidget(); + m_itemList->setAttribute(Qt::WA_MacShowFocusRect, false); + m_itemList->setContextMenuPolicy(Qt::CustomContextMenu); + m_itemList->setSelectionMode(QAbstractItemView::ExtendedSelection); + connect(m_itemList, &QListWidget::customContextMenuRequested, + this, &VCart::handleContextMenuRequested); + connect(m_itemList, &QListWidget::itemActivated, + this, &VCart::openItem); + + QVBoxLayout *mainLayout = new QVBoxLayout(); + mainLayout->addLayout(btnLayout); + mainLayout->addWidget(m_itemList); + mainLayout->setContentsMargins(0, 0, 0, 0); + + setLayout(mainLayout); +} + +void VCart::initActions() +{ + m_openAct = new QAction(tr("&Open"), this); + m_openAct->setToolTip(tr("Open selected notes")); + connect(m_openAct, &QAction::triggered, + this, &VCart::openSelectedItems); + + m_locateAct = new QAction(VIconUtils::menuIcon(":/resources/icons/locate_note.svg"), + tr("Locate To Folder"), + this); + m_locateAct->setToolTip(tr("Locate the folder of current note")); + connect(m_locateAct, &QAction::triggered, + this, &VCart::locateCurrentItem); + + m_deleteAct = new QAction(VIconUtils::menuDangerIcon(":/resources/icons/delete_cart_item.svg"), + tr("&Delete"), + this); + m_deleteAct->setToolTip(tr("Delete selected items from Cart")); + connect(m_deleteAct, &QAction::triggered, + this, &VCart::deleteSelectedItems); +} + +void VCart::handleContextMenuRequested(QPoint p_pos) +{ + QListWidgetItem *item = m_itemList->itemAt(p_pos); + QMenu menu(this); + menu.setToolTipsVisible(true); + + if (item) { + int itemCount = m_itemList->selectedItems().size(); + if (itemCount == 1) { + menu.addAction(m_openAct); + menu.addAction(m_locateAct); + } + + menu.addAction(m_deleteAct); + } + + if (!menu.actions().isEmpty()) { + menu.exec(m_itemList->mapToGlobal(p_pos)); + } +} + +void VCart::addFile(const QString &p_filePath) +{ + if (p_filePath.isEmpty() + || findFileInCart(p_filePath) != -1) { + return; + } + + addItem(p_filePath); +} + +int VCart::findFileInCart(const QString &p_file) const +{ + int cnt = m_itemList->count(); + for (int i = 0; i < cnt; ++i) { + if (VUtils::equalPath(m_itemList->item(i)->data(Qt::UserRole).toString(), + p_file)) { + return i; + } + } + + return -1; +} + +void VCart::addItem(const QString &p_path) +{ + QListWidgetItem *item = new QListWidgetItem(VUtils::fileNameFromPath(p_path)); + item->setToolTip(p_path); + item->setData(Qt::UserRole, p_path); + + m_itemList->addItem(item); + + int cnt = m_itemList->count(); + if (cnt > 0) { + m_numLabel->setText(tr("%1 %2").arg(cnt) + .arg(cnt > 1 ? tr("Items") : tr("Item"))); + } else { + m_numLabel->setText(""); + } +} + +void VCart::deleteSelectedItems() +{ + QList selectedItems = m_itemList->selectedItems(); + for (auto it : selectedItems) { + delete it; + } +} + +void VCart::openSelectedItems() const +{ + openItem(m_itemList->currentItem()); +} + +void VCart::locateCurrentItem() +{ + auto item = m_itemList->currentItem(); + if (!item) { + return; + } + + VFile *file = g_vnote->getInternalFile(getFilePath(item)); + if (file) { + g_mainWin->locateFile(file); + } +} + +void VCart::openItem(const QListWidgetItem *p_item) const +{ + if (!p_item) { + return; + } + + QStringList files; + files << getFilePath(p_item); + g_mainWin->openFiles(files); +} + +QString VCart::getFilePath(const QListWidgetItem *p_item) const +{ + return p_item->data(Qt::UserRole).toString(); +} diff --git a/src/vcart.h b/src/vcart.h new file mode 100644 index 00000000..42bc4c27 --- /dev/null +++ b/src/vcart.h @@ -0,0 +1,57 @@ +#ifndef VCART_H +#define VCART_H + +#include +#include + +#include "vnavigationmode.h" + +class QPushButton; +class QListWidget; +class QListWidgetItem; +class QLabel; +class QAction; +class QKeyEvent; +class QFocusEvent; + +class VCart : public QWidget +{ + Q_OBJECT +public: + explicit VCart(QWidget *p_parent = nullptr); + + void addFile(const QString &p_filePath); + +private slots: + void handleContextMenuRequested(QPoint p_pos); + + void deleteSelectedItems(); + + void openSelectedItems() const; + + void openItem(const QListWidgetItem *p_item) const; + + void locateCurrentItem(); + +private: + void setupUI(); + + void initActions(); + + // Return index of item. + int findFileInCart(const QString &p_file) const; + + void addItem(const QString &p_path); + + QString getFilePath(const QListWidgetItem *p_item) const; + + QPushButton *m_clearBtn; + QLabel *m_numLabel; + QListWidget *m_itemList; + + QAction *m_openAct; + QAction *m_locateAct; + QAction *m_deleteAct; +}; + +#endif // VCART_H diff --git a/src/veditwindow.cpp b/src/veditwindow.cpp index 730d6177..97a94b63 100644 --- a/src/veditwindow.cpp +++ b/src/veditwindow.cpp @@ -1,5 +1,6 @@ #include #include + #include "veditwindow.h" #include "vedittab.h" #include "utils/vutils.h" @@ -12,6 +13,7 @@ #include "vfilelist.h" #include "vconfigmanager.h" #include "utils/viconutils.h" +#include "vcart.h" extern VConfigManager *g_config; extern VMainWindow *g_mainWin; @@ -90,7 +92,7 @@ void VEditWindow::initTabActions() m_closeOthersAct->setToolTip(tr("Close all other note tabs")); connect(m_closeOthersAct, &QAction::triggered, this, [this](){ - int tab = this->m_closeTabAct->data().toInt(); + int tab = this->m_closeOthersAct->data().toInt(); Q_ASSERT(tab != -1); for (int i = tab - 1; i >= 0; --i) { @@ -114,7 +116,7 @@ void VEditWindow::initTabActions() m_closeRightAct->setToolTip(tr("Close all the note tabs to the right of current tab")); connect(m_closeRightAct, &QAction::triggered, this, [this](){ - int tab = this->m_closeTabAct->data().toInt(); + int tab = this->m_closeRightAct->data().toInt(); Q_ASSERT(tab != -1); for (int i = tab + 1; i < this->count();) { @@ -131,7 +133,7 @@ void VEditWindow::initTabActions() m_noteInfoAct->setToolTip(tr("View and edit information of the note")); connect(m_noteInfoAct, &QAction::triggered, this, [this](){ - int tab = this->m_closeTabAct->data().toInt(); + int tab = this->m_noteInfoAct->data().toInt(); Q_ASSERT(tab != -1); VEditTab *editor = getTab(tab); @@ -145,11 +147,25 @@ void VEditWindow::initTabActions() } }); + m_addToCartAct = new QAction(tr("Add To Cart"), this); + m_addToCartAct->setToolTip(tr("Add this note to Cart for further processing")); + connect(m_addToCartAct, &QAction::triggered, + this, [this](){ + int tab = this->m_addToCartAct->data().toInt(); + Q_ASSERT(tab != -1); + + VEditTab *editor = getTab(tab); + QPointer file = editor->getFile(); + Q_ASSERT(file); + g_mainWin->getCart()->addFile(file->fetchPath()); + g_mainWin->showStatusMessage(tr("1 note added to Cart")); + }); + m_openLocationAct = new QAction(tr("Open Note Location"), this); m_openLocationAct->setToolTip(tr("Open the folder containing this note in operating system")); connect(m_openLocationAct, &QAction::triggered, this, [this](){ - int tab = this->m_closeTabAct->data().toInt(); + int tab = this->m_openLocationAct->data().toInt(); Q_ASSERT(tab != -1); VEditTab *editor = getTab(tab); @@ -163,7 +179,7 @@ void VEditWindow::initTabActions() m_reloadAct->setToolTip(tr("Reload the content of this note from disk")); connect(m_reloadAct, &QAction::triggered, this, [this](){ - int tab = this->m_closeTabAct->data().toInt(); + int tab = this->m_reloadAct->data().toInt(); Q_ASSERT(tab != -1); VEditTab *editor = getTab(tab); @@ -175,7 +191,7 @@ void VEditWindow::initTabActions() m_recycleBinAct->setToolTip(tr("Open the recycle bin of this note")); connect(m_recycleBinAct, &QAction::triggered, this, [this]() { - int tab = this->m_closeTabAct->data().toInt(); + int tab = this->m_recycleBinAct->data().toInt(); Q_ASSERT(tab != -1); VEditTab *editor = getTab(tab); @@ -647,6 +663,9 @@ void VEditWindow::tabbarContextMenuRequested(QPoint p_pos) m_reloadAct->setData(tab); menu.addAction(m_reloadAct); + m_addToCartAct->setData(tab); + menu.addAction(m_addToCartAct); + m_noteInfoAct->setData(tab); menu.addAction(m_noteInfoAct); } else if (file->getType() == FileType::Orphan @@ -660,6 +679,9 @@ void VEditWindow::tabbarContextMenuRequested(QPoint p_pos) m_reloadAct->setData(tab); menu.addAction(m_reloadAct); + m_addToCartAct->setData(tab); + menu.addAction(m_addToCartAct); + m_noteInfoAct->setData(tab); menu.addAction(m_noteInfoAct); } diff --git a/src/veditwindow.h b/src/veditwindow.h index ceb7070a..6eb1306c 100644 --- a/src/veditwindow.h +++ b/src/veditwindow.h @@ -205,6 +205,9 @@ private: // View and edit info about this note. QAction *m_noteInfoAct; + // Add this note to Cart. + QAction *m_addToCartAct; + // Open the location (the folder containing this file) of this note. QAction *m_openLocationAct; diff --git a/src/vfilelist.cpp b/src/vfilelist.cpp index 2886d94d..b2d169d3 100644 --- a/src/vfilelist.cpp +++ b/src/vfilelist.cpp @@ -18,6 +18,7 @@ #include "utils/vimnavigationforwidget.h" #include "utils/viconutils.h" #include "dialog/vtipsdialog.h" +#include "vcart.h" extern VConfigManager *g_config; extern VNote *g_vnote; @@ -157,6 +158,11 @@ void VFileList::initActions() connect(m_openLocationAct, &QAction::triggered, this, &VFileList::openFileLocation); + m_addToCartAct = new QAction(tr("Add To Cart"), this); + m_addToCartAct->setToolTip(tr("Add selected notes to Cart for further processing")); + connect(m_addToCartAct, &QAction::triggered, + this, &VFileList::addFileToCart); + m_sortAct = new QAction(VIconUtils::menuIcon(":/resources/icons/sort.svg"), tr("&Sort"), this); @@ -220,6 +226,20 @@ void VFileList::openFileLocation() const } } +void VFileList::addFileToCart() const +{ + QList items = fileList->selectedItems(); + VCart *cart = g_mainWin->getCart(); + + for (int i = 0; i < items.size(); ++i) { + cart->addFile(getVFile(items[i])->fetchPath()); + } + + g_mainWin->showStatusMessage(tr("%1 %2 added to Cart") + .arg(items.size()) + .arg(items.size() > 1 ? tr("notes") : tr("note"))); +} + void VFileList::fileInfo(VNoteFile *p_file) { if (!p_file) { @@ -522,7 +542,9 @@ void VFileList::contextMenuRequested(QPoint pos) return; } - if (item && fileList->selectedItems().size() == 1) { + int selectedSize = fileList->selectedItems().size(); + + if (item && selectedSize == 1) { VNoteFile *file = getVFile(item); if (file) { if (file->getDocType() == DocType::Markdown) { @@ -558,9 +580,13 @@ void VFileList::contextMenuRequested(QPoint pos) if (item) { menu.addSeparator(); - menu.addAction(m_openLocationAct); + if (selectedSize == 1) { + menu.addAction(m_openLocationAct); + } - if (fileList->selectedItems().size() == 1) { + menu.addAction(m_addToCartAct); + + if (selectedSize == 1) { menu.addAction(fileInfoAct); } } diff --git a/src/vfilelist.h b/src/vfilelist.h index b8923068..8c4ff005 100644 --- a/src/vfilelist.h +++ b/src/vfilelist.h @@ -83,6 +83,9 @@ private slots: // Valid only when there is only one selected file. void openFileLocation() const; + // Add selected files to Cart. + void addFileToCart() const; + // Copy selected files to clipboard. // Will put a Json string into the clipboard which contains the information // about copied files. @@ -174,9 +177,13 @@ private: QAction *copyAct; QAction *cutAct; QAction *pasteAct; + QAction *m_openLocationAct; + QAction *m_sortAct; + QAction *m_addToCartAct; + // Context sub-menu of Open With. QMenu *m_openWithMenu; diff --git a/src/vmainwindow.cpp b/src/vmainwindow.cpp index 53c2ac64..8ea10132 100644 --- a/src/vmainwindow.cpp +++ b/src/vmainwindow.cpp @@ -35,6 +35,7 @@ #include "vpalette.h" #include "utils/viconutils.h" #include "dialog/vtipsdialog.h" +#include "vcart.h" extern VConfigManager *g_config; @@ -1259,6 +1260,9 @@ void VMainWindow::initDockWindows() // Snippets. m_snippetList = new VSnippetList(this); + // Cart. + m_cart = new VCart(this); + m_toolBox = new VToolBox(this); m_toolBox->addItem(outline, ":/resources/icons/outline.svg", @@ -1266,6 +1270,9 @@ void VMainWindow::initDockWindows() m_toolBox->addItem(m_snippetList, ":/resources/icons/snippets.svg", tr("Snippets")); + m_toolBox->addItem(m_cart, + ":/resources/icons/cart.svg", + tr("Cart")); toolDock->setWidget(m_toolBox); addDockWidget(Qt::RightDockWidgetArea, toolDock); diff --git a/src/vmainwindow.h b/src/vmainwindow.h index 5a33cfb5..3defb144 100644 --- a/src/vmainwindow.h +++ b/src/vmainwindow.h @@ -37,6 +37,7 @@ class QSystemTrayIcon; class VButtonWithWidget; class VAttachmentList; class VSnippetList; +class VCart; enum class PanelViewState { @@ -63,6 +64,8 @@ public: VSnippetList *getSnippetList() const; + VCart *getCart() const; + // View and edit the information of @p_file, which is an orphan file. void editOrphanFileInfo(VFile *p_file); @@ -304,6 +307,9 @@ private: // View and manage snippets. VSnippetList *m_snippetList; + // View and manage cart. + VCart *m_cart; + VFindReplaceDialog *m_findReplaceDialog; VVimIndicator *m_vimIndicator; VTabIndicator *m_tabIndicator; @@ -413,4 +419,9 @@ inline VSnippetList *VMainWindow::getSnippetList() const return m_snippetList; } +inline VCart *VMainWindow::getCart() const +{ + return m_cart; +} + #endif // VMAINWINDOW_H diff --git a/src/vnote.qrc b/src/vnote.qrc index 2a5cda31..9c02008e 100644 --- a/src/vnote.qrc +++ b/src/vnote.qrc @@ -234,5 +234,8 @@ translations/qdialogbuttonbox_zh_CN.qm translations/qwebengine_zh_CN.qm translations/qt_zh_CN.qm + resources/icons/clear_cart.svg + resources/icons/cart.svg + resources/icons/delete_cart_item.svg diff --git a/src/vsnippetlist.cpp b/src/vsnippetlist.cpp index 3e4c9f9d..094535e8 100644 --- a/src/vsnippetlist.cpp +++ b/src/vsnippetlist.cpp @@ -72,7 +72,6 @@ void VSnippetList::setupUI() m_snippetList->setAttribute(Qt::WA_MacShowFocusRect, false); m_snippetList->setContextMenuPolicy(Qt::CustomContextMenu); m_snippetList->setSelectionMode(QAbstractItemView::ExtendedSelection); - m_snippetList->setEditTriggers(QAbstractItemView::SelectedClicked); connect(m_snippetList, &QListWidget::customContextMenuRequested, this, &VSnippetList::handleContextMenuRequested); connect(m_snippetList, &QListWidget::itemActivated,