From e32ee1fa900d4b87362ea91a6c180b4fa1f453c9 Mon Sep 17 00:00:00 2001 From: Le Tan Date: Mon, 5 Dec 2016 21:50:16 +0800 Subject: [PATCH] refactor: VNotebookSelector Signed-off-by: Le Tan --- src/resources/vnote.qss | 33 +++--- src/src.pro | 6 +- src/vmainwindow.cpp | 31 +----- src/vmainwindow.h | 3 - src/vnofocusitemdelegate.cpp | 17 +++ src/vnofocusitemdelegate.h | 15 +++ src/vnotebook.cpp | 3 +- src/vnotebookselector.cpp | 208 ++++++++++++++++++++++++++++++++--- src/vnotebookselector.h | 45 +++++++- 9 files changed, 291 insertions(+), 70 deletions(-) create mode 100644 src/vnofocusitemdelegate.cpp create mode 100644 src/vnofocusitemdelegate.h diff --git a/src/resources/vnote.qss b/src/resources/vnote.qss index c7d6afff..9680ce11 100644 --- a/src/resources/vnote.qss +++ b/src/resources/vnote.qss @@ -36,18 +36,16 @@ QDockWidget::close-button:hover, QDockWidget::float-button:hover { background-color: @hover-color; } -/* QComboBox */ -QComboBox[OnMainWindow="true"] { +/* QComboBox#NotebookSelector */ +QComboBox#NotebookSelector { border: 1px solid grey; background-color: @base-background; -} - -QComboBox[OnMainWindow="true"]:on { /* shift the text when the popup opens */ + font-size: 14px; padding-top: 3px; - padding-left: 4px; + padding-bottom: 3px; } -QComboBox[OnMainWindow="true"]::drop-down { +QComboBox#NotebookSelector::drop-down { subcontrol-origin: padding; subcontrol-position: top right; width: 20px; @@ -55,24 +53,23 @@ QComboBox[OnMainWindow="true"]::drop-down { background: transparent; } -QComboBox[OnMainWindow="true"]::down-arrow { +QComboBox#NotebookSelector::down-arrow { image: url(:/resources/icons/arrow_dropdown.svg); width: 20px; } -QComboBox[OnMainWindow="true"]::down-arrow:on { /* shift the arrow when popup is open */ - top: 1px; - left: 1px; +QComboBox#NotebookSelector QListWidget { + border: 1px solid grey; + background-color: @base-background; + font-size: 14px; } -QComboBox[OnMainWindow="true"]::item { - padding-left: 20px; - border: none; - height: 20px; +QComboBox#NotebookSelector QListWidget::item { + padding-top: 5px; + padding-bottom: 5px; } -QComboBox[OnMainWindow="true"]::item:selected { - padding-left: 20px; - border: none; +QComboBox#NotebookSelector QListWidget::item:hover { background-color: @hover-color; } +/* End QComboBox#NotebookSelector */ diff --git a/src/src.pro b/src/src.pro index bac38aca..abb95b8b 100644 --- a/src/src.pro +++ b/src/src.pro @@ -45,7 +45,8 @@ SOURCES += main.cpp\ vsingleinstanceguard.cpp \ vdirectory.cpp \ vfile.cpp \ - vnotebookselector.cpp + vnotebookselector.cpp \ + vnofocusitemdelegate.cpp HEADERS += vmainwindow.h \ vdirectorytree.h \ @@ -79,7 +80,8 @@ HEADERS += vmainwindow.h \ vsingleinstanceguard.h \ vdirectory.h \ vfile.h \ - vnotebookselector.h + vnotebookselector.h \ + vnofocusitemdelegate.h RESOURCES += \ vnote.qrc diff --git a/src/vmainwindow.cpp b/src/vmainwindow.cpp index a7480696..856de3eb 100644 --- a/src/vmainwindow.cpp +++ b/src/vmainwindow.cpp @@ -80,30 +80,14 @@ QWidget *VMainWindow::setupDirectoryPanel() notebookLabel = new QLabel(tr("Notebook")); directoryLabel = new QLabel(tr("Directory")); - newNotebookBtn = new QPushButton(QIcon(":/resources/icons/create_notebook.svg"), ""); - newNotebookBtn->setToolTip(tr("Create a new notebook")); - newNotebookBtn->setProperty("OnMainWindow", true); - deleteNotebookBtn = new QPushButton(QIcon(":/resources/icons/delete_notebook.svg"), ""); - deleteNotebookBtn->setToolTip(tr("Delete current notebook")); - deleteNotebookBtn->setProperty("OnMainWindow", true); - notebookInfoBtn = new QPushButton(QIcon(":/resources/icons/notebook_info.svg"), ""); - notebookInfoBtn->setToolTip(tr("View and edit current notebook's information")); - notebookInfoBtn->setProperty("OnMainWindow", true); - notebookSelector = new VNotebookSelector(vnote); - notebookSelector->setProperty("OnMainWindow", true); - notebookSelector->setSizeAdjustPolicy(QComboBox::AdjustToContents); + notebookSelector->setObjectName("NotebookSelector"); + notebookSelector->setSizeAdjustPolicy(QComboBox::AdjustToMinimumContentsLengthWithIcon); + directoryTree = new VDirectoryTree(vnote); - QHBoxLayout *nbBtnLayout = new QHBoxLayout; - nbBtnLayout->addWidget(notebookLabel); - nbBtnLayout->addStretch(); - nbBtnLayout->addWidget(newNotebookBtn); - nbBtnLayout->addWidget(deleteNotebookBtn); - nbBtnLayout->addWidget(notebookInfoBtn); - nbBtnLayout->setContentsMargins(0, 0, 0, 0); QVBoxLayout *nbLayout = new QVBoxLayout; - nbLayout->addLayout(nbBtnLayout); + nbLayout->addWidget(notebookLabel); nbLayout->addWidget(notebookSelector); nbLayout->addWidget(directoryLabel); nbLayout->addWidget(directoryTree); @@ -117,13 +101,6 @@ QWidget *VMainWindow::setupDirectoryPanel() connect(notebookSelector, &VNotebookSelector::curNotebookChanged, this, &VMainWindow::handleCurrentNotebookChanged); - connect(newNotebookBtn, &QPushButton::clicked, - notebookSelector, &VNotebookSelector::newNotebook); - connect(deleteNotebookBtn, SIGNAL(clicked(bool)), - notebookSelector, SLOT(deleteNotebook())); - connect(notebookInfoBtn, SIGNAL(clicked(bool)), - notebookSelector, SLOT(editNotebookInfo())); - connect(directoryTree, &VDirectoryTree::currentDirectoryChanged, this, &VMainWindow::handleCurrentDirectoryChanged); return nbContainer; diff --git a/src/vmainwindow.h b/src/vmainwindow.h index 07d6a678..91b57426 100644 --- a/src/vmainwindow.h +++ b/src/vmainwindow.h @@ -74,9 +74,6 @@ private: QLabel *notebookLabel; QLabel *directoryLabel; VNotebookSelector *notebookSelector; - QPushButton *newNotebookBtn; - QPushButton *deleteNotebookBtn; - QPushButton *notebookInfoBtn; VFileList *fileList; VDirectoryTree *directoryTree; QSplitter *mainSplitter; diff --git a/src/vnofocusitemdelegate.cpp b/src/vnofocusitemdelegate.cpp new file mode 100644 index 00000000..2ea6c008 --- /dev/null +++ b/src/vnofocusitemdelegate.cpp @@ -0,0 +1,17 @@ +#include "vnofocusitemdelegate.h" + +VNoFocusItemDelegate::VNoFocusItemDelegate(QWidget *parent) + : QStyledItemDelegate(parent) +{ + +} + +void VNoFocusItemDelegate::paint(QPainter *painter, const QStyleOptionViewItem &option, + const QModelIndex &index) const +{ + QStyleOptionViewItem itemOp(option); + if (itemOp.state & QStyle::State_HasFocus) { + itemOp.state ^= QStyle::State_HasFocus; + } + QStyledItemDelegate::paint(painter, itemOp, index); +} diff --git a/src/vnofocusitemdelegate.h b/src/vnofocusitemdelegate.h new file mode 100644 index 00000000..794db0ab --- /dev/null +++ b/src/vnofocusitemdelegate.h @@ -0,0 +1,15 @@ +#ifndef VNOFOCUSITEMDELEGATE_H +#define VNOFOCUSITEMDELEGATE_H + +#include + +class VNoFocusItemDelegate : public QStyledItemDelegate +{ + Q_OBJECT +public: + explicit VNoFocusItemDelegate(QWidget *parent = 0); + void paint(QPainter *painter, const QStyleOptionViewItem &option, + const QModelIndex &index) const Q_DECL_OVERRIDE; +}; + +#endif // VNOFOCUSITEMDELEGATE_H diff --git a/src/vnotebook.cpp b/src/vnotebook.cpp index db974310..dd375fa7 100644 --- a/src/vnotebook.cpp +++ b/src/vnotebook.cpp @@ -59,10 +59,11 @@ void VNotebook::deleteNotebook(VNotebook *p_notebook) if (!p_notebook) { return; } + QString path = p_notebook->getPath(); + p_notebook->close(); delete p_notebook; - QString path = p_notebook->getPath(); QDir dir(path); if (!dir.removeRecursively()) { qWarning() << "failed to delete" << path; diff --git a/src/vnotebookselector.cpp b/src/vnotebookselector.cpp index cba3a470..c93391b3 100644 --- a/src/vnotebookselector.cpp +++ b/src/vnotebookselector.cpp @@ -1,6 +1,9 @@ #include "vnotebookselector.h" #include #include +#include +#include +#include #include "vnotebook.h" #include "vconfigmanager.h" #include "dialog/vnewnotebookdialog.h" @@ -10,15 +13,48 @@ #include "utils/vutils.h" #include "vnote.h" #include "veditarea.h" +#include "vnofocusitemdelegate.h" extern VConfigManager vconfig; +const int VNotebookSelector::c_notebookStartIdx = 1; + VNotebookSelector::VNotebookSelector(VNote *vnote, QWidget *p_parent) : QComboBox(p_parent), m_vnote(vnote), m_notebooks(m_vnote->getNotebooks()), - m_editArea(NULL) + m_editArea(NULL), m_lastValidIndex(-1) { + m_listWidget = new QListWidget(this); + m_listWidget->setItemDelegate(new VNoFocusItemDelegate(this)); + m_listWidget->setContextMenuPolicy(Qt::CustomContextMenu); + connect(m_listWidget, &QListWidget::customContextMenuRequested, + this, &VNotebookSelector::requestPopupListContextMenu); + + setModel(m_listWidget->model()); + setView(m_listWidget); + + m_listWidget->viewport()->installEventFilter(this); + + initActions(); + connect(this, SIGNAL(currentIndexChanged(int)), this, SLOT(handleCurIndexChanged(int))); + connect(this, SIGNAL(activated(int)), + this, SLOT(handleItemActivated(int))); +} + +void VNotebookSelector::initActions() +{ + m_deleteNotebookAct = new QAction(QIcon(":/resources/icons/delete_notebook.svg"), + tr("&Delete"), this); + m_deleteNotebookAct->setStatusTip(tr("Delete current notebook")); + connect(m_deleteNotebookAct, SIGNAL(triggered(bool)), + this, SLOT(deleteNotebook())); + + m_notebookInfoAct = new QAction(QIcon(":/resources/icons/notebook_info.svg"), + tr("&Info")); + m_notebookInfoAct->setStatusTip(tr("View and edit current notebook's information")); + connect(m_notebookInfoAct, SIGNAL(triggered(bool)), + this, SLOT(editNotebookInfo())); } void VNotebookSelector::updateComboBox() @@ -28,42 +64,99 @@ void VNotebookSelector::updateComboBox() disconnect(this, SIGNAL(currentIndexChanged(int)), this, SLOT(handleCurIndexChanged(int))); clear(); + m_listWidget->clear(); + + insertAddNotebookItem(); + for (int i = 0; i < m_notebooks.size(); ++i) { - addItem(QIcon(":/resources/icons/notebook_item.svg"), m_notebooks[i]->getName()); + addNotebookItem(m_notebooks[i]->getName()); } setCurrentIndex(-1); connect(this, SIGNAL(currentIndexChanged(int)), this, SLOT(handleCurIndexChanged(int))); - if (m_notebooks.isEmpty() && index != -1) { - index = -1; - vconfig.setCurNotebookIndex(index); + if (m_notebooks.isEmpty()) { + vconfig.setCurNotebookIndex(-1); + setCurrentIndex(0); + } else { + setCurrentIndexNotebook(index); } - setCurrentIndex(index); qDebug() << "notebooks" << m_notebooks.size() << "current index" << index; } +void VNotebookSelector::setCurrentIndexNotebook(int p_index) +{ + if (p_index > -1) { + p_index += c_notebookStartIdx; + } + setCurrentIndex(p_index); +} + +void VNotebookSelector::insertAddNotebookItem() +{ + QListWidgetItem *item = new QListWidgetItem(); + item->setIcon(QIcon(":/resources/icons/create_notebook.svg")); + item->setText("Add Notebook"); + QFont font; + font.setItalic(true); + item->setData(Qt::FontRole, font); + item->setToolTip(tr("Create or import a notebook.")); + m_listWidget->insertItem(0, item); +} + void VNotebookSelector::handleCurIndexChanged(int p_index) { - qDebug() << "current index changed" << p_index; + qDebug() << "current index changed" << p_index << "startIdx" << c_notebookStartIdx; VNotebook *nb = NULL; if (p_index > -1) { - nb = m_notebooks[p_index]; + if (p_index < c_notebookStartIdx) { + // Click a special action item. + if (m_listWidget->count() == c_notebookStartIdx) { + // There is no regular notebook item. Just let it be selected. + p_index = -1; + } else { + // handleItemActivated() will handle the logics. + return; + } + } else { + int nbIdx = p_index - c_notebookStartIdx; + Q_ASSERT(nbIdx >= 0); + nb = m_notebooks[nbIdx]; + } } + m_lastValidIndex = p_index; + QString tooltip; + if (p_index > -1) { + p_index -= c_notebookStartIdx; + tooltip = nb->getName(); + } + setToolTip(tooltip); vconfig.setCurNotebookIndex(p_index); emit curNotebookChanged(nb); } +void VNotebookSelector::handleItemActivated(int p_index) +{ + if (p_index > -1 && p_index < c_notebookStartIdx) { + // Click a special action item + if (m_lastValidIndex > -1) { + setCurrentIndex(m_lastValidIndex); + } + newNotebook(); + } +} + void VNotebookSelector::update() { updateComboBox(); } -void VNotebookSelector::newNotebook() +bool VNotebookSelector::newNotebook() { QString info; QString defaultName("new_notebook"); QString defaultPath; + do { VNewNotebookDialog dialog(tr("Create notebook"), info, defaultName, defaultPath, this); @@ -77,9 +170,11 @@ void VNotebookSelector::newNotebook() continue; } createNotebook(name, path); + return true; } break; } while (true); + return false; } VNotebook *VNotebookSelector::findNotebook(const QString &p_name) @@ -98,14 +193,22 @@ void VNotebookSelector::createNotebook(const QString &p_name, const QString &p_p m_notebooks.append(nb); vconfig.setNotebooks(m_notebooks); - addItem(QIcon(":/resources/icons/notebook_item.svg"), nb->getName()); - setCurrentIndex(m_notebooks.size() - 1); + addNotebookItem(nb->getName()); + setCurrentIndexNotebook(m_notebooks.size() - 1); } void VNotebookSelector::deleteNotebook() { - int curIndex = currentIndex(); - VNotebook *notebook = m_notebooks[curIndex]; + QList items = m_listWidget->selectedItems(); + if (items.isEmpty()) { + return; + } + Q_ASSERT(items.size() == 1); + QListWidgetItem *item = items[0]; + int index = indexOfListItem(item); + + VNotebook *notebook = getNotebookFromComboIndex(index); + Q_ASSERT(notebook); QString curName = notebook->getName(); QString curPath = notebook->getPath(); @@ -126,7 +229,7 @@ void VNotebookSelector::deleteNotebook(VNotebook *p_notebook) m_notebooks.remove(idx); vconfig.setNotebooks(m_notebooks); - removeItem(idx); + removeNotebookItem(idx); VNotebook::deleteNotebook(p_notebook); } @@ -141,11 +244,18 @@ int VNotebookSelector::indexOfNotebook(const VNotebook *p_notebook) return -1; } + void VNotebookSelector::editNotebookInfo() { - int curIndex = currentIndex(); - Q_ASSERT(curIndex > -1); - VNotebook *notebook = m_notebooks[curIndex]; + QList items = m_listWidget->selectedItems(); + if (items.isEmpty()) { + return; + } + Q_ASSERT(items.size() == 1); + QListWidgetItem *item = items[0]; + int index = indexOfListItem(item); + + VNotebook *notebook = getNotebookFromComboIndex(index); QString info; QString curName = notebook->getName(); QString defaultPath = notebook->getPath(); @@ -164,10 +274,72 @@ void VNotebookSelector::editNotebookInfo() continue; } notebook->rename(name); - setItemText(curIndex, name); + updateComboBoxItem(index, name); vconfig.setNotebooks(m_notebooks); emit notebookUpdated(notebook); } break; } while (true); } + +void VNotebookSelector::addNotebookItem(const QString &p_name) +{ + QListWidgetItem *item = new QListWidgetItem(m_listWidget); + item->setText(p_name); + item->setToolTip(p_name); + item->setIcon(QIcon(":/resources/icons/notebook_item.svg")); +} + +void VNotebookSelector::removeNotebookItem(int p_index) +{ + QListWidgetItem *item = m_listWidget->item(p_index + c_notebookStartIdx); + m_listWidget->removeItemWidget(item); + delete item; +} + +void VNotebookSelector::updateComboBoxItem(int p_index, const QString &p_name) +{ + QListWidgetItem *item = m_listWidget->item(p_index); + item->setText(p_name); + item->setToolTip(p_name); +} + +void VNotebookSelector::requestPopupListContextMenu(QPoint p_pos) +{ + QModelIndex index = m_listWidget->indexAt(p_pos); + if (!index.isValid() || index.row() < c_notebookStartIdx) { + return; + } + + QListWidgetItem *item = m_listWidget->itemAt(p_pos); + Q_ASSERT(item); + m_listWidget->clearSelection(); + item->setSelected(true); + + QMenu menu(this); + menu.addAction(m_deleteNotebookAct); + menu.addAction(m_notebookInfoAct); + + menu.exec(m_listWidget->mapToGlobal(p_pos)); +} + +bool VNotebookSelector::eventFilter(QObject *watched, QEvent *event) +{ + if (event->type() == QEvent::MouseButtonRelease) { + if (static_cast(event)->button() == Qt::RightButton) { + return true; + } + } + return QComboBox::eventFilter(watched, event); +} + +int VNotebookSelector::indexOfListItem(const QListWidgetItem *p_item) +{ + int nrItems = m_listWidget->count(); + for (int i = 0; i < nrItems; ++i) { + if (m_listWidget->item(i) == p_item) { + return i; + } + } + return -1; +} diff --git a/src/vnotebookselector.h b/src/vnotebookselector.h index f65b7919..07a47301 100644 --- a/src/vnotebookselector.h +++ b/src/vnotebookselector.h @@ -8,6 +8,9 @@ class VNotebook; class VNote; class VEditArea; +class QListWidget; +class QAction; +class QListWidgetItem; class VNotebookSelector : public QComboBox { @@ -23,23 +26,51 @@ signals: void notebookUpdated(const VNotebook *p_notebook); public slots: - void newNotebook(); + bool newNotebook(); void deleteNotebook(); void editNotebookInfo(); +protected: + bool eventFilter(QObject *watched, QEvent *event) Q_DECL_OVERRIDE; + private slots: void handleCurIndexChanged(int p_index); + void handleItemActivated(int p_index); + void requestPopupListContextMenu(QPoint p_pos); private: + void initActions(); void updateComboBox(); VNotebook *findNotebook(const QString &p_name); + // Return the index of @p_notebook in m_noteboks. int indexOfNotebook(const VNotebook *p_notebook); void createNotebook(const QString &p_name, const QString &p_path); void deleteNotebook(VNotebook *p_notebook); + void addNotebookItem(const QString &p_name); + // @p_index is the index of m_notebooks, NOT of QComboBox. + void removeNotebookItem(int p_index); + // @p_index is the index of QComboBox. + void updateComboBoxItem(int p_index, const QString &p_name); + void insertAddNotebookItem(); + // @p_index is the index of m_notebooks. + void setCurrentIndexNotebook(int p_index); + int indexOfListItem(const QListWidgetItem *p_item); + // @p_index is the idnex of QComboBox. + inline VNotebook *getNotebookFromComboIndex(int p_index); VNote *m_vnote; QVector &m_notebooks; VEditArea *m_editArea; + QListWidget *m_listWidget; + int m_lastValidIndex; + + // Actions + QAction *m_deleteNotebookAct; + QAction *m_notebookInfoAct; + + // We will add several special action item in the combobox. This is the start index + // of the real notebook items related to m_notebooks. + static const int c_notebookStartIdx; }; inline void VNotebookSelector::setEditArea(VEditArea *p_editArea) @@ -47,4 +78,16 @@ inline void VNotebookSelector::setEditArea(VEditArea *p_editArea) m_editArea = p_editArea; } +inline VNotebook *VNotebookSelector::getNotebookFromComboIndex(int p_index) +{ + if (p_index < c_notebookStartIdx) { + return NULL; + } + int nbIdx = p_index - c_notebookStartIdx; + if (nbIdx >= m_notebooks.size()) { + return NULL; + } + return m_notebooks[nbIdx]; +} + #endif // VNOTEBOOKSELECTOR_H