File indexing completed on 2024-04-28 17:06:31
0001 /* 0002 SPDX-FileCopyrightText: 2004 Shie Erlich <erlich@users.sourceforge.net> 0003 SPDX-FileCopyrightText: 2004 Rafi Yanai <yanai@users.sourceforge.net> 0004 SPDX-FileCopyrightText: 2006 Jonas Bähr <jonas.baehr@web.de> 0005 SPDX-FileCopyrightText: 2004-2022 Krusader Krew <https://krusader.org> 0006 0007 SPDX-License-Identifier: GPL-2.0-or-later 0008 */ 0009 0010 #include "kraction.h" 0011 0012 // QtCore 0013 #include <QDebug> 0014 #include <QEvent> 0015 #include <QFile> 0016 #include <QMimeDatabase> 0017 #include <QMimeType> 0018 #include <QRegExp> 0019 #include <QTextStream> 0020 // QtGui 0021 #include <QKeyEvent> 0022 // QtWidgets 0023 #include <QAction> 0024 #include <QBoxLayout> 0025 #include <QCheckBox> 0026 #include <QDialogButtonBox> 0027 #include <QFileDialog> 0028 #include <QLabel> 0029 #include <QLayout> 0030 #include <QPushButton> 0031 #include <QSplitter> 0032 // QtXml 0033 #include <QDomElement> 0034 0035 #include <KConfigCore/KSharedConfig> 0036 #include <KCoreAddons/KShell> 0037 #include <KI18n/KLocalizedString> 0038 #include <KParts/ReadOnlyPart> 0039 #include <KWidgetsAddons/KMessageBox> 0040 #include <KXmlGui/KActionCollection> 0041 0042 #include "../GUI/terminaldock.h" 0043 #include "../defaults.h" 0044 #include "../icon.h" 0045 #include "../krglobal.h" 0046 #include "../krservices.h" 0047 #include "../krusaderview.h" 0048 #include "expander.h" 0049 #include "useraction.h" 0050 0051 // KrActionProcDlg 0052 KrActionProcDlg::KrActionProcDlg(const QString &caption, bool enableStderr, QWidget *parent) 0053 : QDialog(parent) 0054 , _stdout(nullptr) 0055 , _stderr(nullptr) 0056 , _currentTextEdit(nullptr) 0057 { 0058 setWindowTitle(caption); 0059 setWindowModality(Qt::NonModal); 0060 0061 auto *mainLayout = new QVBoxLayout; 0062 setLayout(mainLayout); 0063 0064 // do we need to separate stderr and stdout? 0065 if (enableStderr) { 0066 auto *splitt = new QSplitter(Qt::Horizontal, this); 0067 mainLayout->addWidget(splitt); 0068 // create stdout 0069 QWidget *stdoutWidget = new QWidget(splitt); 0070 auto *stdoutBox = new QVBoxLayout(stdoutWidget); 0071 0072 stdoutBox->addWidget(new QLabel(i18n("Standard Output (stdout)"), stdoutWidget)); 0073 _stdout = new KTextEdit(stdoutWidget); 0074 _stdout->setReadOnly(true); 0075 stdoutBox->addWidget(_stdout); 0076 // create stderr 0077 QWidget *stderrWidget = new QWidget(splitt); 0078 auto *stderrBox = new QVBoxLayout(stderrWidget); 0079 0080 stderrBox->addWidget(new QLabel(i18n("Standard Error (stderr)"), stderrWidget)); 0081 _stderr = new KTextEdit(stderrWidget); 0082 _stderr->setReadOnly(true); 0083 stderrBox->addWidget(_stderr); 0084 } else { 0085 // create stdout 0086 mainLayout->addWidget(new QLabel(i18n("Output"))); 0087 _stdout = new KTextEdit; 0088 _stdout->setReadOnly(true); 0089 mainLayout->addWidget(_stdout); 0090 } 0091 0092 _currentTextEdit = _stdout; 0093 connect(_stdout, &KTextEdit::textChanged, this, &KrActionProcDlg::currentTextEditChanged); 0094 if (_stderr) 0095 connect(_stderr, &KTextEdit::textChanged, this, &KrActionProcDlg::currentTextEditChanged); 0096 0097 KConfigGroup group(krConfig, "UserActions"); 0098 normalFont = group.readEntry("Normal Font", _UserActions_NormalFont); 0099 fixedFont = group.readEntry("Fixed Font", _UserActions_FixedFont); 0100 bool startupState = group.readEntry("Use Fixed Font", _UserActions_UseFixedFont); 0101 toggleFixedFont(startupState); 0102 0103 auto *hbox = new QHBoxLayout; 0104 QCheckBox *useFixedFont = new QCheckBox(i18n("Use font with fixed width")); 0105 useFixedFont->setChecked(startupState); 0106 hbox->addWidget(useFixedFont); 0107 0108 QDialogButtonBox *buttonBox = new QDialogButtonBox(QDialogButtonBox::Close); 0109 hbox->addWidget(buttonBox); 0110 0111 mainLayout->addLayout(hbox); 0112 0113 closeButton = buttonBox->button(QDialogButtonBox::Close); 0114 closeButton->setEnabled(false); 0115 0116 auto *saveAsButton = new QPushButton; 0117 KGuiItem::assign(saveAsButton, KStandardGuiItem::saveAs()); 0118 buttonBox->addButton(saveAsButton, QDialogButtonBox::ActionRole); 0119 0120 killButton = new QPushButton(i18n("Kill")); 0121 killButton->setToolTip(i18n("Kill the running process")); 0122 killButton->setDefault(true); 0123 buttonBox->addButton(killButton, QDialogButtonBox::ActionRole); 0124 0125 connect(killButton, &QPushButton::clicked, this, &KrActionProcDlg::killClicked); 0126 connect(saveAsButton, &QPushButton::clicked, this, &KrActionProcDlg::slotSaveAs); 0127 connect(buttonBox, &QDialogButtonBox::rejected, this, &KrActionProcDlg::reject); 0128 connect(useFixedFont, &QCheckBox::toggled, this, &KrActionProcDlg::toggleFixedFont); 0129 0130 resize(sizeHint() * 2); 0131 } 0132 0133 void KrActionProcDlg::addStderr(const QString &str) 0134 { 0135 if (_stderr) 0136 _stderr->append(str); 0137 else { 0138 _stdout->setFontItalic(true); 0139 _stdout->append(str); 0140 _stdout->setFontItalic(false); 0141 } 0142 } 0143 0144 void KrActionProcDlg::addStdout(const QString &str) 0145 { 0146 _stdout->append(str); 0147 } 0148 0149 void KrActionProcDlg::toggleFixedFont(bool state) 0150 { 0151 if (state) { 0152 _stdout->setFont(fixedFont); 0153 if (_stderr) 0154 _stderr->setFont(fixedFont); 0155 } else { 0156 _stdout->setFont(normalFont); 0157 if (_stderr) 0158 _stderr->setFont(normalFont); 0159 } 0160 } 0161 0162 void KrActionProcDlg::slotSaveAs() 0163 { 0164 QString filename = QFileDialog::getSaveFileName(this, QString(), QString(), i18n("*.txt|Text files\n*|All files")); 0165 if (filename.isEmpty()) 0166 return; 0167 QFile file(filename); 0168 int answer = KMessageBox::Yes; 0169 if (file.exists()) 0170 answer = KMessageBox::warningYesNoCancel(this, // parent 0171 i18n("This file already exists.\nDo you want to overwrite it or append the output?"), // text 0172 i18n("Overwrite or append?"), // caption 0173 KStandardGuiItem::overwrite(), // label for Yes-Button 0174 KGuiItem(i18n("Append")) // label for No-Button 0175 ); 0176 if (answer == KMessageBox::Cancel) 0177 return; 0178 bool open; 0179 if (answer == KMessageBox::No) // this means to append 0180 open = file.open(QIODevice::WriteOnly | QIODevice::Append); 0181 else 0182 open = file.open(QIODevice::WriteOnly); 0183 0184 if (!open) { 0185 KMessageBox::error(this, i18n("Cannot open %1 for writing.\nNothing exported.", filename), i18n("Export failed")); 0186 return; 0187 } 0188 0189 QTextStream stream(&file); 0190 stream << _currentTextEdit->toPlainText(); 0191 file.close(); 0192 } 0193 0194 void KrActionProcDlg::slotProcessFinished() 0195 { 0196 closeButton->setEnabled(true); 0197 killButton->setEnabled(false); 0198 } 0199 0200 void KrActionProcDlg::currentTextEditChanged() 0201 { 0202 if (_stderr && _stderr->hasFocus()) 0203 _currentTextEdit = _stderr; 0204 else 0205 _currentTextEdit = _stdout; 0206 } 0207 0208 // KrActionProc 0209 KrActionProc::KrActionProc(KrActionBase *action) 0210 : _action(action) 0211 , _proc(nullptr) 0212 , _output(nullptr) 0213 { 0214 } 0215 0216 KrActionProc::~KrActionProc() 0217 { 0218 delete _proc; 0219 } 0220 0221 void KrActionProc::start(const QString &cmdLine) 0222 { 0223 QStringList list; 0224 list << cmdLine; 0225 start(list); 0226 } 0227 0228 void KrActionProc::start(QStringList cmdLineList) 0229 { 0230 QString cmd; // this is the command which is really executed (with maybe kdesu, maybe konsole, ...) 0231 // in case no specific working directory has been requested, execute in a relatively safe place 0232 QString workingDir = QDir::tempPath(); 0233 0234 if (!_action->startpath().isEmpty()) 0235 workingDir = _action->startpath(); 0236 0237 if (!_action->user().isEmpty()) { 0238 if (!KrServices::isExecutable(KDESU_PATH)) { 0239 KMessageBox::error(nullptr, 0240 i18n("Cannot run user action, %1 not found or not executable. " 0241 "Please verify that kde-cli-tools are installed.", 0242 QString(KDESU_PATH))); 0243 return; 0244 } 0245 } 0246 0247 if (_action->execType() == KrAction::RunInTE && (!MAIN_VIEW->terminalDock()->initialise())) { 0248 KMessageBox::error(nullptr, i18n("Embedded terminal emulator does not work, using output collection instead.")); 0249 } 0250 0251 for (QStringList::Iterator it = cmdLineList.begin(); it != cmdLineList.end(); ++it) { 0252 if (!cmd.isEmpty()) 0253 cmd += " ; "; // TODO make this separator configurable (users may want && or ||) 0254 // TODO: read header fom config or action-properties and place it on top of each command 0255 if (cmdLineList.count() > 1) 0256 cmd += "echo --------------------------------------- ; "; 0257 cmd += *it; 0258 } 0259 0260 // make sure the command gets executed in the right directory 0261 cmd = "(cd " + KrServices::quote(workingDir) + " && (" + cmd + "))"; 0262 0263 if (_action->execType() == KrAction::RunInTE && MAIN_VIEW->terminalDock()->isInitialised()) { // send the commandline contents to the terminal emulator 0264 if (!_action->user().isEmpty()) { 0265 // "-t" is necessary that kdesu displays the terminal-output of the command 0266 cmd = KrServices::quote(KDESU_PATH) + " -t -u " + _action->user() + " -c " + KrServices::quote(cmd); 0267 } 0268 MAIN_VIEW->terminalDock()->sendInput(cmd + '\n'); 0269 deleteLater(); 0270 } else { // will start a new process 0271 _proc = new KProcess(this); 0272 _proc->clearProgram(); // this clears the arglist too 0273 _proc->setWorkingDirectory(workingDir); 0274 connect(_proc, QOverload<int, QProcess::ExitStatus>::of(&KProcess::finished), this, &KrActionProc::processExited); 0275 0276 if (_action->execType() == KrAction::Normal || _action->execType() == KrAction::Terminal) { // not collect output 0277 if (_action->execType() == KrAction::Terminal) { // run in terminal 0278 KConfigGroup group(krConfig, "UserActions"); 0279 QString term = group.readEntry("Terminal", _UserActions_Terminal); 0280 QStringList termArgs = KShell::splitArgs(term, KShell::TildeExpand); 0281 if (termArgs.isEmpty()) { 0282 KMessageBox::error(nullptr, i18nc("Arg is a string containing the bad quoting.", "Bad quoting in terminal command:\n%1", term)); 0283 deleteLater(); 0284 return; 0285 } 0286 for (int i = 0; i != termArgs.size(); i++) { 0287 if (termArgs[i] == "%t") 0288 termArgs[i] = cmdLineList.join(" ; "); 0289 else if (termArgs[i] == "%d") 0290 termArgs[i] = workingDir; 0291 } 0292 termArgs << "sh" 0293 << "-c" << cmd; 0294 cmd = KrServices::quote(termArgs).join(" "); 0295 } 0296 if (!_action->user().isEmpty()) { 0297 cmd = KrServices::quote(KDESU_PATH) + " -u " + _action->user() + " -c " + KrServices::quote(cmd); 0298 } 0299 } else { // collect output 0300 bool separateStderr = false; 0301 if (_action->execType() == KrAction::CollectOutputSeparateStderr) 0302 separateStderr = true; 0303 _output = new KrActionProcDlg(_action->text(), separateStderr); 0304 // connect the output to the dialog 0305 _proc->setOutputChannelMode(KProcess::SeparateChannels); 0306 connect(_proc, &KProcess::readyReadStandardError, this, &KrActionProc::addStderr); 0307 connect(_proc, &KProcess::readyReadStandardOutput, this, &KrActionProc::addStdout); 0308 connect(_output, &KrActionProcDlg::killClicked, this, &KrActionProc::kill); 0309 _output->show(); 0310 0311 if (!_action->user().isEmpty()) { 0312 // "-t" is necessary that kdesu displays the terminal-output of the command 0313 cmd = KrServices::quote(KDESU_PATH) + " -t -u " + _action->user() + " -c " + KrServices::quote(cmd); 0314 } 0315 } 0316 // printf("cmd: %s\n", cmd.toAscii().data()); 0317 _proc->setShellCommand(cmd); 0318 _proc->start(); 0319 } 0320 } 0321 0322 void KrActionProc::processExited(int /*exitCode*/, QProcess::ExitStatus /*exitStatus*/) 0323 { 0324 // enable the 'close' button on the dialog (if active), disable 'kill' button 0325 if (_output) { 0326 // TODO tell the user the program exit code 0327 _output->slotProcessFinished(); 0328 } 0329 delete this; // banzai!! 0330 } 0331 0332 void KrActionProc::addStderr() 0333 { 0334 if (_output) { 0335 _output->addStderr(QString::fromLocal8Bit(_proc->readAllStandardError().data())); 0336 } 0337 } 0338 0339 void KrActionProc::addStdout() 0340 { 0341 if (_output) { 0342 _output->addStdout(QString::fromLocal8Bit(_proc->readAllStandardOutput().data())); 0343 } 0344 } 0345 0346 // KrAction 0347 KrAction::KrAction(KActionCollection *parent, const QString &name) 0348 : QAction((QObject *)parent) 0349 { 0350 _actionCollection = parent; 0351 setObjectName(name); 0352 parent->addAction(name, this); 0353 0354 connect(this, &KrAction::triggered, this, &KrAction::exec); 0355 } 0356 0357 KrAction::~KrAction() 0358 { 0359 foreach (QWidget *w, associatedWidgets()) 0360 w->removeAction(this); 0361 krUserAction->removeKrAction(this); // Importent! Else Krusader will crash when writing the actions to file 0362 } 0363 0364 bool KrAction::isAvailable(const QUrl ¤tURL) 0365 { 0366 bool available = true; // show per default (FIXME: make the default an attribute of <availability>) 0367 0368 // check protocol 0369 if (!_showonlyProtocol.empty()) { 0370 available = false; 0371 for (auto &it : _showonlyProtocol) { 0372 // qDebug() << "KrAction::isAvailable currentProtocol: " << currentURL.scheme() << " =?= " << *it; 0373 if (currentURL.scheme() == it) { // FIXME remove trailing slashes at the xml-parsing (faster because done only once) 0374 available = true; 0375 break; 0376 } 0377 } 0378 } // check protocol: done 0379 0380 // check the Path-list: 0381 if (available && !_showonlyPath.empty()) { 0382 available = false; 0383 for (auto &it : _showonlyPath) { 0384 if (it.right(1) == "*") { 0385 if (currentURL.path().indexOf(it.left(it.length() - 1)) == 0) { 0386 available = true; 0387 break; 0388 } 0389 } else if (currentURL.adjusted(QUrl::RemoveFilename | QUrl::StripTrailingSlash).path() 0390 == it) { // FIXME remove trailing slashes at the xml-parsing (faster because done only once) 0391 available = true; 0392 break; 0393 } 0394 } 0395 } // check the Path-list: done 0396 0397 // check mime-type 0398 if (available && !_showonlyMime.empty()) { 0399 available = false; 0400 QMimeDatabase db; 0401 QMimeType mime = db.mimeTypeForUrl(currentURL); 0402 if (mime.isValid()) { 0403 for (auto &it : _showonlyMime) { 0404 if (it.contains("/")) { 0405 if (mime.inherits(it)) { // don't use ==; use 'inherits()' instead, which is aware of inheritance (ie: text/x-makefile is also text/plain) 0406 available = true; 0407 break; 0408 } 0409 } else { 0410 if (mime.name().indexOf(it) == 0) { // 0 is the beginning, -1 is not found 0411 available = true; 0412 break; 0413 } 0414 } 0415 } // for 0416 } 0417 } // check the mime-type: done 0418 0419 // check filename 0420 if (available && !_showonlyFile.empty()) { 0421 available = false; 0422 for (auto &it : _showonlyFile) { 0423 QRegExp regex = QRegExp(it, Qt::CaseInsensitive, QRegExp::Wildcard); // case-sensitive = false; wildcards = true 0424 if (regex.exactMatch(currentURL.fileName())) { 0425 available = true; 0426 break; 0427 } 0428 } 0429 } // check the filename: done 0430 0431 return available; 0432 } 0433 0434 bool KrAction::xmlRead(const QDomElement &element) 0435 { 0436 /* 0437 This has to be done elsewhere!! 0438 0439 if ( element.tagName() != "action" ) 0440 return false; 0441 0442 Also the name has to be checked before the action is created! 0443 0444 setName( element.attribute( "name" ).toLatin1() ); 0445 */ 0446 QString attr; 0447 0448 attr = element.attribute("enabled", "true"); // default: "true" 0449 if (attr == "false") { 0450 setEnabled(false); 0451 setVisible(false); 0452 } 0453 0454 for (QDomNode node = element.firstChild(); !node.isNull(); node = node.nextSibling()) { 0455 QDomElement e = node.toElement(); 0456 if (e.isNull()) 0457 continue; // this should skip nodes which are not elements ( i.e. comments, <!-- -->, or text nodes) 0458 0459 if (e.tagName() == "title") 0460 setText(i18n(e.text().toUtf8().constData())); 0461 else if (e.tagName() == "tooltip") 0462 setToolTip(i18n(e.text().toUtf8().constData())); 0463 else if (e.tagName() == "icon") 0464 setIcon(Icon(_iconName = e.text())); 0465 else if (e.tagName() == "category") 0466 setCategory(i18n(e.text().toUtf8().constData())); 0467 else if (e.tagName() == "description") 0468 setWhatsThis(i18n(e.text().toUtf8().constData())); 0469 else if (e.tagName() == "command") 0470 readCommand(e); 0471 else if (e.tagName() == "startpath") 0472 setStartpath(e.text()); 0473 else if (e.tagName() == "availability") 0474 readAvailability(e); 0475 else if (e.tagName() == "defaultshortcut") 0476 _actionCollection->setDefaultShortcut(this, QKeySequence(e.text())); 0477 else 0478 0479 // unknown but not empty 0480 if (!e.tagName().isEmpty()) 0481 qWarning() << "KrAction::xmlRead() - unrecognized tag found: <action name=\"" << objectName() << "\"><" << e.tagName() << ">"; 0482 0483 } // for ( QDomNode node = action->firstChild(); !node.isNull(); node = node.nextSibling() ) 0484 0485 return true; 0486 } // KrAction::xmlRead 0487 0488 QDomElement KrAction::xmlDump(QDomDocument &doc) const 0489 { 0490 QDomElement actionElement = doc.createElement("action"); 0491 actionElement.setAttribute("name", objectName()); 0492 0493 if (!isVisible()) { 0494 actionElement.setAttribute("enabled", "false"); 0495 } 0496 0497 #define TEXT_ELEMENT(TAGNAME, TEXT) \ 0498 { \ 0499 QDomElement e = doc.createElement(TAGNAME); \ 0500 e.appendChild(doc.createTextNode(TEXT)); \ 0501 actionElement.appendChild(e); \ 0502 } 0503 0504 TEXT_ELEMENT("title", text()) 0505 0506 if (!toolTip().isEmpty()) 0507 TEXT_ELEMENT("tooltip", toolTip()) 0508 0509 if (!_iconName.isEmpty()) 0510 TEXT_ELEMENT("icon", _iconName) 0511 0512 if (!category().isEmpty()) 0513 TEXT_ELEMENT("category", category()) 0514 0515 if (!whatsThis().isEmpty()) 0516 TEXT_ELEMENT("description", whatsThis()) 0517 0518 actionElement.appendChild(dumpCommand(doc)); 0519 0520 if (!startpath().isEmpty()) 0521 TEXT_ELEMENT("startpath", startpath()) 0522 0523 QDomElement availabilityElement = dumpAvailability(doc); 0524 0525 if (availabilityElement.hasChildNodes()) 0526 actionElement.appendChild(availabilityElement); 0527 0528 if (!shortcut().isEmpty()) 0529 TEXT_ELEMENT("defaultshortcut", shortcut().toString()) //.toString() would return a localised string which can't be read again 0530 0531 return actionElement; 0532 } // KrAction::xmlDump 0533 0534 void KrAction::readCommand(const QDomElement &element) 0535 { 0536 QString attr; 0537 0538 attr = element.attribute("executionmode", "normal"); // default: "normal" 0539 if (attr == "normal") 0540 setExecType(Normal); 0541 else if (attr == "terminal") 0542 setExecType(Terminal); 0543 else if (attr == "collect_output") 0544 setExecType(CollectOutput); 0545 else if (attr == "collect_output_separate_stderr") 0546 setExecType(CollectOutputSeparateStderr); 0547 else if (attr == "embedded_terminal") 0548 setExecType(RunInTE); 0549 else 0550 qWarning() << "KrAction::readCommand() - unrecognized attribute value found: <action name=\"" << objectName() << "\"><command executionmode=\"" << attr 0551 << "\""; 0552 0553 attr = element.attribute("accept", "local"); // default: "local" 0554 if (attr == "local") 0555 setAcceptURLs(false); 0556 else if (attr == "url") 0557 setAcceptURLs(true); 0558 else 0559 qWarning() << "KrAction::readCommand() - unrecognized attribute value found: <action name=\"" << objectName() << "\"><command accept=\"" << attr 0560 << "\""; 0561 0562 attr = element.attribute("confirmexecution", "false"); // default: "false" 0563 if (attr == "true") 0564 setConfirmExecution(true); 0565 else 0566 setConfirmExecution(false); 0567 0568 setUser(element.attribute("run_as")); 0569 0570 setCommand(element.text()); 0571 0572 } // KrAction::readCommand 0573 0574 QDomElement KrAction::dumpCommand(QDomDocument &doc) const 0575 { 0576 QDomElement commandElement = doc.createElement("command"); 0577 0578 switch (execType()) { 0579 case Terminal: 0580 commandElement.setAttribute("executionmode", "terminal"); 0581 break; 0582 case CollectOutput: 0583 commandElement.setAttribute("executionmode", "collect_output"); 0584 break; 0585 case CollectOutputSeparateStderr: 0586 commandElement.setAttribute("executionmode", "collect_output_separate_stderr"); 0587 break; 0588 case RunInTE: 0589 commandElement.setAttribute("executionmode", "embedded_terminal"); 0590 break; 0591 default: 0592 // don't write the default to file 0593 break; 0594 } 0595 0596 if (acceptURLs()) 0597 commandElement.setAttribute("accept", "url"); 0598 0599 if (confirmExecution()) 0600 commandElement.setAttribute("confirmexecution", "true"); 0601 0602 if (!user().isEmpty()) 0603 commandElement.setAttribute("run_as", user()); 0604 0605 commandElement.appendChild(doc.createTextNode(command())); 0606 0607 return commandElement; 0608 } // KrAction::dumpCommand 0609 0610 void KrAction::readAvailability(const QDomElement &element) 0611 { 0612 for (QDomNode node = element.firstChild(); !node.isNull(); node = node.nextSibling()) { 0613 QDomElement e = node.toElement(); 0614 if (e.isNull()) 0615 continue; // this should skip nodes which are not elements ( i.e. comments, <!-- -->, or text nodes) 0616 0617 QStringList *showlist = nullptr; 0618 0619 if (e.tagName() == "protocol") 0620 showlist = &_showonlyProtocol; 0621 else if (e.tagName() == "path") 0622 showlist = &_showonlyPath; 0623 else if (e.tagName() == "mimetype") 0624 showlist = &_showonlyMime; 0625 else if (e.tagName() == "filename") 0626 showlist = &_showonlyFile; 0627 else { 0628 qWarning() << "KrAction::readAvailability() - unrecognized element found: <action name=\"" << objectName() << "\"><availability><" << e.tagName() 0629 << ">"; 0630 showlist = nullptr; 0631 } 0632 0633 if (showlist) { 0634 for (QDomNode subnode = e.firstChild(); !subnode.isNull(); subnode = subnode.nextSibling()) { 0635 QDomElement subelement = subnode.toElement(); 0636 if (subelement.tagName() == "show") 0637 showlist->append(subelement.text()); 0638 } // for 0639 } // if ( showlist ) 0640 0641 } // for 0642 } // KrAction::readAvailability 0643 0644 QDomElement KrAction::dumpAvailability(QDomDocument &doc) const 0645 { 0646 QDomElement availabilityElement = doc.createElement("availability"); 0647 0648 #define LIST_ELEMENT(TAGNAME, LIST) \ 0649 { \ 0650 QDomElement e = doc.createElement(TAGNAME); \ 0651 for (QStringList::const_iterator it = LIST.constBegin(); it != LIST.constEnd(); ++it) { \ 0652 QDomElement show = doc.createElement("show"); \ 0653 show.appendChild(doc.createTextNode(*it)); \ 0654 e.appendChild(show); \ 0655 } \ 0656 availabilityElement.appendChild(e); \ 0657 } 0658 0659 if (!_showonlyProtocol.isEmpty()) 0660 LIST_ELEMENT("protocol", _showonlyProtocol) 0661 0662 if (!_showonlyPath.isEmpty()) 0663 LIST_ELEMENT("path", _showonlyPath) 0664 0665 if (!_showonlyMime.isEmpty()) 0666 LIST_ELEMENT("mimetype", _showonlyMime) 0667 0668 if (!_showonlyFile.isEmpty()) 0669 LIST_ELEMENT("filename", _showonlyFile) 0670 0671 return availabilityElement; 0672 } // KrAction::dumpAvailability