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

0001 //
0002 // C++ Implementation: clistmanager
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 "clistmanager.h"
0024 
0025 #include "clist.h"
0026 #include "cprofilemanager.h"
0027 
0028 #include <map>
0029 
0030 #include <QDebug>
0031 #include <QDir>
0032 #include <QFile>
0033 #include <QStandardItemModel>
0034 #include <QXmlStreamReader>
0035 #include <QXmlStreamWriter>
0036 
0037 
0038 using namespace std;
0039 
0040 struct cListManager::Private {
0041   map<QString, cList *(*)()> listTypes;
0042   map<QString, QStandardItem *> modelItems;
0043   map<int, map<QString, cList *> > lists;
0044   QStandardItemModel *model;
0045   map<int, cListObject *> objects;
0046   map<cListObject *, int> objectIDs;
0047   int maxObjectID;
0048 };
0049 
0050 cListManager *cListManager::_self = nullptr;
0051 
0052 cListManager *cListManager::self()
0053 {
0054   if (!_self)
0055     _self = new cListManager;
0056   return _self;
0057 }
0058 
0059 cListManager::cListManager () : cActionBase ("listmanager", 0)
0060 {
0061   d = new Private;
0062   d->model = new QStandardItemModel;
0063   d->maxObjectID = 0;
0064  
0065   // properly react on session connect/disconnect
0066   addEventHandler ("profile-init", 5, PT_STRING);
0067   addEventHandler ("profile-load", 5, PT_STRING);
0068   addEventHandler ("disconnected", 5, PT_NOTHING);
0069   addEventHandler ("save", 20, PT_NOTHING);
0070 }
0071 
0072 cListManager::~cListManager ()
0073 {
0074   removeEventHandler ("profile-init");
0075   removeEventHandler ("profile-load");
0076   removeEventHandler ("disconnected");
0077   removeEventHandler ("save");
0078 
0079   delete d->model;
0080   delete d;
0081 }
0082 
0083 void cListManager::eventNothingHandler (QString event, int session)
0084 {
0085   if (event == "disconnected") {
0086     // these will get called for both profile and non-profile sessions -
0087     // for the latter, they'll simply do nothing
0088     cProfileManager::self()->unassignSession (sess());
0089     removeSession (session);
0090   }
0091   if (event == "save") {
0092     saveAll (session);
0093   }
0094 }
0095 
0096 
0097 void cListManager::eventStringHandler (QString event, int session, QString &par1, const QString &)
0098 {
0099   if (event == "profile-init") {
0100     // tie the session to the profile
0101     cProfileManager::self()->assignSession (session, par1);
0102   }
0103   if (event == "profile-load") {
0104     // load all the lists
0105     addSession (session);
0106   }
0107 }
0108 
0109 void cListManager::registerType (const QString &name, const QString &visibleName, cList *(*factory)())
0110 {
0111   // type already registered - do nothing
0112   if (d->listTypes.count (name))
0113     return;
0114   d->listTypes[name] = factory;
0115 
0116   // add the type to the model
0117   QStandardItem *item = new QStandardItem (visibleName);
0118   item->setData (name);  // remember real name
0119   d->modelItems[name] = item;
0120   d->model->invisibleRootItem()->appendRow (item);
0121   d->model->sort (0);
0122 
0123   // create the object in every existing session
0124   // this will ensure that data will be loaded, events hooked, and so on
0125   map<int, map<QString, cList *> >::iterator it;
0126   for (it = d->lists.begin(); it != d->lists.end(); ++it)
0127     getList (it->first, name);
0128 }
0129 
0130 void cListManager::unregisterType (const QString &name)
0131 {
0132   // delete all lists of this type
0133   map<int, map<QString, cList *> >::iterator it;
0134   for (it = d->lists.begin(); it != d->lists.end(); ++it) {
0135     if (it->second.count (name)) {
0136       saveList (it->first, it->second[name]);
0137       delete it->second[name];
0138       it->second.erase (name);
0139     }
0140   }
0141 
0142   // unregister the type
0143   d->listTypes.erase (name);
0144   if (d->modelItems.count (name))
0145     delete d->modelItems[name];
0146   d->modelItems.erase (name);
0147 }
0148   
0149 QStandardItemModel *cListManager::typeModel () const
0150 {
0151   return d->model;
0152 }
0153 
0154 cList *cListManager::getList (int sessId, const QString &name)
0155 {
0156   if (!d->lists.count (sessId)) return nullptr;  // session must exist
0157   if (!d->listTypes.count (name)) return nullptr;  // type must be registered
0158   if (d->lists[sessId].count (name))
0159     return d->lists[sessId][name];  // list exists - return it
0160 
0161   // list doesn't exist yet - create it
0162   cList *list = d->listTypes[name]();  // call the list factory
0163   list->initRootGroup ();
0164   d->lists[sessId][name] = list;
0165   list->setSession (sessId);  // set list's session ID
0166 
0167   // also load list contents
0168   loadList (sessId, list);
0169 
0170   return list;
0171 }
0172 
0173 void cListManager::addSession (int sessId)
0174 {
0175   if (d->lists.count (sessId)) return;  // already exists
0176   map<QString, cList *> empty;
0177   d->lists[sessId] = empty;
0178 
0179   // create every registered list in this session
0180   // this will ensure that data will be loaded, events hooked, and so on
0181   map<QString, cList *(*)()>::iterator it;
0182   for (it = d->listTypes.begin(); it != d->listTypes.end(); ++it)
0183     getList (sessId, it->first);
0184 }
0185 
0186 void cListManager::removeSession (int sessId)
0187 {
0188   if (!d->lists.count (sessId)) return;
0189   map<QString, cList *>::iterator it;
0190   for (it = d->lists[sessId].begin(); it != d->lists[sessId].end(); ++it) {
0191     saveList (sessId, it->second);
0192     it->second->clear ();  // remove all elements from the list
0193     delete it->second;
0194   }
0195   d->lists.erase (sessId);
0196 }
0197 
0198 int cListManager::registerObject (cListObject *obj)
0199 {
0200   int id = objectId (obj);
0201   if (id) return id;  // already registered
0202   id = ++d->maxObjectID;  // generate new object ID
0203   d->objectIDs[obj] = id;
0204   d->objects[id] = obj;
0205   return id;
0206 }
0207 
0208 void cListManager::unregisterObject (cListObject *obj)
0209 {
0210   int id = objectId (obj);
0211   if (!id) return;  // not registered
0212   d->objectIDs.erase (obj);
0213   d->objects.erase (id);
0214 }
0215 
0216 int cListManager::objectId (cListObject *obj) const
0217 {
0218   if (d->objectIDs.count (obj))
0219     return d->objectIDs[obj];
0220   return 0;
0221 }
0222 
0223 cListObject *cListManager::object (int id) const
0224 {
0225   if (d->objects.count (id))
0226     return d->objects[id];
0227   return nullptr;
0228 }
0229 
0230 void cListManager::loadList (int sessId, cList *list)
0231 {
0232   // load the list contents
0233   cProfileManager *pm = cProfileManager::self();
0234   
0235   QString path = pm->profilePath (sessId);
0236   QDir dir = QDir (path);
0237   if (!dir.exists()) QDir::root().mkpath (dir.absolutePath());
0238 
0239   QString fName = list->name() + ".xml";
0240 
0241   QFile f (path + "/" + fName);
0242   if (!f.open(QIODevice::ReadOnly | QIODevice::Text)) {
0243     qDebug() << "No " << fName << " file - nothing to do.";
0244     list->listLoaded ();  // mark the list as loaded
0245     return;  // no profiles - nothing to do
0246   }
0247 
0248   QXmlStreamReader *reader = new QXmlStreamReader (&f);
0249   list->load (reader);
0250 
0251   f.close ();
0252   delete reader;
0253 }
0254 
0255 void cListManager::saveList (int sessId, cList *list)
0256 {
0257   if (!list) return;
0258 
0259   // save the list contents
0260   cProfileManager *pm = cProfileManager::self();
0261 
0262   QString path = pm->profilePath (sessId);
0263   QDir dir = QDir (path);
0264   if (!dir.exists()) QDir::root().mkpath (dir.absolutePath());
0265 
0266   dir.remove (list->name() + ".backup");
0267   QString fName = list->name() + ".xml";
0268   if (!QFile(path + "/" + fName).copy (path + "/" + list->name() + ".backup")) {
0269     qDebug() << "Unable to backup " << fName;  // not fatal, may simply not exist
0270   }
0271 
0272   QFile f (path + "/" + fName);
0273   if (!f.open(QIODevice::WriteOnly | QIODevice::Truncate | QIODevice::Text)) {
0274     qDebug() << "Unable to open " << (path + "/" + fName) << " for writing.";
0275     return;  // problem
0276   }
0277 
0278   QXmlStreamWriter *writer = new QXmlStreamWriter (&f);
0279   list->save (writer);
0280 
0281   f.close ();
0282   delete writer;
0283 }
0284 
0285 void cListManager::saveAll (int sessId)
0286 {
0287   map<QString, cList *(*)()>::iterator it;
0288   for (it = d->listTypes.begin(); it != d->listTypes.end(); ++it)
0289     saveList (sessId, getList (sessId, it->first));
0290 }
0291 
0292 
0293