diff --git a/src/src.pro b/src/src.pro index f07a2c94..250059dd 100644 --- a/src/src.pro +++ b/src/src.pro @@ -133,7 +133,9 @@ SOURCES += main.cpp\ vmathjaxwebdocument.cpp \ vmathjaxinplacepreviewhelper.cpp \ vhistorylist.cpp \ - vexplorer.cpp + vexplorer.cpp \ + vlistue.cpp \ + vuetitlecontentpanel.cpp HEADERS += vmainwindow.h \ vdirectorytree.h \ @@ -260,7 +262,9 @@ HEADERS += vmainwindow.h \ vhistorylist.h \ vhistoryentry.h \ vexplorer.h \ - vexplorerentry.h + vexplorerentry.h \ + vlistue.h \ + vuetitlecontentpanel.h RESOURCES += \ vnote.qrc \ diff --git a/src/vhistorylist.cpp b/src/vhistorylist.cpp index 5b578ebf..fd1ca7d0 100644 --- a/src/vhistorylist.cpp +++ b/src/vhistorylist.cpp @@ -144,7 +144,7 @@ void VHistoryList::pinFolder(const QString &p_folder) void VHistoryList::addFilesInternal(const QStringList &p_files, bool p_isPinned) { for (auto const & file : p_files) { - // Find it in existing enries. + // Find it in existing entries. bool pinnedBefore = false; auto it = findFileInHistory(file); if (it != m_histories.end()) { diff --git a/src/vhistorylist.h b/src/vhistorylist.h index f6237f40..4dc1d013 100644 --- a/src/vhistorylist.h +++ b/src/vhistorylist.h @@ -23,6 +23,8 @@ public: void pinFolder(const QString &p_folder); + const QLinkedList &getHistoryEntries() const; + // Implementations for VNavigationMode. void showNavigation() Q_DECL_OVERRIDE; bool handleKeyNavigation(int p_key, bool &p_succeed) Q_DECL_OVERRIDE; @@ -91,4 +93,10 @@ private: QDate m_currentDate; }; +inline const QLinkedList &VHistoryList::getHistoryEntries() const +{ + const_cast(this)->init(); + + return m_histories; +} #endif // VHISTORYLIST_H diff --git a/src/vlistfolderue.cpp b/src/vlistfolderue.cpp index fbd1cd25..e4ecfdce 100644 --- a/src/vlistfolderue.cpp +++ b/src/vlistfolderue.cpp @@ -4,7 +4,7 @@ #include #include -#include "vlistwidgetdoublerows.h" +#include "vlistwidget.h" #include "vdirectory.h" #include "vdirectorytree.h" #include "vmainwindow.h" @@ -14,40 +14,12 @@ #include "vsearchue.h" #include "utils/vutils.h" #include "vnotebook.h" +#include "vuetitlecontentpanel.h" extern VMainWindow *g_mainWin; extern VNote *g_vnote; -VListFolderPanel::VListFolderPanel(QWidget *p_contentWidget, - QWidget *p_parent) - : QWidget(p_parent) -{ - m_titleLabel = new QLabel(this); - m_titleLabel->setProperty("TitleLabel", true); - - p_contentWidget->setParent(this); - - QVBoxLayout *layout = new QVBoxLayout(); - layout->addWidget(m_titleLabel); - layout->addWidget(p_contentWidget); - - layout->setContentsMargins(0, 0, 0, 0); - - setLayout(layout); -} - -void VListFolderPanel::setTitleLabel(const QString &p_title) -{ - m_titleLabel->setText(p_title); -} - -void VListFolderPanel::clearTitle() -{ - m_titleLabel->clear(); -} - - VListFolderUE::VListFolderUE(QObject *p_parent) : IUniversalEntry(p_parent), m_listWidget(NULL) @@ -72,12 +44,12 @@ void VListFolderUE::init() m_noteIcon = VIconUtils::treeViewIcon(":/resources/icons/note_item.svg"); m_folderIcon = VIconUtils::treeViewIcon(":/resources/icons/dir_item.svg"); - m_listWidget = new VListWidgetDoubleRows(m_widgetParent); + m_listWidget = new VListWidget(m_widgetParent); m_listWidget->setFitContent(true); connect(m_listWidget, SIGNAL(itemActivated(QListWidgetItem *)), this, SLOT(activateItem(QListWidgetItem *))); - m_panel = new VListFolderPanel(m_listWidget, m_widgetParent); + m_panel = new VUETitleContentPanel(m_listWidget, m_widgetParent); m_panel->hide(); } @@ -208,12 +180,11 @@ void VListFolderUE::addResultItem(const QSharedPointer &p_ite { m_data.append(p_item); - QString first, second; + QString text; if (p_item->m_text.isEmpty()) { - first = p_item->m_path; + text = p_item->m_path; } else { - first = p_item->m_text; - second = p_item->m_path; + text = p_item->m_text; } QIcon *icon = NULL; @@ -230,10 +201,12 @@ void VListFolderUE::addResultItem(const QSharedPointer &p_ite break; } - QListWidgetItem *item = m_listWidget->addDoubleRowsItem(*icon, first, second); + QListWidgetItem *item = new QListWidgetItem(*icon, text); item->setData(Qt::UserRole, m_data.size() - 1); item->setToolTip(p_item->m_path); + m_listWidget->addItem(item); + if (m_listWidget->count() == 1) { m_listWidget->setCurrentRow(0); } @@ -282,7 +255,7 @@ bool VListFolderUE::listFolder(const QString &p_path, const QString &p_cmd) m_data.clear(); m_currentFolderPath = dir->fetchPath(); - m_panel->setTitleLabel(m_currentFolderPath); + m_panel->setTitle(m_currentFolderPath); if (!dir->open()) { return true; diff --git a/src/vlistfolderue.h b/src/vlistfolderue.h index 1002b197..d1a45e47 100644 --- a/src/vlistfolderue.h +++ b/src/vlistfolderue.h @@ -7,25 +7,10 @@ #include "vsearchconfig.h" -class VListWidgetDoubleRows; +class VListWidget; class QListWidgetItem; class QLabel; - -class VListFolderPanel : public QWidget -{ - Q_OBJECT -public: - explicit VListFolderPanel(QWidget *p_contentWidget, - QWidget *p_parent = nullptr); - - void setTitleLabel(const QString &p_title); - - void clearTitle(); - -private: - QLabel *m_titleLabel; -}; - +class VUETitleContentPanel; // Universal Entry to list contents of folder. class VListFolderUE : public IUniversalEntry @@ -81,9 +66,9 @@ private: // Current folder path. QString m_currentFolderPath; - VListWidgetDoubleRows *m_listWidget; + VListWidget *m_listWidget; - VListFolderPanel *m_panel; + VUETitleContentPanel *m_panel; }; #endif // VLISTFOLDERUE_H diff --git a/src/vlistue.cpp b/src/vlistue.cpp new file mode 100644 index 00000000..d50a9e81 --- /dev/null +++ b/src/vlistue.cpp @@ -0,0 +1,242 @@ +#include "vlistue.h" + +#include +#include +#include + +#include "vlistwidgetdoublerows.h" +#include "vdirectory.h" +#include "vdirectorytree.h" +#include "vmainwindow.h" +#include "vnote.h" +#include "utils/viconutils.h" +#include "vnotefile.h" +#include "vsearchue.h" +#include "utils/vutils.h" +#include "vnotebook.h" +#include "vuetitlecontentpanel.h" +#include "vhistorylist.h" + +extern VMainWindow *g_mainWin; + +extern VNote *g_vnote; + +VListUE::VListUE(QObject *p_parent) + : IUniversalEntry(p_parent), + m_listWidget(NULL) +{ +} + +QString VListUE::description(int p_id) const +{ + switch (p_id) { + case ID::History: + return tr("List and search history"); + + default: + Q_ASSERT(false); + return tr("Invalid ID %1").arg(p_id); + } +} + +void VListUE::init() +{ + if (m_initialized) { + return; + } + + m_initialized = true; + + m_noteIcon = VIconUtils::treeViewIcon(":/resources/icons/note_item.svg"); + m_folderIcon = VIconUtils::treeViewIcon(":/resources/icons/dir_item.svg"); + + m_listWidget = new VListWidgetDoubleRows(m_widgetParent); + m_listWidget->setFitContent(true); + connect(m_listWidget, SIGNAL(itemActivated(QListWidgetItem *)), + this, SLOT(activateItem(QListWidgetItem *))); + + m_panel = new VUETitleContentPanel(m_listWidget, m_widgetParent); + m_panel->hide(); +} + +QWidget *VListUE::widget(int p_id) +{ + Q_UNUSED(p_id); + + init(); + + return m_panel; +} + +void VListUE::processCommand(int p_id, const QString &p_cmd) +{ + Q_UNUSED(p_id); + + init(); + + clear(-1); + + switch (p_id) { + case ID::History: + listHistory(p_cmd); + break; + + default: + break; + } + + m_listWidget->updateGeometry(); + emit widgetUpdated(); + emit stateUpdated(State::Success); +} + +void VListUE::clear(int p_id) +{ + Q_UNUSED(p_id); + + m_panel->clearTitle(); + m_listWidget->clearAll(); + m_data.clear(); +} + +void VListUE::selectNextItem(int p_id, bool p_forward) +{ + Q_UNUSED(p_id); + + m_listWidget->selectNextItem(p_forward); +} + +void VListUE::activate(int p_id) +{ + Q_UNUSED(p_id); + activateItem(m_listWidget->currentItem()); +} + +const QSharedPointer &VListUE::itemResultData(const QListWidgetItem *p_item) const +{ + Q_ASSERT(p_item); + int idx = p_item->data(Qt::UserRole).toInt(); + Q_ASSERT(idx >= 0 && idx < m_data.size()); + return m_data[idx]; +} + +void VListUE::activateItem(QListWidgetItem *p_item) +{ + if (!p_item) { + return; + } + + emit requestHideUniversalEntry(); + + VSearchUE::activateItem(itemResultData(p_item)); +} + +void VListUE::sort(int p_id) +{ + Q_UNUSED(p_id); + static bool noteFirst = false; + + int cnt = m_listWidget->count(); + if (noteFirst) { + int idx = cnt - 1; + while (true) { + if (itemResultData(m_listWidget->item(idx))->m_type != VSearchResultItem::Note) { + // Move it to the first row. + m_listWidget->moveItem(idx, 0); + } else { + break; + } + } + } else { + int idx = 0; + while (true) { + if (itemResultData(m_listWidget->item(idx))->m_type != VSearchResultItem::Note) { + // Move it to the last row. + m_listWidget->moveItem(idx, cnt - 1); + } else { + break; + } + } + } + + if (cnt) { + m_listWidget->setCurrentRow(0); + } + + noteFirst = !noteFirst; +} + +void VListUE::addResultItem(const QSharedPointer &p_item) +{ + m_data.append(p_item); + + QString first, second; + if (p_item->m_text.isEmpty()) { + first = p_item->m_path; + } else { + first = p_item->m_text; + second = p_item->m_path; + } + + QIcon *icon = NULL; + switch (p_item->m_type) { + case VSearchResultItem::Note: + icon = &m_noteIcon; + break; + + case VSearchResultItem::Folder: + icon = &m_folderIcon; + break; + + default: + break; + } + + QListWidgetItem *item = m_listWidget->addDoubleRowsItem(*icon, first, second); + item->setData(Qt::UserRole, m_data.size() - 1); + item->setToolTip(p_item->m_path); + + if (m_listWidget->count() == 1) { + m_listWidget->setCurrentRow(0); + } +} + +void VListUE::listHistory(const QString &p_cmd) +{ + m_panel->setTitle(tr("History")); + + VHistoryList *history = g_mainWin->getHistoryList(); + const QLinkedList &entries = history->getHistoryEntries(); + if (p_cmd.isEmpty()) { + // List the content. + for (auto it = entries.rbegin(); it != entries.rend(); ++it) { + QSharedPointer item(new VSearchResultItem(it->m_isFolder ? VSearchResultItem::Folder : VSearchResultItem::Note, + VSearchResultItem::LineNumber, + VUtils::fileNameFromPath(it->m_file), + it->m_file)); + addResultItem(item); + } + } else { + // Search the content. + VSearchConfig config(VSearchConfig::CurrentFolder, + VSearchConfig::Name, + VSearchConfig::Note | VSearchConfig::Folder, + VSearchConfig::Internal, + VSearchConfig::NoneOption, + p_cmd, + QString()); + + for (auto it = entries.rbegin(); it != entries.rend(); ++it) { + QString name = VUtils::fileNameFromPath(it->m_file); + if (!config.m_token.matched(name)) { + continue; + } + + QSharedPointer item(new VSearchResultItem(it->m_isFolder ? VSearchResultItem::Folder : VSearchResultItem::Note, + VSearchResultItem::LineNumber, + name, + it->m_file)); + addResultItem(item); + } + } +} diff --git a/src/vlistue.h b/src/vlistue.h new file mode 100644 index 00000000..ffb85f2b --- /dev/null +++ b/src/vlistue.h @@ -0,0 +1,67 @@ +#ifndef VLISTUE_H +#define VLISTUE_H + +#include "iuniversalentry.h" + +#include +#include +#include +#include + +#include "vsearchconfig.h" + +class VListWidgetDoubleRows; +class QListWidgetItem; +class QLabel; +class VUETitleContentPanel; + +class VListUE : public IUniversalEntry +{ + Q_OBJECT +public: + enum ID + { + // List and search the history. + History = 0 + }; + + explicit VListUE(QObject *p_parent = nullptr); + + QString description(int p_id) const Q_DECL_OVERRIDE; + + QWidget *widget(int p_id) Q_DECL_OVERRIDE; + + void processCommand(int p_id, const QString &p_cmd) Q_DECL_OVERRIDE; + + void clear(int p_id) Q_DECL_OVERRIDE; + + void selectNextItem(int p_id, bool p_forward) Q_DECL_OVERRIDE; + + void activate(int p_id) Q_DECL_OVERRIDE; + + void sort(int p_id) Q_DECL_OVERRIDE; + +protected: + void init() Q_DECL_OVERRIDE; + +private slots: + void activateItem(QListWidgetItem *p_item); + +private: + void addResultItem(const QSharedPointer &p_item); + + const QSharedPointer &itemResultData(const QListWidgetItem *p_item) const; + + void listHistory(const QString &p_cmd); + + QVector > m_data; + + QIcon m_noteIcon; + QIcon m_folderIcon; + + VListWidgetDoubleRows *m_listWidget; + + VUETitleContentPanel *m_panel; +}; + +#endif // VLISTUE_H diff --git a/src/vlistwidget.cpp b/src/vlistwidget.cpp index c7e399d7..98ac46c8 100644 --- a/src/vlistwidget.cpp +++ b/src/vlistwidget.cpp @@ -230,3 +230,11 @@ bool VListWidget::isSeparatorItem(const QListWidgetItem *p_item) { return p_item->type() == ItemTypeSeparator; } + +void VListWidget::moveItem(int p_srcRow, int p_destRow) +{ + QListWidgetItem *it = takeItem(p_srcRow); + if (it) { + insertItem(p_destRow, it); + } +} diff --git a/src/vlistwidget.h b/src/vlistwidget.h index 92543bd7..e6caf6a2 100644 --- a/src/vlistwidget.h +++ b/src/vlistwidget.h @@ -34,6 +34,8 @@ public: virtual QSize sizeHint() const Q_DECL_OVERRIDE; + virtual void moveItem(int p_srcRow, int p_destRow); + void setFitContent(bool p_enabled); // Sort @p_list according to @p_sortedIdx. diff --git a/src/vlistwidgetdoublerows.h b/src/vlistwidgetdoublerows.h index 824ac558..6437d31e 100644 --- a/src/vlistwidgetdoublerows.h +++ b/src/vlistwidgetdoublerows.h @@ -23,7 +23,7 @@ public: const QString &p_firstRow, const QString &p_secondRow); - void moveItem(int p_srcRow, int p_destRow); + void moveItem(int p_srcRow, int p_destRow) Q_DECL_OVERRIDE; void clearAll() Q_DECL_OVERRIDE; }; diff --git a/src/vmainwindow.cpp b/src/vmainwindow.cpp index 32731ab3..0df50421 100644 --- a/src/vmainwindow.cpp +++ b/src/vmainwindow.cpp @@ -47,6 +47,7 @@ #include "dialog/vfixnotebookdialog.h" #include "vhistorylist.h" #include "vexplorer.h" +#include "vlistue.h" extern VConfigManager *g_config; @@ -2489,6 +2490,11 @@ QVector VMainWindow::openFiles(const QStringList &p_files, vfiles.reserve(p_files.size()); for (int i = 0; i < p_files.size(); ++i) { + if (!QFileInfo::exists(p_files[i])) { + qWarning() << "file" << p_files[i] << "does not exist"; + continue; + } + VFile *file = NULL; if (!p_forceOrphan) { file = vnote->getInternalFile(p_files[i]); @@ -3135,6 +3141,7 @@ void VMainWindow::initUniversalEntry() m_ue->registerEntry('h', searchUE, VSearchUE::Path_FolderNote_AllNotebook); m_ue->registerEntry('n', searchUE, VSearchUE::Path_FolderNote_CurrentNotebook); m_ue->registerEntry('m', new VListFolderUE(this), 0); + m_ue->registerEntry('j', new VListUE(this), VListUE::History); m_ue->registerEntry('?', new VHelpUE(this), 0); } diff --git a/src/vuetitlecontentpanel.cpp b/src/vuetitlecontentpanel.cpp new file mode 100644 index 00000000..3fceb071 --- /dev/null +++ b/src/vuetitlecontentpanel.cpp @@ -0,0 +1,34 @@ +#include "vuetitlecontentpanel.h" + +#include +#include +#include +#include + +VUETitleContentPanel::VUETitleContentPanel(QWidget *p_contentWidget, + QWidget *p_parent) + : QWidget(p_parent) +{ + m_titleLabel = new QLabel(this); + m_titleLabel->setProperty("TitleLabel", true); + + p_contentWidget->setParent(this); + + QVBoxLayout *layout = new QVBoxLayout(); + layout->addWidget(m_titleLabel); + layout->addWidget(p_contentWidget); + + layout->setContentsMargins(0, 0, 0, 0); + + setLayout(layout); +} + +void VUETitleContentPanel::setTitle(const QString &p_title) +{ + m_titleLabel->setText(p_title); +} + +void VUETitleContentPanel::clearTitle() +{ + m_titleLabel->clear(); +} diff --git a/src/vuetitlecontentpanel.h b/src/vuetitlecontentpanel.h new file mode 100644 index 00000000..21e5b367 --- /dev/null +++ b/src/vuetitlecontentpanel.h @@ -0,0 +1,23 @@ +#ifndef VUETITLECONTENTPANEL_H +#define VUETITLECONTENTPANEL_H + +#include + +class QLabel; + +class VUETitleContentPanel : public QWidget +{ + Q_OBJECT +public: + explicit VUETitleContentPanel(QWidget *p_contentWidget, + QWidget *p_parent = nullptr); + + void setTitle(const QString &p_title); + + void clearTitle(); + +private: + QLabel *m_titleLabel; +}; + +#endif // VUETITLECONTENTPANEL_H