File indexing completed on 2024-04-28 16:54:24

0001 /*
0002     SPDX-FileCopyrightText: 2022 Jonathan Marten <jjm@keelhaul.me.uk>
0003     SPDX-License-Identifier: GPL-2.0-or-later
0004 */
0005 
0006 #include "editcommanddialog.h"
0007 
0008 #include <qbuttongroup.h>
0009 #include <qdialogbuttonbox.h>
0010 #include <qformlayout.h>
0011 #include <qlabel.h>
0012 #include <qlineedit.h>
0013 #include <qpushbutton.h>
0014 #include <qradiobutton.h>
0015 #include <qwindow.h>
0016 
0017 #include <kiconbutton.h>
0018 #include <klocalizedstring.h>
0019 #include <kstandardguiitem.h>
0020 #include <kwindowconfig.h>
0021 
0022 #include "klipper_debug.h"
0023 
0024 #include "configdialog.h"
0025 
0026 static void setIconForCommand(ClipCommand *cmd)
0027 {
0028     // let's try to update icon of the item according to command
0029     QString command = cmd->command;
0030     if (command.contains(QLatin1Char(' '))) {
0031         // get first word
0032         command = command.section(QLatin1Char(' '), 0, 0);
0033     }
0034 
0035     if (QIcon::hasThemeIcon(command)) {
0036         cmd->icon = command;
0037     } else {
0038         cmd->icon.clear();
0039     }
0040 }
0041 
0042 EditCommandDialog::EditCommandDialog(const ClipCommand &command, QWidget *parent)
0043     : QDialog(parent)
0044     , m_command(command)
0045 {
0046     setWindowTitle(i18n("Command Properties"));
0047     QDialogButtonBox *buttons = new QDialogButtonBox(QDialogButtonBox::Ok | QDialogButtonBox::Cancel, this);
0048     m_okButton = buttons->button(QDialogButtonBox::Ok);
0049     m_okButton->setShortcut(Qt::CTRL | Qt::Key_Return);
0050     connect(buttons, &QDialogButtonBox::accepted, this, &EditCommandDialog::slotAccepted);
0051     connect(buttons, &QDialogButtonBox::rejected, this, &QDialog::reject);
0052 
0053     QWidget *optionsWidget = new QWidget(this);
0054     QFormLayout *optionsLayout = new QFormLayout(optionsWidget);
0055 
0056     // Command
0057     m_commandEdit = new QLineEdit(optionsWidget);
0058     m_commandEdit->setClearButtonEnabled(true);
0059     m_commandEdit->setPlaceholderText(i18n("Enter the command and arguments"));
0060     connect(m_commandEdit, &QLineEdit::textEdited, this, &EditCommandDialog::slotUpdateButtons);
0061 
0062     optionsLayout->addRow(i18n("Command:"), m_commandEdit);
0063 
0064     // See ClipCommandProcess::ClipCommandProcess() for the
0065     // substitutions made.  "%0" is the complete text matched by the
0066     // regular expression, which may only match a part of the clipboard
0067     // contents, so it is mentioned here.  However, "%u"/"%U" and "%f"/"%F"
0068     // are exactly equivalent to "%s", the complete clipboard contents,
0069     // so there is no point mentioning them here.
0070     QLabel *hint = ConfigDialog::createHintLabel(xi18nc("@info",
0071                                                         "A <placeholder>&#37;s</placeholder> in the command will be replaced by the \
0072 complete clipboard contents. <placeholder>&#37;0</placeholder> through \
0073 <placeholder>&#37;9</placeholder> will be replaced by the corresponding \
0074 captured texts from the match pattern."),
0075                                                  optionsWidget);
0076     optionsLayout->addRow(QString(), hint);
0077 
0078     // Description
0079     m_descriptionEdit = new QLineEdit(optionsWidget);
0080     m_descriptionEdit->setClearButtonEnabled(true);
0081     m_descriptionEdit->setPlaceholderText(i18n("Enter a description for the command"));
0082     connect(m_descriptionEdit, &QLineEdit::textEdited, this, &EditCommandDialog::slotUpdateButtons);
0083     optionsLayout->addRow(i18n("Description:"), m_descriptionEdit);
0084     optionsLayout->addRow(QString(), new QLabel(this));
0085 
0086     // Radio button group: Output handling
0087     QButtonGroup *buttonGroup = new QButtonGroup(this);
0088 
0089     m_ignoreRadio = new QRadioButton(i18n("Ignore"), this);
0090     buttonGroup->addButton(m_ignoreRadio);
0091     optionsLayout->addRow(i18n("Output from command:"), m_ignoreRadio);
0092 
0093     m_replaceRadio = new QRadioButton(i18n("Replace current clipboard"), this);
0094     buttonGroup->addButton(m_replaceRadio);
0095     optionsLayout->addRow(QString(), m_replaceRadio);
0096 
0097     m_appendRadio = new QRadioButton(i18n("Append to clipboard"), this);
0098     buttonGroup->addButton(m_appendRadio);
0099     optionsLayout->addRow(QString(), m_appendRadio);
0100 
0101     optionsLayout->addRow(QString(), ConfigDialog::createHintLabel(i18n("What happens to the standard output of the command executed."), this));
0102 
0103     optionsLayout->addRow(QString(), new QLabel(this));
0104 
0105     // Icon and reset button
0106     QHBoxLayout *hb = new QHBoxLayout;
0107     hb->setContentsMargins(0, 0, 0, 0);
0108 
0109     m_iconButton = new KIconButton(this);
0110     m_iconButton->setIconSize(KIconLoader::SizeSmall);
0111     hb->addWidget(m_iconButton);
0112 
0113     QPushButton *resetButton = new QPushButton(this);
0114     KStandardGuiItem::assign(resetButton, KStandardGuiItem::Reset);
0115     resetButton->setToolTip(i18n("Reset the icon to the default for the command"));
0116     connect(resetButton, &QAbstractButton::clicked, this, [this]() {
0117         setIconForCommand(&m_command);
0118         m_iconButton->setIcon(m_command.icon);
0119     });
0120     hb->addWidget(resetButton);
0121     optionsLayout->addRow(i18n("Icon:"), hb);
0122 
0123     // Main dialogue layout
0124     QVBoxLayout *mainLayout = new QVBoxLayout(this);
0125     mainLayout->addWidget(optionsWidget);
0126     mainLayout->addStretch();
0127     mainLayout->addWidget(buttons);
0128 
0129     (void)winId();
0130     windowHandle()->resize(560, 440); // default, if there is no saved size
0131     const KConfigGroup grp = KSharedConfig::openConfig()->group(metaObject()->className());
0132     KWindowConfig::restoreWindowSize(windowHandle(), grp);
0133     resize(windowHandle()->size());
0134 
0135     updateWidgets();
0136 }
0137 
0138 void EditCommandDialog::slotUpdateButtons()
0139 {
0140     m_okButton->setEnabled(!m_commandEdit->text().isEmpty() && !m_descriptionEdit->text().isEmpty());
0141 }
0142 
0143 void EditCommandDialog::updateWidgets()
0144 {
0145     m_commandEdit->setText(m_command.command);
0146     m_descriptionEdit->setText(m_command.description);
0147 
0148     m_replaceRadio->setChecked(m_command.output == ClipCommand::REPLACE);
0149     m_appendRadio->setChecked(m_command.output == ClipCommand::ADD);
0150     m_ignoreRadio->setChecked(m_command.output == ClipCommand::IGNORE);
0151 
0152     m_iconButton->setIcon(m_command.icon);
0153 
0154     slotUpdateButtons();
0155 }
0156 
0157 void EditCommandDialog::saveCommand()
0158 {
0159     m_command.command = m_commandEdit->text();
0160     m_command.description = m_descriptionEdit->text();
0161 
0162     if (m_replaceRadio->isChecked()) {
0163         m_command.output = ClipCommand::REPLACE;
0164     } else if (m_appendRadio->isChecked()) {
0165         m_command.output = ClipCommand::ADD;
0166     } else {
0167         m_command.output = ClipCommand::IGNORE;
0168     }
0169 
0170     const QString icon = m_iconButton->icon();
0171     if (!icon.isEmpty()) {
0172         m_command.icon = icon;
0173     } else {
0174         setIconForCommand(&m_command);
0175     }
0176 }
0177 
0178 void EditCommandDialog::slotAccepted()
0179 {
0180     saveCommand();
0181 
0182     KConfigGroup grp = KSharedConfig::openConfig()->group(metaObject()->className());
0183     KWindowConfig::saveWindowSize(windowHandle(), grp);
0184     accept();
0185 }