Commit 365a5298 authored by Tao Guo's avatar Tao Guo Committed by Tao Guo
Browse files

Add new plugin QuickCommands



This plugin can save your favourite commands to sidebar
You can double click the item to invoke the command
Signed-off-by: Tao Guo's avatarTao Guo <guotao945@gmail.com>
parent 06726d8a
......@@ -112,6 +112,7 @@ include_directories(${CMAKE_SOURCE_DIR} ${CMAKE_BINARY_DIR} )
file(GLOB ICONS_SRCS "data/icons/*.png")
option(ENABLE_PLUGIN_SSHMANAGER "Build the SSHManager plugin" ON)
option(ENABLE_PLUGIN_QUICKCOMMANDS "Build the Quick Commands plugin" ON)
add_subdirectory( src )
add_subdirectory( data )
......
if(ENABLE_PLUGIN_SSHMANAGER)
add_subdirectory(SSHManager)
endif()
if(ENABLE_PLUGIN_QUICKCOMMANDS)
add_subdirectory(QuickCommands)
endif()
ki18n_wrap_ui(EXTRA_QUICKCOMMANDSPLUGIN_SRCS qcwidget.ui)
kcoreaddons_add_plugin(konsole_quickcommandsplugin
SOURCES
quickcommandsplugin.cpp
quickcommandswidget.cpp
quickcommandsmodel.cpp
${EXTRA_QUICKCOMMANDSPLUGIN_SRCS}
INSTALL_NAMESPACE
"konsoleplugins"
)
target_link_libraries(konsole_quickcommandsplugin
konsoleprivate
konsoleapp
)
{
"KPlugin": {
"Name": "Quick Commands",
"Name[ar]": "Quick Commands",
"Name[az]": "Quick Commands",
"Name[ca@valencia]": "Quick Commands",
"Name[ca]": "Quick Commands",
"Name[cs]": "Quick Commands",
"Name[de]": "Quick Commands",
"Name[el]": "Quick Commands",
"Name[en_GB]": "Quick Commands",
"Name[es]": "Quick Commands",
"Name[eu]": "Quick Commands",
"Name[fi]": "Quick Commands",
"Name[fr]": "Quick Commands",
"Name[hu]": "Quick Commands",
"Name[ia]": "Quick Commands",
"Name[it]": "Quick Commands",
"Name[ko]": "Quick Commands",
"Name[nl]": "Quick Commands",
"Name[nn]": "Quick Commands",
"Name[pl]": "Quick Commands",
"Name[pt]": "Quick Commands",
"Name[pt_BR]": "Quick Commands",
"Name[ro]": "Quick Commands",
"Name[ru]": "Quick Commands",
"Name[sk]": "Quick Commands",
"Name[sl]": "Quick Commands",
"Name[sv]": "Quick Commands",
"Name[ta]": "Quick Commands",
"Name[tr]": "Quick Commands",
"Name[uk]": "Quick Commands",
"Name[x-test]": "xxQuick Commandsxx",
"Name[zh_CN]": "快捷指令"
}
}
<?xml version="1.0" encoding="UTF-8"?>
<ui version="4.0">
<class>QuickCommandsWidget</class>
<widget class="QWidget" name="QuickCommandsWidget">
<property name="geometry">
<rect>
<x>0</x>
<y>0</y>
<width>424</width>
<height>474</height>
</rect>
</property>
<property name="windowTitle">
<string>Form</string>
</property>
<layout class="QVBoxLayout" name="verticalLayout">
<item>
<widget class="QTreeView" name="commandsTreeView">
<property name="editTriggers">
<set>QAbstractItemView::NoEditTriggers</set>
</property>
<property name="headerHidden">
<bool>true</bool>
</property>
</widget>
</item>
<item>
<widget class="QWidget" name="commandsWidget" native="true">
<layout class="QGridLayout" name="gridLayout">
<item row="0" column="1">
<widget class="QLineEdit" name="name"/>
</item>
<item row="0" column="0">
<widget class="QLabel" name="label">
<property name="text">
<string>Caption</string>
</property>
</widget>
</item>
<item row="1" column="0">
<widget class="QLabel" name="labelGroup">
<property name="text">
<string>Group</string>
</property>
</widget>
</item>
<item row="2" column="0">
<widget class="QLabel" name="label_2">
<property name="text">
<string>Command</string>
</property>
<property name="textFormat">
<enum>Qt::PlainText</enum>
</property>
</widget>
</item>
<item row="2" column="1">
<widget class="QPlainTextEdit" name="command">
<property name="plainText">
<string notr="true"/>
</property>
</widget>
</item>
<item row="1" column="1">
<widget class="QComboBox" name="group">
<property name="editable">
<bool>true</bool>
</property>
<item>
<property name="text">
<string>Default</string>
</property>
</item>
</widget>
</item>
</layout>
</widget>
</item>
<item>
<layout class="QHBoxLayout" name="horizontalLayout">
<item>
<spacer name="horizontalSpacer">
<property name="orientation">
<enum>Qt::Horizontal</enum>
</property>
<property name="sizeHint" stdset="0">
<size>
<width>40</width>
<height>20</height>
</size>
</property>
</spacer>
</item>
<item>
<widget class="QPushButton" name="btnAdd">
<property name="text">
<string>Add</string>
</property>
</widget>
</item>
<item>
<widget class="QPushButton" name="btnSave">
<property name="text">
<string>Save</string>
</property>
</widget>
</item>
<item>
<widget class="QPushButton" name="btnUpdate">
<property name="text">
<string>Update</string>
</property>
</widget>
</item>
<item>
<widget class="QPushButton" name="btnCancel">
<property name="text">
<string>Cancel</string>
</property>
</widget>
</item>
</layout>
</item>
</layout>
</widget>
<resources/>
<connections/>
</ui>
// This file was part of the KDE libraries
// SPDX-FileCopyrightText: 2022 Tao Guo <guotao945@gmail.com>
// SPDX-License-Identifier: GPL-2.0-or-later
#ifndef QUICKCOMMANDDATA_H
#define QUICKCOMMANDDATA_H
#include <QString>
class QuickCommandData
{
public:
QString name;
QString command;
};
Q_DECLARE_METATYPE(QuickCommandData)
#endif // QUICKCOMMANDDATA_H
// This file was part of the KDE libraries
// SPDX-FileCopyrightText: 2022 Tao Guo <guotao945@gmail.com>
// SPDX-License-Identifier: GPL-2.0-or-later
#include "quickcommandsmodel.h"
#include "quickcommanddata.h"
#include <KConfig>
#include <KConfigGroup>
QuickCommandsModel::QuickCommandsModel(QObject *parent)
: QStandardItemModel(parent)
{
load();
}
QuickCommandsModel::~QuickCommandsModel() noexcept
{
save();
}
void QuickCommandsModel::load()
{
auto config = KConfig(QStringLiteral("konsolequickcommandsconfig"), KConfig::OpenFlag::SimpleConfig);
for (const QString &groupName : config.groupList()) {
KConfigGroup group = config.group(groupName);
addTopLevelItem(groupName);
for (const QString &commandGroup : group.groupList()) {
QuickCommandData data;
KConfigGroup element = group.group(commandGroup);
data.name = element.readEntry("name");
data.command = element.readEntry("command");
addChildItem(data, groupName);
}
}
}
void QuickCommandsModel::save()
{
auto config = KConfig(QStringLiteral("konsolequickcommandsconfig"), KConfig::OpenFlag::SimpleConfig);
for (const QString &groupName : config.groupList()) {
config.deleteGroup(groupName);
}
for (int i = 0, end = invisibleRootItem()->rowCount(); i < end; i++) {
QStandardItem *groupItem = invisibleRootItem()->child(i);
const QString groupName = groupItem->text();
KConfigGroup baseGroup = config.group(groupName);
for (int j = 0, end2 = groupItem->rowCount(); j < end2; j++) {
QStandardItem *item = groupItem->child(j);
const auto data = item->data(QuickCommandRole).value<QuickCommandData>();
KConfigGroup element = baseGroup.group(data.name.trimmed());
element.writeEntry("name", data.name);
element.writeEntry("command", data.command);
element.sync();
}
baseGroup.sync();
}
config.sync();
}
QStringList QuickCommandsModel::groups() const
{
QStringList retList;
for (int i = 0, end = invisibleRootItem()->rowCount(); i < end; i++) {
retList.push_back(invisibleRootItem()->child(i)->text());
}
return retList;
}
QStandardItem *QuickCommandsModel::addTopLevelItem(const QString &groupName)
{
for (int i = 0, end = invisibleRootItem()->rowCount(); i < end; i++) {
if (invisibleRootItem()->child(i)->text() == groupName) {
return nullptr;
}
}
auto *newItem = new QStandardItem();
newItem->setText(groupName);
invisibleRootItem()->appendRow(newItem);
invisibleRootItem()->sortChildren(0);
return newItem;
}
bool QuickCommandsModel::addChildItem(const QuickCommandData &data, const QString &groupName)
{
QStandardItem *parentItem = nullptr;
for (int i = 0, end = invisibleRootItem()->rowCount(); i < end; i++) {
if (invisibleRootItem()->child(i)->text() == groupName) {
parentItem = invisibleRootItem()->child(i);
break;
}
}
if (!parentItem)
parentItem = addTopLevelItem(groupName);
for (int i = 0, end = parentItem->rowCount(); i < end; i++) {
if (parentItem->child(i)->text() == data.name)
return false;
}
auto newChild = new QStandardItem();
newChild->setData(QVariant::fromValue(data), QuickCommandRole);
newChild->setText(data.name);
newChild->setToolTip(data.command);
parentItem->appendRow(newChild);
parentItem->sortChildren(0);
return true;
}
bool QuickCommandsModel::editChildItem(const QuickCommandData &data, const QModelIndex &idx, const QString &groupName)
{
QStandardItem *item = itemFromIndex(idx);
QStandardItem *parentItem = item->parent();
for (int i = 0, end = parentItem->rowCount(); i < end; i++) {
if (parentItem->child(i)->text() == data.name && parentItem->child(i) != item)
return false;
}
if (groupName != parentItem->text()) {
if (!addChildItem(data, groupName))
return false;
parentItem->removeRow(item->row());
} else {
item->setData(QVariant::fromValue(data), QuickCommandRole);
item->setText(data.name);
item->setToolTip(data.command);
item->parent()->sortChildren(0);
}
return true;
}
// This file was part of the KDE libraries
// SPDX-FileCopyrightText: 2022 Tao Guo <guotao945@gmail.com>
// SPDX-License-Identifier: GPL-2.0-or-later
#ifndef QUICKCOMMANDSMODEL_H
#define QUICKCOMMANDSMODEL_H
#include <qstandarditemmodel.h>
class QuickCommandData;
class QuickCommandsModel : public QStandardItemModel
{
Q_OBJECT
public:
enum Roles { QuickCommandRole = Qt::UserRole + 1 };
QuickCommandsModel(QObject *parent = nullptr);
~QuickCommandsModel() override;
QStringList groups() const;
bool addChildItem(const QuickCommandData &data, const QString &groupName);
bool editChildItem(const QuickCommandData &data, const QModelIndex &idx, const QString &groupName);
private:
void load();
void save();
QStandardItem *addTopLevelItem(const QString &groupName);
};
#endif // QUICKCOMMANDSMODEL_H
// This file was part of the KDE libraries
// SPDX-FileCopyrightText: 2022 Tao Guo <guotao945@gmail.com>
// SPDX-License-Identifier: GPL-2.0-or-later
#include "quickcommandsplugin.h"
#include "konsoledebug.h"
#include "quickcommandsmodel.h"
#include "quickcommandswidget.h"
#include <KActionCollection>
#include <QMainWindow>
#include "MainWindow.h"
K_PLUGIN_CLASS_WITH_JSON(QuickCommandsPlugin, "konsole_quickcommands.json")
struct QuickCommandsPlugin::Private {
QuickCommandsModel model;
QMap<Konsole::MainWindow *, QuickCommandsWidget *> widgetForWindow;
QMap<Konsole::MainWindow *, QDockWidget *> dockForWindow;
};
QuickCommandsPlugin::QuickCommandsPlugin(QObject *object, const QVariantList &args)
: Konsole::IKonsolePlugin(object, args)
, priv(std::make_unique<Private>())
{
setName(QStringLiteral("QuickCommands"));
}
QuickCommandsPlugin::~QuickCommandsPlugin() = default;
void QuickCommandsPlugin::createWidgetsForMainWindow(Konsole::MainWindow *mainWindow)
{
auto *qcDockWidget = new QDockWidget(mainWindow);
auto *qcWidget = new QuickCommandsWidget(mainWindow);
qcWidget->setModel(&priv->model);
qcDockWidget->setWindowTitle(i18n("Quick Commands"));
qcDockWidget->setWidget(qcWidget);
qcDockWidget->setObjectName(QStringLiteral("QuickCommandsDock"));
qcDockWidget->setVisible(true);
mainWindow->addDockWidget(Qt::LeftDockWidgetArea, qcDockWidget);
priv->widgetForWindow[mainWindow] = qcWidget;
priv->dockForWindow[mainWindow] = qcDockWidget;
}
void QuickCommandsPlugin::activeViewChanged(Konsole::SessionController *controller, Konsole::MainWindow *mainWindow)
{
if (mainWindow)
priv->widgetForWindow[mainWindow]->setCurrentController(controller);
}
QList<QAction *> QuickCommandsPlugin::menuBarActions(Konsole::MainWindow *mainWindow) const
{
QAction *toggleVisibilityAction = new QAction(i18n("Show Quick Commands"), mainWindow);
toggleVisibilityAction->setCheckable(true);
connect(toggleVisibilityAction, &QAction::triggered, priv->dockForWindow[mainWindow], &QDockWidget::setVisible);
connect(priv->dockForWindow[mainWindow], &QDockWidget::visibilityChanged, toggleVisibilityAction, &QAction::setChecked);
return {toggleVisibilityAction};
}
#include "quickcommandsplugin.moc"
// This file was part of the KDE libraries
// SPDX-FileCopyrightText: 2022 Tao Guo <guotao945@gmail.com>
// SPDX-License-Identifier: GPL-2.0-or-later
#ifndef QUICKCOMMANDSPLUGIN_H
#define QUICKCOMMANDSPLUGIN_H
#include <pluginsystem/IKonsolePlugin.h>
namespace Konsole
{
class SessionController;
class MainWindow;
}
class QuickCommandsPlugin : public Konsole::IKonsolePlugin
{
Q_OBJECT
public:
QuickCommandsPlugin(QObject *object, const QVariantList &args);
~QuickCommandsPlugin() override;
void createWidgetsForMainWindow(Konsole::MainWindow *mainWindow) override;
void activeViewChanged(Konsole::SessionController *controller, Konsole::MainWindow *mainWindow) override;
QList<QAction *> menuBarActions(Konsole::MainWindow *mainWindow) const override;
private:
struct Private;
std::unique_ptr<Private> priv;
};
#endif // QUICKCOMMANDSPLUGIN_H
// This file was part of the KDE libraries
// SPDX-FileCopyrightText: 2022 Tao Guo <guotao945@gmail.com>
// SPDX-License-Identifier: GPL-2.0-or-later
#include "quickcommandswidget.h"
#include "konsoledebug.h"
#include "quickcommandsmodel.h"
#include "session/SessionController.h"
#include "terminalDisplay/TerminalDisplay.h"
#include <QMenu>
#include <QSortFilterProxyModel>
#include "ui_qcwidget.h"
#include <KMessageBox>
struct QuickCommandsWidget::Private {
QuickCommandsModel *model = nullptr;
QSortFilterProxyModel *filterModel = nullptr;
Konsole::SessionController *controller = nullptr;
};
QuickCommandsWidget::QuickCommandsWidget(QWidget *parent)
: QWidget(parent)
, ui(std::make_unique<Ui::QuickCommandsWidget>())
, priv(std::make_unique<Private>())
{
ui->setupUi(this);
priv->filterModel = new QSortFilterProxyModel(this);
connect(ui->btnAdd, &QPushButton::clicked, this, &QuickCommandsWidget::addMode);
connect(ui->btnSave, &QPushButton::clicked, this, &QuickCommandsWidget::saveCommand);
connect(ui->btnUpdate, &QPushButton::clicked, this, &QuickCommandsWidget::updateCommand);
connect(ui->btnCancel, &QPushButton::clicked, this, &QuickCommandsWidget::viewMode);
ui->commandsTreeView->setModel(priv->filterModel);
ui->commandsTreeView->setContextMenuPolicy(Qt::CustomContextMenu);
connect(ui->commandsTreeView, &QTreeView::doubleClicked, this, &QuickCommandsWidget::invokeCommand);
connect(ui->commandsTreeView, &QTreeView::customContextMenuRequested, [this](const QPoint &pos) {
QModelIndex idx = ui->commandsTreeView->indexAt(pos);
if (!idx.isValid())
return;
auto sourceIdx = priv->filterModel->mapToSource(idx);
const bool isParent = sourceIdx.parent() == priv->model->invisibleRootItem()->index();
QMenu *menu = new QMenu(this);
if (!isParent) {
auto actionEdit = new QAction(QStringLiteral("Edit"), ui->commandsTreeView);
menu->addAction(actionEdit);
connect(actionEdit, &QAction::triggered, this, &QuickCommandsWidget::triggerEdit);
} else {
auto actionRename = new QAction(QStringLiteral("Rename"), ui->commandsTreeView);
menu->addAction(actionRename);
connect(actionRename, &QAction::triggered, this, &QuickCommandsWidget::triggerRename);
}
auto actionDelete = new QAction(QStringLiteral("Delete"), ui->commandsTreeView);
menu->addAction(actionDelete);
connect(actionDelete, &QAction::triggered, this, &QuickCommandsWidget::triggerDelete);
menu->popup(ui->commandsTreeView->viewport()->mapToGlobal(pos));
});
viewMode();
}
QuickCommandsWidget::~QuickCommandsWidget() = default;
void QuickCommandsWidget::prepareEdit()
{
QString groupName = ui->group->currentText();
ui->group->clear();
ui->group->addItems(priv->model->groups());
ui->group->setCurrentText(groupName);
ui->commandsTreeView->setDisabled(true);
ui->commandsWidget->show();
}
void QuickCommandsWidget::viewMode()
{
ui->commandsTreeView->setDisabled(false);
ui->commandsWidget->hide();
ui->btnAdd->show();
ui->btnSave->hide();
ui->btnUpdate->hide();
ui->btnCancel->hide();
}
void QuickCommandsWidget::addMode()
{
ui->command->setPlainText({});
ui->name->setText({});
ui->btnAdd->hide();
ui->btnSave->show();
ui->btnUpdate->hide();
ui->btnCancel->show();
prepareEdit();
}
void QuickCommandsWidget::editMode()
{
ui->btnAdd->hide();
ui->btnSave->hide();
ui->btnUpdate->show();
ui->btnCancel->show();
prepareEdit();
}
void QuickCommandsWidget::saveCommand()
{