File indexing completed on 2025-01-12 06:47:27
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