support history navigation

This commit is contained in:
Le Tan 2018-05-16 20:35:59 +08:00
parent 4284d20dea
commit f6436bfabf
43 changed files with 1132 additions and 72 deletions

View File

@ -4,7 +4,7 @@
<svg version="1.1" id="Layer_1" xmlns="http://www.w3.org/2000/svg" xmlns:xlink="http://www.w3.org/1999/xlink" x="0px" y="0px"
width="512px" height="512px" viewBox="0 0 512 512" enable-background="new 0 0 512 512" xml:space="preserve">
<g>
<path fill="#010101" d="M169.6,377.6c-22.882,0-41.6,18.718-41.6,41.601c0,22.882,18.718,41.6,41.6,41.6s41.601-18.718,41.601-41.6
<path fill="#000000" d="M169.6,377.6c-22.882,0-41.6,18.718-41.6,41.601c0,22.882,18.718,41.6,41.6,41.6s41.601-18.718,41.601-41.6
C211.2,396.317,192.481,377.6,169.6,377.6z M48,51.2v41.6h41.6l74.883,151.682l-31.308,50.954c-3.118,5.2-5.2,12.482-5.2,19.765
c0,27.85,19.025,41.6,44.825,41.6H416v-40H177.893c-3.118,0-5.2-2.082-5.2-5.2c0-1.036,2.207-5.2,2.207-5.2l20.782-32.8h154.954
c15.601,0,29.128-8.317,36.4-21.836l74.882-128.8c1.237-2.461,2.082-6.246,2.082-10.399c0-11.446-9.364-19.765-20.8-19.765H135.364

Before

Width:  |  Height:  |  Size: 1.1 KiB

After

Width:  |  Height:  |  Size: 1.1 KiB

View File

@ -0,0 +1,10 @@
<?xml version="1.0" encoding="utf-8"?>
<!-- Generator: Adobe Illustrator 16.2.1, SVG Export Plug-In . SVG Version: 6.00 Build 0) -->
<!DOCTYPE svg PUBLIC "-//W3C//DTD SVG 1.1//EN" "http://www.w3.org/Graphics/SVG/1.1/DTD/svg11.dtd">
<svg version="1.1" id="Layer_1" xmlns="http://www.w3.org/2000/svg" xmlns:xlink="http://www.w3.org/1999/xlink" x="0px" y="0px"
width="512px" height="512px" viewBox="0 0 512 512" style="enable-background:new 0 0 512 512;" xml:space="preserve">
<path style="fill:#C9302C" d="M443.6,387.1L312.4,255.4l131.5-130c5.4-5.4,5.4-14.2,0-19.6l-37.4-37.6c-2.6-2.6-6.1-4-9.8-4c-3.7,0-7.2,1.5-9.8,4
L256,197.8L124.9,68.3c-2.6-2.6-6.1-4-9.8-4c-3.7,0-7.2,1.5-9.8,4L68,105.9c-5.4,5.4-5.4,14.2,0,19.6l131.5,130L68.4,387.1
c-2.6,2.6-4.1,6.1-4.1,9.8c0,3.7,1.4,7.2,4.1,9.8l37.4,37.6c2.7,2.7,6.2,4.1,9.8,4.1c3.5,0,7.1-1.3,9.8-4.1L256,313.1l130.7,131.1
c2.7,2.7,6.2,4.1,9.8,4.1c3.5,0,7.1-1.3,9.8-4.1l37.4-37.6c2.6-2.6,4.1-6.1,4.1-9.8C447.7,393.2,446.2,389.7,443.6,387.1z"/>
</svg>

After

Width:  |  Height:  |  Size: 995 B

View File

@ -0,0 +1,9 @@
<?xml version="1.0" encoding="utf-8"?>
<!-- Generator: Adobe Illustrator 16.2.1, SVG Export Plug-In . SVG Version: 6.00 Build 0) -->
<!DOCTYPE svg PUBLIC "-//W3C//DTD SVG 1.1//EN" "http://www.w3.org/Graphics/SVG/1.1/DTD/svg11.dtd">
<svg version="1.1" id="Layer_1" xmlns="http://www.w3.org/2000/svg" xmlns:xlink="http://www.w3.org/1999/xlink" x="0px" y="0px" width="512px" height="512px" viewBox="0 0 512 512" enable-background="new 0 0 512 512" xml:space="preserve">
<g fill-opacity=".9">
<path style="fill:#000000" d="M255.8 48C141 48 48 141.2 48 256s93 208 207.8 208c115 0 208.2-93.2 208.2-208S370.8 48 255.8 48zm.2 374.4c-91.9 0-166.4-74.5-166.4-166.4S164.1 89.6 256 89.6 422.4 164.1 422.4 256 347.9 422.4 256 422.4z"/>
<path style="fill:#000000" d="M266.4 152h-31.2v124.8l109.2 65.5 15.6-25.6-93.6-55.5V152z"/>
</g>
</svg>

After

Width:  |  Height:  |  Size: 836 B

View File

@ -0,0 +1,11 @@
<?xml version="1.0" encoding="utf-8"?>
<!-- Generator: Adobe Illustrator 16.2.1, SVG Export Plug-In . SVG Version: 6.00 Build 0) -->
<!DOCTYPE svg PUBLIC "-//W3C//DTD SVG 1.1//EN" "http://www.w3.org/Graphics/SVG/1.1/DTD/svg11.dtd">
<svg version="1.1" id="Layer_1" xmlns="http://www.w3.org/2000/svg" xmlns:xlink="http://www.w3.org/1999/xlink" x="0px" y="0px"
width="512px" height="512px" viewBox="0 0 512 512" style="enable-background:new 0 0 512 512;" xml:space="preserve">
<path fill="#000000" d="M331.8,228C331.8,228,331.8,228,331.8,228c-1.2-0.5-2.4-1-3.5-1.7c-7-4-12.2-10.9-13.9-19.2L295.9,89.4l-0.2-5.8
c0-7.1,4.1-10.2,10-13l0,0c0.7-0.3,1.4-0.6,2.1-0.9c7.2-3.4,12.1-7.8,12.1-16.3c0-20.1-6.5-21.4-18.2-21.4h-91.3
c-11.7,0-18.2,1.2-18.2,21.4c0,8.5,4.9,12.9,12.1,16.3c0.7,0.3,1.4,0.5,2.1,0.9c0,0,0,0,0,0c5.9,2.9,10,6,10,13l-0.2,5.8
l-18.5,117.7c-1.7,8.3-6.9,15.2-13.9,19.2c-1.1,0.7-2.3,1.2-3.5,1.7c0,0,0,0,0,0c-19.7,10.2-36.2,30.8-36.2,54.7
c0,15.9,3.5,21.3,15.2,21.3H240l12,176h8l12-176h80.8c11.7,0,15.2-4.7,15.2-21.3C368,258.8,351.5,238.2,331.8,228z"/>
</svg>

After

Width:  |  Height:  |  Size: 1.0 KiB

View File

@ -119,6 +119,10 @@ search_hit_item_bg=@master_dark_bg
ue_cmd_busy_border=#3F51B5
ue_cmd_fail_border=@danger_bg
; VListWidget/VTreeWidget separator.
item_separator_fg=@master_light_bg
item_separator_bg=@separator_bg
[widgets]
; Widget color attributes.
@ -138,6 +142,7 @@ menubar_item_selected_bg=@selected_bg
; Menu.
menu_bg=@base_bg
menu_fg=@base_fg
menu_border_bg=@border_bg
menu_item_disabled_fg=@disabled_fg
menu_item_selected_fg=@selected_fg
menu_item_selected_bg=@selected_bg

View File

