diff --git a/addons/snippets/katesnippets.cpp b/addons/snippets/katesnippets.cpp index 55dc604e6..ecf57d746 100644 --- a/addons/snippets/katesnippets.cpp +++ b/addons/snippets/katesnippets.cpp @@ -1,131 +1,131 @@ /* This file is part of the Kate project. * * Copyright (C) 2010 Christoph Cullmann * * This library is free software; you can redistribute it and/or * modify it under the terms of the GNU Library General Public * License as published by the Free Software Foundation; either * version 2 of the License, or (at your option) any later version. * * This library is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU * Library General Public License for more details. * * You should have received a copy of the GNU Library General Public License * along with this library; see the file COPYING.LIB. If not, write to * the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor, * Boston, MA 02110-1301, USA. */ #include "katesnippets.h" #include "snippetcompletionmodel.h" #include "katesnippetglobal.h" #include "snippetview.h" #include #include #include #include #include #include #include K_PLUGIN_FACTORY_WITH_JSON(KateSnippetsPluginFactory, "katesnippetsplugin.json", registerPlugin();) KateSnippetsPlugin::KateSnippetsPlugin(QObject *parent, const QList &) : KTextEditor::Plugin(parent) , m_snippetGlobal(new KateSnippetGlobal(this)) { } KateSnippetsPlugin::~KateSnippetsPlugin() { } QObject *KateSnippetsPlugin::createView(KTextEditor::MainWindow *mainWindow) { KateSnippetsPluginView *view = new KateSnippetsPluginView(this, mainWindow); return view; } KateSnippetsPluginView::KateSnippetsPluginView(KateSnippetsPlugin *plugin, KTextEditor::MainWindow *mainWindow) : QObject(mainWindow), m_plugin(plugin), m_mainWindow(mainWindow), m_toolView(nullptr), m_snippets(nullptr) { KXMLGUIClient::setComponentName(QStringLiteral("katesnippets"), i18n("Snippets tool view")); setXMLFile(QStringLiteral("ui.rc")); // Toolview for snippets m_toolView = mainWindow->createToolView(plugin, QStringLiteral("kate_private_plugin_katesnippetsplugin"), KTextEditor::MainWindow::Right, QIcon::fromTheme(QStringLiteral("document-new")), i18n("Snippets")); // add snippets widget - m_snippets = new SnippetView(KateSnippetGlobal::self(), m_toolView.data()); + m_snippets = new SnippetView(KateSnippetGlobal::self(), mainWindow, m_toolView.data()); m_toolView->layout()->addWidget(m_snippets); - m_snippets->setupActionsForWindow(m_toolView); + m_snippets->setupActionsForWindow(mainWindow->window()); m_toolView->addActions(m_snippets->actions()); // create actions QAction *a = actionCollection()->addAction(QStringLiteral("tools_create_snippet")); a->setIcon(QIcon::fromTheme(QStringLiteral("document-new"))); a->setText(i18n("Create Snippet")); connect(a, &QAction::triggered, this, &KateSnippetsPluginView::createSnippet); connect(mainWindow, &KTextEditor::MainWindow::viewCreated, this, &KateSnippetsPluginView::slotViewCreated); /** * connect for all already existing views */ foreach (KTextEditor::View *view, mainWindow->views()) { slotViewCreated(view); } // register if factory around if (auto factory = m_mainWindow->guiFactory()) { factory->addClient(this); } } KateSnippetsPluginView::~KateSnippetsPluginView() { // cleanup for all views Q_FOREACH (auto view, m_textViews) { if (! view) { continue; } auto iface = qobject_cast(view); iface->unregisterCompletionModel(KateSnippetGlobal::self()->completionModel()); } // unregister if factory around if (auto factory = m_mainWindow->guiFactory()) { factory->removeClient(this); } if (m_toolView) { delete m_toolView; } } void KateSnippetsPluginView::slotViewCreated(KTextEditor::View *view) { m_textViews.append(QPointer(view)); // add snippet completion auto model = KateSnippetGlobal::self()->completionModel(); auto iface = qobject_cast(view); iface->unregisterCompletionModel(model); iface->registerCompletionModel(model); } void KateSnippetsPluginView::createSnippet() { KateSnippetGlobal::self()->createSnippet(m_mainWindow->activeView()); } #include "katesnippets.moc" diff --git a/addons/snippets/snippetview.cpp b/addons/snippets/snippetview.cpp index 545d46fb4..45ab48680 100644 --- a/addons/snippets/snippetview.cpp +++ b/addons/snippets/snippetview.cpp @@ -1,378 +1,378 @@ /* This file is part of the Kate project. * Based on the snippet plugin from KDevelop 4. * * Copyright (C) 2007 Robert Gruber * Copyright (C) 2010 Milian Wolff * Copyright (C) 2012 Christoph Cullmann * * This library is free software; you can redistribute it and/or * modify it under the terms of the GNU Library General Public * License as published by the Free Software Foundation; either * version 2 of the License, or (at your option) any later version. * * This library is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU * Library General Public License for more details. * * You should have received a copy of the GNU Library General Public License * along with this library; see the file COPYING.LIB. If not, write to * the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor, * Boston, MA 02110-1301, USA. */ #include "snippetview.h" #include "snippet.h" #include "katesnippetglobal.h" #include "snippetrepository.h" #include "snippetstore.h" #include "editrepository.h" #include "editsnippet.h" #include #include #include #include #include #include #include #include #include class SnippetFilterModel : public QSortFilterProxyModel { public: SnippetFilterModel(QObject* parent = nullptr) : QSortFilterProxyModel(parent) { }; bool filterAcceptsRow(int sourceRow, const QModelIndex &sourceParent) const override { auto index = sourceModel()->index(sourceRow, 0, sourceParent); auto item = SnippetStore::self()->itemFromIndex(index); if ( ! item ) { return false; } auto snippet = dynamic_cast(item); if ( ! snippet ) { return true; } return QSortFilterProxyModel::filterAcceptsRow(sourceRow, sourceParent); } }; void SnippetView::setupActionsForWindow(QWidget* widget) { const auto& model = SnippetStore::self(); for ( int i = 0; i < model->rowCount(); i++ ) { auto index = model->index(i, 0, QModelIndex()); auto item = model->itemFromIndex(index); auto repo = dynamic_cast(item); if ( ! repo ) { continue; } for ( int j = 0; j < model->rowCount(index); j++ ) { auto item = model->itemFromIndex(model->index(j, 0, index)); auto snippet = dynamic_cast(item); if ( ! snippet ) { continue; } snippet->registerActionForView(widget); } } } -SnippetView::SnippetView(KateSnippetGlobal* plugin, QWidget* parent) +SnippetView::SnippetView(KateSnippetGlobal* plugin, KTextEditor::MainWindow *mainWindow, QWidget* parent) : QWidget(parent), Ui::SnippetViewBase(), m_plugin(plugin) { Ui::SnippetViewBase::setupUi(this); setWindowTitle(i18n("Snippets")); setWindowIcon(QIcon::fromTheme(QStringLiteral("document-new"), windowIcon())); snippetTree->setContextMenuPolicy( Qt::CustomContextMenu ); snippetTree->viewport()->installEventFilter( this ); connect(snippetTree, &QTreeView::customContextMenuRequested, this, &SnippetView::contextMenu); m_proxy = new SnippetFilterModel(this); m_proxy->setFilterKeyColumn(0); m_proxy->setSourceModel(SnippetStore::self()); connect(filterText, &KLineEdit::textChanged, m_proxy, &QSortFilterProxyModel::setFilterFixedString); snippetTree->setModel(m_proxy); snippetTree->header()->hide(); m_addRepoAction = new QAction(QIcon::fromTheme(QStringLiteral("folder-new")), i18n("Add Repository"), this); connect(m_addRepoAction, &QAction::triggered, this, &SnippetView::slotAddRepo); addAction(m_addRepoAction); m_editRepoAction = new QAction(QIcon::fromTheme(QStringLiteral("folder-txt")), i18n("Edit Repository"), this); connect(m_editRepoAction, &QAction::triggered, this, &SnippetView::slotEditRepo); addAction(m_editRepoAction); m_removeRepoAction = new QAction(QIcon::fromTheme(QStringLiteral("edit-delete")), i18n("Remove Repository"), this); connect(m_removeRepoAction, &QAction::triggered, this, &SnippetView::slotRemoveRepo); addAction(m_removeRepoAction); const bool newStuffAllowed = KAuthorized::authorize(QStringLiteral("ghns")); m_putNewStuffAction = new QAction(QIcon::fromTheme(QStringLiteral("get-hot-new-stuff")), i18n("Publish Repository"), this); m_putNewStuffAction->setVisible(newStuffAllowed); connect(m_putNewStuffAction, &QAction::triggered, this, &SnippetView::slotSnippetToGHNS); addAction(m_putNewStuffAction); QAction* separator = new QAction(this); separator->setSeparator(true); addAction(separator); m_addSnippetAction = new QAction(QIcon::fromTheme(QStringLiteral("document-new")), i18n("Add Snippet"), this); connect(m_addSnippetAction, &QAction::triggered, this, &SnippetView::slotAddSnippet); addAction(m_addSnippetAction); m_editSnippetAction = new QAction(QIcon::fromTheme(QStringLiteral("document-edit")), i18n("Edit Snippet"), this); connect(m_editSnippetAction, &QAction::triggered, this, &SnippetView::slotEditSnippet); addAction(m_editSnippetAction); m_removeSnippetAction = new QAction(QIcon::fromTheme(QStringLiteral("document-close")), i18n("Remove Snippet"), this); connect(m_removeSnippetAction, &QAction::triggered, this, &SnippetView::slotRemoveSnippet); addAction(m_removeSnippetAction); addAction(separator); m_getNewStuffAction = new QAction(QIcon::fromTheme(QStringLiteral("get-hot-new-stuff")), i18n("Get New Snippets"), this); m_getNewStuffAction->setVisible(newStuffAllowed); connect(m_getNewStuffAction, &QAction::triggered, this, &SnippetView::slotGHNS); addAction(m_getNewStuffAction); connect(snippetTree->selectionModel(), &QItemSelectionModel::selectionChanged, this, &SnippetView::validateActions); validateActions(); - connect(snippetTree->model(), &QAbstractItemModel::rowsInserted, this, [this]() { setupActionsForWindow(this); }); + connect(snippetTree->model(), &QAbstractItemModel::rowsInserted, this, [this, mainWindow]() { setupActionsForWindow(mainWindow->window()); }); m_proxy->setDynamicSortFilter(true); m_proxy->sort(0, Qt::AscendingOrder); } void SnippetView::validateActions() { QStandardItem* item = currentItem(); Snippet* selectedSnippet = dynamic_cast( item ); SnippetRepository* selectedRepo = dynamic_cast( item ); m_addRepoAction->setEnabled(true); m_editRepoAction->setEnabled(selectedRepo); m_removeRepoAction->setEnabled(selectedRepo); m_putNewStuffAction->setEnabled(selectedRepo); m_addSnippetAction->setEnabled(selectedRepo || selectedSnippet); m_editSnippetAction->setEnabled(selectedSnippet); m_removeSnippetAction->setEnabled(selectedSnippet); } QStandardItem* SnippetView::currentItem() { ///TODO: support multiple selected items QModelIndex index = snippetTree->currentIndex(); index = m_proxy->mapToSource(index); return SnippetStore::self()->itemFromIndex( index ); } void SnippetView::slotSnippetClicked (const QModelIndex & index) { QStandardItem* item = SnippetStore::self()->itemFromIndex( m_proxy->mapToSource(index) ); if (!item) return; Snippet* snippet = dynamic_cast( item ); if (!snippet) return; m_plugin->insertSnippet( snippet ); } void SnippetView::contextMenu (const QPoint& pos) { QModelIndex index = snippetTree->indexAt( pos ); index = m_proxy->mapToSource(index); QStandardItem* item = SnippetStore::self()->itemFromIndex( index ); if (!item) { // User clicked into an empty place of the tree QMenu menu(this); menu.addSection(i18n("Snippets")); menu.addAction(m_addRepoAction); menu.addAction(m_getNewStuffAction); menu.exec(snippetTree->mapToGlobal(pos)); } else if (Snippet* snippet = dynamic_cast( item )) { QMenu menu(this); menu.addSection(i18n("Snippet: %1", snippet->text())); menu.addAction(m_editSnippetAction); menu.addAction(m_removeSnippetAction); menu.exec(snippetTree->mapToGlobal(pos)); } else if (SnippetRepository* repo = dynamic_cast( item )) { QMenu menu(this); menu.addSection(i18n("Repository: %1", repo->text())); menu.addAction(m_addSnippetAction); menu.addSeparator(); menu.addAction(m_editRepoAction); menu.addAction(m_removeRepoAction); menu.addAction(m_putNewStuffAction); menu.exec(snippetTree->mapToGlobal(pos)); } } void SnippetView::slotEditSnippet() { QStandardItem* item = currentItem(); if (!item) return; Snippet* snippet = dynamic_cast( item ); if (!snippet) return; SnippetRepository* repo = dynamic_cast( item->parent() ); if (!repo) return; EditSnippet dlg(repo, snippet, this); dlg.exec(); } void SnippetView::slotAddSnippet() { QStandardItem* item = currentItem(); if (!item) return; SnippetRepository* repo = dynamic_cast( item ); if (!repo) { repo = dynamic_cast( item->parent() ); if ( !repo ) return; } EditSnippet dlg(repo, nullptr, this); dlg.exec(); } void SnippetView::slotRemoveSnippet() { QStandardItem* item = currentItem(); if (!item) return; SnippetRepository* repo = dynamic_cast( item->parent() ); if (!repo) return; int ans = KMessageBox::warningContinueCancel( QApplication::activeWindow(), i18n("Do you really want to delete the snippet \"%1\"?", item->text()) ); if ( ans == KMessageBox::Continue ) { item->parent()->removeRow(item->row()); repo->save(); } } void SnippetView::slotAddRepo() { EditRepository dlg(nullptr, this); dlg.exec(); } void SnippetView::slotEditRepo() { QStandardItem* item = currentItem(); if (!item) return; SnippetRepository* repo = dynamic_cast( item ); if (!repo) return; EditRepository dlg(repo, this); dlg.exec(); } void SnippetView::slotRemoveRepo() { QStandardItem* item = currentItem(); if (!item) return; SnippetRepository* repo = dynamic_cast( item ); if (!repo) return; int ans = KMessageBox::warningContinueCancel( QApplication::activeWindow(), i18n("Do you really want to delete the repository \"%1\" with all its snippets?", repo->text()) ); if ( ans == KMessageBox::Continue ) { repo->remove(); } } void SnippetView::slotGHNS() { KNS3::DownloadDialog dialog(QStringLiteral(":/katesnippets/ktexteditor_codesnippets_core.knsrc"), this); dialog.exec(); foreach ( const KNS3::Entry& entry, dialog.changedEntries() ) { foreach ( const QString& path, entry.uninstalledFiles() ) { if ( path.endsWith(QLatin1String(".xml")) ) { if ( SnippetRepository* repo = SnippetStore::self()->repositoryForFile(path) ) { repo->remove(); } } } foreach ( const QString& path, entry.installedFiles() ) { if ( path.endsWith(QLatin1String(".xml")) ) { SnippetStore::self()->appendRow(new SnippetRepository(path)); } } } } void SnippetView::slotSnippetToGHNS() { QStandardItem* item = currentItem(); if ( !item) return; SnippetRepository* repo = dynamic_cast( item ); if ( !repo ) return; KNS3::UploadDialog dialog(QStringLiteral(":/katesnippets/ktexteditor_codesnippets_core.knsrc"), this); dialog.setUploadFile(QUrl::fromLocalFile(repo->file())); dialog.setUploadName(repo->text()); dialog.exec(); } bool SnippetView::eventFilter(QObject* obj, QEvent* e) { // no, listening to activated() is not enough since that would also trigger the edit mode which we _dont_ want here // users may still rename stuff via select + F2 though if (obj == snippetTree->viewport()) { const bool singleClick = style()->styleHint(QStyle::SH_ItemView_ActivateItemOnSingleClick, nullptr, this); if ( (!singleClick && e->type() == QEvent::MouseButtonDblClick) || (singleClick && e->type() == QEvent::MouseButtonRelease) ) { QMouseEvent* mouseEvent = dynamic_cast(e); Q_ASSERT(mouseEvent); QModelIndex clickedIndex = snippetTree->indexAt(mouseEvent->pos()); if (clickedIndex.isValid() && clickedIndex.parent().isValid()) { slotSnippetClicked(clickedIndex); e->accept(); return true; } } } return QObject::eventFilter(obj, e); } diff --git a/addons/snippets/snippetview.h b/addons/snippets/snippetview.h index 682c8a7bc..adab26c0d 100644 --- a/addons/snippets/snippetview.h +++ b/addons/snippets/snippetview.h @@ -1,122 +1,124 @@ /* This file is part of the Kate project. * Based on the snippet plugin from KDevelop 4. * * Copyright (C) 2007 Robert Gruber * Copyright (C) 2010 Milian Wolff * Copyright (C) 2012 Christoph Cullmann * Copyright (C) 2014 Sven Brauch * * This library is free software; you can redistribute it and/or * modify it under the terms of the GNU Library General Public * License as published by the Free Software Foundation; either * version 2 of the License, or (at your option) any later version. * * This library is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU * Library General Public License for more details. * * You should have received a copy of the GNU Library General Public License * along with this library; see the file COPYING.LIB. If not, write to * the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor, * Boston, MA 02110-1301, USA. */ #ifndef SNIPPETVIEW_H #define SNIPPETVIEW_H +#include + #include "ui_snippetview.h" class QStandardItem; class KateSnippetGlobal; class QAction; class QSortFilterProxyModel; namespace KTextEditor { } /** * This class gets embedded into the right tool view by the KateSnippetGlobal. * @author Robert Gruber * @author Milian Wolff */ class SnippetView : public QWidget, public Ui::SnippetViewBase { Q_OBJECT public: - explicit SnippetView(KateSnippetGlobal* plugin, QWidget* parent = nullptr); + explicit SnippetView(KateSnippetGlobal* plugin, KTextEditor::MainWindow *mainWindow, QWidget* parent = nullptr); public: void setupActionsForWindow(QWidget* widget); private Q_SLOTS: /** * Opens the "Add Repository" dialog. */ void slotAddRepo(); /** * Opens the "Edit repository" dialog. */ void slotEditRepo(); /** * Removes the selected repository from the disk. */ void slotRemoveRepo(); /** * Insert the selected snippet into the current file */ void slotSnippetClicked(const QModelIndex & index); /** * Open the edit dialog for the selected snippet */ void slotEditSnippet(); /** * Removes the selected snippet from the tree and the filesystem */ void slotRemoveSnippet(); /** * Creates a new snippet and open the edit dialog for it */ void slotAddSnippet(); /** * Slot to get hot new stuff. */ void slotGHNS(); /** * Slot to put the selected snippet to GHNS */ void slotSnippetToGHNS(); void contextMenu (const QPoint & pos); /// disables or enables available actions based on the currently selected item void validateActions(); /// insert snippet on double click bool eventFilter(QObject* , QEvent* ) override; private: QStandardItem* currentItem(); KateSnippetGlobal* m_plugin; QSortFilterProxyModel* m_proxy; QAction *m_addRepoAction; QAction *m_removeRepoAction; QAction *m_editRepoAction; QAction *m_addSnippetAction; QAction *m_removeSnippetAction; QAction *m_editSnippetAction; QAction *m_getNewStuffAction; QAction *m_putNewStuffAction; }; #endif