File indexing completed on 2024-03-24 15:43:31

0001 //
0002 // C++ Implementation: ctriggereditor
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 "ctriggereditor.h"
0024 
0025 #include "cactionmanager.h"
0026 #include "cpattern.h"
0027 #include "cscripteditor.h"
0028 #include "cwindowlist.h"
0029 
0030 #include <QCheckBox>
0031 #include <QComboBox>
0032 #include <QDialog>
0033 #include <QFileDialog>
0034 #include <QGroupBox>
0035 #include <QLabel>
0036 #include <QGridLayout>
0037 #include <QHBoxLayout>
0038 #include <QLineEdit>
0039 #include <QPushButton>
0040 #include <QSpinBox>
0041 #include <QSplitter>
0042 #include <QTabWidget>
0043 #include <QTreeWidget>
0044 #include <QVBoxLayout>
0045 
0046 #include <kcolorbutton.h>
0047 #include <KLocalizedString>
0048 #include <kmessagebox.h>
0049 #include <ktextedit.h>
0050 
0051 struct cTriggerEditor::Private {
0052   // Basic
0053   QLineEdit *cmd;
0054   QComboBox *type;
0055   QLineEdit *condition;
0056   KTextEdit *rcmd;
0057   QPushButton *editregexp;
0058 
0059   // Basic - testarea
0060   QLineEdit *text;
0061   QLabel *matched, *replacement;
0062   QTreeWidget *variables;
0063 
0064   // Script
0065   cScriptEditor *script;
0066 
0067   // Options
0068   QCheckBox *check1, *check2, *check3, *check4;
0069   QComboBox *actMatched, *actNotMatched;
0070 
0071   // Colors
0072   QCheckBox *chkiscolor;
0073   QComboBox *clrtype, *fgselect, *bgselect;
0074   KColorButton *fgcolsel, *bgcolsel;
0075   QSpinBox *backrefno;
0076   QTreeWidget *colorizations;
0077 #define MAX_COLORIZATIONS 10
0078   int cnum;
0079   int fgcolor[MAX_COLORIZATIONS], bgcolor[MAX_COLORIZATIONS];
0080   QColor fgc[MAX_COLORIZATIONS], bgc[MAX_COLORIZATIONS];
0081   QString ctype[MAX_COLORIZATIONS];
0082 
0083   // Rewrite
0084   QCheckBox *chkrewrite;
0085   QComboBox *cbrewritevar;
0086   QSpinBox *rewritebackrefno;
0087   QLineEdit *edrewritetext;
0088 
0089   // Special
0090   QCheckBox *chkgag, *chknotify, *chkprompt;
0091   QCheckBox *chksound;
0092   QLineEdit *edsoundname;
0093 
0094   // Windows
0095   QCheckBox *chkwindow;
0096   QComboBox *windowlist;
0097   QCheckBox *chkgagoutput;
0098   QLineEdit *wname;
0099 };
0100 
0101 //color list
0102 QString *cltextk;
0103 // type list
0104 QString *ltype;
0105 
0106 cTriggerEditor::cTriggerEditor (QWidget *parent)
0107   : cListEditor (parent)
0108 {
0109   d = new Private;
0110 
0111   if (!cltextk) {
0112     cltextk = new QString[18];
0113     int i = 0;
0114     cltextk[i++] = i18n("Keep");
0115     cltextk[i++] = i18n("Black");
0116     cltextk[i++] = i18n("Red");
0117     cltextk[i++] = i18n("Green");
0118     cltextk[i++] = i18n("Yellow");
0119     cltextk[i++] = i18n("Blue");
0120     cltextk[i++] = i18n("Magenta");
0121     cltextk[i++] = i18n("Cyan");
0122     cltextk[i++] = i18n("Gray");
0123     cltextk[i++] = i18n("Dark gray");
0124     cltextk[i++] = i18n("Bright red");
0125     cltextk[i++] = i18n("Bright green");
0126     cltextk[i++] = i18n("Bright yellow");
0127     cltextk[i++] = i18n("Bright blue");
0128     cltextk[i++] = i18n("Bright magenta");
0129     cltextk[i++] = i18n("Bright cyan");
0130     cltextk[i++] = i18n("White");
0131     cltextk[i++] = i18n("Other");
0132   }
0133   if (!ltype) {
0134     ltype = new QString[7];
0135     int i = 0;
0136     ltype[i++] = i18n("Whole line");
0137     ltype[i++] = i18n("Matching text");
0138     ltype[i++] = i18n("Prefix");
0139     ltype[i++] = i18n("Suffix");
0140     ltype[i++] = i18n("Full prefix");
0141     ltype[i++] = i18n("Full suffix");
0142     ltype[i++] = i18n ("Backreference");
0143   }
0144 }
0145 
0146 cTriggerEditor::~cTriggerEditor ()
0147 {
0148   // the GUI elements will be destroyed automatically
0149   delete d;
0150 }
0151 
0152 void cTriggerEditor::createGUI(QWidget *parent)
0153 {
0154   QVBoxLayout *mainLayout = new QVBoxLayout (parent);
0155   QTabWidget *tabs = new QTabWidget (parent);
0156   mainLayout->addWidget (tabs);
0157 
0158   // the Basic tab
0159   QSplitter *basicTab = new QSplitter (tabs);
0160   basicTab->setOrientation (Qt::Vertical);
0161   QFrame *basicPage = new QFrame (basicTab);
0162   QGridLayout *basiclayout = new QGridLayout (basicPage);
0163 
0164   // command
0165   QLabel *cl = new QLabel (i18n ("&Trigger text"), basicPage);
0166   d->cmd = new QLineEdit (basicPage);
0167   cl->setBuddy (d->cmd);
0168   d->cmd->setWhatsThis (i18n ("Command that will be replaced if you enter it."));
0169   
0170   //comparison type
0171   QWidget *hbComboEdit = new QWidget (basicPage);
0172   QHBoxLayout *comboEditLayout = new QHBoxLayout (hbComboEdit);;
0173   comboEditLayout->setSpacing(3);
0174   QLabel *ctl = new QLabel ("&Comparison type", basicPage);
0175   d->type = new QComboBox (hbComboEdit);
0176   ctl->setBuddy (d->type);
0177   d->type->clear ();
0178   d->type->addItem (i18n ("Exact match"));
0179   d->type->addItem (i18n ("Sub-string"));
0180   d->type->addItem (i18n ("Begins with"));
0181   d->type->addItem (i18n ("Ends with"));
0182   d->type->addItem (i18n ("Regular expression"));
0183   d->type->setWhatsThis( i18n ("Type of matching. Trigger will only be activated "
0184       "if this passes this type of test. Note that triggers are always matched as whole words."));
0185   comboEditLayout->addWidget (d->type);
0186 
0187   //condition
0188   QLabel *cndl = new QLabel ("Con&dition", basicPage);
0189   d->condition = new QLineEdit (basicPage);
0190   cndl->setBuddy (d->condition);
0191   d->condition->setWhatsThis( i18n ("Conditional triggering. If this is set, the actions "
0192       "will only fire if the condition is true (that means, if it evaluates as non-zero)."));
0193 
0194    //replacement command(s)
0195   QLabel *rcl = new QLabel (i18n ("&Command(s) to send:"), basicPage);
0196   d->rcmd = new KTextEdit (basicPage);
0197   d->rcmd->setWordWrapMode (QTextOption::NoWrap);
0198   rcl->setBuddy (d->rcmd);
0199   d->rcmd->setWhatsThis( i18n ("Command(s) that will replace command you've entered."));
0200 
0201   //test area
0202   QGroupBox *testarea = new QGroupBox (i18n ("Test area"), basicTab);
0203   QGridLayout *testlayout = new QGridLayout (testarea);
0204   QLabel *textlabel = new QLabel (i18n ("&Text: "), testarea);
0205   d->text = new QLineEdit (testarea);
0206   textlabel->setBuddy (d->text);
0207   d->matched = new QLabel ("", testarea);
0208   d->replacement = new QLabel ("", testarea);
0209   d->variables = new QTreeWidget (testarea);
0210   d->variables->setHeaderLabels (QStringList() << i18n ("Name") << i18n ("Value"));
0211   d->variables->setAllColumnsShowFocus (true);
0212   d->variables->setUniformRowHeights (true);
0213   d->variables->setRootIsDecorated (false);
0214   testarea->setWhatsThis( i18n("This is testing area. You can test your trigger "
0215         "here to see if it does what you want it to do. Simply "
0216         "type in some text and see what happens."));
0217   testlayout->setSpacing (5);
0218   testlayout->addWidget (textlabel, 0, 0);
0219   testlayout->addWidget (d->text, 0, 1);
0220   testlayout->addWidget (d->matched, 1, 0, 1, 2);
0221   testlayout->addWidget (d->replacement, 2, 0, 1, 2);
0222   testlayout->addWidget (d->variables, 3, 0, 1, 2);
0223 
0224   basiclayout->setSpacing (5);
0225   basiclayout->addWidget (cl, 0, 0);
0226   basiclayout->addWidget (d->cmd, 0, 1);
0227   basiclayout->addWidget (ctl, 1, 0);
0228   basiclayout->addWidget (hbComboEdit, 1, 1);
0229   basiclayout->addWidget (cndl, 2, 0);
0230   basiclayout->addWidget (d->condition, 2, 1);
0231   basiclayout->addWidget (rcl, 3, 0);
0232   basiclayout->addWidget (d->rcmd, 4, 0, 1, 2);
0233   basiclayout->setRowStretch (4, 10);
0234 
0235   basicTab->addWidget (basicPage);
0236   basicTab->addWidget (testarea);
0237 
0238   // the Script tab
0239   QFrame *scriptPage = new QFrame (tabs);
0240   QVBoxLayout *scriptlayout = new QVBoxLayout (scriptPage);
0241   d->script = new cScriptEditor (scriptPage);
0242   scriptlayout->addWidget (d->script);
0243 
0244   // the Options tab
0245   QFrame *optionsPage = new QFrame (tabs);
0246   QVBoxLayout *optionslayout = new QVBoxLayout (optionsPage);
0247 
0248   QGroupBox *options = new QGroupBox (i18n ("&Options"), optionsPage);
0249   QGridLayout *optionsBoxLayout = new QGridLayout (options);
0250 
0251   d->check1 = new QCheckBox (i18n ("Whole words only"), options);
0252   d->check1->setWhatsThis( i18n("When enabled, this trigger will only match "
0253     "the text if there are spaces or nothing before/after the matched string."));
0254 
0255   d->check2 = new QCheckBox (i18n ("Case sensitive"), options);
0256   d->check2->setWhatsThis( i18n ("When this option is on, upper case and "
0257       "lower case letters are treated as different characters, otherwise "
0258       "they're considered to be the same."));
0259 
0260   d->check3 = new QCheckBox (i18n ("Show but do not send"), options);
0261   d->check3->setWhatsThis (i18n ("When enabled, the text will not be sent to the MUD, it will only be "
0262       "displayed on the screen."));
0263 
0264   d->check4 =  new QCheckBox (i18n ("Global matching"), options);
0265   d->check4->setWhatsThis( i18n ("<p>With global matching, one trigger/trigger can match multiple "
0266       "times, if it contains the pattern more than once. For example, if pattern is abc, "
0267       "it matches only once on abcdabcd of global matching is off, but twice if it's on. "
0268       "For each match, the requested actions are performed - so the commands can be sent "
0269       "multiple times, once per match.</p>"
0270       "<p>Note that failing the condition does not terminate scanning, so you can use "
0271       "this to highlight names from a list (using the condition to check if a match is in the "
0272       "list), or something like that."));
0273 
0274   optionsBoxLayout->addWidget (d->check1, 0, 0);
0275   optionsBoxLayout->addWidget (d->check2, 0, 1);
0276   optionsBoxLayout->addWidget (d->check3, 1, 0);
0277   optionsBoxLayout->addWidget (d->check4, 1, 1);
0278 
0279   QWidget *commonEditor = createCommonAttribEditor (optionsPage);
0280 
0281   QWidget *matcheds = new QWidget (optionsPage);
0282   QGridLayout *matchedslayout = new QGridLayout (matcheds);
0283   
0284   QLabel *m1l = new QLabel ("Action if &matched", matcheds);
0285   d->actMatched = new QComboBox (matcheds);
0286   m1l->setBuddy (d->actMatched);
0287   d->actMatched->addItem (i18n ("Continue matching"));
0288   d->actMatched->addItem (i18n ("Stop matching"));
0289   d->actMatched->addItem (i18n ("Leave group"));
0290 
0291   QLabel *m2l = new QLabel ("Action if &not matched", matcheds);
0292   d->actNotMatched = new QComboBox (matcheds);
0293   m2l->setBuddy (d->actMatched);
0294   d->actNotMatched->addItem (i18n ("Continue matching"));
0295   d->actNotMatched->addItem (i18n ("Stop matching"));
0296   d->actNotMatched->addItem (i18n ("Leave group"));
0297 
0298   matchedslayout->setSpacing (10);
0299   matchedslayout->addWidget (m1l, 0, 0);
0300   matchedslayout->addWidget (d->actMatched, 0, 1);
0301   matchedslayout->addWidget (m2l, 1, 0);
0302   matchedslayout->addWidget (d->actNotMatched, 1, 1);
0303   matchedslayout->setColumnStretch (1, 1);
0304 
0305   optionslayout->setSpacing (10);
0306   optionslayout->addWidget (options);
0307   optionslayout->addWidget (matcheds);
0308   optionslayout->addWidget (commonEditor);
0309 
0310   // the Color replacement tab
0311   // TODO: this page is very user unfriendly, improve it !!!
0312   QFrame *colorPage = new QFrame (tabs);
0313   QVBoxLayout *colorlayout = new QVBoxLayout (colorPage);
0314   
0315   d->chkiscolor = new QCheckBox (i18n ("&Enable color replacement"), colorPage);
0316   QGroupBox *colorgroup = new QGroupBox (i18n ("Color replacement"), colorPage);
0317   QVBoxLayout *colorgroupLayout = new QVBoxLayout (colorgroup);
0318 
0319   QStringList types;
0320   for (int i = 0; i < 7; i++)
0321     types.append (ltype[i]);
0322   QStringList colorlist;
0323   for (int i = 0; i < 18; i++)
0324     colorlist.append (cltextk[i]);
0325 
0326   QWidget *onecolor = new QWidget (colorgroup);
0327   QGridLayout *onecolorlayout = new QGridLayout (onecolor);
0328   onecolorlayout->setSpacing (10);
0329   d->clrtype = new QComboBox (onecolor);
0330   d->clrtype->addItems (types);
0331   d->fgselect = new QComboBox (onecolor);
0332   d->fgselect->addItems (colorlist);
0333   d->bgselect = new QComboBox (onecolor);
0334   d->bgselect->addItems (colorlist);
0335   d->fgcolsel = new KColorButton (Qt::white, onecolor);
0336   d->bgcolsel = new KColorButton (Qt::black, onecolor);
0337   d->backrefno = new QSpinBox (onecolor);
0338   d->backrefno->setRange (0, 100);
0339   QPushButton *btadd = new QPushButton (i18n ("&Add"), onecolor);
0340   QPushButton *btremove = new QPushButton (i18n ("&Remove"), onecolor);
0341   QLabel *l1 = new QLabel (i18n ("&Colorize"), onecolor);
0342   l1->setBuddy (d->clrtype);
0343   QLabel *l2 = new QLabel (i18n ("&Foreground"), onecolor);
0344   l2->setBuddy (d->fgselect);
0345   QLabel *l3 = new QLabel (i18n ("&Background"), onecolor);
0346   l3->setBuddy (d->bgselect);
0347   QLabel *l4 = new QLabel (i18n ("&Back-reference"), onecolor);
0348   l4->setBuddy (d->backrefno);
0349 
0350   onecolorlayout->addWidget (l1, 0, 0);
0351   onecolorlayout->addWidget (l2, 0, 1);
0352   onecolorlayout->addWidget (l3, 0, 2);
0353   onecolorlayout->addWidget (d->clrtype, 1, 0);
0354   onecolorlayout->addWidget (d->fgselect, 1, 1);
0355   onecolorlayout->addWidget (d->bgselect, 1, 2);
0356   onecolorlayout->addWidget (d->fgcolsel, 2, 1);
0357   onecolorlayout->addWidget (d->bgcolsel, 2, 2);
0358   onecolorlayout->addWidget (l4, 3, 0);
0359   onecolorlayout->addWidget (d->backrefno, 4, 0);
0360   onecolorlayout->addWidget (btadd, 4, 1);
0361   onecolorlayout->addWidget (btremove, 4, 2);
0362 
0363   d->colorizations = new QTreeWidget (colorgroup);
0364   d->colorizations->setHeaderLabels (QStringList() << i18n ("Type") << i18n ("Foreground") << i18n ("Background"));
0365   d->colorizations->setAllColumnsShowFocus (true);
0366   d->colorizations->setUniformRowHeights (true);
0367   d->colorizations->setRootIsDecorated (false);
0368 
0369   colorgroupLayout->addWidget (onecolor);
0370   colorgroupLayout->addWidget (d->colorizations);
0371 
0372   colorlayout->setSpacing (10);
0373   colorlayout->addWidget (d->chkiscolor);
0374   colorlayout->addWidget (colorgroup);
0375 
0376   connect (d->chkiscolor, &QCheckBox::toggled, colorgroup, &QGroupBox::setEnabled);
0377   connect (btadd, &QPushButton::clicked, this, &cTriggerEditor::addColorization);
0378   connect (btremove, &QPushButton::clicked, this, &cTriggerEditor::removeColorization);
0379   d->chkiscolor->setChecked (false);
0380   colorgroup->setEnabled (false);
0381 
0382   // the Rewrite text tab
0383   QFrame *rewritePage = new QFrame (tabs);
0384   QVBoxLayout *rewritelayout = new QVBoxLayout (rewritePage);
0385   
0386   d->chkrewrite = new QCheckBox (i18n ("Text &rewrite trigger"), rewritePage);
0387   connect (d->chkrewrite, &QCheckBox::toggled, this, &cTriggerEditor::rewriteChanged);
0388 
0389   QGroupBox *rewritegroup = new QGroupBox (i18n ("Rewrite text"), rewritePage);
0390   QGridLayout *rewritegrouplayout = new QGridLayout (rewritegroup);
0391   rewritegrouplayout->setSpacing (10);
0392 
0393   QLabel *l5 = new QLabel (i18n ("&Change this part of line:"), rewritegroup);
0394   d->cbrewritevar = new QComboBox (rewritegroup);
0395   d->cbrewritevar->addItems (types);
0396   l5->setBuddy (d->cbrewritevar);
0397   QLabel *l6 = new QLabel (i18n ("&Back-reference"), rewritegroup);
0398   d->rewritebackrefno = new QSpinBox (rewritegroup);
0399   d->rewritebackrefno->setRange (0, 100);
0400   l6->setBuddy(d->rewritebackrefno);
0401   QLabel *l7 = new QLabel (i18n ("&To this value:"), rewritegroup);
0402   d->edrewritetext = new QLineEdit (rewritegroup);
0403   l7->setBuddy (d->edrewritetext);
0404 
0405   rewritegrouplayout->addWidget (l5, 0, 0);
0406   rewritegrouplayout->addWidget (l6, 1, 0);
0407   rewritegrouplayout->addWidget (l7, 2, 0);
0408   rewritegrouplayout->addWidget (d->cbrewritevar, 0, 1);
0409   rewritegrouplayout->addWidget (d->edrewritetext, 2, 1);
0410   rewritegrouplayout->addWidget (d->rewritebackrefno, 1, 1);
0411   rewritegrouplayout->addWidget (new QWidget (rewritegroup), 3, 0);
0412   rewritegrouplayout->setRowStretch (3, 0);
0413   
0414   connect (d->chkrewrite, &QCheckBox::toggled, rewritegroup, &QGroupBox::setEnabled);
0415   d->chkrewrite->setChecked (false);
0416   rewritegroup->setEnabled (false);
0417   
0418   rewritelayout->setSpacing (10);
0419   rewritelayout->addWidget (d->chkrewrite);
0420   rewritelayout->addWidget (rewritegroup);
0421 
0422 
0423   // the Special trigger tab
0424   QFrame *specialPage = new QFrame (tabs);
0425   QGridLayout *speciallayout = new QGridLayout (specialPage);
0426   d->chkgag = new QCheckBox (i18n ("Do not show (&gag) the line"), specialPage);
0427   d->chkgag->setWhatsThis( i18n ("This will prevent the matched line "
0428       "from being displayed in the output window."));
0429   d->chknotify = new QCheckBox (i18n ("&Notify"), specialPage);
0430   d->chknotify->setWhatsThis( i18n ("This setting only takes effect if you "
0431     "have disabled the \"Always notify\" option in Global settings and "
0432     "at least one of global/local notification is enabled. It will "
0433     "activate notification if the KMuddy window and/or this session "
0434     "is not active at the moment.\nUseful if you only want to be notified "
0435     "of some events (tells, combat, ...)."));
0436 
0437   d->chkprompt = new QCheckBox (i18n ("&Prompt-detection trigger"), specialPage);
0438   d->chkprompt->setWhatsThis( i18n ("Enabling this will turn this trigger "
0439     "into a prompt detection trigger, that is, text will be passed to these "
0440     "triggers even if no newline was received, the text will be displayed "
0441     "as a prompt if the trigger gets matched, and most other options will "
0442     "NOT be taken into effect - prompt-detect trigger cannot send out "
0443     "text, gag lines, do notification. Colorization is still possible."));
0444   d->chksound = new QCheckBox (i18n ("Play s&ound file"), specialPage);
0445   d->chksound->setWhatsThis( i18n ("This trigger will play a sound. Useful "
0446     "as a notification of important events, or to assign sounds to some "
0447     "events."));
0448   d->edsoundname = new QLineEdit (specialPage);
0449   QPushButton *button = new QPushButton ("&Browse...", specialPage);
0450   connect (button, &QPushButton::clicked, this, &cTriggerEditor::browseForSoundFile);
0451 
0452   speciallayout->setSpacing (10);
0453   speciallayout->addWidget (d->chkgag, 0, 0);
0454   speciallayout->addWidget (d->chknotify, 1, 0);
0455   speciallayout->addWidget (d->chkprompt, 2, 0);
0456   speciallayout->addWidget (d->chksound, 3, 0);
0457   speciallayout->addWidget (d->edsoundname, 3, 1);
0458   speciallayout->addWidget (button, 3, 2);
0459   speciallayout->setRowStretch (4, 5);
0460 
0461   // the Output windows tab
0462   QFrame *windowPage = new QFrame (tabs);
0463   QGridLayout *windowlayout = new QGridLayout (windowPage);
0464   d->chkwindow = new QCheckBox (i18n ("Send output to a separate window"), windowPage);
0465   d->chkwindow->setWhatsThis( i18n ("This will send the matched text to a separate output window"));
0466   
0467   QGroupBox *outwindow = new QGroupBox(i18n ("Output Windows"), windowPage);
0468   QVBoxLayout *owlayout = new QVBoxLayout (outwindow);
0469   connect (d->chkwindow, &QCheckBox::toggled, outwindow, &QGroupBox::setEnabled);
0470   d->chkwindow->setChecked (false);
0471   outwindow->setEnabled (false);
0472   
0473   QLabel *wll = new QLabel("&Select window", outwindow);
0474   d->windowlist = new QComboBox(outwindow);
0475   wll->setBuddy(d->windowlist);
0476   d->windowlist->clear();
0477   
0478   d->chkgagoutput = new QCheckBox (i18n ("&Gag output in main window"), outwindow);
0479   d->chkgagoutput->setWhatsThis( i18n ("This will cause output sent to a separate window not to "
0480       "be displayed in main KMuddy session window"));
0481 
0482   QLabel *wnl = new QLabel (i18n ("&Window name"), outwindow);
0483   d->wname = new QLineEdit (outwindow);
0484   wnl->setBuddy(d->wname);
0485 
0486   QPushButton *createwindow = new QPushButton (i18n ("&Create window"), outwindow);
0487   connect (createwindow, &QPushButton::clicked, this, &cTriggerEditor::createOutputWindow);
0488 
0489   owlayout->addWidget (wll);
0490   owlayout->addWidget (d->windowlist);
0491   owlayout->addWidget (d->chkgagoutput);
0492   owlayout->addWidget (wnl);
0493   owlayout->addWidget (d->wname);
0494   owlayout->addWidget (createwindow);
0495   owlayout->addStretch ();
0496 
0497   windowlayout->setSpacing(10);
0498   windowlayout->addWidget(d->chkwindow, 0, 0);
0499   windowlayout->addWidget(outwindow, 1, 0, 1, 3);
0500 
0501 
0502   //make testarea work!
0503   connect (d->text, &QLineEdit::textChanged, this, &cTriggerEditor::updateTest);
0504   connect (d->cmd, &QLineEdit::textChanged, this, &cTriggerEditor::updateTest);
0505   connect (d->rcmd, &KTextEdit::textChanged, this, &cTriggerEditor::updateTest);
0506   connect (d->type, QOverload<int>::of(&QComboBox::activated), this, &cTriggerEditor::updateTest);
0507   connect (d->check1, &QCheckBox::toggled, this, &cTriggerEditor::updateTest);
0508   connect (d->check2, &QCheckBox::toggled, this, &cTriggerEditor::updateTest);
0509 
0510 
0511   tabs->addTab (basicTab, i18n ("&Basic"));
0512   tabs->addTab (scriptPage, i18n ("&Script"));
0513   tabs->addTab (optionsPage, i18n ("&Options"));
0514   tabs->addTab (colorPage, i18n ("Color replacement"));
0515   tabs->addTab (rewritePage, i18n ("Rewrite text"));
0516   tabs->addTab (specialPage, i18n ("Special trigger"));
0517   tabs->addTab (windowPage, i18n ("Output windows"));
0518 }
0519 
0520 void cTriggerEditor::updateTest ()
0521 {
0522   QString txt = d->text->text();
0523   // pattern used to test
0524   cPattern pattern;
0525 
0526   //set it up with dialog data
0527   pattern.setPattern (d->cmd->text ());
0528   cPattern::PatternType pt;
0529   switch (d->type->currentIndex ()) {
0530     case 0: pt = cPattern::exact; break;
0531     case 1: pt = cPattern::substring; break;
0532     case 2: pt = cPattern::begin; break;
0533     case 3: pt = cPattern::end; break;
0534     case 4: pt = cPattern::regexp; break;
0535     default: pt = cPattern::begin;
0536   }
0537   pattern.setMatching (pt);
0538   pattern.setCaseSensitive (d->check2->isChecked ());
0539 
0540   pattern.setWholeWords (d->check1->isChecked ());
0541 
0542   bool ismatch = pattern.match (txt);
0543 
0544   //write results of the matching
0545   d->variables->clear ();
0546   if (!ismatch) {
0547     d->matched->setText (i18n ("This text did not match your trigger."));
0548     d->replacement->setText ("");
0549     return;
0550   }
0551 
0552   d->matched->setText (i18n ("This text matches your trigger."));
0553   QStringList ntext = d->rcmd->toPlainText().split ("\n");
0554   QStringList::iterator it;
0555   QString nt;
0556   for (it = ntext.begin(); it != ntext.end(); ++it)
0557   {
0558     QString text = *it;
0559     pattern.expandPseudoVariables (text);
0560     nt += text + "\n  ";
0561   }
0562   
0563   QList<QTreeWidgetItem *> items;
0564   items << new QTreeWidgetItem (d->variables, QStringList() << "$matched" << pattern.getVariable ("matched"));
0565   items << new QTreeWidgetItem (d->variables, QStringList() << "$matched" << pattern.getVariable ("matched"));
0566   items << new QTreeWidgetItem (d->variables, QStringList() << "$prefix" << pattern.getVariable ("prefix"));
0567   items << new QTreeWidgetItem (d->variables, QStringList() << "$suffix" << pattern.getVariable ("suffix"));
0568   items << new QTreeWidgetItem (d->variables, QStringList() << "$prefixfull" << pattern.getVariable ("prefixfull"));
0569   items << new QTreeWidgetItem (d->variables, QStringList() << "$suffixfull" << pattern.getVariable ("suffixfull"));
0570   if (pattern.matching() == cPattern::regexp)
0571     for (int i = 0; i < pattern.getBackRefList().count(); i++)
0572       items << new QTreeWidgetItem (d->variables, QStringList() << "$"+QString::number(i) << pattern.getBackRefList()[i]);
0573   d->variables->addTopLevelItems (items);
0574 }
0575 
0576 void cTriggerEditor::addColorization ()
0577 {
0578   if (d->cnum == MAX_COLORIZATIONS)  //limit reached!
0579   {
0580     KMessageBox::error (this, i18n ("Maximum number of colorizations reached."));
0581     return;
0582   }
0583   int fg = d->fgselect->currentIndex ();
0584   int bg = d->bgselect->currentIndex ();
0585   QString varname;
0586   int t = d->clrtype->currentIndex ();
0587 
0588   switch (t) {
0589     case 0: varname = "$line"; break;
0590     case 1: varname = "$matched"; break;
0591     case 2: varname = "$prefix"; break;
0592     case 3: varname = "$suffix"; break;
0593     case 4: varname = "$prefixfull"; break;
0594     case 5: varname = "$suffixfull"; break;
0595     case 6: varname = "$"; break;
0596   };
0597   if (t == 6)
0598     varname += QString::number (d->backrefno->value ());
0599 
0600   //values are ready, fill'em in!
0601   d->fgcolor[d->cnum] = fg;
0602   d->bgcolor[d->cnum] = bg;
0603   d->fgc[d->cnum] = d->fgcolsel->color();
0604   d->bgc[d->cnum] = d->bgcolsel->color();
0605   d->ctype[d->cnum] = varname;
0606   d->cnum++;
0607   updateColorizationsList ();
0608 }
0609 
0610 void cTriggerEditor::removeColorization ()
0611 {
0612   QTreeWidgetItem *item = d->colorizations->currentItem();
0613   if (!item) return;
0614   int num = d->colorizations->indexOfTopLevelItem (item);
0615   if (num == -1) return;
0616   for (int i = num; i < d->cnum - 1; i++)
0617   {
0618     d->ctype[i] = d->ctype[i + 1];
0619     d->fgcolor[i] = d->fgcolor[i + 1];
0620     d->bgcolor[i] = d->bgcolor[i + 1];
0621     d->fgc[i] = d->fgc[i + 1];
0622     d->bgc[i] = d->bgc[i + 1];
0623   }
0624   d->cnum--;
0625   //this will also fix item numbers
0626   updateColorizationsList ();
0627 }
0628 
0629 void cTriggerEditor::updateColorizationsList ()
0630 {
0631   //erase old data
0632   d->colorizations->clear ();
0633 
0634   //now I fill in data, item by item...
0635   //for each item:
0636   for (int i = 0; i < d->cnum; i++)
0637   {
0638     QString stype, sfg, sbg;
0639 
0640     //prepare strings
0641     QString varname = d->ctype[i];
0642     if (varname == "$line")
0643       stype = ltype[0];
0644     else if (varname == "$matched")
0645       stype = ltype[1];
0646     else if ((varname == "$prefix") || (varname == "$prefixtrim"))
0647       stype = ltype[2];
0648     else if ((varname == "$suffix") || (varname == "$suffixtrim"))
0649       stype = ltype[3];
0650     else if (varname == "$prefixfull")
0651       stype = ltype[4];
0652     else if (varname == "$suffixfull")
0653       stype = ltype[5];
0654     else if (varname[0] == '$')
0655     {
0656       //now it *should* be a back-reference
0657       varname = varname.mid(1);
0658       bool ok;
0659       varname.toInt (&ok);
0660       if (ok) //back-ref -> good :)
0661         stype = ltype[6] + " " + varname;
0662       else
0663         stype = i18n ("Unknown");
0664     }
0665 
0666     //fg/bg color
0667     //custom color is displayed in #rrggbb format... we may need to invent something better
0668     int fg = d->fgcolor[i];
0669     int bg = d->bgcolor[i];
0670     sfg = (fg == 17) ? d->fgc[i].name() : cltextk[fg];
0671     sbg = (bg == 17) ? d->bgc[i].name() : cltextk[bg];
0672     
0673     //fill'em in!
0674     QTreeWidgetItem *item = new QTreeWidgetItem (QStringList() << stype << sfg << sbg);
0675     d->colorizations->addTopLevelItem (item);
0676     if (i == d->cnum - 1)  //last item shall be selected
0677       d->colorizations->setCurrentItem (item);
0678   }
0679 }
0680 
0681 void cTriggerEditor::browseForSoundFile ()
0682 {
0683   //open some file and place its name to the edit box
0684   QString fName = QFileDialog::getOpenFileName (this, i18n ("Choose sound file"), QString(), "audio/x-wav audio/mpeg audio/ogg");
0685   if (!(fName.isEmpty()))
0686     d->edsoundname->setText (fName);
0687 }
0688 
0689 void cTriggerEditor::createOutputWindow ()
0690 {
0691   QString winname;
0692   
0693   winname = d->wname->text();
0694   if(!winname.isEmpty())
0695   {
0696     cWindowList *list = dynamic_cast<cWindowList *>(cActionManager::self()->object ("windowlist", object()->list()->session()));
0697     list->add(winname);
0698     d->windowlist->clear();
0699     QStringList wlist = list->windowList();
0700     d->windowlist->addItems(wlist);
0701   }
0702   else
0703     KMessageBox::error(this, i18n("Window name is empty!"));
0704 }
0705 
0706 void cTriggerEditor::rewriteChanged (bool val)
0707 {
0708   if (val) {
0709     d->check4->setChecked (false);
0710     d->check4->setEnabled (false);
0711   }
0712   else {
0713     d->check4->setEnabled (true);
0714   }
0715 }
0716 
0717 
0718 void cTriggerEditor::fillGUI (const cListObjectData &data)
0719 {
0720   // Common attributes
0721   fillCommonAttribEditor (data);
0722 
0723   // Basic
0724   d->cmd->setText (data.strValue ("pattern"));
0725   d->type->setCurrentIndex (data.intValue ("matching"));
0726   d->condition->setText (data.strValue ("condition"));
0727   QStringList newtext;
0728   for (int i = 1; i <= data.intValue ("newtext-count"); ++i)
0729     newtext << data.strValue ("newtext-" + QString::number (i));
0730   d->rcmd->setPlainText (newtext.join("\n"));
0731 
0732   // Script
0733   d->script->setText (data.strValue ("script"));
0734 
0735   // Options
0736   d->check1->setChecked (data.boolValue ("whole-words"));
0737   d->check2->setChecked (data.boolValue ("cs"));
0738   d->check3->setChecked (data.boolValue ("dont-send"));
0739   d->check4->setChecked (data.boolValue ("global"));
0740   d->actMatched->setCurrentIndex (data.intValue ("action-matched"));
0741   d->actNotMatched->setCurrentIndex (data.intValue ("action-not-matched"));
0742 
0743   // Colors
0744   d->chkiscolor->setChecked (data.boolValue ("colorize"));
0745   d->cnum = 0;
0746   if (d->chkiscolor->isChecked()) {
0747     d->cnum = data.intValue ("colorize-count");
0748     for (int i = 0; i < d->cnum; i++) {
0749       if (i >= MAX_COLORIZATIONS) break;  // FIXME: limits are bad
0750       d->ctype[i] = data.strValue ("colorize-variable-"+QString::number(i+1));
0751       int fg = data.intValue ("colorize-fg-"+QString::number(i+1));
0752       int bg = data.intValue ("colorize-bg-"+QString::number(i+1));
0753       if (fg == 0)
0754         d->fgcolor[i] = 0;
0755       else if (fg > 0) {  // RGB
0756         d->fgcolor[i] = 17;
0757         fg--;
0758         d->fgc[i].setBlue (fg % 256);
0759         fg /= 256;
0760         d->fgc[i].setGreen (fg % 256);
0761         fg /= 256;
0762         d->fgc[i].setRed (fg % 256);
0763       } else  // ANSI
0764         d->fgcolor[i] = fg + 17;
0765       if (bg == 0)
0766         d->bgcolor[i] = 0;
0767       else if (bg > 0) {  // RGB
0768         d->bgcolor[i] = 17;
0769         bg--;
0770         d->bgc[i].setBlue (bg % 256);
0771         bg /= 256;
0772         d->bgc[i].setGreen (bg % 256);
0773         bg /= 256;
0774         d->bgc[i].setRed (bg % 256);
0775       } else  // ANSI
0776         d->bgcolor[i] = bg + 17;
0777     }
0778   }
0779   updateColorizationsList ();
0780 
0781   // Rewrite
0782   d->chkrewrite->setChecked (data.boolValue ("rewrite"));
0783   d->edrewritetext->setText (data.strValue ("rewrite-text"));
0784   QString varname = data.strValue ("rewrite-var");
0785   bool ok = false;
0786   int number = varname.toInt (&ok);
0787   if (ok) {
0788     d->cbrewritevar->setCurrentIndex (6);
0789     d->rewritebackrefno->setValue (number);
0790   } else {
0791     int item = -1;
0792     if (varname == "line") item = 0;
0793     else if (varname == "matched") item = 1;
0794     else if ((varname == "prefix") || (varname == "prefixtrim")) item = 2;
0795     else if ((varname == "suffix") || (varname == "suffixtrim")) item = 3;
0796     else if (varname == "prefixfull") item = 4;
0797     else if (varname == "suffixfull") item = 5;
0798     d->cbrewritevar->setCurrentIndex (item);
0799     d->rewritebackrefno->setValue (0);
0800   }
0801 
0802   // Special
0803   d->chkgag->setChecked (data.boolValue ("gag"));
0804   d->chknotify->setChecked (data.boolValue ("notify"));
0805   d->chkprompt->setChecked (data.boolValue ("prompt"));
0806   d->chksound->setChecked (data.boolValue ("sound"));
0807   d->edsoundname->setText (data.strValue ("sound-file"));
0808 
0809   // Output windows
0810   d->chkwindow->setChecked (data.boolValue ("output-window"));
0811   d->chkgagoutput->setChecked (data.boolValue ("output-gag-in-main"));
0812   d->windowlist->clear();
0813   cWindowList *list = dynamic_cast<cWindowList *>(cActionManager::self()->object ("windowlist", object()->list()->session()));
0814   if (list) {
0815     QStringList wlist = list->windowList();
0816     d->windowlist->addItems(wlist);
0817     d->windowlist->setCurrentIndex (wlist.indexOf (data.strValue ("output-window-name")));
0818   }
0819 
0820 }
0821 
0822 void cTriggerEditor::getDataFromGUI (cListObjectData *data)
0823 {
0824   // Comon attributes
0825   getDataFromCommonAttribEditor (data);
0826 
0827   // Basic
0828   data->strValues["pattern"] = d->cmd->text();
0829   data->intValues["matching"] = d->type->currentIndex();
0830   data->strValues["condition"] = d->condition->text();
0831 
0832   QStringList ntext = d->rcmd->toPlainText().split ("\n");
0833   data->intValues["newtext-count"] = ntext.size();
0834   QStringList::iterator it;
0835   int i;
0836   for (it = ntext.begin(), i = 1; it != ntext.end(); ++i, ++it)
0837     data->strValues["newtext-" + QString::number (i)] = *it;
0838 
0839   // Script
0840   data->strValues["script"] = d->script->text();
0841 
0842   // Options
0843   data->boolValues["whole-words"] = d->check1->isChecked();
0844   data->boolValues["cs"] = d->check2->isChecked();
0845   data->boolValues["dont-send"] = d->check3->isChecked();
0846   data->boolValues["global"] = d->check4->isChecked();
0847   data->intValues["action-matched"] = d->actMatched->currentIndex();
0848   data->intValues["action-not-matched"] = d->actNotMatched->currentIndex();
0849 
0850   // Colors
0851   data->boolValues["colorize"] = d->chkiscolor->isChecked();
0852   if (d->chkiscolor->isChecked()) {
0853     data->intValues["colorize-count"] = d->cnum;
0854     for (int i = 0; i < d->cnum; i++) {
0855       int fg = d->fgcolor[i];
0856       if (fg == 17) {  // RGB
0857         fg = d->fgc[i].red() * 256 * 256 + d->fgc[i].green() * 256 + d->fgc[i].blue()+ 1;
0858       } else if (fg > 0) fg -= 17;
0859       int bg = d->bgcolor[i];
0860       if (bg == 17) {  // RGB
0861         bg = d->bgc[i].red() * 256 * 256 + d->bgc[i].green() * 256 + d->bgc[i].blue()+ 1;
0862       } else if (bg > 0) bg -= 17;
0863       data->intValues["colorize-fg-"+QString::number(i+1)] = fg;
0864       data->intValues["colorize-bg-"+QString::number(i+1)] = bg;
0865       data->strValues["colorize-variable-"+QString::number(i+1)] = d->ctype[i];
0866     }
0867   }
0868 
0869   // Rewrite
0870   data->boolValues["rewrite"] = d->chkrewrite->isChecked ();
0871   data->strValues["rewrite-text"] = d->edrewritetext->text();
0872   QString varname;
0873   switch (d->cbrewritevar->currentIndex ())
0874   {
0875     case 0: varname = "line"; break;
0876     case 1: varname = "matched"; break;
0877     case 2: varname = "prefix"; break;
0878     case 3: varname = "suffix"; break;
0879     case 4: varname = "prefixfull"; break;
0880     case 5: varname = "suffixfull"; break;
0881     case 6: varname = QString::number (d->rewritebackrefno->value()); break;
0882   }
0883   data->strValues["rewrite-var"] = varname;
0884 
0885   // Special
0886   data->boolValues["gag"] = d->chkgag->isChecked ();
0887   data->boolValues["notify"] = d->chknotify->isChecked ();
0888   data->boolValues["prompt"] = d->chkprompt->isChecked ();
0889   data->boolValues["sound"] = d->chksound->isChecked ();
0890   data->strValues["sound-file"] = d->edsoundname->text ();
0891 
0892   // Output windows
0893   data->boolValues["output-window"] = d->chkwindow->isChecked ();
0894   data->boolValues["output-gag-in-main"] = d->chkgagoutput->isChecked();
0895   data->strValues["output-window-name"] = d->windowlist->currentText();
0896 
0897 }
0898 
0899 #include "moc_ctriggereditor.cpp"