@ -40,7 +40,7 @@ QMenuBar::item:selected {
QMenu {
background: @menu_bg;
color: @menu_fg;
margin: 2px;
border: 2px solid @menu_border_bg;
}
QMenu::icon {
@ -402,10 +402,10 @@ VButtonMenuItem:disabled {
/* QComboBox */
QComboBox#NotebookSelector {
border: none;
font-size: 13pt;
padding-top: 3px;
padding-bottom: 3px;
icon-size: $30px;
font-size: 12pt;
padding-top: 5px;
padding-bottom: 5px;
icon-size: $24px;
font-weight: bold;
color: @combobox_notebookselector_fg;
background: @combobox_notebookselector_bg;
@ -424,14 +424,14 @@ QComboBox#NotebookSelector:hover {
QComboBox#NotebookSelector QListWidget {
border: 1px solid @combobox_view_border;
background-color: @combobox_bg;
font-size: 13pt;
font-size: 12pt;
font-weight: normal;
icon-size: $30px;
icon-size: $24px;
}
QComboBox#NotebookSelector QListWidget::item {
padding-top: $10px;
padding-bottom: $10px;
padding-top: $5px;
padding-bottom: $5px;
}
QComboBox#NotebookSelector QListWidget::item:hover {
@ -851,6 +851,10 @@ QListView::item:selected:!active {
color: @listview_item_selected_inactive_fg;
background: @listview_item_selected_inactive_bg;
}
QListView::item:disabled {
background: transparent;
}
/* End QListView */
/* QSplitter */
@ -1250,6 +1254,10 @@ QWidget[ToolBoxTitle="true"] {
border-bottom: 2px solid @toolbox_title_border;
}
QWidget[ToolBoxTitle="true"] QPushButton[ToolBoxTitleBtn="true"] {
height: $20px;
}
QWidget[MainEditor="true"] {
border: none;
}

View File

@ -87,6 +87,10 @@ search_hit_item_bg=#80CBC4
ue_cmd_busy_border=#3F51B5
ue_cmd_fail_border=@danger_bg
; VListWidget/VTreeWidget separator.
item_separator_fg=@content_fg
item_separator_bg=@separator_bg
[widgets]
; Widget color attributes.

View File

@ -294,10 +294,10 @@ VButtonMenuItem:disabled {
/* QComboBox */
QComboBox#NotebookSelector {
border: none;
font-size: 13pt;
padding-top: 3px;
padding-bottom: 3px;
icon-size: $30px;
font-size: 12pt;
padding-top: 5px;
padding-bottom: 5px;
icon-size: $24px;
background: @combobox_bg;
}
@ -328,13 +328,13 @@ QComboBox#NotebookSelector::down-arrow:disabled {
QComboBox#NotebookSelector QListWidget {
border: 1px solid @combobox_view_border;
background-color: @combobox_bg;
font-size: 13pt;
icon-size: $30px;
font-size: 12pt;
icon-size: $24px;
}
QComboBox#NotebookSelector QListWidget::item {
padding-top: $10px;
padding-bottom: $10px;
padding-top: $5px;
padding-bottom: $5px;
}
QComboBox#NotebookSelector QListWidget::item:hover {

View File

@ -113,6 +113,10 @@ search_hit_item_bg=#CCE7E4
ue_cmd_busy_border=#3F51B5
ue_cmd_fail_border=@danger_bg
; VListWidget/VTreeWidget separator.
item_separator_fg=@master_dark_bg
item_separator_bg=@separator_bg
[widgets]
; Widget color attributes.
@ -120,7 +124,7 @@ ue_cmd_fail_border=@danger_bg
widget_fg=@base_fg
; Separator of dock widgets.
dock_separator_bg=@border_bg
dock_separator_bg=@separator_bg
dock_separator_hover_bg=@hover_bg
dock_separator_pressed_bg=@pressed_bg
@ -132,6 +136,7 @@ menubar_item_selected_bg=@selected_bg
; Menu.
menu_bg=@base_bg
menu_fg=@base_fg
menu_border_bg=@border_bg
menu_item_disabled_fg=@disabled_fg
menu_item_selected_fg=@selected_fg
menu_item_selected_bg=@selected_bg

View File

@ -40,7 +40,7 @@ QMenuBar::item:selected {
QMenu {
background: @menu_bg;
color: @menu_fg;
margin: 2px;
border: 2px solid @menu_border_bg;
}
QMenu::icon {
@ -402,10 +402,10 @@ VButtonMenuItem:disabled {
/* QComboBox */
QComboBox#NotebookSelector {
border: none;
font-size: 13pt;
padding-top: 3px;
padding-bottom: 3px;
icon-size: $30px;
font-size: 12pt;
padding-top: 5px;
padding-bottom: 5px;
icon-size: $24px;
font-weight: bold;
color: @combobox_notebookselector_fg;
background: @combobox_notebookselector_bg;
@ -424,14 +424,14 @@ QComboBox#NotebookSelector:hover {
QComboBox#NotebookSelector QListWidget {
border: 1px solid @combobox_view_border;
background-color: @combobox_bg;
font-size: 13pt;
font-size: 12pt;
font-weight: normal;
icon-size: $30px;
icon-size: $24px;
}
QComboBox#NotebookSelector QListWidget::item {
padding-top: $10px;
padding-bottom: $10px;
padding-top: $5px;
padding-bottom: $5px;
}
QComboBox#NotebookSelector QListWidget::item:hover {
@ -851,6 +851,10 @@ QListView::item:selected:!active {
color: @listview_item_selected_inactive_fg;
background: @listview_item_selected_inactive_bg;
}
QListView::item:disabled {
background: transparent;
}
/* End QListView */
/* QSplitter */
@ -1249,6 +1253,10 @@ QWidget[ToolBoxTitle="true"] {
border-bottom: $2px solid @toolbox_title_border;
}
QWidget[ToolBoxTitle="true"] QPushButton[ToolBoxTitleBtn="true"] {
height: $20px;
}
QWidget[MainEditor="true"] {
border: none;
}

View File

@ -209,6 +209,10 @@ enable_wildcard_in_simple_search=true
; scope,object,target,engine,option,pattern
search_options=4,2,7,0,0,""
; Number of items in history
; 0 to disable history
history_size=50
[export]
; Path of the wkhtmltopdf tool
wkhtmltopdf=wkhtmltopdf

View File

@ -131,7 +131,8 @@ SOURCES += main.cpp\
vlivepreviewhelper.cpp \
vmathjaxpreviewhelper.cpp \
vmathjaxwebdocument.cpp \
vmathjaxinplacepreviewhelper.cpp
vmathjaxinplacepreviewhelper.cpp \
vhistorylist.cpp
HEADERS += vmainwindow.h \
vdirectorytree.h \
@ -254,7 +255,9 @@ HEADERS += vmainwindow.h \
vmathjaxpreviewhelper.h \
vmathjaxwebdocument.h \
vmathjaxinplacepreviewhelper.h \
markdownitoption.h
markdownitoption.h \
vhistorylist.h \
vhistoryentry.h
RESOURCES += \
vnote.qrc \

View File

@ -41,7 +41,7 @@ void VCart::setupUI()
g_mainWin,
MessageBoxType::Danger);
if (ret == QMessageBox::Ok) {
m_itemList->clear();
m_itemList->clearAll();
updateNumberLabel();
}
}
@ -55,7 +55,7 @@ void VCart::setupUI()
btnLayout->addWidget(m_numLabel);
btnLayout->setContentsMargins(0, 0, 0, 0);
m_itemList = new QListWidget();
m_itemList = new VListWidget();
m_itemList->setAttribute(Qt::WA_MacShowFocusRect, false);
m_itemList->setContextMenuPolicy(Qt::CustomContextMenu);
m_itemList->setSelectionMode(QAbstractItemView::ExtendedSelection);
@ -109,9 +109,9 @@ void VCart::handleContextMenuRequested(QPoint p_pos)
menu.setToolTipsVisible(true);
if (item) {
int itemCount = m_itemList->selectedItems().size();
if (itemCount == 1) {
menu.addAction(m_openAct);
menu.addAction(m_openAct);
if (m_itemList->selectedItems().size() == 1) {
menu.addAction(m_locateAct);
}
@ -174,7 +174,15 @@ void VCart::deleteSelectedItems()
void VCart::openSelectedItems() const
{
openItem(m_itemList->currentItem());
QStringList files;
QList<QListWidgetItem *> selectedItems = m_itemList->selectedItems();
for (auto it : selectedItems) {
files << getFilePath(it);
}
if (!files.isEmpty()) {
g_mainWin->openFiles(files);
}
}
void VCart::locateCurrentItem()
@ -266,3 +274,22 @@ void VCart::updateNumberLabel() const
m_numLabel->setText(tr("%1 %2").arg(cnt)
.arg(cnt > 1 ? tr("Items") : tr("Item")));
}
void VCart::showNavigation()
{
VNavigationMode::showNavigation(m_itemList);
}
bool VCart::handleKeyNavigation(int p_key, bool &p_succeed)
{
static bool secondKey = false;
return VNavigationMode::handleKeyNavigation(m_itemList,
secondKey,
p_key,
p_succeed);
}
QWidget *VCart::getContentWidget() const
{
return m_itemList;
}

View File

@ -7,14 +7,12 @@
#include "vnavigationmode.h"
class QPushButton;
class QListWidget;
class VListWidget;
class QListWidgetItem;
class QLabel;
class QAction;
class QKeyEvent;
class QFocusEvent;
class VCart : public QWidget
class VCart : public QWidget, public VNavigationMode
{
Q_OBJECT
public:
@ -26,6 +24,12 @@ public:
QVector<QString> getFiles() const;
QWidget *getContentWidget() const;
// Implementations for VNavigationMode.
void showNavigation() Q_DECL_OVERRIDE;
bool handleKeyNavigation(int p_key, bool &p_succeed) Q_DECL_OVERRIDE;
private slots:
void handleContextMenuRequested(QPoint p_pos);
@ -55,7 +59,7 @@ private:
QPushButton *m_clearBtn;
QLabel *m_numLabel;
QListWidget *m_itemList;
VListWidget *m_itemList;
QAction *m_openAct;
QAction *m_locateAct;

View File

@ -293,6 +293,11 @@ void VConfigManager::initialize()
m_enableGraphviz = getConfigFromSettings("global", "enable_graphviz").toBool();
m_graphvizDot = getConfigFromSettings("web", "graphviz_dot").toString();
m_historySize = getConfigFromSettings("global", "history_size").toInt();
if (m_historySize < 0) {
m_historySize = 0;
}
}
void VConfigManager::initSettings()
@ -1210,9 +1215,42 @@ void VConfigManager::setLastOpenedFiles(const QVector<VFileSessionInfo> &p_files
}
m_sessionSettings->endArray();
qDebug() << "write" << p_files.size()
<< "items in [last_opened_files] section";
}
void VConfigManager::getHistory(QLinkedList<VHistoryEntry> &p_history)
{
p_history.clear();
int size = m_sessionSettings->beginReadArray("history");
for (int i = 0; i < size; ++i) {
m_sessionSettings->setArrayIndex(i);
p_history.append(VHistoryEntry::fromSettings(m_sessionSettings));
}
m_sessionSettings->endArray();
}
void VConfigManager::setHistory(const QLinkedList<VHistoryEntry> &p_history)
{
if (m_hasReset) {
return;
}
const QString section("history");
// Clear it first
m_sessionSettings->beginGroup(section);
m_sessionSettings->remove("");
m_sessionSettings->endGroup();
m_sessionSettings->beginWriteArray(section);
int i = 0;
for (auto it = p_history.begin(); it != p_history.end(); ++it, ++i) {
m_sessionSettings->setArrayIndex(i);
it->toSettings(m_sessionSettings);
}
m_sessionSettings->endArray();
}
QVector<VMagicWord> VConfigManager::getCustomMagicWords()

