diff --git a/klipper/CMakeLists.txt b/klipper/CMakeLists.txt index 66ba3e17a..ce888caee 100644 --- a/klipper/CMakeLists.txt +++ b/klipper/CMakeLists.txt @@ -1,109 +1,107 @@ set(KLIPPER_VERSION_STRING ${PROJECT_VERSION}) add_definitions(-DTRANSLATION_DOMAIN=\"klipper\") set(libklipper_common_SRCS klipper.cpp urlgrabber.cpp configdialog.cpp history.cpp historyitem.cpp historymodel.cpp historystringitem.cpp klipperpopup.cpp popupproxy.cpp historyimageitem.cpp historyurlitem.cpp actionstreewidget.cpp editactiondialog.cpp clipcommandprocess.cpp ) ecm_qt_declare_logging_category(libklipper_common_SRCS HEADER klipper_debug.h IDENTIFIER KLIPPER_LOG CATEGORY_NAME org.kde.klipper) find_package(KF5Prison ${KF5_MIN_VERSION}) set_package_properties(KF5Prison PROPERTIES DESCRIPTION "Prison library" URL "http://projects.kde.org/prison" TYPE OPTIONAL PURPOSE "Needed to create mobile barcodes from clipboard data" ) set(HAVE_PRISON ${KF5Prison_FOUND}) configure_file(config-klipper.h.cmake ${CMAKE_CURRENT_BINARY_DIR}/config-klipper.h ) kde4_add_app_icon(libklipper_common_SRCS "${KDE4_ICON_INSTALL_DIR}/oxygen/*/apps/klipper.png") ki18n_wrap_ui(libklipper_common_SRCS generalconfig.ui actionsconfig.ui editactiondialog.ui) kconfig_add_kcfg_files(libklipper_common_SRCS klippersettings.kcfgc) set(klipper_KDEINIT_SRCS ${libklipper_common_SRCS} main.cpp tray.cpp) kf5_add_kdeinit_executable(klipper ${klipper_KDEINIT_SRCS}) target_link_libraries(kdeinit_klipper Qt5::Concurrent - KF5::Completion # klineedit - port away? KF5::ConfigGui KF5::CoreAddons KF5::DBusAddons KF5::GlobalAccel KF5::IconThemes KF5::KIOWidgets KF5::Notifications KF5::Service KF5::TextWidgets KF5::WindowSystem KF5::WidgetsAddons KF5::XmlGui ${ZLIB_LIBRARY} ) if (X11_FOUND) target_link_libraries(kdeinit_klipper XCB::XCB Qt5::X11Extras) endif() if (HAVE_PRISON) target_link_libraries(kdeinit_klipper KF5::Prison) endif () install(TARGETS kdeinit_klipper ${KDE_INSTALL_TARGETS_DEFAULT_ARGS}) install(TARGETS klipper ${KDE_INSTALL_TARGETS_DEFAULT_ARGS}) install(PROGRAMS org.kde.klipper.desktop DESTINATION ${KDE_INSTALL_APPDIR}) install(PROGRAMS klipper.desktop DESTINATION ${KDE_INSTALL_AUTOSTARTDIR}) # Plasma Data Engine set(plasma_engine_clipboard_SRCS ${libklipper_common_SRCS} clipboardengine.cpp clipboardservice.cpp clipboardjob.cpp) add_library(plasma_engine_clipboard MODULE ${plasma_engine_clipboard_SRCS}) kcoreaddons_desktop_to_json(plasma_engine_clipboard plasma-dataengine-clipboard.desktop) target_link_libraries(plasma_engine_clipboard Qt5::Concurrent Qt5::DBus Qt5::Widgets # QAction KF5::ConfigGui - KF5::Completion # klineedit - port away? KF5::CoreAddons # KUrlMimeData KF5::GlobalAccel KF5::IconThemes KF5::KIOWidgets # PreviewJob KF5::Plasma KF5::Notifications KF5::Service KF5::TextWidgets # KTextEdit KF5::WidgetsAddons # KMessageBox KF5::WindowSystem KF5::XmlGui # KActionCollection ${ZLIB_LIBRARY} ) if (X11_FOUND) target_link_libraries(plasma_engine_clipboard XCB::XCB Qt5::X11Extras) endif() if (HAVE_PRISON) target_link_libraries(plasma_engine_clipboard KF5::Prison) endif () install(TARGETS plasma_engine_clipboard DESTINATION ${KDE_INSTALL_PLUGINDIR}/plasma/dataengine) install(FILES plasma-dataengine-clipboard.desktop DESTINATION ${KDE_INSTALL_KSERVICES5DIR}) install(FILES org.kde.plasma.clipboard.operations DESTINATION ${PLASMA_DATA_INSTALL_DIR}/services) if(BUILD_TESTING) add_subdirectory(autotests) endif() install( FILES klipper.categories DESTINATION ${KDE_INSTALL_CONFDIR} ) diff --git a/klipper/editactiondialog.cpp b/klipper/editactiondialog.cpp index 0982e8564..16f4051d0 100644 --- a/klipper/editactiondialog.cpp +++ b/klipper/editactiondialog.cpp @@ -1,390 +1,390 @@ /* This file is part of the KDE project Copyright (C) 2009 by Dmitry Suzdalev This program is free software; you can redistribute it and/or modify it under the terms of the GNU General Public License as published by the Free Software Foundation; either version 2 of the License, or (at your option) any later version. This program 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 General Public License for more details. You should have received a copy of the GNU General Public License along with this program; see the file COPYING. If not, write to the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. */ #include "editactiondialog.h" #include #include #include "klipper_debug.h" #include #include #include #include #include "urlgrabber.h" #include "ui_editactiondialog.h" namespace { static QString output2text(ClipCommand::Output output) { switch(output) { case ClipCommand::IGNORE: return QString(i18n("Ignore")); case ClipCommand::REPLACE: return QString(i18n("Replace Clipboard")); case ClipCommand::ADD: return QString(i18n("Add to Clipboard")); } return QString(); } } /** * Show dropdown of editing Output part of commands */ class ActionOutputDelegate : public QItemDelegate { public: ActionOutputDelegate(QObject* parent = nullptr) : QItemDelegate(parent){ } QWidget* createEditor(QWidget* parent, const QStyleOptionViewItem& /*option*/, const QModelIndex& /*index*/) const override { QComboBox* editor = new QComboBox(parent); editor->setInsertPolicy(QComboBox::NoInsert); editor->addItem(output2text(ClipCommand::IGNORE), QVariant::fromValue(ClipCommand::IGNORE)); editor->addItem(output2text(ClipCommand::REPLACE), QVariant::fromValue(ClipCommand::REPLACE)); editor->addItem(output2text(ClipCommand::ADD), QVariant::fromValue(ClipCommand::ADD)); return editor; } void setEditorData(QWidget* editor, const QModelIndex& index) const override { QComboBox* ed = static_cast(editor); QVariant data(index.model()->data(index, Qt::EditRole)); ed->setCurrentIndex(static_cast(data.value())); } void setModelData(QWidget* editor, QAbstractItemModel* model, const QModelIndex& index) const override { QComboBox* ed = static_cast(editor); model->setData(index, ed->itemData(ed->currentIndex())); } void updateEditorGeometry(QWidget* editor, const QStyleOptionViewItem& option, const QModelIndex& /*index*/) const override { editor->setGeometry(option.rect); } }; class ActionDetailModel : public QAbstractTableModel { public: ActionDetailModel(ClipAction* action, QObject* parent = nullptr); QVariant data(const QModelIndex& index, int role = Qt::DisplayRole) const override; bool setData(const QModelIndex& index, const QVariant& value, int role = Qt::EditRole) override; Qt::ItemFlags flags(const QModelIndex& index) const override; int rowCount(const QModelIndex& parent = QModelIndex()) const override; int columnCount(const QModelIndex& parent) const override; QVariant headerData(int section, Qt::Orientation orientation, int role = Qt::DisplayRole) const override; const QList& commands() const { return m_commands; } void addCommand(const ClipCommand& command); void removeCommand(const QModelIndex& index); private: enum column_t { COMMAND_COL = 0, OUTPUT_COL = 1, DESCRIPTION_COL = 2 }; QList m_commands; QVariant displayData(ClipCommand* command, column_t colunm) const; QVariant editData(ClipCommand* command, column_t column) const; QVariant decorationData(ClipCommand* command, column_t column) const; void setIconForCommand(ClipCommand& cmd); }; ActionDetailModel::ActionDetailModel(ClipAction* action, QObject* parent): QAbstractTableModel(parent), m_commands(action->commands()) { } Qt::ItemFlags ActionDetailModel::flags(const QModelIndex& /*index*/) const { return Qt::ItemIsEditable | Qt::ItemIsEnabled | Qt::ItemIsSelectable; } void ActionDetailModel::setIconForCommand(ClipCommand& cmd) { // let's try to update icon of the item according to command QString command = cmd.command; if ( command.contains( QLatin1Char(' ') ) ) { // get first word command = command.section( QLatin1Char(' '), 0, 0 ); } QPixmap iconPix = KIconLoader::global()->loadIcon( command, KIconLoader::Small, 0, KIconLoader::DefaultState, QStringList(), nullptr, true /* canReturnNull */ ); if ( !iconPix.isNull() ) { cmd.icon = command; } else { cmd.icon.clear(); } } bool ActionDetailModel::setData(const QModelIndex& index, const QVariant& value, int role) { if (role == Qt::EditRole) { ClipCommand cmd = m_commands.at(index.row()); switch (static_cast(index.column())) { case COMMAND_COL: cmd.command = value.toString(); setIconForCommand(cmd); break; case OUTPUT_COL: cmd.output = value.value(); break; case DESCRIPTION_COL: cmd.description = value.toString(); break; } m_commands.replace(index.row(), cmd); emit dataChanged(index, index); return true; } return false; } int ActionDetailModel::columnCount(const QModelIndex& /*parent*/) const { return 3; } int ActionDetailModel::rowCount(const QModelIndex&) const { return m_commands.count(); } QVariant ActionDetailModel::displayData(ClipCommand* command, ActionDetailModel::column_t column) const { switch (column) { case COMMAND_COL: return command->command; case OUTPUT_COL: return output2text(command->output); case DESCRIPTION_COL: return command->description; } return QVariant(); } QVariant ActionDetailModel::decorationData(ClipCommand* command, ActionDetailModel::column_t column) const { switch (column) { case COMMAND_COL: return command->icon.isEmpty() ? QIcon::fromTheme( QStringLiteral("system-run") ) : QIcon::fromTheme( command->icon ); case OUTPUT_COL: case DESCRIPTION_COL: break; } return QVariant(); } QVariant ActionDetailModel::editData(ClipCommand* command, ActionDetailModel::column_t column) const { switch (column) { case COMMAND_COL: return command->command; case OUTPUT_COL: return QVariant::fromValue(command->output); case DESCRIPTION_COL: return command->description; } return QVariant(); } QVariant ActionDetailModel::headerData(int section, Qt::Orientation orientation, int role) const { if (orientation == Qt::Horizontal && role == Qt::DisplayRole) { switch(static_cast(section)) { case COMMAND_COL: return i18n("Command"); case OUTPUT_COL: return i18n("Output Handling"); case DESCRIPTION_COL: return i18n("Description"); } } return QAbstractTableModel::headerData(section, orientation, role); } QVariant ActionDetailModel::data(const QModelIndex& index, int role) const { const int column = index.column(); const int row = index.row(); ClipCommand cmd = m_commands.at(row); switch (role) { case Qt::DisplayRole: return displayData(&cmd, static_cast(column)); case Qt::DecorationRole: return decorationData(&cmd, static_cast(column)); case Qt::EditRole: return editData(&cmd, static_cast(column)); } return QVariant(); } void ActionDetailModel::addCommand(const ClipCommand& command) { beginInsertRows(QModelIndex(), rowCount(), rowCount()); m_commands << command; endInsertRows(); } void ActionDetailModel::removeCommand(const QModelIndex& index) { int row = index.row(); beginRemoveRows(QModelIndex(), row, row); m_commands.removeAt(row); endRemoveRows(); } EditActionDialog::EditActionDialog(QWidget* parent) : QDialog(parent) { setWindowTitle(i18n("Action Properties")); QDialogButtonBox *buttons = new QDialogButtonBox(QDialogButtonBox::Ok | QDialogButtonBox::Cancel, this); buttons->button(QDialogButtonBox::Ok)->setShortcut(Qt::CTRL | Qt::Key_Return); connect(buttons, &QDialogButtonBox::accepted, this, &EditActionDialog::slotAccepted); connect(buttons, &QDialogButtonBox::rejected, this, &QDialog::reject); QWidget* dlgWidget = new QWidget(this); m_ui = new Ui::EditActionDialog; m_ui->setupUi(dlgWidget); - m_ui->leRegExp->setClearButtonShown(true); - m_ui->leDescription->setClearButtonShown(true); + m_ui->leRegExp->setClearButtonEnabled(true); + m_ui->leDescription->setClearButtonEnabled(true); m_ui->pbAddCommand->setIcon(QIcon::fromTheme(QStringLiteral("list-add"))); m_ui->pbRemoveCommand->setIcon(QIcon::fromTheme(QStringLiteral("list-remove"))); // For some reason, the default row height is 30 pixel. Set it to the minimum sectionSize instead, // which is the font height+struts. m_ui->twCommandList->verticalHeader()->setDefaultSectionSize(m_ui->twCommandList->verticalHeader()->minimumSectionSize()); m_ui->twCommandList->horizontalHeader()->setDefaultAlignment(Qt::AlignLeft); QVBoxLayout *layout = new QVBoxLayout(this); layout->addWidget(dlgWidget); layout->addWidget(buttons); connect(m_ui->pbAddCommand, &QPushButton::clicked, this, &EditActionDialog::onAddCommand); connect(m_ui->pbRemoveCommand, &QPushButton::clicked, this, &EditActionDialog::onRemoveCommand); const KConfigGroup grp = KSharedConfig::openConfig()->group("EditActionDialog"); KWindowConfig::restoreWindowSize(windowHandle(), grp); QByteArray hdrState = grp.readEntry("ColumnState", QByteArray()); if (!hdrState.isEmpty()) { qCDebug(KLIPPER_LOG) << "Restoring column state"; m_ui->twCommandList->horizontalHeader()->restoreState(QByteArray::fromBase64(hdrState)); } // do this after restoreState() m_ui->twCommandList->horizontalHeader()->setHighlightSections(false); } EditActionDialog::~EditActionDialog() { delete m_ui; } void EditActionDialog::setAction(ClipAction* act, int commandIdxToSelect) { m_action = act; m_model = new ActionDetailModel(act, this); m_ui->twCommandList->setModel(m_model); m_ui->twCommandList->setItemDelegateForColumn(1, new ActionOutputDelegate); connect(m_ui->twCommandList->selectionModel(), &QItemSelectionModel::selectionChanged, this, &EditActionDialog::onSelectionChanged); updateWidgets( commandIdxToSelect ); } void EditActionDialog::updateWidgets(int commandIdxToSelect) { if (!m_action) { qCDebug(KLIPPER_LOG) << "no action to edit was set"; return; } m_ui->leRegExp->setText(m_action->regExp()); m_ui->automatic->setChecked(m_action->automatic()); m_ui->leDescription->setText(m_action->description()); if (commandIdxToSelect != -1) { m_ui->twCommandList->setCurrentIndex( m_model->index( commandIdxToSelect ,0 ) ); } // update Remove button onSelectionChanged(); } void EditActionDialog::saveAction() { if (!m_action) { qCDebug(KLIPPER_LOG) << "no action to edit was set"; return; } m_action->setRegExp( m_ui->leRegExp->text() ); m_action->setDescription( m_ui->leDescription->text() ); m_action->setAutomatic( m_ui->automatic->isChecked() ); m_action->clearCommands(); foreach ( const ClipCommand& cmd, m_model->commands() ){ m_action->addCommand( cmd ); } } void EditActionDialog::slotAccepted() { saveAction(); qCDebug(KLIPPER_LOG) << "Saving dialogue state"; KConfigGroup grp = KSharedConfig::openConfig()->group("EditActionDialog"); KWindowConfig::saveWindowSize(windowHandle(), grp); grp.writeEntry("ColumnState", m_ui->twCommandList->horizontalHeader()->saveState().toBase64()); accept(); } void EditActionDialog::onAddCommand() { m_model->addCommand(ClipCommand(i18n( "new command" ), i18n( "Command Description" ), true, QLatin1String("") )); m_ui->twCommandList->edit( m_model->index( m_model->rowCount()-1, 0 )); } void EditActionDialog::onRemoveCommand() { m_model->removeCommand(m_ui->twCommandList->selectionModel()->currentIndex()); } void EditActionDialog::onSelectionChanged() { m_ui->pbRemoveCommand->setEnabled( m_ui->twCommandList->selectionModel() && m_ui->twCommandList->selectionModel()->hasSelection() ); } diff --git a/klipper/editactiondialog.ui b/klipper/editactiondialog.ui index 2da221c73..5e03c8b31 100644 --- a/klipper/editactiondialog.ui +++ b/klipper/editactiondialog.ui @@ -1,226 +1,220 @@ EditActionDialog 0 0 362 329 0 Action properties: - + 200 0 - + Regular expression: Qt::AlignRight|Qt::AlignTrailing|Qt::AlignVCenter Description: Qt::AlignRight|Qt::AlignTrailing|Qt::AlignVCenter Automatic: Qt::AlignRight|Qt::AlignTrailing|Qt::AlignVCenter automatic Qt::LeftToRight List of commands for this action: Qt::Horizontal QSizePolicy::Fixed 15 20 Qt::Horizontal QSizePolicy::Fixed 15 20 Qt::Vertical QSizePolicy::Fixed 0 15 Add Command Remove Command Qt::Vertical QSizePolicy::Fixed 20 15 Double-click an item to edit true QAbstractItemView::SingleSelection QAbstractItemView::SelectRows false Qt::NoPen false true false false twCommandList leRegExp automatic leDescription pbRemoveCommand pbAddCommand - - - KLineEdit - QLineEdit -
klineedit.h
-
-
+