File indexing completed on 2024-05-05 17:56:44
0001 /* 0002 SPDX-FileCopyrightText: 2004-2007 Jonas Bähr <jonas.baehr@web.de> 0003 SPDX-FileCopyrightText: 2004-2022 Krusader Krew <https://krusader.org> 0004 0005 SPDX-License-Identifier: GPL-2.0-or-later 0006 */ 0007 0008 #include "actionproperty.h" 0009 #include "addplaceholderpopup.h" 0010 0011 #include "../UserAction/kraction.h" 0012 #include "../UserAction/useraction.h" 0013 #include "../icon.h" 0014 #include "../krglobal.h" 0015 #include "../krusader.h" 0016 0017 // QtWidgets 0018 #include <QFileDialog> 0019 #include <QInputDialog> 0020 0021 #include <KI18n/KLocalizedString> 0022 #include <KWidgetsAddons/KMessageBox> 0023 #include <KXmlGui/KActionCollection> 0024 0025 ActionProperty::ActionProperty(QWidget *parent, KrAction *action) 0026 : QWidget(parent) 0027 , _modified(false) 0028 { 0029 setupUi(this); 0030 0031 if (action) { 0032 _action = action; 0033 updateGUI(_action); 0034 } 0035 0036 ButtonAddPlaceholder->setIcon(Icon("list-add")); 0037 ButtonAddStartpath->setIcon(Icon("document-open")); 0038 0039 // fill with all existing categories 0040 cbCategory->addItems(krUserAction->allCategories()); 0041 0042 connect(ButtonAddPlaceholder, &QToolButton::clicked, this, &ActionProperty::addPlaceholder); 0043 connect(ButtonAddStartpath, &QToolButton::clicked, this, &ActionProperty::addStartpath); 0044 connect(ButtonNewProtocol, &QToolButton::clicked, this, &ActionProperty::newProtocol); 0045 connect(ButtonEditProtocol, &QToolButton::clicked, this, &ActionProperty::editProtocol); 0046 connect(ButtonRemoveProtocol, &QToolButton::clicked, this, &ActionProperty::removeProtocol); 0047 connect(ButtonAddPath, &QToolButton::clicked, this, &ActionProperty::addPath); 0048 connect(ButtonEditPath, &QToolButton::clicked, this, &ActionProperty::editPath); 0049 connect(ButtonRemovePath, &QToolButton::clicked, this, &ActionProperty::removePath); 0050 connect(ButtonAddMime, &QToolButton::clicked, this, &ActionProperty::addMime); 0051 connect(ButtonEditMime, &QToolButton::clicked, this, &ActionProperty::editMime); 0052 connect(ButtonRemoveMime, &QToolButton::clicked, this, &ActionProperty::removeMime); 0053 connect(ButtonNewFile, &QToolButton::clicked, this, &ActionProperty::newFile); 0054 connect(ButtonEditFile, &QToolButton::clicked, this, &ActionProperty::editFile); 0055 connect(ButtonRemoveFile, &QToolButton::clicked, this, &ActionProperty::removeFile); 0056 connect(KeyButtonShortcut, &KKeySequenceWidget::keySequenceChanged, this, &ActionProperty::changedShortcut); 0057 // track modifications: 0058 connect(leDistinctName, &KLineEdit::textChanged, this, [=]() { 0059 setModified(true); 0060 }); 0061 connect(leTitle, &KLineEdit::textChanged, this, [=]() { 0062 setModified(true); 0063 }); 0064 connect(ButtonIcon, &KIconButton::iconChanged, this, [=]() { 0065 setModified(true); 0066 }); 0067 connect(cbCategory, &KComboBox::currentTextChanged, this, [=]() { 0068 setModified(true); 0069 }); 0070 connect(leTooltip, &KLineEdit::textChanged, this, [=]() { 0071 setModified(true); 0072 }); 0073 connect(textDescription, &KTextEdit::textChanged, this, [=]() { 0074 setModified(true); 0075 }); 0076 connect(leCommandline, &KLineEdit::textChanged, this, [=]() { 0077 setModified(true); 0078 }); 0079 connect(leStartpath, &KLineEdit::textChanged, this, [=]() { 0080 setModified(true); 0081 }); 0082 connect(chkSeparateStdError, &QCheckBox::clicked, this, &ActionProperty::setModified); 0083 connect(radioCollectOutput, &QRadioButton::clicked, this, &ActionProperty::setModified); 0084 connect(radioNormal, &QRadioButton::clicked, this, &ActionProperty::setModified); 0085 connect(radioTE, &QRadioButton::clicked, this, &ActionProperty::setModified); 0086 connect(radioTerminal, &QRadioButton::clicked, this, &ActionProperty::setModified); 0087 connect(radioLocal, &QRadioButton::clicked, this, &ActionProperty::setModified); 0088 connect(radioUrl, &QRadioButton::clicked, this, &ActionProperty::setModified); 0089 connect(KeyButtonShortcut, &KKeySequenceWidget::keySequenceChanged, this, [=]() { 0090 setModified(true); 0091 }); 0092 connect(chkEnabled, &QCheckBox::clicked, this, &ActionProperty::setModified); 0093 connect(leDifferentUser, &KLineEdit::textChanged, this, [=]() { 0094 setModified(true); 0095 }); 0096 connect(chkDifferentUser, &QCheckBox::clicked, this, &ActionProperty::setModified); 0097 connect(chkConfirmExecution, &QCheckBox::clicked, this, &ActionProperty::setModified); 0098 connect(chkSeparateStdError, &QCheckBox::clicked, this, &ActionProperty::setModified); 0099 // The modified-state of the ShowOnly-lists is tracked in the access-functions below 0100 } 0101 0102 ActionProperty::~ActionProperty() = default; 0103 0104 void ActionProperty::changedShortcut(const QKeySequence &shortcut) 0105 { 0106 KeyButtonShortcut->setKeySequence(shortcut); 0107 } 0108 0109 void ActionProperty::clear() 0110 { 0111 _action = nullptr; 0112 0113 // This prevents the changed-signal from being emitted during the GUI-update 0114 _modified = true; // The real state is set at the end of this function. 0115 0116 leDistinctName->clear(); 0117 cbCategory->clearEditText(); 0118 leTitle->clear(); 0119 leTooltip->clear(); 0120 textDescription->clear(); 0121 leCommandline->clear(); 0122 leStartpath->clear(); 0123 KeyButtonShortcut->clearKeySequence(); 0124 0125 lbShowonlyProtocol->clear(); 0126 lbShowonlyPath->clear(); 0127 lbShowonlyMime->clear(); 0128 lbShowonlyFile->clear(); 0129 0130 chkSeparateStdError->setChecked(false); 0131 radioNormal->setChecked(true); 0132 0133 radioLocal->setChecked(true); 0134 0135 chkEnabled->setChecked(true); 0136 0137 chkConfirmExecution->setChecked(false); 0138 0139 ButtonIcon->resetIcon(); 0140 0141 leDifferentUser->clear(); 0142 chkDifferentUser->setChecked(false); 0143 0144 setModified(false); 0145 } 0146 0147 void ActionProperty::updateGUI(KrAction *action) 0148 { 0149 if (action) 0150 _action = action; 0151 if (!_action) 0152 return; 0153 0154 // This prevents the changed-signal from being emitted during the GUI-update. 0155 _modified = true; // The real state is set at the end of this function. 0156 0157 leDistinctName->setText(_action->objectName()); 0158 cbCategory->lineEdit()->setText(_action->category()); 0159 leTitle->setText(_action->text()); 0160 leTooltip->setText(_action->toolTip()); 0161 textDescription->setText(_action->whatsThis()); 0162 leCommandline->setText(_action->command()); 0163 leCommandline->home(false); 0164 leStartpath->setText(_action->startpath()); 0165 KeyButtonShortcut->setKeySequence(_action->shortcut()); 0166 0167 lbShowonlyProtocol->clear(); 0168 lbShowonlyProtocol->addItems(_action->showonlyProtocol()); 0169 lbShowonlyPath->clear(); 0170 lbShowonlyPath->addItems(_action->showonlyPath()); 0171 lbShowonlyMime->clear(); 0172 lbShowonlyMime->addItems(_action->showonlyMime()); 0173 lbShowonlyFile->clear(); 0174 lbShowonlyFile->addItems(_action->showonlyFile()); 0175 0176 chkSeparateStdError->setChecked(false); 0177 switch (_action->execType()) { 0178 case KrAction::CollectOutputSeparateStderr: 0179 chkSeparateStdError->setChecked(true); 0180 radioCollectOutput->setChecked(true); 0181 break; 0182 case KrAction::CollectOutput: 0183 radioCollectOutput->setChecked(true); 0184 break; 0185 case KrAction::Terminal: 0186 radioTerminal->setChecked(true); 0187 break; 0188 case KrAction::RunInTE: 0189 radioTE->setChecked(true); 0190 break; 0191 default: // case KrAction::Normal: 0192 radioNormal->setChecked(true); 0193 break; 0194 } 0195 0196 if (_action->acceptURLs()) 0197 radioUrl->setChecked(true); 0198 else 0199 radioLocal->setChecked(true); 0200 0201 chkEnabled->setChecked(_action->isVisible()); 0202 0203 chkConfirmExecution->setChecked(_action->confirmExecution()); 0204 0205 if (!_action->icon().isNull()) 0206 ButtonIcon->setIcon(_action->iconName()); 0207 else 0208 ButtonIcon->resetIcon(); 0209 0210 leDifferentUser->setText(_action->user()); 0211 if (_action->user().isEmpty()) 0212 chkDifferentUser->setChecked(false); 0213 else 0214 chkDifferentUser->setChecked(true); 0215 0216 setModified(false); 0217 } 0218 0219 void ActionProperty::updateAction(KrAction *action) 0220 { 0221 if (action) 0222 _action = action; 0223 if (!_action) 0224 return; 0225 0226 if (_action->category() != cbCategory->currentText()) { 0227 _action->setCategory(cbCategory->currentText()); 0228 // Update the category-list 0229 cbCategory->clear(); 0230 cbCategory->addItems(krUserAction->allCategories()); 0231 cbCategory->lineEdit()->setText(_action->category()); 0232 } 0233 0234 _action->setObjectName(leDistinctName->text()); 0235 _action->setText(leTitle->text()); 0236 _action->setToolTip(leTooltip->text()); 0237 _action->setWhatsThis(textDescription->toPlainText()); 0238 _action->setCommand(leCommandline->text()); 0239 _action->setStartpath(leStartpath->text()); 0240 _action->setShortcut(KeyButtonShortcut->keySequence()); 0241 0242 QStringList list; 0243 0244 for (int i1 = 0; i1 != lbShowonlyProtocol->count(); i1++) { 0245 QListWidgetItem *lbi = lbShowonlyProtocol->item(i1); 0246 0247 list << lbi->text(); 0248 } 0249 _action->setShowonlyProtocol(list); 0250 0251 list = QStringList(); 0252 for (int i1 = 0; i1 != lbShowonlyPath->count(); i1++) { 0253 QListWidgetItem *lbi = lbShowonlyPath->item(i1); 0254 0255 list << lbi->text(); 0256 } 0257 _action->setShowonlyPath(list); 0258 0259 list = QStringList(); 0260 for (int i1 = 0; i1 != lbShowonlyMime->count(); i1++) { 0261 QListWidgetItem *lbi = lbShowonlyMime->item(i1); 0262 0263 list << lbi->text(); 0264 } 0265 _action->setShowonlyMime(list); 0266 0267 list = QStringList(); 0268 for (int i1 = 0; i1 != lbShowonlyFile->count(); i1++) { 0269 QListWidgetItem *lbi = lbShowonlyFile->item(i1); 0270 0271 list << lbi->text(); 0272 } 0273 _action->setShowonlyFile(list); 0274 0275 if (radioCollectOutput->isChecked() && chkSeparateStdError->isChecked()) 0276 _action->setExecType(KrAction::CollectOutputSeparateStderr); 0277 else if (radioCollectOutput->isChecked() && !chkSeparateStdError->isChecked()) 0278 _action->setExecType(KrAction::CollectOutput); 0279 else if (radioTerminal->isChecked()) 0280 _action->setExecType(KrAction::Terminal); 0281 else if (radioTE->isChecked()) 0282 _action->setExecType(KrAction::RunInTE); 0283 else 0284 _action->setExecType(KrAction::Normal); 0285 0286 if (radioUrl->isChecked()) 0287 _action->setAcceptURLs(true); 0288 else 0289 _action->setAcceptURLs(false); 0290 0291 _action->setEnabled(chkEnabled->isChecked()); 0292 _action->setVisible(chkEnabled->isChecked()); 0293 0294 _action->setConfirmExecution(chkConfirmExecution->isChecked()); 0295 0296 _action->setIcon(Icon(ButtonIcon->icon())); 0297 _action->setIconName(ButtonIcon->icon()); 0298 0299 _action->setUser(leDifferentUser->text()); 0300 0301 setModified(false); 0302 } 0303 0304 void ActionProperty::addPlaceholder() 0305 { 0306 AddPlaceholderPopup popup(this); 0307 QString exp = popup.getPlaceholder(mapToGlobal(QPoint(ButtonAddPlaceholder->pos().x() + ButtonAddPlaceholder->width() + 6, // 6 is the default margin 0308 ButtonAddPlaceholder->pos().y()))); 0309 leCommandline->insert(exp); 0310 } 0311 0312 void ActionProperty::addStartpath() 0313 { 0314 QString folder = QFileDialog::getExistingDirectory(this); 0315 if (!folder.isEmpty()) { 0316 leStartpath->setText(folder); 0317 } 0318 } 0319 0320 void ActionProperty::newProtocol() 0321 { 0322 bool ok; 0323 0324 QString currentText; 0325 if (lbShowonlyProtocol->currentItem()) 0326 currentText = lbShowonlyProtocol->currentItem()->text(); 0327 0328 QString text = QInputDialog::getText(this, i18n("New protocol"), i18n("Set a protocol:"), QLineEdit::Normal, currentText, &ok); 0329 if (ok && !text.isEmpty()) { 0330 lbShowonlyProtocol->addItems(text.split(';')); 0331 setModified(); 0332 } 0333 } 0334 0335 void ActionProperty::editProtocol() 0336 { 0337 if (lbShowonlyProtocol->currentItem() == nullptr) 0338 return; 0339 0340 bool ok; 0341 0342 QString currentText = lbShowonlyProtocol->currentItem()->text(); 0343 0344 QString text = QInputDialog::getText(this, i18n("Edit Protocol"), i18n("Set another protocol:"), QLineEdit::Normal, currentText, &ok); 0345 if (ok && !text.isEmpty()) { 0346 lbShowonlyProtocol->currentItem()->setText(text); 0347 setModified(); 0348 } 0349 } 0350 0351 void ActionProperty::removeProtocol() 0352 { 0353 if (lbShowonlyProtocol->currentItem() != nullptr) { 0354 delete lbShowonlyProtocol->currentItem(); 0355 setModified(); 0356 } 0357 } 0358 0359 void ActionProperty::addPath() 0360 { 0361 QString folder = QFileDialog::getExistingDirectory(this); 0362 if (!folder.isEmpty()) { 0363 lbShowonlyPath->addItem(folder); 0364 setModified(); 0365 } 0366 } 0367 0368 void ActionProperty::editPath() 0369 { 0370 if (lbShowonlyPath->currentItem() == nullptr) 0371 return; 0372 0373 bool ok; 0374 0375 QString currentText = lbShowonlyPath->currentItem()->text(); 0376 0377 QString text = QInputDialog::getText(this, i18n("Edit Path"), i18n("Set another path:"), QLineEdit::Normal, currentText, &ok); 0378 if (ok && !text.isEmpty()) { 0379 lbShowonlyPath->currentItem()->setText(text); 0380 setModified(); 0381 } 0382 } 0383 0384 void ActionProperty::removePath() 0385 { 0386 if (lbShowonlyPath->currentItem() != nullptr) { 0387 delete lbShowonlyPath->currentItem(); 0388 setModified(); 0389 } 0390 } 0391 0392 void ActionProperty::addMime() 0393 { 0394 bool ok; 0395 0396 QString currentText; 0397 if (lbShowonlyMime->currentItem()) 0398 currentText = lbShowonlyMime->currentItem()->text(); 0399 0400 QString text = QInputDialog::getText(this, i18n("New MIME Type"), i18n("Set a MIME type:"), QLineEdit::Normal, currentText, &ok); 0401 if (ok && !text.isEmpty()) { 0402 lbShowonlyMime->addItems(text.split(';')); 0403 setModified(); 0404 } 0405 } 0406 0407 void ActionProperty::editMime() 0408 { 0409 if (lbShowonlyMime->currentItem() == nullptr) 0410 return; 0411 0412 bool ok; 0413 0414 QString currentText = lbShowonlyMime->currentItem()->text(); 0415 0416 QString text = QInputDialog::getText(this, i18n("Edit MIME Type"), i18n("Set another MIME type:"), QLineEdit::Normal, currentText, &ok); 0417 if (ok && !text.isEmpty()) { 0418 lbShowonlyMime->currentItem()->setText(text); 0419 setModified(); 0420 } 0421 } 0422 0423 void ActionProperty::removeMime() 0424 { 0425 if (lbShowonlyMime->currentItem() != nullptr) { 0426 delete lbShowonlyMime->currentItem(); 0427 setModified(); 0428 } 0429 } 0430 0431 void ActionProperty::newFile() 0432 { 0433 bool ok; 0434 0435 QString currentText; 0436 if (lbShowonlyFile->currentItem()) 0437 currentText = lbShowonlyFile->currentItem()->text(); 0438 0439 QString text = QInputDialog::getText(this, i18n("New File Name"), i18n("Set a file name:"), QLineEdit::Normal, currentText, &ok); 0440 if (ok && !text.isEmpty()) { 0441 lbShowonlyFile->addItems(text.split(';')); 0442 setModified(); 0443 } 0444 } 0445 0446 void ActionProperty::editFile() 0447 { 0448 if (lbShowonlyFile->currentItem() == nullptr) 0449 return; 0450 0451 bool ok; 0452 0453 QString currentText = lbShowonlyFile->currentItem()->text(); 0454 0455 QString text = QInputDialog::getText(this, i18n("Edit File Name"), i18n("Set another file name:"), QLineEdit::Normal, currentText, &ok); 0456 if (ok && !text.isEmpty()) { 0457 lbShowonlyFile->currentItem()->setText(text); 0458 setModified(); 0459 } 0460 } 0461 0462 void ActionProperty::removeFile() 0463 { 0464 if (lbShowonlyFile->currentItem() != nullptr) { 0465 delete lbShowonlyFile->currentItem(); 0466 setModified(); 0467 } 0468 } 0469 0470 bool ActionProperty::validProperties() 0471 { 0472 if (leDistinctName->text().simplified().isEmpty()) { 0473 KMessageBox::error(this, i18n("Please set a unique name for the useraction")); 0474 leDistinctName->setFocus(); 0475 return false; 0476 } 0477 if (leTitle->text().simplified().isEmpty()) { 0478 KMessageBox::error(this, i18n("Please set a title for the menu entry")); 0479 leTitle->setFocus(); 0480 return false; 0481 } 0482 if (leCommandline->text().simplified().isEmpty()) { 0483 KMessageBox::error(this, i18n("Command line is empty")); 0484 leCommandline->setFocus(); 0485 return false; 0486 } 0487 if (leDistinctName->isEnabled()) 0488 if (krApp->actionCollection()->action(leDistinctName->text())) { 0489 KMessageBox::error(this, 0490 i18n("There already is an action with this name.\n" 0491 "If you do not have such a useraction the name is used by Krusader for an internal action.")); 0492 leDistinctName->setFocus(); 0493 return false; 0494 } 0495 0496 return true; 0497 } 0498 0499 void ActionProperty::setModified(bool m) 0500 { 0501 if (m && !_modified) { // emit only when the state _changes_to_true_, 0502 emit changed(); 0503 } 0504 _modified = m; 0505 }