File indexing completed on 2024-04-21 15:08:21

0001 //
0002 // C++ Implementation: clistgroup
0003 //
0004 // Description: 
0005 //
0006 /*
0007 Copyright 2007-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 "clistgroup.h"
0024 
0025 #include "clist.h"
0026 #include "clistmanager.h"
0027 
0028 #include <KLocalizedString>
0029 
0030 #include <QXmlStreamReader>
0031 #include <QXmlStreamWriter>
0032 
0033 struct cListGroup::Private {
0034   QString tag;
0035   int objectCount;
0036   std::list<cListObject *> objects;
0037   std::list<cListObject *> priorityList;
0038 };
0039 
0040 cListGroup::cListGroup (cList *list) : cListObject (list)
0041 {
0042   d = new Private;
0043   d->objectCount = 0;
0044 }
0045 
0046 cListGroup::~cListGroup()
0047 {
0048   delete d;
0049 }
0050 
0051 void cListGroup::addObject (cListObject *obj)
0052 {
0053   list()->notifyAdding (this, objectCount());
0054   d->objects.push_back (obj);
0055   generatePriorityList ();
0056   list()->addDone();
0057 }
0058 
0059 void cListGroup::removeObject (cListObject *obj)
0060 {
0061   list()->notifyRemoving (obj);
0062   d->objects.remove (obj);
0063   generatePriorityList ();
0064   list()->removeDone ();
0065 }
0066 
0067 void cListGroup::objectChanged (cListObject *)
0068 {
0069   generatePriorityList ();
0070 }
0071 
0072 const std::list<cListObject *> *cListGroup::objectList ()
0073 {
0074   return &d->objects;
0075 }
0076 
0077 const std::list<cListObject *> *cListGroup::priorityList ()
0078 {
0079   return &d->priorityList;
0080 }
0081 
0082 void cListGroup::updateVisibleName ()
0083 {
0084   setVisibleName (name());
0085 }
0086 
0087 void cListGroup::setTag (const QString &tag)
0088 {
0089   d->tag = tag;
0090 }
0091 
0092 QString cListGroup::tag ()
0093 {
0094   return d->tag;
0095 }
0096 
0097 cListObject *cListGroup::objectAt (int pos)
0098 {
0099   std::list<cListObject *>::iterator it = d->objects.begin();
0100   for (int p = 0; p < pos; ++p) ++it;
0101   if (it == d->objects.end()) return nullptr;   // hit end of list - no such object
0102   return *it;
0103 }
0104 
0105 int cListGroup::objectPosition (cListObject *obj)
0106 {
0107   int pos = 0;
0108   std::list<cListObject *>::iterator it;
0109   for (it = d->objects.begin(); it != d->objects.end(); ++it) {
0110     if (*it == obj) return pos;
0111     pos++;
0112   }
0113   return -1;  // not found
0114 }
0115 
0116 void cListGroup::moveObjectUp (int pos)
0117 {
0118   cListObject *obj = objectAt (pos);
0119   if (!obj) return;
0120   moveObjectToPosition (obj, pos - 1);
0121 }
0122 
0123 void cListGroup::moveObjectDown (int pos)
0124 {
0125   cListObject *obj = objectAt (pos);
0126   if (!obj) return;
0127   moveObjectToPosition (obj, pos + 1);
0128 }
0129 
0130 void cListGroup::moveObjectToPosition (cListObject *obj, int pos)
0131 {
0132   if (pos < 0) return;
0133   if (pos >= objectCount()) return;
0134 
0135   removeObject (obj); // need full removal with resorting, so that the model stays valid
0136 
0137   list()->notifyAdding (this, pos);
0138   std::list<cListObject *>::iterator it = d->objects.begin(), it2;
0139   for (int p = 0; p < pos; ++p) ++it;   // move to position
0140   d->objects.insert (it, obj);   // and insert the object there
0141   generatePriorityList ();
0142   list()->addDone();
0143   list()->notifyChanged (obj);
0144 }
0145 
0146 int cListGroup::objectCount () const
0147 {
0148   return d->objectCount;
0149 }
0150 
0151 bool cListGroup::compareObjects (cListObject *a, cListObject *b)
0152 {
0153   if (a->priority() != b->priority())
0154     return (a->priority() > b->priority());  // higher priority goes first
0155   return (a->positionInGroup() < b->positionInGroup());   // same priority - base ordering on position
0156 }
0157 
0158 void cListGroup::generatePriorityList ()
0159 {
0160   // recompute object positions
0161   std::list<cListObject *>::iterator it;
0162   int pos = 0;
0163   for (it = d->objects.begin(), pos = 0; it != d->objects.end(); ++it, ++pos)
0164     (*it)->setPositionInGroup (pos);
0165 
0166   // also fix object count
0167   d->objectCount = d->objects.size();
0168 
0169   // recompute priorities
0170   d->priorityList.clear ();
0171   d->priorityList = d->objects;
0172   d->priorityList.sort (compareObjects);
0173 
0174   for (it = d->priorityList.begin(), pos = 0; it != d->priorityList.end(); ++it, ++pos)
0175     (*it)->setPriorityInGroup (pos);
0176 }
0177 
0178 cList::TraverseAction cListGroup::traverse (int traversalType)
0179 {
0180   if (!enabled()) return cList::Continue;
0181 
0182   // create a copy of the priority list
0183   // this makes things slower, but it's necessary, as the callback could alter the list
0184   // TODO: implement some flag that would disable this behaviour for callbacks that do not alter the list ?
0185   // TODO: or perhaps simply prohibit such callbacks ?
0186   std::list<cListObject *> pl = d->priorityList;
0187   std::list<cListObject *>::iterator it;
0188   cListManager *lm = cListManager::self();
0189   for (it = pl.begin(); it != pl.end(); ++it) {
0190     cListObject *obj = *it;
0191     if (!lm->objectId (obj)) continue;  // object doesn't exist anymore ? skip it
0192     if (!obj->enabled()) continue; // object not enabled - continue
0193     cList::TraverseAction act = obj->traverse (traversalType);
0194     // we must stop - so stop
0195     if (act == cList::Stop) return cList::Stop;
0196     // we must leave the group - do so    
0197     if (act == cList::LeaveGroup) break;
0198   }
0199   // we're done here, tell the parent to continue
0200   return cList::Continue;
0201 }
0202 
0203 void cListGroup::load (QXmlStreamReader *reader)
0204 {
0205   setEnabled (true);
0206   setPriority (DEFAULT_OBJECT_PRIORITY);  // revert priority to default
0207 
0208   QString en = reader->attributes().value ("enabled").toString();
0209   if ((!en.isEmpty()) && (en.toLower() == "false"))
0210     setEnabled (false);
0211   QString pri = reader->attributes().value ("priority").toString();
0212   if (!pri.isEmpty()) {
0213     int p = pri.toInt();
0214     if (p) setPriority (p);
0215   }
0216 
0217   // okay, now traverse child tags, if any
0218   while (!reader->atEnd()) {
0219     reader->readNext ();
0220     // Error ? Break out.
0221     if (reader->hasError()) break;
0222     // we're done with the tag
0223     if (reader->isEndElement() && (reader->name() == "group")) break;
0224     if (!reader->isStartElement()) continue;  // anything else than start of element - ignore it and continue with the next
0225     if (reader->name() == "group") {
0226       // a new group
0227       QString name = reader->attributes().value ("name").toString();
0228       if (name.isEmpty()) {
0229         reader->raiseError (i18n ("Error in file - group with no name."));
0230         return;
0231       }
0232       if (list()->group (name)) {
0233         reader->raiseError (i18n ("Error in file - duplicate group name."));
0234         return;
0235       }
0236       cListGroup *g = list()->addGroup (this, name);
0237       g->load (reader);
0238     } else if (reader->name() == "object") {
0239       // a new object
0240       cListObject *obj = list()->newObject();
0241       list()->addToGroup (this, obj);
0242       // set object name, if any
0243       QString name = reader->attributes().value ("name").toString();
0244       if (!name.isEmpty())
0245         list()->setObjectName (obj, name);
0246       // and load other parameters
0247       obj->load (reader);
0248     }
0249   }
0250 }
0251 
0252 void cListGroup::save (QXmlStreamWriter *writer)
0253 {
0254   writer->writeStartElement ("group");
0255 
0256   writer->writeAttribute ("name", name());
0257   if (!enabled())
0258     writer->writeAttribute ("enabled", "false");
0259   if (priority() != DEFAULT_OBJECT_PRIORITY)
0260     writer->writeAttribute ("priority", QString::number (priority()));
0261 
0262   // save child elements
0263   std::list<cListObject *>::iterator it;
0264   for (it = d->objects.begin(); it != d->objects.end(); ++it)
0265     (*it)->save (writer);
0266 
0267   writer->writeEndElement ();  // end the group element
0268 }
0269 
0270