View File

@ -7,6 +7,7 @@
#include <QVector>
#include <QSettings>
#include <QHash>
#include <QLinkedList>
#include "vnotebook.h"
#include "hgmarkdownhighlighter.h"
@ -15,6 +16,7 @@
#include "vfilesessioninfo.h"
#include "utils/vmetawordmanager.h"
#include "markdownitoption.h"
#include "vhistoryentry.h"
class QJsonObject;
class QString;
@ -356,6 +358,13 @@ public:
// Write last opened files to [last_opened_files] of session.ini.
void setLastOpenedFiles(const QVector<VFileSessionInfo> &p_files);
// Read history from [history] of session.ini.
void getHistory(QLinkedList<VHistoryEntry> &p_history);
void setHistory(const QLinkedList<VHistoryEntry> &p_history);
int getHistorySize() const;
// Read custom magic words from [magic_words] section.
QVector<VMagicWord> getCustomMagicWords();
@ -884,6 +893,9 @@ private:
QString m_plantUMLCmd;
// Size of history.
int m_historySize;
// The name of the config file in each directory, obsolete.
// Use c_dirConfigFile instead.
static const QString c_obsoleteDirConfigFile;
@ -2284,4 +2296,9 @@ inline void VConfigManager::setGraphvizDot(const QString &p_dotPath)
m_graphvizDot = p_dotPath;
setConfigToSettings("web", "graphviz_dot", p_dotPath);
}
inline int VConfigManager::getHistorySize() const
{
return m_historySize;
}
#endif // VCONFIGMANAGER_H

View File

@ -13,6 +13,7 @@
#include "utils/vimnavigationforwidget.h"
#include "utils/viconutils.h"
#include "vfilelist.h"
#include "vhistorylist.h"
extern VMainWindow *g_mainWin;
@ -146,6 +147,13 @@ void VDirectoryTree::initActions()
connect(m_openLocationAct, &QAction::triggered,
this, &VDirectoryTree::openDirectoryLocation);
m_pinToHistoryAct = new QAction(VIconUtils::menuIcon(":/resources/icons/pin.svg"),
tr("Pin To History"),
this);
m_pinToHistoryAct->setToolTip(tr("Pin selected folder to History"));
connect(m_pinToHistoryAct, &QAction::triggered,
this, &VDirectoryTree::pinDirectoryToHistory);
m_reloadAct = new QAction(tr("&Reload From Disk"), this);
m_reloadAct->setToolTip(tr("Reload the content of this folder (or notebook) from disk"));
connect(m_reloadAct, &QAction::triggered,
@ -435,6 +443,7 @@ void VDirectoryTree::contextMenuRequested(QPoint pos)
if (item) {
menu.addAction(m_openLocationAct);
menu.addAction(m_pinToHistoryAct);
menu.addAction(dirInfoAct);
}
@ -1211,3 +1220,11 @@ VDirectory *VDirectoryTree::currentDirectory() const
return NULL;
}
void VDirectoryTree::pinDirectoryToHistory()
{
QTreeWidgetItem *curItem = currentItem();
V_ASSERT(curItem);
g_mainWin->getHistoryList()->pinFolder(getVDirectory(curItem)->fetchPath());
g_mainWin->showStatusMessage(tr("1 folder pinned to History"));
}

View File

@ -93,6 +93,9 @@ private slots:
// Sort sub-folders of current item's folder.
void sortItems();
// Pin selected directory to History.
void pinDirectoryToHistory();
protected:
void mousePressEvent(QMouseEvent *event) Q_DECL_OVERRIDE;
@ -176,6 +179,7 @@ private:
QAction *cutAct;
QAction *pasteAct;
QAction *m_openLocationAct;
QAction *m_pinToHistoryAct;
QAction *m_sortAct;
// Reload content from disk.

View File

@ -1131,7 +1131,8 @@ void VEditArea::recordClosedFile(const VFileSessionInfo &p_file)
}
m_lastClosedFiles.push(p_file);
qDebug() << "pushed closed file" << p_file.m_file;
emit fileClosed(p_file.m_file);
}
void VEditArea::handleFileTimerTimeout()

View File

@ -105,6 +105,9 @@ signals:
// Emit when Vim status updated.
void vimStatusUpdated(const VVim *p_vim);
// Emit when @p_file is closed.
void fileClosed(const QString &p_file);
protected:
void mousePressEvent(QMouseEvent *event) Q_DECL_OVERRIDE;

