diff --git a/addons/externaltools/configwidget.ui b/addons/externaltools/configwidget.ui
index 63dd92d6a..a9d065417 100644
--- a/addons/externaltools/configwidget.ui
+++ b/addons/externaltools/configwidget.ui
@@ -1,118 +1,118 @@
ExternalToolsConfigWidget
0
0
504
296
0
0
0
0
-
-
Qt::Vertical
20
98
-
Qt::Vertical
17
108
-
-
- New...
+ &New...
-
- Edit...
+ Edit&...
-
- Remove
+ &Remove
-
Qt::Horizontal
40
20
-
-
+
- Insert Separator
+ New &Category
-
-
-
This list shows all the configured tools, represented by their menu text.
diff --git a/addons/externaltools/externaltoolsplugin.cpp b/addons/externaltools/externaltoolsplugin.cpp
index 48897280a..50705a309 100644
--- a/addons/externaltools/externaltoolsplugin.cpp
+++ b/addons/externaltools/externaltoolsplugin.cpp
@@ -1,222 +1,219 @@
/* This file is part of the KDE project
*
* Copyright 2019 Dominik Haumann
*
* 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 "externaltoolsplugin.h"
#include "kateexternaltool.h"
#include "kateexternaltoolscommand.h"
#include "katemacroexpander.h"
#include "katetoolrunner.h"
#include "kateexternaltoolsconfigwidget.h"
#include "externaltools.h"
#include
#include
#include
#include
#include
#include
#include
#include
#include
#include
#include
#include
#include
K_PLUGIN_FACTORY_WITH_JSON(KateExternalToolsFactory, "externaltoolsplugin.json",
registerPlugin();)
KateExternalToolsPlugin::KateExternalToolsPlugin(QObject* parent, const QList&)
: KTextEditor::Plugin(parent)
{
reload();
}
KateExternalToolsPlugin::~KateExternalToolsPlugin()
{
delete m_command;
m_command = nullptr;
}
QObject* KateExternalToolsPlugin::createView(KTextEditor::MainWindow* mainWindow)
{
KateExternalToolsPluginView* view = new KateExternalToolsPluginView(mainWindow, this);
connect(this, &KateExternalToolsPlugin::externalToolsChanged, view, &KateExternalToolsPluginView::rebuildMenu);
return view;
}
void KateExternalToolsPlugin::reload()
{
m_commands.clear();
KConfig _config(QStringLiteral("externaltools"), KConfig::NoGlobals, QStandardPaths::ApplicationsLocation);
KConfigGroup config(&_config, "Global");
const QStringList tools = config.readEntry("tools", QStringList());
for (QStringList::const_iterator it = tools.begin(); it != tools.end(); ++it) {
- if (*it == QStringLiteral("---"))
- continue;
-
config = KConfigGroup(&_config, *it);
auto t = new KateExternalTool();
t->load(config);
m_tools.push_back(t);
// FIXME test for a command name first!
if (t->hasexec && (!t->cmdname.isEmpty())) {
m_commands.push_back(t->cmdname);
}
}
if (KAuthorized::authorizeAction(QStringLiteral("shell_access"))) {
delete m_command;
m_command = new KateExternalToolsCommand(this);
}
Q_EMIT externalToolsChanged();
}
QStringList KateExternalToolsPlugin::commands() const
{
return m_commands;
}
const KateExternalTool* KateExternalToolsPlugin::toolForCommand(const QString& cmd) const
{
for (auto tool : m_tools) {
if (tool->cmdname == cmd) {
return tool;
}
}
return nullptr;
}
const QVector KateExternalToolsPlugin::tools() const
{
return m_tools;
}
void KateExternalToolsPlugin::runTool(const KateExternalTool& tool, KTextEditor::View* view)
{
// expand the macros in command if any,
// and construct a command with an absolute path
auto mw = view->mainWindow();
// save documents if requested
if (tool.saveMode == KateExternalTool::SaveMode::CurrentDocument) {
view->document()->save();
} else if (tool.saveMode == KateExternalTool::SaveMode::AllDocuments) {
foreach (KXMLGUIClient* client, mw->guiFactory()->clients()) {
if (QAction* a = client->actionCollection()->action(QStringLiteral("file_save_all"))) {
a->trigger();
break;
}
}
}
// copy tool
auto copy = new KateExternalTool(tool);
MacroExpander macroExpander(view);
if (!macroExpander.expandMacrosShellQuote(copy->arguments)) {
KMessageBox::sorry(view, i18n("Failed to expand the arguments '%1'.", copy->arguments),
i18n("Kate External Tools"));
return;
}
if (!macroExpander.expandMacrosShellQuote(copy->workingDir)) {
KMessageBox::sorry(view, i18n("Failed to expand the working directory '%1'.", copy->workingDir),
i18n("Kate External Tools"));
return;
}
// Allocate runner on heap such that it lives as long as the child
// process is running and does not block the main thread.
auto runner = new KateToolRunner(copy, this);
connect(runner, &KateToolRunner::toolFinished, this, &KateExternalToolsPlugin::handleToolFinished);
runner->run();
}
void KateExternalToolsPlugin::handleToolFinished(KateToolRunner* runner)
{
runner->deleteLater();
}
int KateExternalToolsPlugin::configPages() const
{
return 1;
}
KTextEditor::ConfigPage* KateExternalToolsPlugin::configPage(int number, QWidget* parent)
{
if (number == 0) {
return new KateExternalToolsConfigWidget(parent, this);
}
return nullptr;
}
KateExternalToolsPluginView::KateExternalToolsPluginView(KTextEditor::MainWindow* mainWindow,
KateExternalToolsPlugin* plugin)
: QObject(mainWindow)
, m_plugin(plugin)
, m_mainWindow(mainWindow)
{
KXMLGUIClient::setComponentName(QLatin1String("externaltools"), i18n("External Tools"));
setXMLFile(QLatin1String("ui.rc"));
if (KAuthorized::authorizeAction(QStringLiteral("shell_access"))) {
m_externalToolsMenu = new KateExternalToolsMenuAction(i18n("External Tools"), actionCollection(), plugin, mainWindow);
actionCollection()->addAction(QStringLiteral("tools_external"), m_externalToolsMenu);
m_externalToolsMenu->setWhatsThis(i18n("Launch external helper applications"));
}
mainWindow->guiFactory()->addClient(this);
}
void KateExternalToolsPluginView::rebuildMenu()
{
if (m_externalToolsMenu) {
KXMLGUIFactory* f = factory();
f->removeClient(this);
reloadXML();
m_externalToolsMenu->reload();
f->addClient(this);
}
}
KateExternalToolsPluginView::~KateExternalToolsPluginView()
{
m_mainWindow->guiFactory()->removeClient(this);
delete m_externalToolsMenu;
m_externalToolsMenu = nullptr;
}
KTextEditor::MainWindow* KateExternalToolsPluginView::mainWindow() const
{
return m_mainWindow;
}
#include "externaltoolsplugin.moc"
// kate: space-indent on; indent-width 4; replace-tabs on;
diff --git a/addons/externaltools/kateexternaltoolsconfigwidget.cpp b/addons/externaltools/kateexternaltoolsconfigwidget.cpp
index 0211d8c29..32223562f 100644
--- a/addons/externaltools/kateexternaltoolsconfigwidget.cpp
+++ b/addons/externaltools/kateexternaltoolsconfigwidget.cpp
@@ -1,398 +1,374 @@
/* This file is part of the KDE project
*
* Copyright 2019 Dominik Haumann
*
* 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.
*/
// TODO
// Icons
// Direct shortcut setting
#include "kateexternaltoolsconfigwidget.h"
#include "externaltoolsplugin.h"
#include "kateexternaltool.h"
#include "katemacroexpander.h"
#include "katetoolrunner.h"
#include
#include
#include
#include
#include
#include
#include
#include
#include
#include
#include
#include
#include
#include
#include
#include
#include
#include
#include
#include
#include
#include
#include
#include
#include
#include
#include
#include
// BEGIN ToolItem
/**
* This is a QListBoxItem, that has a KateExternalTool. The text is the Name
* of the tool.
*/
class ToolItem : public QListWidgetItem
{
public:
ToolItem(QListWidget* lb, const QPixmap& icon, KateExternalTool* tool)
: QListWidgetItem(icon, tool->name, lb)
, tool(tool)
{
}
~ToolItem() {}
KateExternalTool* tool;
};
// END ToolItem
// BEGIN KateExternalToolServiceEditor
KateExternalToolServiceEditor::KateExternalToolServiceEditor(KateExternalTool* tool, QWidget* parent)
: QDialog(parent)
, tool(tool)
{
setWindowTitle(i18n("Edit External Tool"));
ui = new Ui::ToolDialog();
ui->setupUi(this);
ui->btnIcon->setIconSize(KIconLoader::SizeSmall);
connect(ui->buttonBox, &QDialogButtonBox::accepted, this, &KateExternalToolServiceEditor::slotOKClicked);
connect(ui->buttonBox, &QDialogButtonBox::rejected, this, &QDialog::reject);
connect(ui->btnMimeType, &QToolButton::clicked, this, &KateExternalToolServiceEditor::showMTDlg);
if (tool) {
ui->edtName->setText(tool->name);
if (!tool->icon.isEmpty())
ui->btnIcon->setIcon(tool->icon);
ui->edtExecutable->setText(tool->executable);
ui->edtArgs->setText(tool->arguments);
ui->edtInput->setText(tool->input);
ui->edtCommand->setText(tool->cmdname);
ui->edtWorkingDir->setText(tool->workingDir);
ui->edtMimeType->setText(tool->mimetypes.join(QStringLiteral("; ")));
ui->cmbSave->setCurrentIndex(static_cast(tool->saveMode));
ui->chkIncludeStderr->setChecked(tool->includeStderr);
}
}
void KateExternalToolServiceEditor::slotOKClicked()
{
if (ui->edtName->text().isEmpty() || ui->edtExecutable->text().isEmpty()) {
QMessageBox::information(this, i18n("External Tool"),
i18n("You must specify at least a name and an executable"));
return;
}
accept();
}
void KateExternalToolServiceEditor::showMTDlg()
{
QString text = i18n("Select the MimeTypes for which to enable this tool.");
QStringList list
= ui->edtMimeType->text().split(QRegularExpression(QStringLiteral("\\s*;\\s*")), QString::SkipEmptyParts);
KMimeTypeChooserDialog d(i18n("Select Mime Types"), text, list, QStringLiteral("text"), this);
if (d.exec() == QDialog::Accepted) {
ui->edtMimeType->setText(d.chooser()->mimeTypes().join(QStringLiteral(";")));
}
}
// END KateExternalToolServiceEditor
// BEGIN KateExternalToolsConfigWidget
KateExternalToolsConfigWidget::KateExternalToolsConfigWidget(QWidget* parent, KateExternalToolsPlugin* plugin)
: KTextEditor::ConfigPage(parent)
, m_plugin(plugin)
{
setupUi(this);
btnMoveUp->setIcon(QIcon::fromTheme(QStringLiteral("go-up")));
btnMoveDown->setIcon(QIcon::fromTheme(QStringLiteral("go-down")));
connect(lbTools, &QListWidget::itemSelectionChanged, this, &KateExternalToolsConfigWidget::slotSelectionChanged);
connect(lbTools, &QListWidget::itemDoubleClicked, this, &KateExternalToolsConfigWidget::slotEdit);
connect(btnNew, &QPushButton::clicked, this, &KateExternalToolsConfigWidget::slotNew);
connect(btnRemove, &QPushButton::clicked, this, &KateExternalToolsConfigWidget::slotRemove);
connect(btnEdit, &QPushButton::clicked, this, &KateExternalToolsConfigWidget::slotEdit);
- connect(btnSeparator, &QPushButton::clicked, this, &KateExternalToolsConfigWidget::slotInsertSeparator);
connect(btnMoveUp, &QPushButton::clicked, this, &KateExternalToolsConfigWidget::slotMoveUp);
connect(btnMoveDown, &QPushButton::clicked, this, &KateExternalToolsConfigWidget::slotMoveDown);
m_config = new KConfig(QStringLiteral("externaltools"), KConfig::NoGlobals, QStandardPaths::ApplicationsLocation);
reset();
slotSelectionChanged();
}
KateExternalToolsConfigWidget::~KateExternalToolsConfigWidget()
{
delete m_config;
}
QString KateExternalToolsConfigWidget::name() const
{
return i18n("External Tools");
}
QString KateExternalToolsConfigWidget::fullName() const
{
return i18n("External Tools");
}
QIcon KateExternalToolsConfigWidget::icon() const
{
return QIcon();
}
void KateExternalToolsConfigWidget::reset()
{
// m_tools.clear();
lbTools->clear();
// load the files from a KConfig
const QStringList tools = m_config->group("Global").readEntry("tools", QStringList());
for (int i = 0; i < tools.size(); ++i) {
const QString& toolSection = tools[i];
- if (toolSection == QStringLiteral("---")) {
- new QListWidgetItem(QStringLiteral("---"), lbTools);
- } else {
- KConfigGroup cg(m_config, toolSection);
- KateExternalTool* t = new KateExternalTool();
- t->load(cg);
-
- if (t->hasexec) // we only show tools that are also in the menu.
- new ToolItem(lbTools, t->icon.isEmpty() ? blankIcon() : SmallIcon(t->icon), t);
- else
- delete t;
- }
+ KConfigGroup cg(m_config, toolSection);
+ KateExternalTool* t = new KateExternalTool();
+ t->load(cg);
+
+ if (t->hasexec) // we only show tools that are also in the menu.
+ new ToolItem(lbTools, t->icon.isEmpty() ? blankIcon() : SmallIcon(t->icon), t);
+ else
+ delete t;
}
m_changed = false;
}
QPixmap KateExternalToolsConfigWidget::blankIcon()
{
QPixmap pm(KIconLoader::SizeSmall, KIconLoader::SizeSmall);
pm.fill();
pm.setMask(pm.createHeuristicMask());
return pm;
}
void KateExternalToolsConfigWidget::apply()
{
if (!m_changed)
return;
m_changed = false;
QStringList tools;
for (int i = 0; i < lbTools->count(); i++) {
- if (lbTools->item(i)->text() == QStringLiteral("---")) {
- tools << QStringLiteral("---");
- continue;
- }
const QString toolSection = QStringLiteral("Tool ") + QString::number(i);
tools << toolSection;
KConfigGroup cg(m_config, toolSection);
KateExternalTool* t = static_cast(lbTools->item(i))->tool;
t->save(cg);
}
m_config->group("Global").writeEntry("tools", tools);
m_config->sync();
m_plugin->reload();
}
void KateExternalToolsConfigWidget::slotSelectionChanged()
{
// update button state
bool hs = lbTools->currentItem() != nullptr;
btnEdit->setEnabled(hs && dynamic_cast(lbTools->currentItem()));
btnRemove->setEnabled(hs);
btnMoveUp->setEnabled((lbTools->currentRow() > 0) && hs);
btnMoveDown->setEnabled((lbTools->currentRow() < (int)lbTools->count() - 1) && hs);
}
void KateExternalToolsConfigWidget::slotNew()
{
// display a editor, and if it is OK'd, create a new tool and
// create a listbox item for it
KateExternalToolServiceEditor editor(nullptr, this);
if (editor.exec() == QDialog::Accepted) {
KateExternalTool* t = new KateExternalTool();
t->name = editor.ui->edtName->text();
t->icon = editor.ui->btnIcon->icon();
t->executable = editor.ui->edtExecutable->text();
t->arguments = editor.ui->edtArgs->text();
t->input = editor.ui->edtInput->toPlainText();
t->workingDir = editor.ui->edtWorkingDir->text();
t->mimetypes = editor.ui->edtMimeType->text().split(QRegularExpression(QStringLiteral("\\s*;\\s*")),
QString::SkipEmptyParts);
t->saveMode = static_cast(editor.ui->cmbSave->currentIndex());
t->includeStderr = editor.ui->chkIncludeStderr->isChecked();
// This is sticky, it does not change again, so that shortcuts sticks
// TODO check for dups
t->actionName = QStringLiteral("externaltool_") + QString(t->name).remove(QRegExp(QStringLiteral("\\W+")));
new ToolItem(lbTools, t->icon.isEmpty() ? blankIcon() : SmallIcon(t->icon), t);
emit changed();
m_changed = true;
}
}
void KateExternalToolsConfigWidget::slotRemove()
{
// add the tool action name to a list of removed items,
// remove the current listbox item
if (lbTools->currentRow() > -1) {
ToolItem* i = dynamic_cast(lbTools->currentItem());
if (i)
m_removed << i->tool->actionName;
delete lbTools->takeItem(lbTools->currentRow());
emit changed();
m_changed = true;
}
}
void KateExternalToolsConfigWidget::slotEdit()
{
if (!dynamic_cast(lbTools->currentItem()))
return;
// show the item in an editor
KateExternalTool* t = static_cast(lbTools->currentItem())->tool;
KateExternalToolServiceEditor editor(t, this);
editor.resize(m_config->group("Editor").readEntry("Size", QSize()));
if (editor.exec() /*== KDialog::Ok*/) {
bool elementChanged = ((editor.ui->btnIcon->icon() != t->icon) || (editor.ui->edtName->text() != t->name));
t->name = editor.ui->edtName->text();
t->icon = editor.ui->btnIcon->icon();
t->executable = editor.ui->edtExecutable->text();
t->arguments = editor.ui->edtArgs->text();
t->input = editor.ui->edtInput->toPlainText();
t->cmdname = editor.ui->edtCommand->text();
t->workingDir = editor.ui->edtWorkingDir->text();
t->mimetypes
= editor.ui->edtMimeType->text().split(QRegExp(QStringLiteral("\\s*;\\s*")), QString::SkipEmptyParts);
t->saveMode = static_cast(editor.ui->cmbSave->currentIndex());
t->includeStderr = editor.ui->chkIncludeStderr->isChecked();
// if the icon has changed or name changed, I have to renew the listbox item :S
if (elementChanged) {
int idx = lbTools->row(lbTools->currentItem());
delete lbTools->takeItem(idx);
lbTools->insertItem(idx, new ToolItem(nullptr, t->icon.isEmpty() ? blankIcon() : SmallIcon(t->icon), t));
}
emit changed();
m_changed = true;
}
m_config->group("Editor").writeEntry("Size", editor.size());
m_config->sync();
}
-void KateExternalToolsConfigWidget::slotInsertSeparator()
-{
- lbTools->insertItem(lbTools->currentRow() + 1, QStringLiteral("---"));
- emit changed();
- m_changed = true;
-}
-
void KateExternalToolsConfigWidget::slotMoveUp()
{
// move the current item in the listbox upwards if possible
QListWidgetItem* item = lbTools->currentItem();
if (!item)
return;
int idx = lbTools->row(item);
if (idx < 1)
return;
if (dynamic_cast(item)) {
KateExternalTool* tool = static_cast(item)->tool;
delete lbTools->takeItem(idx);
lbTools->insertItem(idx - 1,
new ToolItem(nullptr, tool->icon.isEmpty() ? blankIcon() : SmallIcon(tool->icon), tool));
- } else // a separator!
- {
- delete lbTools->takeItem(idx);
- lbTools->insertItem(idx - 1, new QListWidgetItem(QStringLiteral("---")));
}
lbTools->setCurrentRow(idx - 1);
slotSelectionChanged();
emit changed();
m_changed = true;
}
void KateExternalToolsConfigWidget::slotMoveDown()
{
// move the current item in the listbox downwards if possible
QListWidgetItem* item = lbTools->currentItem();
if (!item)
return;
int idx = lbTools->row(item);
if (idx > lbTools->count() - 1)
return;
if (dynamic_cast(item)) {
KateExternalTool* tool = static_cast(item)->tool;
delete lbTools->takeItem(idx);
lbTools->insertItem(idx + 1,
new ToolItem(nullptr, tool->icon.isEmpty() ? blankIcon() : SmallIcon(tool->icon), tool));
- } else // a separator!
- {
- delete lbTools->takeItem(idx);
- lbTools->insertItem(idx + 1, new QListWidgetItem(QStringLiteral("---")));
}
lbTools->setCurrentRow(idx + 1);
slotSelectionChanged();
emit changed();
m_changed = true;
}
// END KateExternalToolsConfigWidget
// kate: space-indent on; indent-width 4; replace-tabs on;
diff --git a/addons/externaltools/kateexternaltoolsconfigwidget.h b/addons/externaltools/kateexternaltoolsconfigwidget.h
index 9c43681a2..42e0ca9dd 100644
--- a/addons/externaltools/kateexternaltoolsconfigwidget.h
+++ b/addons/externaltools/kateexternaltoolsconfigwidget.h
@@ -1,115 +1,114 @@
/* This file is part of the KDE project
*
* Copyright 2019 Dominik Haumann
*
* 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 KTEXTEDITOR_EXTERNALTOOLS_CONFIGWIDGET_H
#define KTEXTEDITOR_EXTERNALTOOLS_CONFIGWIDGET_H
#include "ui_configwidget.h"
#include "ui_tooldialog.h"
#include
#include
#include
#include
#include
#include
#include
#include
#include
#include
class KActionCollection;
class KateExternalToolsPlugin;
class KateExternalTool;
/**
* The config widget.
* The config widget allows the user to view a list of services of the type
* "Kate/ExternalTool" and add, remove or edit them.
*/
class KateExternalToolsConfigWidget : public KTextEditor::ConfigPage, public Ui::ExternalToolsConfigWidget
{
Q_OBJECT
public:
KateExternalToolsConfigWidget(QWidget* parent, KateExternalToolsPlugin* plugin);
virtual ~KateExternalToolsConfigWidget();
QString name() const override;
QString fullName() const override;
QIcon icon() const override;
public Q_SLOTS:
void apply() override;
void reset() override;
void defaults() override { reset(); } // double sigh
private Q_SLOTS:
void slotNew();
void slotEdit();
void slotRemove();
- void slotInsertSeparator();
void slotMoveUp();
void slotMoveDown();
void slotSelectionChanged();
private:
QPixmap blankIcon();
QStringList m_removed;
class KConfig* m_config = nullptr;
bool m_changed = false;
KateExternalToolsPlugin* m_plugin;
};
/**
* A Dialog to edit a single KateExternalTool object
*/
class KateExternalToolServiceEditor : public QDialog
{
Q_OBJECT
public:
explicit KateExternalToolServiceEditor(KateExternalTool* tool = nullptr, QWidget* parent = nullptr);
private Q_SLOTS:
/**
* Run when the OK button is clicked, to ensure critical values are provided.
*/
void slotOKClicked();
/**
* show a mimetype chooser dialog
*/
void showMTDlg();
public:
Ui::ToolDialog* ui;
private:
KateExternalTool* tool;
};
#endif // KTEXTEDITOR_EXTERNALTOOLS_CONFIGWIDGET_H
// kate: space-indent on; indent-width 4; replace-tabs on;