| 123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554 |
- #include "vtagexplorer.h"
- #include <QtWidgets>
- #include "utils/viconutils.h"
- #include "vmainwindow.h"
- #include "vlistwidget.h"
- #include "vnotebook.h"
- #include "vconfigmanager.h"
- #include "vsearch.h"
- #include "vnote.h"
- #include "vcart.h"
- #include "vhistorylist.h"
- #include "vnotefile.h"
- #include "utils/vutils.h"
- #include "vnavigationmode.h"
- #include "vcaptain.h"
- extern VMainWindow *g_mainWin;
- extern VConfigManager *g_config;
- extern VNote *g_vnote;
- #define MAX_DISPLAY_LENGTH 10
- VTagExplorer::VTagExplorer(QWidget *p_parent)
- : QWidget(p_parent),
- m_uiInitialized(false),
- m_notebook(NULL),
- m_notebookChanged(true),
- m_search(NULL)
- {
- }
- void VTagExplorer::setupUI()
- {
- if (m_uiInitialized) {
- return;
- }
- m_uiInitialized = true;
- m_notebookLabel = new QLabel(tr("Tags"), this);
- m_notebookLabel->setProperty("TitleLabel", true);
- m_tagList = new VListWidget(this);
- m_tagList->setAttribute(Qt::WA_MacShowFocusRect, false);
- connect(m_tagList, &QListWidget::itemActivated,
- this, [this](const QListWidgetItem *p_item) {
- QString tag;
- if (p_item) {
- tag = p_item->text();
- }
- bool ret = activateTag(tag);
- if (ret && !tag.isEmpty() && m_fileList->count() == 0) {
- promptToRemoveEmptyTag(tag);
- }
- });
- QVBoxLayout *tagLayout = new QVBoxLayout();
- tagLayout->addWidget(m_notebookLabel);
- tagLayout->addWidget(m_tagList);
- tagLayout->setContentsMargins(0, 0, 0, 0);
- QWidget *tagWidget = new QWidget(this);
- tagWidget->setLayout(tagLayout);
- m_tagLabel = new QLabel(tr("Notes"), this);
- m_tagLabel->setProperty("TitleLabel", true);
- m_splitBtn = new QPushButton(VIconUtils::buttonIcon(":/resources/icons/split_window.svg"),
- "",
- this);
- m_splitBtn->setToolTip(tr("Split"));
- m_splitBtn->setCheckable(true);
- m_splitBtn->setProperty("CornerBtn", true);
- m_splitBtn->setFocusPolicy(Qt::NoFocus);
- connect(m_splitBtn, &QPushButton::clicked,
- this, [this](bool p_checked) {
- g_config->setEnableSplitTagFileList(p_checked);
- setupFileListSplitOut(p_checked);
- });
- QHBoxLayout *titleLayout = new QHBoxLayout();
- titleLayout->addWidget(m_tagLabel);
- titleLayout->addWidget(m_splitBtn);
- titleLayout->addStretch();
- titleLayout->setContentsMargins(0, 0, 0, 0);
- m_fileList = new VListWidget(this);
- m_fileList->setAttribute(Qt::WA_MacShowFocusRect, false);
- m_fileList->setContextMenuPolicy(Qt::CustomContextMenu);
- m_fileList->setSelectionMode(QAbstractItemView::ExtendedSelection);
- connect(m_fileList, &QListWidget::itemActivated,
- this, &VTagExplorer::openFileItem);
- connect(m_fileList, &QListWidget::customContextMenuRequested,
- this, &VTagExplorer::handleFileListContextMenuRequested);
- QVBoxLayout *fileLayout = new QVBoxLayout();
- fileLayout->addLayout(titleLayout);
- fileLayout->addWidget(m_fileList);
- fileLayout->setContentsMargins(0, 0, 0, 0);
- QWidget *fileWidget = new QWidget(this);
- fileWidget->setLayout(fileLayout);
- m_splitter = new QSplitter(this);
- m_splitter->setObjectName("TagExplorerSplitter");
- m_splitter->addWidget(tagWidget);
- m_splitter->addWidget(fileWidget);
- setupFileListSplitOut(g_config->getEnableSplitTagFileList());
- QVBoxLayout *mainLayout = new QVBoxLayout();
- mainLayout->addWidget(m_splitter);
- mainLayout->setContentsMargins(0, 0, 0, 0);
- setLayout(mainLayout);
- restoreStateAndGeometry();
- }
- void VTagExplorer::showEvent(QShowEvent *p_event)
- {
- setupUI();
- QWidget::showEvent(p_event);
- updateContent();
- }
- void VTagExplorer::focusInEvent(QFocusEvent *p_event)
- {
- setupUI();
- QWidget::focusInEvent(p_event);
- m_tagList->setFocus();
- }
- void VTagExplorer::setNotebook(VNotebook *p_notebook)
- {
- if (p_notebook == m_notebook) {
- return;
- }
- setupUI();
- m_notebook = p_notebook;
- m_notebookChanged = true;
- if (!isVisible()) {
- return;
- }
- updateContent();
- }
- void VTagExplorer::updateContent()
- {
- if (m_notebook) {
- updateNotebookLabel();
- const QStringList &tags = m_notebook->getTags();
- if (m_notebookChanged || tagListObsolete(tags)) {
- updateTagList(tags);
- }
- } else {
- clear();
- }
- m_notebookChanged = false;
- }
- void VTagExplorer::clear()
- {
- setupUI();
- m_fileList->clearAll();
- m_tagList->clearAll();
- updateTagLabel("");
- updateNotebookLabel();
- }
- void VTagExplorer::updateNotebookLabel()
- {
- QString text = tr("Tags");
- QString tooltip;
- if (m_notebook) {
- QString name = m_notebook->getName();
- tooltip = name;
- if (name.size() > MAX_DISPLAY_LENGTH) {
- name = name.left(MAX_DISPLAY_LENGTH) + QStringLiteral("...");
- }
- text = tr("Tags (%1)").arg(name);
- }
- m_notebookLabel->setText(text);
- m_notebookLabel->setToolTip(tooltip);
- }
- bool VTagExplorer::tagListObsolete(const QStringList &p_tags) const
- {
- if (m_tagList->count() != p_tags.size()) {
- return true;
- }
- for (int i = 0; i < p_tags.size(); ++i) {
- if (p_tags[i] != m_tagList->item(i)->text()) {
- return true;
- }
- }
- return false;
- }
- void VTagExplorer::updateTagLabel(const QString &p_tag)
- {
- QString text = tr("Notes");
- QString tooltip;
- if (!p_tag.isEmpty()) {
- QString name = p_tag;
- tooltip = name;
- if (name.size() > MAX_DISPLAY_LENGTH) {
- name = name.left(MAX_DISPLAY_LENGTH) + QStringLiteral("...");
- }
- text = tr("Notes (%1)").arg(name);
- }
- m_tagLabel->setText(text);
- m_tagLabel->setToolTip(tooltip);
- }
- bool VTagExplorer::activateTag(const QString &p_tag)
- {
- updateTagLabel(p_tag);
- m_fileList->clearAll();
- if (p_tag.isEmpty()) {
- return false;
- }
- // Search this tag within current notebook.
- g_mainWin->showStatusMessage(tr("Searching for tag \"%1\"").arg(p_tag));
- QVector<VNotebook *> notebooks;
- notebooks.append(m_notebook);
- getVSearch()->clear();
- // We could not use WholeWordOnly here, since "c#" won't match a word.
- int opts = VSearchConfig::CaseSensitive | VSearchConfig::RegularExpression;
- QString pattern = QRegExp::escape(p_tag);
- pattern = "^" + pattern + "$";
- QSharedPointer<VSearchConfig> config(new VSearchConfig(VSearchConfig::CurrentNotebook,
- VSearchConfig::Tag,
- VSearchConfig::Note,
- VSearchConfig::Internal,
- opts,
- pattern,
- QString()));
- getVSearch()->setConfig(config);
- QSharedPointer<VSearchResult> result = getVSearch()->search(notebooks);
- bool ret = result->m_state == VSearchState::Success;
- handleSearchFinished(result);
- return ret;
- }
- void VTagExplorer::updateTagList(const QStringList &p_tags)
- {
- // Clear.
- m_tagList->clearAll();
- activateTag("");
- for (auto const & tag : p_tags) {
- addTagItem(tag);
- }
- if (m_tagList->count() > 0) {
- m_tagList->setCurrentRow(0, QItemSelectionModel::ClearAndSelect);
- }
- }
- void VTagExplorer::addTagItem(const QString &p_tag)
- {
- QListWidgetItem *item = new QListWidgetItem(VIconUtils::treeViewIcon(":/resources/icons/tag.svg"),
- p_tag);
- item->setToolTip(p_tag);
- m_tagList->addItem(item);
- }
- void VTagExplorer::saveStateAndGeometry()
- {
- if (!m_uiInitialized) {
- return;
- }
- g_config->setTagExplorerSplitterState(m_splitter->saveState());
- }
- void VTagExplorer::restoreStateAndGeometry()
- {
- const QByteArray state = g_config->getTagExplorerSplitterState();
- if (!state.isEmpty()) {
- m_splitter->restoreState(state);
- }
- }
- void VTagExplorer::initVSearch()
- {
- m_search = new VSearch(this);
- connect(m_search, &VSearch::resultItemAdded,
- this, &VTagExplorer::handleSearchItemAdded);
- connect(m_search, &VSearch::resultItemsAdded,
- this, &VTagExplorer::handleSearchItemsAdded);
- connect(m_search, &VSearch::finished,
- this, &VTagExplorer::handleSearchFinished);
- m_noteIcon = VIconUtils::treeViewIcon(":/resources/icons/note_item.svg");
- }
- void VTagExplorer::handleSearchItemAdded(const QSharedPointer<VSearchResultItem> &p_item)
- {
- appendItemToFileList(p_item);
- }
- void VTagExplorer::appendItemToFileList(const QSharedPointer<VSearchResultItem> &p_item)
- {
- Q_ASSERT(p_item->m_type == VSearchResultItem::Note);
- QListWidgetItem *item = new QListWidgetItem(m_noteIcon,
- p_item->m_text.isEmpty() ? p_item->m_path : p_item->m_text);
- item->setData(Qt::UserRole, p_item->m_path);
- item->setToolTip(p_item->m_path);
- m_fileList->addItem(item);
- }
- void VTagExplorer::handleSearchItemsAdded(const QList<QSharedPointer<VSearchResultItem> > &p_items)
- {
- for (auto const & it : p_items) {
- appendItemToFileList(it);
- }
- }
- void VTagExplorer::handleSearchFinished(const QSharedPointer<VSearchResult> &p_result)
- {
- Q_ASSERT(p_result->m_state != VSearchState::Idle);
- QString msg;
- switch (p_result->m_state) {
- case VSearchState::Busy:
- // Only synchronized search.
- Q_ASSERT(false);
- msg = tr("Invalid busy state when searching for tag");
- break;
- case VSearchState::Success:
- qDebug() << "search succeeded";
- msg = tr("Search for tag succeeded");
- break;
- case VSearchState::Fail:
- qDebug() << "search failed";
- msg = tr("Search for tag failed");
- break;
- case VSearchState::Cancelled:
- qDebug() << "search cancelled";
- msg = tr("Search for tag calcelled");
- break;
- default:
- break;
- }
- m_search->clear();
- if (!msg.isEmpty()) {
- g_mainWin->showStatusMessage(msg);
- }
- }
- void VTagExplorer::openFileItem(QListWidgetItem *p_item) const
- {
- if (!p_item) {
- return;
- }
- QStringList files;
- files << getFilePath(p_item);
- g_mainWin->openFiles(files);
- }
- void VTagExplorer::openSelectedFileItems() const
- {
- QStringList files;
- QList<QListWidgetItem *> selectedItems = m_fileList->selectedItems();
- for (auto it : selectedItems) {
- files << getFilePath(it);
- }
- if (!files.isEmpty()) {
- g_mainWin->openFiles(files);
- }
- }
- QString VTagExplorer::getFilePath(const QListWidgetItem *p_item) const
- {
- return p_item->data(Qt::UserRole).toString();
- }
- void VTagExplorer::handleFileListContextMenuRequested(QPoint p_pos)
- {
- QListWidgetItem *item = m_fileList->itemAt(p_pos);
- if (!item) {
- return;
- }
- QMenu menu(this);
- menu.setToolTipsVisible(true);
- QAction *openAct = new QAction(tr("&Open"), &menu);
- openAct->setToolTip(tr("Open selected notes"));
- connect(openAct, &QAction::triggered,
- this, &VTagExplorer::openSelectedFileItems);
- menu.addAction(openAct);
- QList<QListWidgetItem *> selectedItems = m_fileList->selectedItems();
- if (selectedItems.size() == 1) {
- QAction *locateAct = new QAction(VIconUtils::menuIcon(":/resources/icons/locate_note.svg"),
- tr("&Locate To Folder"),
- &menu);
- locateAct->setToolTip(tr("Locate the folder of current note"));
- connect(locateAct, &QAction::triggered,
- this, &VTagExplorer::locateCurrentFileItem);
- menu.addAction(locateAct);
- }
- menu.addSeparator();
- QAction *addToCartAct = new QAction(VIconUtils::menuIcon(":/resources/icons/cart.svg"),
- tr("Add To Cart"),
- &menu);
- addToCartAct->setToolTip(tr("Add selected notes to Cart for further processing"));
- connect(addToCartAct, &QAction::triggered,
- this, &VTagExplorer::addFileToCart);
- menu.addAction(addToCartAct);
- QAction *pinToHistoryAct = new QAction(VIconUtils::menuIcon(":/resources/icons/pin.svg"),
- tr("Pin To History"),
- &menu);
- pinToHistoryAct->setToolTip(tr("Pin selected notes to History"));
- connect(pinToHistoryAct, &QAction::triggered,
- this, &VTagExplorer::pinFileToHistory);
- menu.addAction(pinToHistoryAct);
- menu.exec(m_fileList->mapToGlobal(p_pos));
- }
- void VTagExplorer::locateCurrentFileItem() const
- {
- auto item = m_fileList->currentItem();
- if (!item) {
- return;
- }
- VFile *file = g_vnote->getInternalFile(getFilePath(item));
- if (file) {
- g_mainWin->locateFile(file);
- }
- }
- void VTagExplorer::addFileToCart() const
- {
- QList<QListWidgetItem *> items = m_fileList->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")));
- }
- void VTagExplorer::pinFileToHistory() const
- {
- QList<QListWidgetItem *> items = m_fileList->selectedItems();
- QStringList files;
- for (int i = 0; i < items.size(); ++i) {
- files << getFilePath(items[i]);
- }
- 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 VTagExplorer::promptToRemoveEmptyTag(const QString &p_tag)
- {
- Q_ASSERT(!p_tag.isEmpty());
- int ret = VUtils::showMessage(QMessageBox::Warning,
- tr("Warning"),
- tr("Empty tag detected! Do you want to remove it?"),
- tr("The tag <span style=\"%1\">%2</span> seems not to "
- "be assigned to any note currently.")
- .arg(g_config->c_dataTextStyle)
- .arg(p_tag),
- QMessageBox::Ok | QMessageBox::Cancel,
- QMessageBox::Cancel,
- this,
- MessageBoxType::Danger);
- if (ret == QMessageBox::Cancel) {
- return;
- }
- // Remove the tag from m_notebook.
- m_notebook->removeTag(p_tag);
- updateContent();
- }
- void VTagExplorer::registerNavigationTarget()
- {
- setupUI();
- VNavigationModeListWidgetWrapper *tagWrapper = new VNavigationModeListWidgetWrapper(m_tagList, this);
- g_mainWin->getCaptain()->registerNavigationTarget(tagWrapper);
- VNavigationModeListWidgetWrapper *fileWrapper = new VNavigationModeListWidgetWrapper(m_fileList, this);
- g_mainWin->getCaptain()->registerNavigationTarget(fileWrapper);
- }
- void VTagExplorer::setupFileListSplitOut(bool p_enabled)
- {
- m_splitBtn->setChecked(p_enabled);
- if (p_enabled) {
- m_splitter->setOrientation(Qt::Horizontal);
- m_splitter->setStretchFactor(0, 1);
- m_splitter->setStretchFactor(1, 1);
- } else {
- m_splitter->setOrientation(Qt::Vertical);
- m_splitter->setStretchFactor(0, 1);
- m_splitter->setStretchFactor(1, 2);
- }
- }
|