View File

@ -14,6 +14,7 @@
#include "vconfigmanager.h"
#include "utils/viconutils.h"
#include "vcart.h"
#include "vhistorylist.h"
extern VConfigManager *g_config;
extern VMainWindow *g_mainWin;
@ -167,7 +168,9 @@ void VEditWindow::initTabActions()
}
});
m_addToCartAct = new QAction(tr("Add To Cart"), this);
m_addToCartAct = new QAction(VIconUtils::menuIcon(":/resources/icons/cart.svg"),
tr("Add To Cart"),
this);
m_addToCartAct->setToolTip(tr("Add this note to Cart for further processing"));
connect(m_addToCartAct, &QAction::triggered,
this, [this](){
@ -181,6 +184,24 @@ void VEditWindow::initTabActions()
g_mainWin->showStatusMessage(tr("1 note added to Cart"));
});
m_pinToHistoryAct = new QAction(VIconUtils::menuIcon(":/resources/icons/pin.svg"),
tr("Pin To History"),
this);
m_pinToHistoryAct->setToolTip(tr("Pin this note to History"));
connect(m_pinToHistoryAct, &QAction::triggered,
this, [this](){
int tab = this->m_pinToHistoryAct->data().toInt();
Q_ASSERT(tab != -1);
VEditTab *editor = getTab(tab);
QPointer<VFile> file = editor->getFile();
Q_ASSERT(file);
QStringList files;
files << file->fetchPath();
g_mainWin->getHistoryList()->pinFiles(files);
g_mainWin->showStatusMessage(tr("1 note pinned to History"));
});
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,
@ -692,6 +713,9 @@ void VEditWindow::tabbarContextMenuRequested(QPoint p_pos)
m_addToCartAct->setData(tab);
menu.addAction(m_addToCartAct);
m_pinToHistoryAct->setData(tab);
menu.addAction(m_pinToHistoryAct);
m_noteInfoAct->setData(tab);
menu.addAction(m_noteInfoAct);
} else if (file->getType() == FileType::Orphan
@ -708,6 +732,9 @@ void VEditWindow::tabbarContextMenuRequested(QPoint p_pos)
m_addToCartAct->setData(tab);
menu.addAction(m_addToCartAct);
m_pinToHistoryAct->setData(tab);
menu.addAction(m_pinToHistoryAct);
m_noteInfoAct->setData(tab);
menu.addAction(m_noteInfoAct);
}

View File

@ -231,6 +231,9 @@ private:
// Add this note to Cart.
QAction *m_addToCartAct;
// Pin this note to History.
QAction *m_pinToHistoryAct;
// Open the location (the folder containing this file) of this note.
QAction *m_openLocationAct;

View File

