diff --git a/plugins/externalscript/externalscriptitem.cpp b/plugins/externalscript/externalscriptitem.cpp index aa1ea3a691..3224e50441 100644 --- a/plugins/externalscript/externalscriptitem.cpp +++ b/plugins/externalscript/externalscriptitem.cpp @@ -1,152 +1,163 @@ /* This plugin is part of KDevelop. Copyright (C) 2010 Milian Wolff This library is free software; you can redistribute it and/or modify it under the terms of the GNU Lesser General Public License as published by the Free Software Foundation; either version 2.1 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 Lesser General Public License for more details. You should have received a copy of the GNU Lesser General Public License along with this library; if not, write to the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA */ #include "externalscriptitem.h" #include "externalscriptplugin.h" #include #include #include #include #include ExternalScriptItem::ExternalScriptItem() { } +QString ExternalScriptItem::key() const +{ + return m_key; +} + +void ExternalScriptItem::setKey(const QString& key) +{ + m_key = key; +} + + QString ExternalScriptItem::command() const { return m_command; } void ExternalScriptItem::setCommand( const QString& command ) { m_command = command; } void ExternalScriptItem::setWorkingDirectory ( const QString& workingDirectory ) { m_workingDirectory = workingDirectory; } QString ExternalScriptItem::workingDirectory() const { return m_workingDirectory; } ExternalScriptItem::SaveMode ExternalScriptItem::saveMode() const { return m_saveMode; } void ExternalScriptItem::setSaveMode( ExternalScriptItem::SaveMode mode ) { m_saveMode = mode; } ExternalScriptItem::OutputMode ExternalScriptItem::outputMode() const { return m_outputMode; } void ExternalScriptItem::setOutputMode( ExternalScriptItem::OutputMode mode ) { m_outputMode = mode; } ExternalScriptItem::ErrorMode ExternalScriptItem::errorMode() const { return m_errorMode; } void ExternalScriptItem::setErrorMode( ExternalScriptItem::ErrorMode mode ) { m_errorMode = mode; } ExternalScriptItem::InputMode ExternalScriptItem::inputMode() const { return m_inputMode; } void ExternalScriptItem::setInputMode( ExternalScriptItem::InputMode mode ) { m_inputMode = mode; } int ExternalScriptItem::filterMode() const { return m_filterMode; } void ExternalScriptItem::setFilterMode( int mode ) { m_filterMode = mode; } QAction* ExternalScriptItem::action() { ///TODO: this is quite ugly, or is it? if someone knows how to do it better, please refactor if ( !m_action ) { static int actionCount = 0; m_action = new QAction( QStringLiteral("executeScript%1").arg(actionCount), ExternalScriptPlugin::self() ); m_action->setData( QVariant::fromValue(this) ); ExternalScriptPlugin::self()->connect( m_action, &QAction::triggered, ExternalScriptPlugin::self(), &ExternalScriptPlugin::executeScriptFromActionData ); m_action->setShortcut( QKeySequence() ); // action needs to be added to a widget before it can work... KDevelop::ICore::self()->uiController()->activeMainWindow()->addAction(m_action); } Q_ASSERT( m_action ); return m_action; } bool ExternalScriptItem::showOutput() const { return m_showOutput; } void ExternalScriptItem::setShowOutput( bool show ) { m_showOutput = show; } bool ExternalScriptItem::performParameterReplacement() const { return m_performReplacements; } void ExternalScriptItem::setPerformParameterReplacement ( bool perform ) { m_performReplacements = perform; } void ExternalScriptItem::save() const { ExternalScriptPlugin::self()->saveItem( this ); } // kate: indent-mode cstyle; space-indent on; indent-width 2; replace-tabs on; diff --git a/plugins/externalscript/externalscriptitem.h b/plugins/externalscript/externalscriptitem.h index 192d7c679a..edfafe7e0a 100644 --- a/plugins/externalscript/externalscriptitem.h +++ b/plugins/externalscript/externalscriptitem.h @@ -1,217 +1,228 @@ /* This plugin is part of KDevelop. Copyright (C) 2010 Milian Wolff This library is free software; you can redistribute it and/or modify it under the terms of the GNU Lesser General Public License as published by the Free Software Foundation; either version 2.1 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 Lesser General Public License for more details. You should have received a copy of the GNU Lesser General Public License along with this library; if not, write to the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA */ #ifndef KDEVPLATFORM_PLUGIN_EXTERNALSCRIPTITEM_H #define KDEVPLATFORM_PLUGIN_EXTERNALSCRIPTITEM_H #include class QAction; /** * NOTE: use @c text() and @c setText() to define the label/name of the external script. */ class ExternalScriptItem : public QStandardItem { public: ExternalScriptItem(); + /** + * The key is supposed to be unique inside the model + * @return The key of this script item + */ + QString key() const; + /** + * Sets the label + */ + void setKey( const QString& key ); + /** * @return The command to execute. */ QString command() const; /** * Sets the command to execute. */ void setCommand( const QString& command ); /** * @return The working directory where to execute the command. * If this is empty (default), it should be derived from the active document. */ QString workingDirectory() const; /** * Specify the working directory where the command should be executed */ void setWorkingDirectory( const QString& workingDirectory ); /** * Whether placeholders like %b etc. in the command should be substituted. Default is true. * */ bool performParameterReplacement() const; /** * Set whether placeholders like %b etc. in the command should be substituted. Default is true. * */ void setPerformParameterReplacement(bool perform); enum SaveMode { /// Nothing needs to be saved. SaveNone, /// Currently active document gets saved. SaveCurrentDocument, /// All opened documents get saved. SaveAllDocuments }; /** * @return @c SaveMode that decides what document should be saved before executing this script. */ SaveMode saveMode() const; /** * Sets the @c SaveMode that decides what document should be saved before executing this script. */ void setSaveMode( SaveMode mode ); /** * @return what type of filter should be applied to the execution of the external script **/ int filterMode() const; /** * Sets the filtering mode **/ void setFilterMode( int mode ); /// Defines what should be done with the @c STDOUT of a script run. enum OutputMode { /// Ignore output and do nothing. OutputNone, /// Output gets inserted at the cursor position of the current document. OutputInsertAtCursor, /// Current selection gets replaced in the active document. /// If no selection exists, the output will get inserted at the /// current cursor position in the active document view. OutputReplaceSelectionOrInsertAtCursor, /// Current selection gets replaced in the active document. /// If no selection exists, the whole document gets replaced. OutputReplaceSelectionOrDocument, /// The whole contents of the active document gets replaced. OutputReplaceDocument, /// Create a new file from the output. OutputCreateNewFile }; /** * @return @c OutputMode that decides what parts of the active document should be replaced by the * @c STDOUT of the @c command() execution. */ OutputMode outputMode() const; /** * Sets the @c OutputMode that decides what parts of the active document should be replaced by the * @c STDOUT of the @c command() execution. */ void setOutputMode( OutputMode mode ); /// Defines what should be done with the @c STDERR of a script run. enum ErrorMode { /// Ignore errors and do nothing. ErrorNone, /// Merge with @c STDOUT and use @c OutputMode. ErrorMergeOutput, /// Errors get inserted at the cursor position of the current document. ErrorInsertAtCursor, /// Current selection gets replaced in the active document. /// If no selection exists, the output will get inserted at the /// current cursor position in the active document view. ErrorReplaceSelectionOrInsertAtCursor, /// Current selection gets replaced in the active document. /// If no selection exists, the whole document gets replaced. ErrorReplaceSelectionOrDocument, /// The whole contents of the active document gets replaced. ErrorReplaceDocument, /// Create a new file from the errors. ErrorCreateNewFile }; /** * @return @c ErrorMode that decides what parts of the active document should be replaced by the * @c STDERR of the @c command() execution. */ ErrorMode errorMode() const; /** * Sets the @c ErrorMode that decides what parts of the active document should be replaced by the * @c STDERR of the @c command() execution. */ void setErrorMode( ErrorMode mode ); enum InputMode { /// Nothing gets streamed to the @c STDIN of the external script. InputNone, /// Current selection gets streamed into the @c STDIN of the external script. /// If no selection exists, nothing gets streamed. InputSelectionOrNone, /// Current selection gets streamed into the @c STDIN of the external script. /// If no selection exists, the whole document gets streamed. InputSelectionOrDocument, /// The whole contents of the active document get streamed into the @c STDIN of the external script. InputDocument, }; /** * @return @c InputMode that decides what parts of the active document should be streamded into * the @c STDIN of the external script. */ InputMode inputMode() const; /** * Sets the @c InputMode that decides what parts of the active document should be streamded into * the @c STDIN of the external script. */ void setInputMode( InputMode mode ); /** * Action to trigger insertion of this snippet. */ QAction* action(); /** * @return True when this command should have its output shown, false otherwise. */ bool showOutput() const; /** * Set @p show to true when the output of this command shout be shown, false otherwise. */ void setShowOutput( bool show ); ///TODO: custom icon ///TODO: mimetype / language filter ///TODO: kate commandline integration ///TODO: filter for local/remote files /** * Saves this item after changes. */ void save() const; private: + QString m_key; QString m_command; QString m_workingDirectory; SaveMode m_saveMode = SaveNone; OutputMode m_outputMode = OutputNone; ErrorMode m_errorMode = ErrorNone; InputMode m_inputMode = InputNone; QAction* m_action = nullptr; bool m_showOutput = true; int m_filterMode = 0; bool m_performReplacements = true; }; Q_DECLARE_METATYPE(ExternalScriptItem*) #endif // KDEVPLATFORM_PLUGIN_EXTERNALSCRIPTITEM_H // kate: indent-mode cstyle; space-indent on; indent-width 2; replace-tabs on; diff --git a/plugins/externalscript/externalscriptplugin.cpp b/plugins/externalscript/externalscriptplugin.cpp index d0389586e1..89b70eb7f4 100644 --- a/plugins/externalscript/externalscriptplugin.cpp +++ b/plugins/externalscript/externalscriptplugin.cpp @@ -1,385 +1,410 @@ /* This plugin is part of KDevelop. Copyright (C) 2010 Milian Wolff This library is free software; you can redistribute it and/or modify it under the terms of the GNU Lesser General Public License as published by the Free Software Foundation; either version 2.1 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 Lesser General Public License for more details. You should have received a copy of the GNU Lesser General Public License along with this library; if not, write to the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA */ #include "externalscriptplugin.h" #include "externalscriptview.h" #include "externalscriptitem.h" #include "externalscriptjob.h" #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include K_PLUGIN_FACTORY_WITH_JSON(ExternalScriptFactory, "kdevexternalscript.json", registerPlugin();) class ExternalScriptViewFactory: public KDevelop::IToolViewFactory { public: explicit ExternalScriptViewFactory( ExternalScriptPlugin *plugin ): m_plugin( plugin ) {} QWidget* create( QWidget *parent = nullptr ) override { return new ExternalScriptView( m_plugin, parent ); } Qt::DockWidgetArea defaultPosition() override { return Qt::RightDockWidgetArea; } QString id() const override { return QStringLiteral("org.kdevelop.ExternalScriptView"); } private: ExternalScriptPlugin *m_plugin; }; // We extend ExternalScriptJob so that it deletes the temporarily created item on destruction class ExternalScriptJobOwningItem : public ExternalScriptJob { Q_OBJECT public: ExternalScriptJobOwningItem( ExternalScriptItem* item, const QUrl &url, ExternalScriptPlugin* parent ) : ExternalScriptJob(item, url, parent), m_item(item) { } ~ExternalScriptJobOwningItem() override { delete m_item; } private: ExternalScriptItem* m_item; }; ExternalScriptPlugin* ExternalScriptPlugin::m_self = nullptr; ExternalScriptPlugin::ExternalScriptPlugin( QObject* parent, const QVariantList& /*args*/ ) : IPlugin( QStringLiteral("kdevexternalscript"), parent ), m_model( new QStandardItemModel( this ) ), m_factory( new ExternalScriptViewFactory( this ) ) { Q_ASSERT( !m_self ); m_self = this; QDBusConnection::sessionBus().registerObject( QStringLiteral("/org/kdevelop/ExternalScriptPlugin"), this, QDBusConnection::ExportScriptableSlots ); setXMLFile( QStringLiteral("kdevexternalscript.rc") ); //BEGIN load config KConfigGroup config = getConfig(); foreach( const QString& group, config.groupList() ) { KConfigGroup script = config.group( group ); if ( script.hasKey( "name" ) && script.hasKey( "command" ) ) { ExternalScriptItem* item = new ExternalScriptItem; + item->setKey( script.name() ); item->setText( script.readEntry( "name" ) ); item->setCommand( script.readEntry( "command" )); item->setInputMode( static_cast( script.readEntry( "inputMode", 0u ) ) ); item->setOutputMode( static_cast( script.readEntry( "outputMode", 0u ) ) ); item->setErrorMode( static_cast( script.readEntry( "errorMode", 0u ) ) ); item->setSaveMode( static_cast( script.readEntry( "saveMode", 0u ) ) ); item->setFilterMode( script.readEntry( "filterMode", 0u )); item->action()->setShortcut( QKeySequence( script.readEntry( "shortcuts" ) ) ); item->setShowOutput( script.readEntry( "showOutput", true ) ); m_model->appendRow( item ); } } //END load config core()->uiController()->addToolView( i18n( "External Scripts" ), m_factory ); - connect( m_model, &QStandardItemModel::rowsRemoved, - this, &ExternalScriptPlugin::rowsRemoved ); + connect( m_model, &QStandardItemModel::rowsAboutToBeRemoved, + this, &ExternalScriptPlugin::rowsAboutToBeRemoved ); connect( m_model, &QStandardItemModel::rowsInserted, this, &ExternalScriptPlugin::rowsInserted ); const bool firstUse = config.readEntry( "firstUse", true ); if ( firstUse ) { // some example scripts ExternalScriptItem* item = new ExternalScriptItem; item->setText( i18n("Quick Compile") ); item->setCommand( QStringLiteral("g++ -o %b %f && ./%b") ); m_model->appendRow( item ); #ifndef Q_OS_WIN item = new ExternalScriptItem; item->setText( i18n("Sort Selection") ); item->setCommand( QStringLiteral("sort") ); item->setInputMode( ExternalScriptItem::InputSelectionOrDocument ); item->setOutputMode( ExternalScriptItem::OutputReplaceSelectionOrDocument ); item->setShowOutput( false ); m_model->appendRow( item ); item = new ExternalScriptItem; item->setText( i18n("Google Selection") ); item->setCommand( QStringLiteral("xdg-open \"https://www.google.com/search?q=%s\"") ); item->setShowOutput( false ); m_model->appendRow( item ); item = new ExternalScriptItem; item->setText( i18n("Paste to Hastebin") ); item->setCommand( QStringLiteral("a=$(cat); curl -X POST -s -d \"$a\" https://hastebin.com/documents | awk -F '\"' '{print \"https://hastebin.com/\"$4}' | xargs xdg-open ;") ); item->setInputMode( ExternalScriptItem::InputSelectionOrDocument ); item->setShowOutput( false ); m_model->appendRow( item ); #endif config.writeEntry( "firstUse", false ); config.sync(); } } ExternalScriptPlugin* ExternalScriptPlugin::self() { return m_self; } ExternalScriptPlugin::~ExternalScriptPlugin() { m_self = nullptr; } KDevelop::ContextMenuExtension ExternalScriptPlugin::contextMenuExtension(KDevelop::Context* context, QWidget* parent) { m_urls.clear(); int folderCount = 0; if ( context->type() == KDevelop::Context::FileContext ) { KDevelop::FileContext* filectx = static_cast(context); m_urls = filectx->urls(); } else if ( context->type() == KDevelop::Context::ProjectItemContext ) { KDevelop::ProjectItemContext* projctx = static_cast(context); foreach( KDevelop::ProjectBaseItem* item, projctx->items() ) { if ( item->file() ) { m_urls << item->file()->path().toUrl(); } else if ( item->folder() ) { m_urls << item->folder()->path().toUrl(); folderCount++; } } } else if ( context->type() == KDevelop::Context::EditorContext ) { KDevelop::EditorContext* econtext = static_cast(context); m_urls << econtext->url(); } if ( !m_urls.isEmpty() ) { KDevelop::ContextMenuExtension ext; QMenu* menu = nullptr; for ( int row = 0; row < m_model->rowCount(); ++row ) { ExternalScriptItem* item = dynamic_cast( m_model->item( row ) ); Q_ASSERT( item ); if (context->type() != KDevelop::Context::EditorContext) { // filter scripts that depend on an opened document // if the context menu was not requested inside the editor if (item->performParameterReplacement() && item->command().contains(QStringLiteral("%s"))) { continue; } else if (item->inputMode() == ExternalScriptItem::InputSelectionOrNone) { continue; } } if ( folderCount == m_urls.count() ) { // when only folders filter items that don't have %d parameter (or another parameter) if (item->performParameterReplacement() && (!item->command().contains(QStringLiteral("%d")) || item->command().contains(QStringLiteral("%s")) || item->command().contains(QStringLiteral("%u")) || item->command().contains(QStringLiteral("%f")) || item->command().contains(QStringLiteral("%b")) || item->command().contains(QStringLiteral("%n")) ) ) { continue; } } if (!menu) { menu = new QMenu(i18n("External Scripts"), parent); } QAction* scriptAction = new QAction(item->text(), menu); scriptAction->setData( QVariant::fromValue( item )); connect( scriptAction, &QAction::triggered, this, &ExternalScriptPlugin::executeScriptFromContextMenu ); menu->addAction( scriptAction ); } if (menu) { ext.addAction( KDevelop::ContextMenuExtension::ExtensionGroup, menu->menuAction() ); } return ext; } return KDevelop::IPlugin::contextMenuExtension(context, parent); } void ExternalScriptPlugin::unload() { core()->uiController()->removeToolView( m_factory ); KDevelop::IPlugin::unload(); } KConfigGroup ExternalScriptPlugin::getConfig() const { return KSharedConfig::openConfig()->group("External Scripts"); } QStandardItemModel* ExternalScriptPlugin::model() const { return m_model; } void ExternalScriptPlugin::execute( ExternalScriptItem* item, const QUrl& url ) const { ExternalScriptJob* job = new ExternalScriptJob( item, url, const_cast(this) ); KDevelop::ICore::self()->runController()->registerJob( job ); } void ExternalScriptPlugin::execute(ExternalScriptItem* item) const { auto document = KDevelop::ICore::self()->documentController()->activeDocument(); execute( item, document ? document->url() : QUrl() ); } bool ExternalScriptPlugin::executeCommand ( const QString& command, const QString& workingDirectory ) const { ExternalScriptItem* item = new ExternalScriptItem; item->setCommand(command); item->setWorkingDirectory(workingDirectory); item->setPerformParameterReplacement(false); qCDebug(PLUGIN_EXTERNALSCRIPT) << "executing command " << command << " in dir " << workingDirectory << " as external script"; ExternalScriptJobOwningItem* job = new ExternalScriptJobOwningItem( item, QUrl(), const_cast(this) ); // When a command is executed, for example through the terminal, we don't want the command output to be risen job->setVerbosity(KDevelop::OutputJob::Silent); KDevelop::ICore::self()->runController()->registerJob( job ); return true; } QString ExternalScriptPlugin::executeCommandSync ( const QString& command, const QString& workingDirectory ) const { qCDebug(PLUGIN_EXTERNALSCRIPT) << "executing command " << command << " in working-dir " << workingDirectory; KProcess process; process.setWorkingDirectory( workingDirectory ); process.setShellCommand( command ); process.setOutputChannelMode( KProcess::OnlyStdoutChannel ); process.execute(); return QString::fromLocal8Bit(process.readAll()); } void ExternalScriptPlugin::executeScriptFromActionData() const { QAction* action = dynamic_cast( sender() ); Q_ASSERT( action ); ExternalScriptItem* item = action->data().value(); Q_ASSERT( item ); execute( item ); } void ExternalScriptPlugin::executeScriptFromContextMenu() const { QAction* action = dynamic_cast( sender() ); Q_ASSERT( action ); ExternalScriptItem* item = action->data().value(); Q_ASSERT( item ); foreach( const QUrl& url, m_urls) { KDevelop::ICore::self()->documentController()->openDocument( url ); execute( item, url ); } } void ExternalScriptPlugin::rowsInserted( const QModelIndex& /*parent*/, int start, int end ) { - for ( int i = start; i <= end; ++i ) { - saveItemForRow( i ); + setupKeys( start, end ); + for ( int row = start; row <= end; ++row ) { + saveItemForRow( row ); } } -void ExternalScriptPlugin::rowsRemoved( const QModelIndex& /*parent*/, int start, int end ) +void ExternalScriptPlugin::rowsAboutToBeRemoved( const QModelIndex& /*parent*/, int start, int end ) { KConfigGroup config = getConfig(); - for ( int i = start; i <= end; ++i ) { - KConfigGroup child = config.group( QStringLiteral("script %1").arg(i) ); + for ( int row = start; row <= end; ++row ) { + const ExternalScriptItem* const item = static_cast( m_model->item( row ) ); + KConfigGroup child = config.group( item->key() ); qCDebug(PLUGIN_EXTERNALSCRIPT) << "removing config group:" << child.name(); child.deleteGroup(); } config.sync(); } void ExternalScriptPlugin::saveItem( const ExternalScriptItem* item ) { const QModelIndex index = m_model->indexFromItem( item ); Q_ASSERT( index.isValid() ); - saveItemForRow( index.row() ); + + getConfig().group( item->key() ).deleteGroup(); // delete the previous group + setupKeys( index.row(), index.row() ); + saveItemForRow( index.row() ); // save the new group } void ExternalScriptPlugin::saveItemForRow( int row ) { const QModelIndex idx = m_model->index( row, 0 ); Q_ASSERT( idx.isValid() ); ExternalScriptItem* item = dynamic_cast( m_model->item( row ) ); Q_ASSERT( item ); qCDebug(PLUGIN_EXTERNALSCRIPT) << "save extern script:" << item << idx; - KConfigGroup config = getConfig().group( QStringLiteral("script %1").arg( row ) ); + KConfigGroup config = getConfig().group( item->key() ); config.writeEntry( "name", item->text() ); config.writeEntry( "command", item->command() ); config.writeEntry( "inputMode", (uint) item->inputMode() ); config.writeEntry( "outputMode", (uint) item->outputMode() ); config.writeEntry( "errorMode", (uint) item->errorMode() ); config.writeEntry( "saveMode", (uint) item->saveMode() ); config.writeEntry( "shortcuts", item->action()->shortcut().toString() ); config.writeEntry( "showOutput", item->showOutput() ); config.writeEntry( "filterMode", item->filterMode()); config.sync(); } +void ExternalScriptPlugin::setupKeys(int start, int end) +{ + QStringList keys = getConfig().groupList(); + + for ( int row = start; row <= end; ++row ) { + ExternalScriptItem* const item = static_cast( m_model->item( row ) ); + + int nextSuffix = 2; + QString keyCandidate = item->text(); + for (; keys.contains( keyCandidate ); ++nextSuffix) { + keyCandidate = item->text() + QString::number( nextSuffix ); + } + + qCDebug(PLUGIN_EXTERNALSCRIPT) << "set key" << keyCandidate << "for" << item << item->command(); + item->setKey(keyCandidate); + keys.push_back(keyCandidate); + } +} + #include "externalscriptplugin.moc" // kate: indent-mode cstyle; space-indent on; indent-width 2; replace-tabs on; diff --git a/plugins/externalscript/externalscriptplugin.h b/plugins/externalscript/externalscriptplugin.h index 9276395364..e5ad8c4818 100644 --- a/plugins/externalscript/externalscriptplugin.h +++ b/plugins/externalscript/externalscriptplugin.h @@ -1,104 +1,114 @@ /* This plugin is part of KDevelop. Copyright (C) 2010 Milian Wolff This library is free software; you can redistribute it and/or modify it under the terms of the GNU Lesser General Public License as published by the Free Software Foundation; either version 2.1 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 Lesser General Public License for more details. You should have received a copy of the GNU Lesser General Public License along with this library; if not, write to the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA */ #ifndef KDEVPLATFORM_PLUGIN_EXTERNALSCRIPTPLUGIN_H #define KDEVPLATFORM_PLUGIN_EXTERNALSCRIPTPLUGIN_H #include #include #include #include class ExternalScriptItem; class QStandardItem; class QStandardItemModel; class QModelIndex; class ExternalScriptPlugin : public KDevelop::IPlugin { Q_OBJECT Q_CLASSINFO( "D-Bus Interface", "org.kdevelop.ExternalScriptPlugin" ) public: explicit ExternalScriptPlugin( QObject *parent, const QVariantList &args = QVariantList() ); ~ExternalScriptPlugin() override; void unload() override; KDevelop::ContextMenuExtension contextMenuExtension(KDevelop::Context* context, QWidget* parent) override; static ExternalScriptPlugin* self(); /** * @return The model storing all external scripts managed by this plugin. * @NOTE: always append() items, never insert in the middle! */ QStandardItemModel* model() const; /** * Executes @p script. */ void execute(ExternalScriptItem* item, const QUrl &url) const; /** * Executes @p script. */ void execute(ExternalScriptItem* item) const; /** * Returns config group to store all settings for this plugin in. */ KConfigGroup getConfig() const; + /** + * Saves the @p script to the config and updates the key + */ void saveItem(const ExternalScriptItem* item); public Q_SLOTS: void executeScriptFromActionData() const; /** * Executes the command (Used by the shell-integration) * */ Q_SCRIPTABLE bool executeCommand(const QString& command, const QString& workingDirectory) const; /** * Executes the command synchronously and returns the output text (Used by the shell-integration) * */ Q_SCRIPTABLE QString executeCommandSync(const QString& command, const QString& workingDirectory) const; - + private Q_SLOTS: - void rowsRemoved( const QModelIndex& parent, int start, int end ); + void rowsAboutToBeRemoved( const QModelIndex& parent, int start, int end ); void rowsInserted( const QModelIndex& parent, int start, int end ); void executeScriptFromContextMenu() const; private: /// @param row row in the model for the item to save void saveItemForRow( int row ); + /** + * Sets up unique keys for items in the range [start, end] + * @param start start of the range + * @param end end of the range + */ + void setupKeys( int start, int end ); + QStandardItemModel* m_model; QList m_urls; static ExternalScriptPlugin* m_self; class ExternalScriptViewFactory *m_factory; }; #endif // KDEVPLATFORM_PLUGIN_EXTERNALSCRIPTPLUGIN_H // kate: indent-mode cstyle; space-indent on; indent-width 2; replace-tabs on;