File indexing completed on 2024-04-14 04:00:08

0001 //
0002 // C++ Implementation: clisteditor
0003 //
0004 // Description: list editor widget - base class
0005 //
0006 /*
0007 Copyright 2008-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 "clisteditor.h"
0024 #include "clist.h"
0025 #include "clistmanager.h"
0026 
0027 #include <QLabel>
0028 #include <QCheckBox>
0029 #include <QPushButton>
0030 #include <QSpinBox>
0031 #include <QVBoxLayout>
0032 
0033 #include <KLocalizedString>
0034 #include <kmessagebox.h>
0035 #include <klineedit.h>
0036 
0037 struct cListEditor::Private {
0038   cListObject *obj;
0039   int objNum;
0040   cListObjectData data;      // data from the object
0041   cListObjectData guiData;   // data, as filled into the GUI
0042 
0043   // GUI elements of the common attrib editor
0044   QSpinBox *edpriority;
0045   QCheckBox *chkenabled;
0046   KLineEdit *edname;
0047 
0048   QWidget *centralBar;
0049   bool guiCreated;
0050   bool saving;
0051 };
0052 
0053 cListEditor::cListEditor (QWidget *parent)
0054   : QWidget (parent)
0055 {
0056   d = new Private;
0057   d->objNum = 0;
0058   d->obj = nullptr;
0059   d->guiCreated = false;
0060   d->saving = false;
0061 
0062   // set our policy to expanding, and give us a grid layout.
0063   QSizePolicy qsp (QSizePolicy::Expanding, QSizePolicy::Expanding);
0064   setSizePolicy (qsp);
0065   QVBoxLayout *layout = new QVBoxLayout (this);
0066   layout->setSpacing (5);
0067 
0068   d->centralBar = new QWidget (this);
0069   d->centralBar->setSizePolicy (qsp);
0070   QWidget *buttonBar = new QWidget (this);
0071   QHBoxLayout *buttonLayout = new QHBoxLayout (buttonBar);
0072   buttonLayout->setSpacing (20);
0073   buttonLayout->setAlignment (Qt::AlignCenter);
0074 
0075   QPushButton *saveButton = new QPushButton (i18n ("&Apply changes"), buttonBar);
0076   QPushButton *undoButton = new QPushButton (i18n ("&Undo changes"), buttonBar);
0077   connect (saveButton, &QPushButton::clicked, this, &cListEditor::saveClicked);
0078   connect (undoButton, &QPushButton::clicked, this, &cListEditor::undoClicked);
0079   
0080   layout->addWidget (d->centralBar);
0081   layout->addWidget (buttonBar);
0082   // row 1 is fixed, row 0 will grow to fill the available space.
0083   layout->setStretchFactor (d->centralBar, 1);
0084   buttonLayout->addWidget (saveButton);
0085   buttonLayout->addWidget (undoButton);
0086 }
0087 
0088 cListEditor::~cListEditor ()
0089 {
0090   delete d;
0091 }
0092 
0093 void cListEditor::setObject (cListObject *obj)
0094 {
0095   if (d->obj) {
0096     disconnect (d->obj, &cListObject::changed, this, &cListEditor::objectChanged);
0097     d->obj = nullptr;
0098   }
0099 
0100   if (!obj) return;
0101   if (!d->guiCreated)
0102   {
0103     d->guiCreated = true;
0104     createGUI (d->centralBar);
0105   }
0106 
0107   d->obj = obj;
0108   d->objNum = cListManager::self()->objectId (obj);
0109   connect (d->obj, &cListObject::changed, this, &cListEditor::objectChanged);
0110   loadDataFromObject ();
0111   fillGUI (d->data);
0112 }
0113 
0114 cListObject *cListEditor::object ()
0115 {
0116   return d->obj;
0117 }
0118 
0119 void cListEditor::objectChanged (cListObject *obj)
0120 {
0121   if (d->saving) return;  // ignore events triggered by our saving
0122   if (obj != d->obj) return;   // this should never happen
0123 
0124   // okay, so merge in the changes
0125   // we have three lists - original object data, new object data, and data from the dialog
0126   // we replace original data with new data except where something changed in the dialog
0127   cListObjectData oldData = d->data;
0128   loadDataFromObject ();
0129   getDataFromGUI (&d->guiData);
0130 
0131   oldData.name = (d->guiData.name == oldData.name) ? d->data.name : d->guiData.name;
0132   oldData.priority = (d->guiData.priority == oldData.priority) ? d->data.priority : d->guiData.priority;
0133   oldData.enabled = (d->guiData.enabled == oldData.enabled) ? d->data.enabled : d->guiData.enabled;
0134   std::map<QString, int>::iterator it1;
0135   for (it1 = d->guiData.intValues.begin(); it1 != d->guiData.intValues.end(); ++it1)
0136     oldData.intValues[it1->first] = (it1->second == oldData.intValues[it1->first]) ? d->data.intValues[it1->first] : it1->second;
0137   std::map<QString, QString>::iterator it2;
0138   for (it2 = d->guiData.strValues.begin(); it2 != d->guiData.strValues.end(); ++it2)
0139     oldData.strValues[it2->first] = (it2->second == oldData.strValues[it2->first]) ? d->data.strValues[it2->first] : it2->second;
0140   std::map<QString, bool>::iterator it3;;
0141   for (it3 = d->guiData.boolValues.begin(); it3 != d->guiData.boolValues.end(); ++it3)
0142     oldData.boolValues[it3->first] = (it3->second == oldData.boolValues[it3->first]) ? d->data.boolValues[it3->first] : it3->second;
0143 
0144   fillGUI (oldData);
0145 }
0146 
0147 bool cListEditor::objectValid ()
0148 {
0149   if (!d->obj) return false;
0150   return (cListManager::self()->objectId (d->obj) != 0);
0151 }
0152 
0153 void cListEditor::getGUIData ()
0154 {
0155   // set some sane default, in case that getDataFromGUI doesn't fill something in
0156   d->guiData.name = d->data.name;
0157   d->guiData.enabled = d->data.enabled;
0158   d->guiData.priority = d->data.priority;
0159   d->guiData.intValues.clear();
0160   d->guiData.strValues.clear();
0161   d->guiData.boolValues.clear();
0162   getDataFromGUI (&d->guiData);
0163 }
0164 
0165 bool cListEditor::changed ()
0166 {
0167   if (!objectValid()) return false;
0168 
0169   // retrieve data
0170   getGUIData ();
0171   cListObject *obj = d->obj;
0172 
0173   // compare data
0174   if (d->guiData.name != obj->name()) return true;
0175   if (d->guiData.priority != obj->priority()) return true;
0176   if (d->guiData.enabled != obj->enabled()) return true;
0177   std::map<QString, int>::iterator it1;
0178   for (it1 = d->guiData.intValues.begin(); it1 != d->guiData.intValues.end(); ++it1)
0179     if (obj->intVal (it1->first) != it1->second)
0180       return true;
0181   std::map<QString, QString>::iterator it2;
0182   for (it2 = d->guiData.strValues.begin(); it2 != d->guiData.strValues.end(); ++it2)
0183     if (obj->strVal (it2->first) != it2->second)
0184       return true;
0185   std::map<QString, bool>::iterator it3;;
0186   for (it3 = d->guiData.boolValues.begin(); it3 != d->guiData.boolValues.end(); ++it3)
0187     if (obj->boolVal (it3->first) != it3->second)
0188       return true;
0189   return false;  // no difference
0190 }
0191 
0192 void cListEditor::saveChanges ()
0193 {
0194   getGUIData ();
0195   saveDataToObject ();
0196   // update our internal data, so that subsequent attempts to undo restore
0197   // the current status
0198   loadDataFromObject ();
0199 }
0200 
0201 void cListEditor::saveClicked ()
0202 {
0203   saveChanges ();
0204 }
0205 
0206 void cListEditor::undoClicked ()
0207 {
0208   // TODO: ask the user if he really means it
0209   fillGUI (d->data);
0210 }
0211 
0212 QWidget *cListEditor::createCommonAttribEditor (QWidget *parent)
0213 {
0214   QWidget *widget = new QWidget (parent);
0215   QGridLayout *layout = new QGridLayout (widget);
0216   layout->setSpacing (5);
0217   d->chkenabled = new QCheckBox (i18n ("&Enabled"), widget);
0218   d->edpriority = new QSpinBox (widget);
0219   d->edpriority->setRange (1, 1000);
0220   d->edname = new KLineEdit (widget);
0221   d->edname->setValidator (new QRegExpValidator (QRegExp("^[0-9A-Za-z_ ]+$"), this));
0222   QLabel *plabel = new QLabel (i18n("&Priority"), widget);
0223   plabel->setBuddy (d->edpriority);
0224   QLabel *label = new QLabel (i18n("&Name"), widget);
0225   label->setBuddy (d->edname);
0226   layout->addWidget (d->chkenabled, 0, 0, 1, 2);
0227   layout->addWidget (plabel, 1, 0);
0228   layout->addWidget (d->edpriority, 1, 1);
0229   layout->addWidget (label, 2, 0);
0230   layout->addWidget (d->edname, 2, 1);
0231   return widget;
0232 }
0233 
0234 void cListEditor::fillCommonAttribEditor (const cListObjectData &data)
0235 {
0236   d->chkenabled->setChecked (data.enabled);
0237   d->edname->setText (data.name);
0238   d->edpriority->setValue (data.priority);
0239 }
0240 
0241 void cListEditor::getDataFromCommonAttribEditor (cListObjectData *data)
0242 {
0243   data->enabled = d->chkenabled->isChecked ();
0244   data->name = d->edname->text();
0245   data->priority = d->edpriority->value ();
0246 }
0247 
0248 
0249 void cListEditor::loadDataFromObject ()
0250 {
0251   if (!objectValid()) return;
0252   d->data = d->obj->data();
0253 
0254   // add default property values
0255   const std::map<QString, cListProperty> props = d->obj->list()->getPropertyList ();
0256   std::map<QString, cListProperty>::const_iterator it;
0257   for (it = props.begin(); it != props.end(); ++it) {
0258     switch (it->second.type) {
0259       case Int:
0260         if (d->data.intValues.count (it->second.name)) break;  // we have a value
0261         // no value - assign default
0262         d->data.intValues[it->second.name] = it->second.defIntValue;
0263         break;
0264       case String:
0265         if (d->data.strValues.count (it->second.name)) break;  // we have a value
0266         // no value - assign default
0267         d->data.strValues[it->second.name] = it->second.defStrValue;
0268         break;
0269       case Bool:
0270         if (d->data.boolValues.count (it->second.name)) break;  // we have a value
0271         // no value - assign default
0272         d->data.boolValues[it->second.name] = it->second.defBoolValue;
0273         break;
0274     };
0275   }
0276 }
0277 
0278 void cListEditor::saveDataToObject ()
0279 {
0280   cListObject *obj = d->obj;
0281   d->saving = true;
0282   if (d->guiData.name != obj->name()) {
0283     if (obj->isGroup()) {
0284       cListGroup *g = obj->list()->group (d->guiData.name);
0285       if (g) {
0286         KMessageBox::error (this, i18n ("Cannot rename the group, as a group with this name already exists."));
0287         return;
0288       }
0289       obj->list()->renameGroup ((cListGroup *) obj, d->guiData.name);
0290     } else {
0291       cListObject *o = obj->list()->getObject (d->guiData.name);
0292       if (o) {
0293         KMessageBox::error (this, i18n ("Cannot rename the object, as an object with this name already exists."));
0294         return;
0295       }
0296       obj->list()->setObjectName (obj, d->guiData.name);
0297     }
0298   }
0299   if (d->guiData.priority != obj->priority())
0300     obj->setPriority (d->guiData.priority);
0301   if (d->guiData.enabled != obj->enabled())
0302     obj->setEnabled (d->guiData.enabled);
0303 
0304   std::map<QString, int>::iterator it1;
0305   for (it1 = d->guiData.intValues.begin(); it1 != d->guiData.intValues.end(); ++it1)
0306     obj->setInt (it1->first, it1->second);
0307   std::map<QString, QString>::iterator it2;
0308   for (it2 = d->guiData.strValues.begin(); it2 != d->guiData.strValues.end(); ++it2)
0309     obj->setStr (it2->first, it2->second);
0310   std::map<QString, bool>::iterator it3;;
0311   for (it3 = d->guiData.boolValues.begin(); it3 != d->guiData.boolValues.end(); ++it3)
0312     obj->setBool (it3->first, it3->second);
0313   d->saving = false;
0314 }
0315 
0316 #include "moc_clisteditor.cpp"