@ -20,6 +20,7 @@
#include "utils/viconutils.h"
#include "dialog/vtipsdialog.h"
#include "vcart.h"
#include "vhistorylist.h"
extern VConfigManager *g_config;
extern VNote *g_vnote;
@ -190,11 +191,20 @@ void VFileList::initActions()
connect(m_openLocationAct, &QAction::triggered,
this, &VFileList::openFileLocation);
m_addToCartAct = new QAction(tr("Add To Cart"), this);
m_addToCartAct = new QAction(VIconUtils::menuIcon(":/resources/icons/cart.svg"),
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_pinToHistoryAct = new QAction(VIconUtils::menuIcon(":/resources/icons/pin.svg"),
tr("Pin To History"),
this);
m_pinToHistoryAct->setToolTip(tr("Pin selected notes to History"));
connect(m_pinToHistoryAct, &QAction::triggered,
this, &VFileList::pinFileToHistory);
m_sortAct = new QAction(VIconUtils::menuIcon(":/resources/icons/sort.svg"),
tr("&Sort"),
this);
@ -276,6 +286,22 @@ void VFileList::addFileToCart() const
.arg(items.size() > 1 ? tr("notes") : tr("note")));
}
void VFileList::pinFileToHistory() const
{
QList<QListWidgetItem *> items = fileList->selectedItems();
QStringList files;
for (int i = 0; i < items.size(); ++i) {
files << getVFile(items[i])->fetchPath();
}
g_mainWin->getHistoryList()->pinFiles(files);
g_mainWin->showStatusMessage(tr("%1 %2 pinned to History")
.arg(items.size())
.arg(items.size() > 1 ? tr("notes") : tr("note")));
}
void VFileList::fileInfo(VNoteFile *p_file)
{
if (!p_file) {
@ -621,6 +647,7 @@ void VFileList::contextMenuRequested(QPoint pos)
}
menu.addAction(m_addToCartAct);
menu.addAction(m_pinToHistoryAct);
if (selectedSize == 1) {
menu.addAction(fileInfoAct);

View File

@ -89,6 +89,9 @@ private slots:
// Add selected files to Cart.
void addFileToCart() const;
// Add selected files to History and pin them.
void pinFileToHistory() const;
// Copy selected files to clipboard.
// Will put a Json string into the clipboard which contains the information
// about copied files.
@ -195,6 +198,8 @@ private:
QAction *m_addToCartAct;
QAction *m_pinToHistoryAct;
// Context sub-menu of Open With.
QMenu *m_openWithMenu;

64
src/vhistoryentry.h Normal file
View File

@ -0,0 +1,64 @@
#ifndef VHISTORYENTRY_H
#define VHISTORYENTRY_H
#include <QDate>
#include <QSettings>
namespace HistoryConfig
{
static const QString c_file = "file";
static const QString c_date = "date";
static const QString c_pinned = "pinned";
static const QString c_isFolder = "is_folder";
}
class VHistoryEntry
{
public:
VHistoryEntry()
: m_isPinned(false),
m_isFolder(false)
{
}
VHistoryEntry(const QString &p_file,
const QDate &p_date,
bool p_isPinned = false,
bool p_isFolder = false)
: m_file(p_file), m_isPinned(p_isPinned), m_isFolder(p_isFolder)
{
m_date = p_date.toString(Qt::ISODate);
}
// Fetch VHistoryEntry from @p_settings.
static VHistoryEntry fromSettings(const QSettings *p_settings)
{
VHistoryEntry entry;
entry.m_file = p_settings->value(HistoryConfig::c_file).toString();
entry.m_date = p_settings->value(HistoryConfig::c_date).toString();
entry.m_isPinned = p_settings->value(HistoryConfig::c_pinned).toBool();
entry.m_isFolder = p_settings->value(HistoryConfig::c_isFolder).toBool();
return entry;
}
void toSettings(QSettings *p_settings) const
{
p_settings->setValue(HistoryConfig::c_file, m_file);
p_settings->setValue(HistoryConfig::c_date, m_date);
p_settings->setValue(HistoryConfig::c_pinned, m_isPinned);
p_settings->setValue(HistoryConfig::c_isFolder, m_isFolder);
}
// File path.
QString m_file;
// Accessed date.
// UTC in Qt::ISODate format.
QString m_date;
bool m_isPinned;
bool m_isFolder;
};
#endif // VHISTORYENTRY_H

507
src/vhistorylist.cpp Normal file
View File

@ -0,0 +1,507 @@
#include "vhistorylist.h"
#include <QtWidgets>
#include <QDebug>
#include "utils/viconutils.h"
#include "utils/vutils.h"
#include "vlistwidget.h"
#include "vconfigmanager.h"
#include "vmainwindow.h"
#include "vcart.h"
#include "vnote.h"
#include "vnotefile.h"
#include "vdirectory.h"
extern VMainWindow *g_mainWin;
extern VConfigManager *g_config;
extern VNote *g_vnote;
VHistoryList::VHistoryList(QWidget *p_parent)
: QWidget(p_parent),
m_initialized(false),
m_updatePending(true),
m_currentDate(QDate::currentDate())
{
setupUI();
}
void VHistoryList::setupUI()
{
m_clearBtn = new QPushButton(VIconUtils::buttonDangerIcon(":/resources/icons/clear_history.svg"), "");
m_clearBtn->setToolTip(tr("Clear"));
m_clearBtn->setProperty("FlatBtn", true);
connect(m_clearBtn, &QPushButton::clicked,
this, [this]() {
init();
if (m_histories.size() > 0) {
int ret = VUtils::showMessage(QMessageBox::Warning,
tr("Warning"),
tr("Are you sure to clear History?"),
"",
QMessageBox::Ok | QMessageBox::Cancel,
QMessageBox::Ok,
g_mainWin,
MessageBoxType::Danger);
if (ret == QMessageBox::Ok) {
m_histories.clear();
g_config->setHistory(m_histories);
m_updatePending = true;
updateList();
}
}
});
QHBoxLayout *btnLayout = new QHBoxLayout;
btnLayout->addWidget(m_clearBtn);
btnLayout->addStretch();
btnLayout->setContentsMargins(0, 0, 0, 0);
m_itemList = new VListWidget();
m_itemList->setAttribute(Qt::WA_MacShowFocusRect, false);
m_itemList->setContextMenuPolicy(Qt::CustomContextMenu);
m_itemList->setSelectionMode(QAbstractItemView::ExtendedSelection);
connect(m_itemList, &QListWidget::customContextMenuRequested,
this, &VHistoryList::handleContextMenuRequested);
connect(m_itemList, &QListWidget::itemActivated,
this, &VHistoryList::openItem);
QVBoxLayout *mainLayout = new QVBoxLayout();
mainLayout->addLayout(btnLayout);
mainLayout->addWidget(m_itemList);
mainLayout->setContentsMargins(3, 0, 3, 0);
setLayout(mainLayout);
}
void VHistoryList::initActions()
{
m_openAct = new QAction(tr("&Open"), this);
m_openAct->setToolTip(tr("Open selected notes"));
connect(m_openAct, &QAction::triggered,
this, &VHistoryList::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, &VHistoryList::locateCurrentItem);
m_pinAct = new QAction(VIconUtils::menuIcon(":/resources/icons/pin.svg"),
tr("Pin"),
this);
m_pinAct->setToolTip(tr("Pin selected notes in History"));
connect(m_pinAct, &QAction::triggered,
this, &VHistoryList::pinSelectedItems);
m_unpinAct = new QAction(tr("Unpin"), this);
m_unpinAct->setToolTip(tr("Unpin selected notes in History"));
connect(m_unpinAct, &QAction::triggered,
this, &VHistoryList::unpinSelectedItems);
m_addToCartAct = new QAction(VIconUtils::menuIcon(":/resources/icons/cart.svg"),
tr("Add To Cart"),
this);
m_addToCartAct->setToolTip(tr("Add selected notes to Cart for further processing"));
connect(m_addToCartAct, &QAction::triggered,
this, &VHistoryList::addFileToCart);
}
void VHistoryList::addFile(const QString &p_filePath)
{
init();
QStringList files;
files << p_filePath;
addFilesInternal(files, false);
if (isVisible()) {
updateList();
}
}
void VHistoryList::pinFiles(const QStringList &p_files)
{
init();
addFilesInternal(p_files, true);
if (isVisible()) {
updateList();
}
}
void VHistoryList::unpinFiles(const QStringList &p_files)
{
init();
for (auto const & file : p_files) {
auto it = findFileInHistory(file);
if (it != m_histories.end()) {
it->m_isPinned = false;
}
}
g_config->setHistory(m_histories);
m_updatePending = true;
}
void VHistoryList::pinFolder(const QString &p_folder)
{
init();
auto it = findFileInHistory(p_folder);
if (it != m_histories.end()) {
return;
}
m_histories.append(VHistoryEntry(p_folder, QDate::currentDate(), true, true));
checkHistorySize();
g_config->setHistory(m_histories);
m_updatePending = true;
if (isVisible()) {
updateList();
}
}
void VHistoryList::addFilesInternal(const QStringList &p_files, bool p_isPinned)
{
for (auto const & file : p_files) {
// Find it in existing enries.
bool pinnedBefore = false;
auto it = findFileInHistory(file);
if (it != m_histories.end()) {
pinnedBefore = it->m_isPinned;
m_histories.erase(it);
}
// Append an entry at the end.
bool pin = p_isPinned ? true : (pinnedBefore ? true : false);
m_histories.append(VHistoryEntry(file, QDate::currentDate(), pin));
}
checkHistorySize();
g_config->setHistory(m_histories);
m_updatePending = true;
}
void VHistoryList::checkHistorySize()
{
int numToRemove = m_histories.size() - g_config->getHistorySize();
for (auto rit = m_histories.begin(); numToRemove > 0 && rit != m_histories.end();) {
if (rit->m_isPinned) {
++rit;
continue;
}
rit = m_histories.erase(rit);
--numToRemove;
}
}
void VHistoryList::init()
{
if (m_initialized) {
return;
}
m_folderIcon = VIconUtils::treeViewIcon(":/resources/icons/dir_item.svg");
initActions();
g_config->getHistory(m_histories);
m_initialized = true;
m_updatePending = true;
}
void VHistoryList::showEvent(QShowEvent *p_event)
{
init();
if (m_currentDate != QDate::currentDate()) {
m_currentDate = QDate::currentDate();
m_updatePending = true;
}
updateList();
QWidget::showEvent(p_event);
}
QLinkedList<VHistoryEntry>::iterator VHistoryList::findFileInHistory(const QString &p_file)
{
for (QLinkedList<VHistoryEntry>::iterator it = m_histories.begin();
it != m_histories.end();
++it) {
if (VUtils::equalPath(p_file, it->m_file)) {
return it;
}
}
return m_histories.end();
}
struct SeparatorItem
{
SeparatorItem()
: m_valid(false)
{
}
QString m_date;
QListWidgetItem *m_item;
bool m_valid;
};
void VHistoryList::updateList()
{
if (!m_updatePending) {
return;
}
m_updatePending = false;
m_itemList->clearAll();
if (m_histories.isEmpty()) {
return;
}
// Add separators.
// Pinned separator.
SeparatorItem pinItem;
pinItem.m_item = VListWidget::createSeparatorItem(tr("Pinned"));
m_itemList->addItem(pinItem.m_item);
const int sepSize = 4;
QString sepText[4] = {tr("Today"), tr("Yesterday"), tr("Last 7 Days"), tr("Older")};
QVector<SeparatorItem> seps(sepSize);
seps[0].m_date = m_currentDate.toString(Qt::ISODate);
seps[1].m_date = m_currentDate.addDays(-1).toString(Qt::ISODate);
seps[2].m_date = m_currentDate.addDays(-7).toString(Qt::ISODate);
// Leave the last string empty.
for (int i = 0; i < sepSize; ++i) {
seps[i].m_item = VListWidget::createSeparatorItem(sepText[i]);
m_itemList->addItem(seps[i].m_item);
}
for (auto it = m_histories.cbegin(); it != m_histories.cend(); ++it) {
QListWidgetItem *item = new QListWidgetItem(VUtils::fileNameFromPath(it->m_file));
item->setToolTip(it->m_file);
item->setData(Qt::UserRole, (qulonglong)&(*it));
if (it->m_isFolder) {
item->setIcon(m_folderIcon);
}
if (it->m_isPinned) {
m_itemList->insertItem(m_itemList->row(pinItem.m_item) + 1, item);
pinItem.m_valid = true;
continue;
}
for (int i = 0; i < sepSize; ++i) {
if (it->m_date >= seps[i].m_date) {
m_itemList->insertItem(m_itemList->row(seps[i].m_item) + 1, item);
seps[i].m_valid = true;
break;
}
}
}
// We always display pinned separator.
for (int i = 0; i < sepSize; ++i) {
if (!seps[i].m_valid) {
delete seps[i].m_item;
}
}
seps.clear();
}
QWidget *VHistoryList::getContentWidget() const
{
return m_itemList;
}
void VHistoryList::handleContextMenuRequested(QPoint p_pos)
{
QListWidgetItem *item = m_itemList->itemAt(p_pos);
if (!item || VListWidget::isSeparatorItem(item)) {
return;
}
QMenu menu(this);
menu.setToolTipsVisible(true);
menu.addAction(m_openAct);
QList<QListWidgetItem *> selectedItems = m_itemList->selectedItems();
if (selectedItems.size() == 1) {
menu.addAction(m_locateAct);
}
bool allPinned = true, allUnpinned = true;
for (auto const & it : selectedItems) {
if (getHistoryEntry(it)->m_isPinned) {
allUnpinned = false;
} else {
allPinned = false;
}
}
if (allUnpinned) {
menu.addAction(m_pinAct);
} else if (allPinned) {
menu.addAction(m_unpinAct);
}
menu.addSeparator();
menu.addAction(m_addToCartAct);
menu.exec(m_itemList->mapToGlobal(p_pos));
}
bool VHistoryList::isFolder(const QListWidgetItem *p_item) const
{
return getHistoryEntry(p_item)->m_isFolder;
}
VHistoryEntry *VHistoryList::getHistoryEntry(const QListWidgetItem *p_item) const
{
return (VHistoryEntry *)p_item->data(Qt::UserRole).toULongLong();
}
QString VHistoryList::getFilePath(const QListWidgetItem *p_item) const
{
return getHistoryEntry(p_item)->m_file;
}
void VHistoryList::pinSelectedItems()
{
QStringList files;
QList<QListWidgetItem *> selectedItems = m_itemList->selectedItems();
for (auto it : selectedItems) {
files << getFilePath(it);
}
pinFiles(files);
}
void VHistoryList::unpinSelectedItems()
{
QStringList files;
QList<QListWidgetItem *> selectedItems = m_itemList->selectedItems();
for (auto it : selectedItems) {
files << getFilePath(it);
}
unpinFiles(files);
if (isVisible()) {
updateList();
}
}
void VHistoryList::openSelectedItems() const
{
QStringList files;
QList<QListWidgetItem *> selectedItems = m_itemList->selectedItems();
if (selectedItems.size() == 1 && isFolder(selectedItems.first())) {
// Locate to the folder.
VDirectory *dir = g_vnote->getInternalDirectory(getFilePath(selectedItems.first()));
if (dir) {
g_mainWin->locateDirectory(dir);
}
return;
}
for (auto it : selectedItems) {
if (isFolder(it)) {
// Skip folders.
continue;
}
files << getFilePath(it);
}
if (!files.isEmpty()) {
g_mainWin->openFiles(files);
}
}
void VHistoryList::openItem(const QListWidgetItem *p_item) const
{
if (!p_item) {
return;
}
if (isFolder(p_item)) {
// Locate to the folder.
VDirectory *dir = g_vnote->getInternalDirectory(getFilePath(p_item));
if (dir) {
g_mainWin->locateDirectory(dir);
}
return;
}
QStringList files;
files << getFilePath(p_item);
g_mainWin->openFiles(files);
}
void VHistoryList::locateCurrentItem()
{
auto item = m_itemList->currentItem();
if (!item) {
return;
}
VFile *file = g_vnote->getInternalFile(getFilePath(item));
if (file) {
g_mainWin->locateFile(file);
}
}
void VHistoryList::showNavigation()
{
VNavigationMode::showNavigation(m_itemList);
}
bool VHistoryList::handleKeyNavigation(int p_key, bool &p_succeed)
{
static bool secondKey = false;
return VNavigationMode::handleKeyNavigation(m_itemList,
secondKey,
p_key,
p_succeed);
}
void VHistoryList::addFileToCart() const
{
QList<QListWidgetItem *> items = m_itemList->selectedItems();
VCart *cart = g_mainWin->getCart();
for (int i = 0; i < items.size(); ++i) {
cart->addFile(getFilePath(items[i]));
}
g_mainWin->showStatusMessage(tr("%1 %2 added to Cart")
.arg(items.size())
.arg(items.size() > 1 ? tr("notes") : tr("note")));
}

104
src/vhistorylist.h Normal file
View File

@ -0,0 +1,104 @@
#ifndef VHISTORYLIST_H
#define VHISTORYLIST_H
#include <QWidget>
#include <QLinkedList>
#include <QIcon>
#include "vhistoryentry.h"
#include "vnavigationmode.h"
class QPushButton;
class VListWidget;
class QListWidgetItem;
class QLabel;
class QAction;
class QShowEvent;
class VHistoryList : public QWidget, public VNavigationMode
{
Q_OBJECT
public:
explicit VHistoryList(QWidget *p_parent = nullptr);
QWidget *getContentWidget() const;
void pinFiles(const QStringList &p_files);
void pinFolder(const QString &p_folder);
// Implementations for VNavigationMode.
void showNavigation() Q_DECL_OVERRIDE;
bool handleKeyNavigation(int p_key, bool &p_succeed) Q_DECL_OVERRIDE;
public slots:
void addFile(const QString &p_filePath);
protected:
void showEvent(QShowEvent *p_event) Q_DECL_OVERRIDE;
private slots:
void handleContextMenuRequested(QPoint p_pos);
void openSelectedItems() const;
void openItem(const QListWidgetItem *p_item) const;
void pinSelectedItems();
void unpinSelectedItems();
void locateCurrentItem();
// Add selected files to Cart.
void addFileToCart() const;
private:
void setupUI();
void initActions();
// Read data from config file.
void init();
void updateList();
QLinkedList<VHistoryEntry>::iterator findFileInHistory(const QString &p_file);
QString getFilePath(const QListWidgetItem *p_item) const;
VHistoryEntry *getHistoryEntry(const QListWidgetItem *p_item) const;
bool isFolder(const QListWidgetItem *p_item) const;
// @p_isPinned won't change it if an item is pinned already.
void addFilesInternal(const QStringList &p_files, bool p_isPinned);
void unpinFiles(const QStringList &p_files);
void checkHistorySize();
QPushButton *m_clearBtn;
VListWidget *m_itemList;
QAction *m_openAct;
QAction *m_locateAct;
QAction *m_pinAct;
QAction *m_unpinAct;
QAction *m_addToCartAct;
// Whether data is loaded.
bool m_initialized;
// New files are appended to the end.
QLinkedList<VHistoryEntry> m_histories;
// Whether we need to update the list.
bool m_updatePending;
QDate m_currentDate;
QIcon m_folderIcon;
};
#endif // VHISTORYLIST_H

View File

@ -8,6 +8,9 @@
#include "utils/vutils.h"
#include "utils/vimnavigationforwidget.h"
#include "vstyleditemdelegate.h"
#include "vpalette.h"
extern VPalette *g_palette;
VListWidget::VListWidget(QWidget *p_parent)
: QListWidget(p_parent),
@ -20,7 +23,7 @@ VListWidget::VListWidget(QWidget *p_parent)
m_searchInput->hide();
m_delegate = new VStyledItemDelegate(this);
m_delegate = new VStyledItemDelegate(this, NULL);
setItemDelegate(m_delegate);
}
@ -108,6 +111,10 @@ QList<void *> VListWidget::searchItems(const QString &p_text,
QList<void *> res;
res.reserve(items.size());
for (int i = 0; i < items.size(); ++i) {
if (items[i]->type() == ItemTypeSeparator) {
continue;
}
res.append(items[i]);
}
@ -212,3 +219,14 @@ QSize VListWidget::sizeHint() const
}
}
QListWidgetItem *VListWidget::createSeparatorItem(const QString &p_text)
{
QListWidgetItem *item = new QListWidgetItem(p_text, NULL, ItemTypeSeparator);
item->setFlags(Qt::NoItemFlags);
return item;
}
bool VListWidget::isSeparatorItem(const QListWidgetItem *p_item)
{
return p_item->type() == ItemTypeSeparator;
}

