| 123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624625 |
- #include "vsnippetlist.h"
- #include <QtWidgets>
- #include "vconfigmanager.h"
- #include "dialog/veditsnippetdialog.h"
- #include "utils/vutils.h"
- #include "utils/vimnavigationforwidget.h"
- #include "dialog/vsortdialog.h"
- #include "dialog/vconfirmdeletiondialog.h"
- #include "vmainwindow.h"
- #include "utils/viconutils.h"
- extern VConfigManager *g_config;
- extern VMainWindow *g_mainWin;
- const QString VSnippetList::c_infoShortcutSequence = "F2";
- VSnippetList::VSnippetList(QWidget *p_parent)
- : QWidget(p_parent)
- {
- setupUI();
- initShortcuts();
- initActions();
- if (!readSnippetsFromConfig()) {
- VUtils::showMessage(QMessageBox::Warning,
- tr("Warning"),
- tr("Fail to read snippets from <span style=\"%1\">%2</span>.")
- .arg(g_config->c_dataTextStyle)
- .arg(g_config->getSnippetConfigFolder()),
- "",
- QMessageBox::Ok,
- QMessageBox::Ok,
- this);
- }
- updateContent();
- }
- void VSnippetList::setupUI()
- {
- m_addBtn = new QPushButton(VIconUtils::buttonIcon(":/resources/icons/add_snippet.svg"), "");
- m_addBtn->setToolTip(tr("New Snippet"));
- m_addBtn->setProperty("FlatBtn", true);
- connect(m_addBtn, &QPushButton::clicked,
- this, &VSnippetList::newSnippet);
- m_locateBtn = new QPushButton(VIconUtils::buttonIcon(":/resources/icons/locate_snippet.svg"), "");
- m_locateBtn->setToolTip(tr("Open Folder"));
- m_locateBtn->setProperty("FlatBtn", true);
- connect(m_locateBtn, &QPushButton::clicked,
- this, [this]() {
- makeSureFolderExist();
- QUrl url = QUrl::fromLocalFile(g_config->getSnippetConfigFolder());
- QDesktopServices::openUrl(url);
- });
- m_numLabel = new QLabel();
- QHBoxLayout *btnLayout = new QHBoxLayout;
- btnLayout->addWidget(m_addBtn);
- btnLayout->addWidget(m_locateBtn);
- btnLayout->addStretch();
- btnLayout->addWidget(m_numLabel);
- btnLayout->setContentsMargins(0, 0, 3, 0);
- m_snippetList = new QListWidget();
- m_snippetList->setAttribute(Qt::WA_MacShowFocusRect, false);
- m_snippetList->setContextMenuPolicy(Qt::CustomContextMenu);
- m_snippetList->setSelectionMode(QAbstractItemView::ExtendedSelection);
- connect(m_snippetList, &QListWidget::customContextMenuRequested,
- this, &VSnippetList::handleContextMenuRequested);
- connect(m_snippetList, &QListWidget::itemActivated,
- this, &VSnippetList::handleItemActivated);
- QVBoxLayout *mainLayout = new QVBoxLayout();
- mainLayout->addLayout(btnLayout);
- mainLayout->addWidget(m_snippetList);
- mainLayout->setContentsMargins(0, 0, 0, 0);
- setLayout(mainLayout);
- }
- void VSnippetList::initActions()
- {
- m_applyAct = new QAction(VIconUtils::menuIcon(":/resources/icons/apply_snippet.svg"),
- tr("&Apply"),
- this);
- m_applyAct->setToolTip(tr("Insert this snippet in editor"));
- connect(m_applyAct, &QAction::triggered,
- this, [this]() {
- QListWidgetItem *item = m_snippetList->currentItem();
- handleItemActivated(item);
- });
- m_infoAct = new QAction(VIconUtils::menuIcon(":/resources/icons/snippet_info.svg"),
- tr("&Info\t%1").arg(VUtils::getShortcutText(c_infoShortcutSequence)),
- this);
- m_infoAct->setToolTip(tr("View and edit snippet's information"));
- connect(m_infoAct, &QAction::triggered,
- this, &VSnippetList::snippetInfo);
- m_deleteAct = new QAction(VIconUtils::menuDangerIcon(":/resources/icons/delete_snippet.svg"),
- tr("&Delete"),
- this);
- m_deleteAct->setToolTip(tr("Delete selected snippets"));
- connect(m_deleteAct, &QAction::triggered,
- this, &VSnippetList::deleteSelectedItems);
- m_sortAct = new QAction(VIconUtils::menuIcon(":/resources/icons/sort.svg"),
- tr("&Sort"),
- this);
- m_sortAct->setToolTip(tr("Sort snippets manually"));
- connect(m_sortAct, &QAction::triggered,
- this, &VSnippetList::sortItems);
- }
- void VSnippetList::initShortcuts()
- {
- QShortcut *infoShortcut = new QShortcut(QKeySequence(c_infoShortcutSequence), this);
- infoShortcut->setContext(Qt::WidgetWithChildrenShortcut);
- connect(infoShortcut, &QShortcut::activated,
- this, &VSnippetList::snippetInfo);
- }
- void VSnippetList::newSnippet()
- {
- QString defaultName = VUtils::getFileNameWithSequence(g_config->getSnippetConfigFolder(),
- "snippet");
- VSnippet tmpSnippet(defaultName);
- QString info = tr("Magic words are supported in the content of the snippet.");
- VEditSnippetDialog dialog(tr("Create Snippet"),
- info,
- m_snippets,
- tmpSnippet,
- this);
- if (dialog.exec() == QDialog::Accepted) {
- makeSureFolderExist();
- VSnippet snippet(dialog.getNameInput(),
- dialog.getTypeInput(),
- dialog.getContentInput(),
- dialog.getCursorMarkInput(),
- dialog.getSelectionMarkInput(),
- dialog.getShortcutInput(),
- dialog.getAutoIndentInput());
- QString errMsg;
- if (!addSnippet(snippet, &errMsg)) {
- VUtils::showMessage(QMessageBox::Warning,
- tr("Warning"),
- tr("Fail to create snippet <span style=\"%1\">%2</span>.")
- .arg(g_config->c_dataTextStyle)
- .arg(snippet.getName()),
- errMsg,
- QMessageBox::Ok,
- QMessageBox::Ok,
- this);
- updateContent();
- }
- }
- }
- void VSnippetList::handleContextMenuRequested(QPoint p_pos)
- {
- QListWidgetItem *item = m_snippetList->itemAt(p_pos);
- QMenu menu(this);
- menu.setToolTipsVisible(true);
- if (item) {
- int itemCount = m_snippetList->selectedItems().size();
- if (itemCount == 1) {
- menu.addAction(m_applyAct);
- menu.addAction(m_infoAct);
- }
- menu.addAction(m_deleteAct);
- }
- m_snippetList->update();
- if (m_snippets.size() > 1) {
- if (!menu.actions().isEmpty()) {
- menu.addSeparator();
- }
- menu.addAction(m_sortAct);
- }
- if (!menu.actions().isEmpty()) {
- menu.exec(m_snippetList->mapToGlobal(p_pos));
- }
- }
- void VSnippetList::handleItemActivated(QListWidgetItem *p_item)
- {
- const VSnippet *snip = getSnippet(p_item);
- if (snip) {
- VEditTab *tab = g_mainWin->getCurrentTab();
- if (tab) {
- tab->applySnippet(snip);
- }
- }
- }
- void VSnippetList::deleteSelectedItems()
- {
- QVector<ConfirmItemInfo> items;
- const QList<QListWidgetItem *> selectedItems = m_snippetList->selectedItems();
- if (selectedItems.isEmpty()) {
- return;
- }
- for (auto const & item : selectedItems) {
- QString name = item->data(Qt::UserRole).toString();
- items.push_back(ConfirmItemInfo(name,
- name,
- "",
- NULL));
- }
- QString text = tr("Are you sure to delete these snippets?");
- QString info = tr("Click \"Cancel\" to leave them untouched.");
- VConfirmDeletionDialog dialog(tr("Confirm Deleting Snippets"),
- text,
- info,
- items,
- false,
- false,
- false,
- this);
- if (dialog.exec()) {
- items = dialog.getConfirmedItems();
- QList<QString> names;
- for (auto const & item : items) {
- names.append(item.m_name);
- }
- QString errMsg;
- if (!deleteSnippets(names, &errMsg)) {
- VUtils::showMessage(QMessageBox::Warning,
- tr("Warning"),
- tr("Fail to delete snippets."),
- errMsg,
- QMessageBox::Ok,
- QMessageBox::Ok,
- this);
- }
- updateContent();
- }
- }
- void VSnippetList::sortItems()
- {
- if (m_snippets.size() < 2) {
- return;
- }
- VSortDialog dialog(tr("Sort Snippets"),
- tr("Sort snippets in the configuration file."),
- this);
- QTreeWidget *tree = dialog.getTreeWidget();
- tree->clear();
- tree->setColumnCount(1);
- QStringList headers;
- headers << tr("Name");
- tree->setHeaderLabels(headers);
- for (int i = 0; i < m_snippets.size(); ++i) {
- QTreeWidgetItem *item = new QTreeWidgetItem(tree, QStringList(m_snippets[i].getName()));
- item->setData(0, Qt::UserRole, i);
- }
- dialog.treeUpdated();
- if (dialog.exec()) {
- QVector<QVariant> data = dialog.getSortedData();
- Q_ASSERT(data.size() == m_snippets.size());
- QVector<int> sortedIdx(data.size(), -1);
- for (int i = 0; i < data.size(); ++i) {
- sortedIdx[i] = data[i].toInt();
- }
- QString errMsg;
- if (!sortSnippets(sortedIdx, &errMsg)) {
- VUtils::showMessage(QMessageBox::Warning,
- tr("Warning"),
- tr("Fail to sort snippets."),
- errMsg,
- QMessageBox::Ok,
- QMessageBox::Ok,
- this);
- }
- updateContent();
- }
- }
- void VSnippetList::snippetInfo()
- {
- if (m_snippetList->selectedItems().size() != 1) {
- return;
- }
- QListWidgetItem *item = m_snippetList->currentItem();
- VSnippet *snip = getSnippet(item);
- if (!snip) {
- return;
- }
- QString info = tr("Magic words are supported in the content of the snippet.");
- VEditSnippetDialog dialog(tr("Snippet Information"),
- info,
- m_snippets,
- *snip,
- this);
- if (dialog.exec() == QDialog::Accepted) {
- QString errMsg;
- bool ret = true;
- if (snip->getName() != dialog.getNameInput()) {
- // Delete the original snippet file.
- if (!deleteSnippetFile(*snip, &errMsg)) {
- ret = false;
- }
- }
- if (snip->update(dialog.getNameInput(),
- dialog.getTypeInput(),
- dialog.getContentInput(),
- dialog.getCursorMarkInput(),
- dialog.getSelectionMarkInput(),
- dialog.getShortcutInput(),
- dialog.getAutoIndentInput())) {
- if (!writeSnippetFile(*snip, &errMsg)) {
- ret = false;
- }
- if (!writeSnippetsToConfig()) {
- VUtils::addErrMsg(&errMsg,
- tr("Fail to write snippets configuration file."));
- ret = false;
- }
- updateContent();
- }
- if (!ret) {
- VUtils::showMessage(QMessageBox::Warning,
- tr("Warning"),
- tr("Fail to update information of snippet <span style=\"%1\">%2</span>.")
- .arg(g_config->c_dataTextStyle)
- .arg(snip->getName()),
- errMsg,
- QMessageBox::Ok,
- QMessageBox::Ok,
- this);
- }
- }
- }
- void VSnippetList::makeSureFolderExist() const
- {
- QString path = g_config->getSnippetConfigFolder();
- if (!QFileInfo::exists(path)) {
- QDir dir;
- dir.mkpath(path);
- }
- }
- void VSnippetList::updateContent()
- {
- m_snippetList->clear();
- for (int i = 0; i < m_snippets.size(); ++i) {
- const VSnippet &snip = m_snippets[i];
- QString text = QString("%1%2").arg(snip.getName())
- .arg(snip.getShortcut().isNull()
- ? "" : QString(" [%1]").arg(snip.getShortcut()));
- QListWidgetItem *item = new QListWidgetItem(text);
- item->setToolTip(snip.getName());
- item->setData(Qt::UserRole, snip.getName());
- m_snippetList->addItem(item);
- }
- int cnt = m_snippetList->count();
- if (cnt > 0) {
- m_numLabel->setText(tr("%1 %2").arg(cnt)
- .arg(cnt > 1 ? tr("Snippets") : tr("Snippet")));
- m_snippetList->setFocus();
- } else {
- m_numLabel->setText("");
- m_addBtn->setFocus();
- }
- }
- bool VSnippetList::addSnippet(const VSnippet &p_snippet, QString *p_errMsg)
- {
- if (!writeSnippetFile(p_snippet, p_errMsg)) {
- return false;
- }
- m_snippets.push_back(p_snippet);
- bool ret = true;
- if (!writeSnippetsToConfig()) {
- VUtils::addErrMsg(p_errMsg,
- tr("Fail to write snippets configuration file."));
- m_snippets.pop_back();
- ret = false;
- }
- updateContent();
- return ret;
- }
- bool VSnippetList::writeSnippetsToConfig() const
- {
- makeSureFolderExist();
- QJsonObject snippetJson;
- snippetJson[SnippetConfig::c_version] = "1";
- QJsonArray snippetArray;
- for (int i = 0; i < m_snippets.size(); ++i) {
- snippetArray.append(m_snippets[i].toJson());
- }
- snippetJson[SnippetConfig::c_snippets] = snippetArray;
- return VUtils::writeJsonToDisk(g_config->getSnippetConfigFilePath(),
- snippetJson);
- }
- bool VSnippetList::readSnippetsFromConfig()
- {
- m_snippets.clear();
- if (!QFileInfo::exists(g_config->getSnippetConfigFilePath())) {
- return true;
- }
- QJsonObject snippets = VUtils::readJsonFromDisk(g_config->getSnippetConfigFilePath());
- if (snippets.isEmpty()) {
- qWarning() << "invalid snippets configuration file" << g_config->getSnippetConfigFilePath();
- return false;
- }
- // [snippets] section.
- bool ret = true;
- QJsonArray snippetArray = snippets[SnippetConfig::c_snippets].toArray();
- for (int i = 0; i < snippetArray.size(); ++i) {
- VSnippet snip = VSnippet::fromJson(snippetArray[i].toObject());
- // Read the content.
- QString filePath(QDir(g_config->getSnippetConfigFolder()).filePath(snip.getName()));
- QString content = VUtils::readFileFromDisk(filePath);
- if (content.isNull()) {
- qWarning() << "fail to read snippet" << snip.getName();
- ret = false;
- continue;
- }
- snip.setContent(content);
- m_snippets.push_back(snip);
- }
- return ret;
- }
- void VSnippetList::keyPressEvent(QKeyEvent *p_event)
- {
- if (VimNavigationForWidget::injectKeyPressEventForVim(m_snippetList,
- p_event)) {
- return;
- }
- QWidget::keyPressEvent(p_event);
- }
- void VSnippetList::showNavigation()
- {
- VNavigationMode::showNavigation(m_snippetList);
- }
- bool VSnippetList::handleKeyNavigation(int p_key, bool &p_succeed)
- {
- static bool secondKey = false;
- return VNavigationMode::handleKeyNavigation(m_snippetList,
- secondKey,
- p_key,
- p_succeed);
- }
- int VSnippetList::getSnippetIndex(QListWidgetItem *p_item) const
- {
- if (!p_item) {
- return -1;
- }
- QString name = p_item->data(Qt::UserRole).toString();
- for (int i = 0; i < m_snippets.size(); ++i) {
- if (m_snippets[i].getName() == name) {
- return i;
- }
- }
- Q_ASSERT(false);
- return -1;
- }
- VSnippet *VSnippetList::getSnippet(QListWidgetItem *p_item)
- {
- int idx = getSnippetIndex(p_item);
- if (idx == -1) {
- return NULL;
- } else {
- return &m_snippets[idx];
- }
- }
- bool VSnippetList::writeSnippetFile(const VSnippet &p_snippet, QString *p_errMsg)
- {
- // Create and write to the snippet file.
- QString filePath = getSnippetFilePath(p_snippet);
- if (!VUtils::writeFileToDisk(filePath, p_snippet.getContent())) {
- VUtils::addErrMsg(p_errMsg,
- tr("Fail to add write the snippet file %1.")
- .arg(filePath));
- return false;
- }
- return true;
- }
- QString VSnippetList::getSnippetFilePath(const VSnippet &p_snippet) const
- {
- return QDir(g_config->getSnippetConfigFolder()).filePath(p_snippet.getName());
- }
- bool VSnippetList::sortSnippets(const QVector<int> &p_sortedIdx, QString *p_errMsg)
- {
- V_ASSERT(p_sortedIdx.size() == m_snippets.size());
- auto ori = m_snippets;
- for (int i = 0; i < p_sortedIdx.size(); ++i) {
- m_snippets[i] = ori[p_sortedIdx[i]];
- }
- bool ret = true;
- if (!writeSnippetsToConfig()) {
- VUtils::addErrMsg(p_errMsg,
- tr("Fail to write snippets configuration file."));
- m_snippets = ori;
- ret = false;
- }
- return ret;
- }
- bool VSnippetList::deleteSnippets(const QList<QString> &p_snippets,
- QString *p_errMsg)
- {
- if (p_snippets.isEmpty()) {
- return true;
- }
- bool ret = true;
- QSet<QString> targets = QSet<QString>::fromList(p_snippets);
- for (auto it = m_snippets.begin(); it != m_snippets.end();) {
- if (targets.contains(it->getName())) {
- // Remove it.
- if (!deleteSnippetFile(*it, p_errMsg)) {
- ret = false;
- }
- it = m_snippets.erase(it);
- } else {
- ++it;
- }
- }
- if (!writeSnippetsToConfig()) {
- VUtils::addErrMsg(p_errMsg,
- tr("Fail to write snippets configuration file."));
- ret = false;
- }
- return ret;
- }
- bool VSnippetList::deleteSnippetFile(const VSnippet &p_snippet, QString *p_errMsg)
- {
- QString filePath = getSnippetFilePath(p_snippet);
- if (!VUtils::deleteFile(filePath)) {
- VUtils::addErrMsg(p_errMsg,
- tr("Fail to remove snippet file %1.")
- .arg(filePath));
- return false;
- }
- return true;
- }
- void VSnippetList::focusInEvent(QFocusEvent *p_event)
- {
- QWidget::focusInEvent(p_event);
- if (m_snippets.isEmpty()) {
- m_addBtn->setFocus();
- } else {
- m_snippetList->setFocus();
- }
- }
|