File indexing completed on 2024-04-14 14:32:17

0001 //
0002 // C++ Implementation: caliaseditor
0003 //
0004 // Description: 
0005 //
0006 /*
0007 Copyright 2002-2011 Tomas Mecir <kmuddy@kmuddy.com>
0008 
0009 This program is free software; you can redistribute it and/or
0010 modify it under the terms of the GNU General Public License as
0011 published by the Free Software Foundation; either version 2 of 
0012 the License, or (at your option) any later version.
0013 
0014 This program is distributed in the hope that it will be useful,
0015 but WITHOUT ANY WARRANTY; without even the implied warranty of
0016 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
0017 GNU General Public License for more details.
0018 
0019 You should have received a copy of the GNU General Public License
0020 along with this program.  If not, see <http://www.gnu.org/licenses/>.
0021 */
0022 
0023 #include "caliaseditor.h"
0024 
0025 #include "cpattern.h"
0026 #include "cscripteditor.h"
0027 
0028 #include <QCheckBox>
0029 #include <QComboBox>
0030 #include <QDialog>
0031 #include <QGridLayout>
0032 #include <QGroupBox>
0033 #include <QLabel>
0034 #include <QLineEdit>
0035 #include <QPushButton>
0036 #include <QSplitter>
0037 #include <QTabWidget>
0038 #include <QTreeWidget>
0039 #include <QVBoxLayout>
0040 
0041 #include <KLocalizedString>
0042 #include <KTextEdit>
0043 
0044 struct cAliasEditor::Private {
0045   // Basic
0046   QLineEdit *cmd;
0047   QComboBox *type;
0048   QLineEdit *condition;
0049   KTextEdit *rcmd;
0050 
0051   // Basic - testarea
0052   QLineEdit *text;
0053   QLabel *matched, *replacement;
0054   QTreeWidget *variables;
0055 
0056   // Script
0057   cScriptEditor *script;
0058 
0059   // Options
0060   QCheckBox *check1, *check2, *check3, *check4, *check5;
0061 };
0062 
0063 cAliasEditor::cAliasEditor (QWidget *parent)
0064   : cListEditor (parent)
0065 {
0066   d = new Private;
0067 }
0068 
0069 cAliasEditor::~cAliasEditor ()
0070 {
0071   // the GUI elements will be destroyed automatically
0072   delete d;
0073 }
0074 
0075 void cAliasEditor::createGUI(QWidget *parent)
0076 {
0077   QVBoxLayout *mainLayout = new QVBoxLayout (parent);
0078   QTabWidget *tabs = new QTabWidget (parent);
0079   mainLayout->addWidget (tabs);
0080 
0081   // the Basic tab
0082   QSplitter *basicTab = new QSplitter (tabs);
0083   basicTab->setOrientation (Qt::Vertical);
0084   QFrame *basicPage = new QFrame (basicTab);
0085   QGridLayout *basiclayout = new QGridLayout (basicPage);
0086 
0087   // command
0088   QLabel *cl = new QLabel (i18n ("&Alias text"), basicPage);
0089   d->cmd = new QLineEdit (basicPage);
0090   cl->setBuddy (d->cmd);
0091   d->cmd->setWhatsThis (i18n ("Command that will be replaced if you enter it."));
0092   
0093   //comparison type
0094   QWidget *hbComboEdit = new QWidget (basicPage);
0095   QHBoxLayout *comboEditLayout = new QHBoxLayout (hbComboEdit);;
0096   comboEditLayout->setSpacing(3);
0097   QLabel *ctl = new QLabel ("&Comparison type", basicPage);
0098   d->type = new QComboBox (hbComboEdit);
0099   ctl->setBuddy (d->type);
0100   d->type->clear ();
0101   d->type->addItem (i18n ("Exact match"));
0102   d->type->addItem (i18n ("Sub-string"));
0103   d->type->addItem (i18n ("Begins with"));
0104   d->type->addItem (i18n ("Ends with"));
0105   d->type->addItem (i18n ("Regular expression"));
0106   d->type->setWhatsThis( i18n ("Type of matching. Alias will only be activated "
0107       "if this passes this type of test. Note that aliases are always matched as whole words."));
0108   comboEditLayout->addWidget (d->type);
0109 
0110   //condition
0111   QLabel *cndl = new QLabel ("Con&dition", basicPage);
0112   d->condition = new QLineEdit (basicPage);
0113   cndl->setBuddy (d->condition);
0114   d->condition->setWhatsThis( i18n ("Conditional triggering. If this is set, the actions "
0115       "will only fire if the condition is true (that means, if it evaluates as non-zero)."));
0116 
0117    //replacement command(s)
0118   QLabel *rcl = new QLabel (i18n ("&Replacement text(s)"), basicPage);
0119   d->rcmd = new KTextEdit (basicPage);
0120   d->rcmd->setWordWrapMode (QTextOption::NoWrap);
0121   rcl->setBuddy (d->rcmd);
0122   d->rcmd->setWhatsThis( i18n ("Command(s) that will replace command you have entered."));
0123 
0124   //test area
0125   QGroupBox *testarea = new QGroupBox (i18n ("Test area"), basicTab);
0126   QGridLayout *testlayout = new QGridLayout (testarea);
0127   QLabel *textlabel = new QLabel (i18n ("&Text: "), testarea);
0128   d->text = new QLineEdit (testarea);
0129   textlabel->setBuddy (d->text);
0130   d->matched = new QLabel ("", testarea);
0131   d->replacement = new QLabel ("", testarea);
0132   d->variables = new QTreeWidget (testarea);
0133   d->variables->setHeaderLabels (QStringList() << i18n ("Name") << i18n ("Value"));
0134   d->variables->setAllColumnsShowFocus (true);
0135   d->variables->setUniformRowHeights (true);
0136   d->variables->setRootIsDecorated (true);
0137   testarea->setWhatsThis( i18n("This is testing area. You can test your alias "
0138         "here to see if it does what you want it to do. Simply "
0139         "type in some text and see what happens."));
0140   testlayout->setSpacing (5);
0141   testlayout->addWidget (textlabel, 0, 0);
0142   testlayout->addWidget (d->text, 0, 1);
0143   testlayout->addWidget (d->matched, 1, 0, 1, 2);
0144   testlayout->addWidget (d->replacement, 2, 0, 1, 2);
0145   testlayout->addWidget (d->variables, 3, 0, 1, 2);
0146 
0147   basiclayout->setSpacing (5);
0148   basiclayout->addWidget (cl, 0, 0);
0149   basiclayout->addWidget (d->cmd, 0, 1);
0150   basiclayout->addWidget (ctl, 1, 0);
0151   basiclayout->addWidget (hbComboEdit, 1, 1);
0152   basiclayout->addWidget (cndl, 2, 0);
0153   basiclayout->addWidget (d->condition, 2, 1);
0154   basiclayout->addWidget (rcl, 3, 0);
0155   basiclayout->addWidget (d->rcmd, 4, 0, 1, 2);
0156   basiclayout->setRowStretch (4, 10);
0157 
0158   basicTab->addWidget (basicPage);
0159   basicTab->addWidget (testarea);
0160 
0161   // the Script tab
0162   QFrame *scriptPage = new QFrame (tabs);
0163   QVBoxLayout *scriptlayout = new QVBoxLayout (scriptPage);
0164   d->script = new cScriptEditor (scriptPage);
0165   scriptlayout->addWidget (d->script);
0166 
0167   // the Options tab
0168   QFrame *optionsPage = new QFrame (tabs);
0169   QVBoxLayout *optionslayout = new QVBoxLayout (optionsPage);
0170 
0171   QGroupBox *options = new QGroupBox (i18n ("&Options"), optionsPage);
0172   QGridLayout *optionsBoxLayout = new QGridLayout (options);
0173 
0174   d->check1 = new QCheckBox (i18n ("Send original command"), options);
0175   d->check1->setWhatsThis( i18n ("If this alias matches your command, "
0176         "a replacement command will be sent. If you enable this option, "
0177         "both original and replacement commands are sent (original command "
0178         "is sent first)."));
0179 
0180   d->check2 = new QCheckBox (i18n ("Whole words only"), options);
0181   d->check2->setWhatsThis( i18n("When enabled, this alias will only match "
0182     "the text if there are spaces or nothing before/after the matched string."));
0183 
0184   d->check3 = new QCheckBox (i18n ("Case sensitive"), options);
0185   d->check3->setWhatsThis( i18n ("When this option is on, upper case and "
0186       "lower case letters are treated as different characters, otherwise "
0187       "they're considered to be the same."));
0188 
0189   d->check4 = new QCheckBox (i18n ("Include prefix/suffix"), options);
0190   d->check4->setWhatsThis (i18n ("Prefix/suffix of matched text "
0191       "will be automatically appended to the expanded text."));
0192 
0193   d->check5 = new QCheckBox (i18n ("Global matching"), options);
0194   d->check5->setWhatsThis( i18n ("<p>With global matching, one alias/trigger can match multiple "
0195       "times, if it contains the pattern more than once. For example, if pattern is abc, "
0196       "it matches only once on abcdabcd of global matching is off, but twice if it is on. "
0197       "For each match, the requested actions are performed - so the commands can be sent "
0198       "multiple times, once per match.</p>"
0199       "<p>Note that failing the condition doesn't terminate scanning, so you can use "
0200       "this to highlight names from a list (using the condition to check if a match is in the "
0201       "list), or something like that."));
0202 
0203   optionsBoxLayout->addWidget (d->check1, 0, 1);
0204   optionsBoxLayout->addWidget (d->check2, 0, 0);
0205   optionsBoxLayout->addWidget (d->check3, 1, 0);
0206   optionsBoxLayout->addWidget (d->check4, 1, 1);
0207   optionsBoxLayout->addWidget (d->check5, 2, 0);
0208 
0209   QWidget *commonEditor = createCommonAttribEditor (optionsPage);
0210 
0211   optionslayout->setSpacing (10);
0212   optionslayout->addWidget (options);
0213   optionslayout->addWidget (commonEditor);
0214 
0215 
0216   //make testarea work!
0217   connect (d->text, &QLineEdit::textChanged, this, &cAliasEditor::updateTest);
0218   connect (d->cmd, &QLineEdit::textChanged, this, &cAliasEditor::updateTest);
0219   connect (d->rcmd, &KTextEdit::textChanged, this, &cAliasEditor::updateTest);
0220   connect (d->type, QOverload<int>::of(&QComboBox::activated), this, &cAliasEditor::updateTest);
0221   connect (d->check3, &QCheckBox::toggled, this, &cAliasEditor::updateTest);
0222   connect (d->check2, &QCheckBox::toggled, this, &cAliasEditor::updateTest);
0223   connect (d->check4, &QCheckBox::toggled, this, &cAliasEditor::updateTest);
0224 
0225 
0226   tabs->addTab (basicTab, i18n ("&Basic"));
0227   tabs->addTab (scriptPage, i18n ("&Script"));
0228   tabs->addTab (optionsPage, i18n ("&Options"));
0229 }
0230 
0231 void cAliasEditor::updateTest ()
0232 {
0233   QString txt = d->text->text();
0234   // pattern used to test
0235   cPattern pattern;
0236 
0237   //set it up with dialog data
0238   pattern.setPattern (d->cmd->text ());
0239   cPattern::PatternType pt;
0240   switch (d->type->currentIndex ()) {
0241     case 0: pt = cPattern::exact; break;
0242     case 1: pt = cPattern::substring; break;
0243     case 2: pt = cPattern::begin; break;
0244     case 3: pt = cPattern::end; break;
0245     case 4: pt = cPattern::regexp; break;
0246     default: pt = cPattern::begin;
0247   }
0248   pattern.setMatching (pt);
0249   pattern.setCaseSensitive (d->check3->isChecked ());
0250 
0251   pattern.setWholeWords (d->check2->isChecked ());
0252 
0253   bool prefixsuffix = d->check4->isChecked ();
0254 
0255   bool ismatch = pattern.match (txt);
0256 
0257   //write results of the matching
0258   d->variables->clear ();
0259   if (!ismatch) {
0260     d->matched->setText (i18n ("This text did not match your alias."));
0261     d->replacement->setText ("");
0262     return;
0263   }
0264 
0265   d->matched->setText (i18n ("This text matches your alias."));
0266   QStringList ntext = d->rcmd->toPlainText().split ("\n");
0267   QString nt;
0268   QStringList::iterator it;
0269   //we cannot use QStringList::join because of prefix/suffix stuff
0270   for (it = ntext.begin(); it != ntext.end(); ++it)
0271   {
0272     QString text = *it;
0273     pattern.expandPseudoVariables (text);
0274     if (prefixsuffix)
0275       text = pattern.getPrefix() + text + pattern.getSuffix();
0276     nt += text + "\n  ";
0277   }
0278   
0279   d->replacement->setText (i18n ("Command: ") + nt);
0280   QList<QTreeWidgetItem *> items;
0281   items << new QTreeWidgetItem (d->variables, QStringList() << "$matched" << pattern.getVariable ("matched"));
0282   items << new QTreeWidgetItem (d->variables, QStringList() << "$matched" << pattern.getVariable ("matched"));
0283   items << new QTreeWidgetItem (d->variables, QStringList() << "$prefix" << pattern.getVariable ("prefix"));
0284   items << new QTreeWidgetItem (d->variables, QStringList() << "$suffix" << pattern.getVariable ("suffix"));
0285   items << new QTreeWidgetItem (d->variables, QStringList() << "$prefixfull" << pattern.getVariable ("prefixfull"));
0286   items << new QTreeWidgetItem (d->variables, QStringList() << "$suffixfull" << pattern.getVariable ("suffixfull"));
0287   if (pattern.matching() == cPattern::regexp)
0288     for (int i = 0; i < pattern.getBackRefList().count(); i++)
0289       items << new QTreeWidgetItem (d->variables, QStringList() << "$"+QString::number(i) << pattern.getBackRefList()[i]);
0290   d->variables->addTopLevelItems (items);
0291 }
0292 
0293 
0294 void cAliasEditor::fillGUI (const cListObjectData &data)
0295 {
0296   // Common attributes
0297   fillCommonAttribEditor (data);
0298 
0299   // Basic
0300   d->cmd->setText (data.strValue ("pattern"));
0301   d->type->setCurrentIndex (data.intValue ("matching"));
0302   d->condition->setText (data.strValue ("condition"));
0303   QStringList newtext;
0304   for (int i = 1; i <= data.intValue ("newtext-count"); ++i)
0305     newtext << data.strValue ("newtext-" + QString::number (i));
0306   d->rcmd->setPlainText (newtext.join("\n"));
0307 
0308   // Script
0309   d->script->setText (data.strValue ("script"));
0310 
0311   // Options
0312 
0313   d->check1->setChecked (data.boolValue ("orig"));
0314   d->check2->setChecked (data.boolValue ("whole-words"));
0315   d->check3->setChecked (data.boolValue ("cs"));
0316   d->check4->setChecked (data.boolValue ("prefix-suffix"));
0317   d->check5->setChecked (data.boolValue ("global"));
0318 }
0319 
0320 void cAliasEditor::getDataFromGUI (cListObjectData *data)
0321 {
0322   // Comon attributes
0323   getDataFromCommonAttribEditor (data);
0324 
0325   // Basic
0326   data->strValues["pattern"] = d->cmd->text();
0327   data->intValues["matching"] = d->type->currentIndex();
0328   data->strValues["condition"] = d->condition->text();
0329 
0330   QStringList ntext = d->rcmd->toPlainText().split ("\n");
0331   data->intValues["newtext-count"] = ntext.size();
0332   QStringList::iterator it; int i;
0333   for (i = 1, it = ntext.begin(); it != ntext.end(); ++i, ++it)
0334     data->strValues["newtext-" + QString::number (i)] = *it;
0335 
0336   // Script
0337   data->strValues["script"] = d->script->text();
0338 
0339   // Options
0340   data->boolValues["orig"] = d->check1->isChecked();
0341   data->boolValues["whole-words"] = d->check2->isChecked();
0342   data->boolValues["cs"] = d->check3->isChecked();
0343   data->boolValues["prefix-suffix"] = d->check4->isChecked();
0344   data->boolValues["global"] = d->check5->isChecked();
0345 }
0346 
0347 #include "moc_caliaseditor.cpp"