View File

@ -34,10 +34,14 @@ public:
virtual QSize sizeHint() const Q_DECL_OVERRIDE;
void setFitContent(bool p_enabled);
// Sort @p_list according to @p_sortedIdx.
static void sortListWidget(QListWidget *p_list, const QVector<int> &p_sortedIdx);
void setFitContent(bool p_enabled);
static QListWidgetItem *createSeparatorItem(const QString &p_text);
static bool isSeparatorItem(const QListWidgetItem *p_item);
private slots:
void handleSearchModeTriggered(bool p_inSearchMode, bool p_focus);

View File

@ -45,6 +45,7 @@
#include "vhelpue.h"
#include "vlistfolderue.h"
#include "dialog/vfixnotebookdialog.h"
#include "vhistorylist.h"
extern VConfigManager *g_config;
@ -64,6 +65,8 @@ extern QFile g_logFile;
#define COLOR_PIXMAP_ICON_SIZE 64
#define NAVI_BOX_NOTEBOOKS_IDX 0
VMainWindow::VMainWindow(VSingleInstanceGuard *p_guard, QWidget *p_parent)
: QMainWindow(p_parent),
@ -145,10 +148,12 @@ void VMainWindow::registerCaptainAndNavigationTargets()
m_captain->registerNavigationTarget(m_notebookSelector);
m_captain->registerNavigationTarget(m_dirTree);
m_captain->registerNavigationTarget(m_fileList);
m_captain->registerNavigationTarget(m_historyList);
m_captain->registerNavigationTarget(m_editArea);
m_captain->registerNavigationTarget(m_toolBox);
m_captain->registerNavigationTarget(outline);
m_captain->registerNavigationTarget(m_snippetList);
m_captain->registerNavigationTarget(m_cart);
m_captain->registerNavigationTarget(m_searcher);
// Register Captain mode targets.
@ -196,14 +201,7 @@ void VMainWindow::registerCaptainAndNavigationTargets()
void VMainWindow::setupUI()
{
m_naviBox = new VToolBox();
setupNotebookPanel();
m_naviBox->addItem(m_nbSplitter,
":/resources/icons/notebook.svg",
tr("Notebooks"),
m_dirTree);
setupNaviBox();
m_editArea = new VEditArea();
m_editArea->setSizePolicy(QSizePolicy::Expanding, QSizePolicy::Expanding);
@ -211,6 +209,9 @@ void VMainWindow::setupUI()
m_fileList->setEditArea(m_editArea);
m_dirTree->setEditArea(m_editArea);
connect(m_editArea, &VEditArea::fileClosed,
m_historyList, &VHistoryList::addFile);
// Main Splitter
m_mainSplitter = new QSplitter();
m_mainSplitter->setObjectName("MainSplitter");
@ -265,6 +266,23 @@ void VMainWindow::setupUI()
initTrayIcon();
}
void VMainWindow::setupNaviBox()
{
m_naviBox = new VToolBox();
setupNotebookPanel();
m_naviBox->addItem(m_nbSplitter,
":/resources/icons/notebook.svg",
tr("Notebooks"),
m_dirTree);
m_historyList = new VHistoryList();
m_naviBox->addItem(m_historyList,
":/resources/icons/history.svg",
tr("History"),
m_historyList->getContentWidget());
}
void VMainWindow::setupNotebookPanel()
{
m_notebookSelector = new VNotebookSelector();
@ -1265,7 +1283,8 @@ void VMainWindow::initToolsDock()
tr("Snippets"));
m_toolBox->addItem(m_cart,
":/resources/icons/cart.svg",
tr("Cart"));
tr("Cart"),
m_cart->getContentWidget());
m_toolDock->setWidget(m_toolBox);
addDockWidget(Qt::RightDockWidgetArea, m_toolDock);
@ -3134,5 +3153,5 @@ void VMainWindow::kickOffStartUpTimer(const QStringList &p_files)
void VMainWindow::showNotebookPanel()
{
changePanelView(PanelViewState::VerticalMode);
m_naviBox->setCurrentIndex(0, false);
m_naviBox->setCurrentIndex(NAVI_BOX_NOTEBOOKS_IDX, false);
}

View File

@ -42,6 +42,7 @@ class VCart;
class VSearcher;
class QPrinter;
class VUniversalEntry;
class VHistoryList;
enum class PanelViewState
{
@ -79,6 +80,8 @@ public:
VNotebookSelector *getNotebookSelector() const;
VHistoryList *getHistoryList() const;
// View and edit the information of @p_file, which is an orphan file.
void editOrphanFileInfo(VFile *p_file);
@ -199,6 +202,8 @@ protected:
private:
void setupUI();
void setupNaviBox();
void setupNotebookPanel();
void initToolBar();
@ -442,6 +447,8 @@ private:
VUniversalEntry *m_ue;
VHistoryList *m_historyList;
// Interval of the shared memory timer in ms.
static const int c_sharedMemTimerInterval;
};
@ -481,6 +488,11 @@ inline VCart *VMainWindow::getCart() const
return m_cart;
}
inline VHistoryList *VMainWindow::getHistoryList() const
{
return m_historyList;
}
inline VDirectoryTree *VMainWindow::getDirectoryTree() const
{
return m_dirTree;

View File

@ -70,7 +70,7 @@ QList<QListWidgetItem *> VNavigationMode::getVisibleItems(const QListWidget *p_w
QList<QListWidgetItem *> items;
for (int i = 0; i < p_widget->count(); ++i) {
QListWidgetItem *item = p_widget->item(i);
if (!item->isHidden()) {
if (!item->isHidden() && item->flags() != Qt::NoItemFlags) {
items.append(item);
}
}

View File

@ -214,5 +214,8 @@
<file>utils/markdown-it/markdown-it-imsize.min.js</file>
<file>utils/markdown-it/markdown-it-emoji.min.js</file>
<file>resources/icons/notebook.svg</file>
<file>resources/icons/history.svg</file>
<file>resources/icons/clear_history.svg</file>
<file>resources/icons/pin.svg</file>
</qresource>
</RCC>

View File

@ -9,6 +9,7 @@
#include "vmainwindow.h"
#include "vnotefile.h"
#include "vcart.h"
#include "vhistorylist.h"
extern VNote *g_vnote;
@ -53,10 +54,19 @@ void VSearchResultTree::initActions()
connect(m_locateAct, &QAction::triggered,
this, &VSearchResultTree::locateCurrentItem);
m_addToCartAct = new QAction(tr("Add To Cart"), this);
m_addToCartAct = new QAction(VIconUtils::menuIcon(":/resources/icons/cart.svg"),
tr("Add To Cart"),
this);
m_addToCartAct->setToolTip(tr("Add selected notes to Cart for further processing"));
connect(m_addToCartAct, &QAction::triggered,
this, &VSearchResultTree::addSelectedItemsToCart);
m_pinToHistoryAct = new QAction(VIconUtils::menuIcon(":/resources/icons/pin.svg"),
tr("Pin To History"),
this);
m_pinToHistoryAct->setToolTip(tr("Pin selected notes to History"));
connect(m_pinToHistoryAct, &QAction::triggered,
this, &VSearchResultTree::pinSelectedItemsToHistory);
}
void VSearchResultTree::updateResults(const QList<QSharedPointer<VSearchResultItem> > &p_items)
@ -165,6 +175,7 @@ void VSearchResultTree::handleContextMenuRequested(QPoint p_pos)
if (hasNote) {
menu.addAction(m_addToCartAct);
menu.addAction(m_pinToHistoryAct);
}
menu.exec(mapToGlobal(p_pos));
@ -207,6 +218,25 @@ void VSearchResultTree::addSelectedItemsToCart()
}
}
void VSearchResultTree::pinSelectedItemsToHistory()
{
QList<QTreeWidgetItem *> items = selectedItems();
QStringList files;
for (int i = 0; i < items.size(); ++i) {
const QSharedPointer<VSearchResultItem> &resItem = itemResultData(items[i]);
if (resItem->m_type == VSearchResultItem::Note) {
files << resItem->m_path;
}
}
if (!files.isEmpty()) {
g_mainWin->getHistoryList()->pinFiles(files);
g_mainWin->showStatusMessage(tr("%1 %2 pinned to History")
.arg(files.size())
.arg(files.size() > 1 ? tr("notes") : tr("note")));
}
}
VSearchResultItem::ItemType VSearchResultTree::itemResultType(const QTreeWidgetItem *p_item) const
{
Q_ASSERT(p_item);

View File

@ -34,6 +34,8 @@ private slots:
void addSelectedItemsToCart();
void pinSelectedItemsToHistory();
private:
void appendItem(const QSharedPointer<VSearchResultItem> &p_item);
@ -56,6 +58,8 @@ private:
QAction *m_locateAct;
QAction *m_addToCartAct;
QAction *m_pinToHistoryAct;
};
#endif // VSEARCHRESULTTREE_H

View File

@ -10,6 +10,7 @@
#include "dialog/vconfirmdeletiondialog.h"
#include "vmainwindow.h"
#include "utils/viconutils.h"
#include "vlistwidget.h"
extern VConfigManager *g_config;
@ -70,7 +71,7 @@ void VSnippetList::setupUI()
btnLayout->addWidget(m_numLabel);
btnLayout->setContentsMargins(0, 0, 0, 0);
m_snippetList = new QListWidget();
m_snippetList = new VListWidget();
m_snippetList->setAttribute(Qt::WA_MacShowFocusRect, false);
m_snippetList->setContextMenuPolicy(Qt::CustomContextMenu);
m_snippetList->setSelectionMode(QAbstractItemView::ExtendedSelection);
@ -380,7 +381,7 @@ void VSnippetList::makeSureFolderExist() const
void VSnippetList::updateContent()
{
m_snippetList->clear();
m_snippetList->clearAll();
for (int i = 0; i < m_snippets.size(); ++i) {
const VSnippet &snip = m_snippets[i];

View File

@ -9,7 +9,7 @@
#include "vnavigationmode.h"
class QPushButton;
class QListWidget;
class VListWidget;
class QListWidgetItem;
class QLabel;
class QAction;
@ -92,7 +92,7 @@ private:
QPushButton *m_addBtn;
QPushButton *m_locateBtn;
QLabel *m_numLabel;
QListWidget *m_snippetList;
VListWidget *m_snippetList;
QAction *m_applyAct;
QAction *m_infoAct;

View File

@ -1,17 +1,25 @@
#include "vstyleditemdelegate.h"
#include <QPainter>
#include <QDebug>
#include <QListWidget>
#include <QListWidgetItem>
#include <QTreeWidgetItem>
#include "vpalette.h"
#include "vtreewidget.h"
extern VPalette *g_palette;
VStyledItemDelegate::VStyledItemDelegate(QObject *p_parent)
: QStyledItemDelegate(p_parent)
VStyledItemDelegate::VStyledItemDelegate(QListWidget *p_list, VTreeWidget *p_tree)
: QStyledItemDelegate(p_list ? (QObject *)p_list : (QObject *)p_tree),
m_list(p_list),
m_tree(p_tree)
{
Q_ASSERT(!(m_list && m_tree));
m_itemHitBg = QBrush(QColor(g_palette->color("search_hit_item_bg")));
m_itemHitFg = QBrush(QColor(g_palette->color("search_hit_item_fg")));
m_itemSeparatorBg = QBrush(QColor(g_palette->color("item_separator_bg")));
m_itemSeparatorFg = QBrush(QColor(g_palette->color("item_separator_fg")));
}
void VStyledItemDelegate::paint(QPainter *p_painter,
@ -25,7 +33,30 @@ void VStyledItemDelegate::paint(QPainter *p_painter,
// option.palette.setBrush(QPalette::Base, m_itemHitBg);
option.palette.setBrush(QPalette::Text, m_itemHitFg);
QStyledItemDelegate::paint(p_painter, option, p_index);
} else if (itemType(p_index) == ItemTypeSeparator) {
QStyleOptionViewItem option(p_option);
p_painter->fillRect(option.rect, m_itemSeparatorBg);
option.palette.setBrush(QPalette::Text, m_itemSeparatorFg);
QStyledItemDelegate::paint(p_painter, option, p_index);
} else {
QStyledItemDelegate::paint(p_painter, p_option, p_index);
}
}
int VStyledItemDelegate::itemType(const QModelIndex &p_index) const
{
int type = 0;
if (m_list) {
QListWidgetItem *item = m_list->item(p_index.row());
if (item) {
type = item->type();
}
} else if (m_tree) {
QTreeWidgetItem *item = m_tree->getItemFromIndex(p_index);
if (item) {
type = item->type();
}
}
return type;
}

View File

@ -5,11 +5,16 @@
#include <QBrush>
#include <QSet>
class QListWidget;
class VTreeWidget;
// Should be larger then QListWidgetItem::UserType and QTreeWidgetItem::UserType.
#define ItemTypeSeparator 2000
class VStyledItemDelegate : public QStyledItemDelegate
{
public:
explicit VStyledItemDelegate(QObject *p_parent = Q_NULLPTR);
explicit VStyledItemDelegate(QListWidget *p_list = nullptr, VTreeWidget *p_tree = nullptr);
virtual void paint(QPainter *p_painter,
const QStyleOptionViewItem &p_option,
@ -22,11 +27,19 @@ public:
private:
bool isHit(const QModelIndex &p_index) const;
QBrush m_itemHitBg;
int itemType(const QModelIndex &p_index) const;
QBrush m_itemHitBg;
QBrush m_itemHitFg;
QBrush m_itemSeparatorBg;
QBrush m_itemSeparatorFg;
QSet<QModelIndex> m_hitItems;
// m_list OR m_tree (but not both) could be not NULL.
const QListWidget *m_list;
const VTreeWidget *m_tree;
};
inline void VStyledItemDelegate::setHitItems(const QSet<QModelIndex> &p_hitItems)

View File

@ -52,6 +52,7 @@ int VToolBox::addItem(QWidget *p_widget,
QPushButton *btn = new QPushButton(icon, "");
btn->setToolTip(p_text);
btn->setProperty("FlatBtn", true);
btn->setProperty("ToolBoxTitleBtn", true);
connect(btn, &QPushButton::clicked,
this, [this]() {
QObject *btn = sender();

View File

@ -44,7 +44,7 @@ VTreeWidget::VTreeWidget(QWidget *p_parent)
effect->setOpacity(SEARCH_INPUT_IDLE_OPACITY);
});
m_delegate = new VStyledItemDelegate(this);
m_delegate = new VStyledItemDelegate(NULL, this);
setItemDelegate(m_delegate);
connect(this, &VTreeWidget::itemExpanded,
@ -155,6 +155,10 @@ QList<void *> VTreeWidget::searchItems(const QString &p_text,
QList<void *> res;
res.reserve(items.size());
for (int i = 0; i < items.size(); ++i) {
if (items[i]->type() == ItemTypeSeparator) {
continue;
}
res.append(items[i]);
}

View File

@ -43,6 +43,8 @@ public:
void setFitContent(bool p_enabled);
QTreeWidgetItem *getItemFromIndex(const QModelIndex &p_index) const;
protected:
void keyPressEvent(QKeyEvent *p_event) Q_DECL_OVERRIDE;
@ -95,4 +97,9 @@ inline void VTreeWidget::setFitContent(bool p_enabled)
setSizeAdjustPolicy(m_fitContent ? QAbstractScrollArea::AdjustToContents
: QAbstractScrollArea::AdjustIgnored);
}
inline QTreeWidgetItem *VTreeWidget::getItemFromIndex(const QModelIndex &p_index) const
{
return itemFromIndex(p_index);
}
#endif // VTREEWIDGET_H

View File

@ -16,8 +16,6 @@
extern VConfigManager *g_config;
extern VPalette *g_palette;
VVimIndicator::VVimIndicator(QWidget *p_parent)
: QWidget(p_parent), m_vim(NULL)
{