lib

property.cpp

00001 /* This file is part of the KDE project
00002    Copyright (C) 2004 Cedric Pasteur <cedric.pasteur@free.fr>
00003    Copyright (C) 2004 Alexander Dymo <cloudtemple@mskat.net>
00004    Copyright (C) 2004-2006 Jaroslaw Staniek <js@iidea.pl>
00005 
00006    This library is free software; you can redistribute it and/or
00007    modify it under the terms of the GNU Library General Public
00008    License as published by the Free Software Foundation; either
00009    version 2 of the License, or (at your option) any later version.
00010 
00011    This library is distributed in the hope that it will be useful,
00012    but WITHOUT ANY WARRANTY; without even the implied warranty of
00013    MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
00014    Library General Public License for more details.
00015 
00016    You should have received a copy of the GNU Library General Public License
00017    along with this library; see the file COPYING.LIB.  If not, write to
00018    the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor,
00019  * Boston, MA 02110-1301, USA.
00020 */
00021 
00022 #include "property.h"
00023 #include "customproperty.h"
00024 #include "set.h"
00025 #include "factory.h"
00026 
00027 #include <kdebug.h>
00028 
00029 #include <qobject.h>
00030 #include <qptrdict.h>
00031 #include <qasciidict.h>
00032 #include <qguardedptr.h>
00033 
00034 namespace KoProperty {
00035 
00036 QT_STATIC_CONST_IMPL Property Property::null;
00037 
00039 class PropertyPrivate
00040 {
00041     public:
00042         PropertyPrivate()
00043         : caption(0), listData(0), changed(false), storable(true), 
00044          readOnly(false), visible(true),
00045          autosync(-1), custom(0), useCustomProperty(true),
00046          sets(0), parent(0), children(0), relatedProperties(0),
00047          sortingKey(0)
00048         {
00049         }
00050 
00051         inline void setCaptionForDisplaying(const QString& captionForDisplaying)
00052         {
00053             delete caption;
00054             if (captionForDisplaying.simplifyWhiteSpace()!=captionForDisplaying)
00055                 caption = new QString(captionForDisplaying.simplifyWhiteSpace());
00056             else
00057                 caption = 0;
00058             this->captionForDisplaying = captionForDisplaying;
00059         }
00060 
00061         ~PropertyPrivate()
00062         {
00063             delete caption;
00064             caption = 0;
00065             delete listData;
00066             delete children;
00067             delete relatedProperties;
00068             delete custom;
00069             delete sets;
00070         }
00071 
00072     int type;
00073     QCString name;
00074     QString captionForDisplaying;
00075     QString* caption;
00076     QString description;
00077     QVariant value;
00078     QVariant oldValue;
00080     Property::ListData* listData;
00081 //  QMap<QString, QVariant> *valueList;
00082     QString icon;
00083 
00084     bool changed : 1;
00085     bool storable : 1;
00086     bool readOnly : 1;
00087     bool visible : 1;
00088     int autosync;
00089     QMap<QCString, QVariant> options;
00090 
00091     CustomProperty *custom;
00093     bool useCustomProperty;
00094 
00096     QGuardedPtr<Set> set;
00098     QPtrDict< QGuardedPtr<Set> > *sets;
00099 //  QValueList<Set*>  sets;
00100 
00101     Property  *parent;
00102     QValueList<Property*>  *children;
00104     QValueList<Property*>  *relatedProperties;
00105 
00106     int sortingKey;
00107 };
00108 }
00109 
00110 using namespace KoProperty;
00111 
00113 
00114 Property::ListData::ListData(const QStringList& keys_, const QStringList& names_)
00115  : names(names_)
00116 // , fixed(true)
00117 {
00118     setKeysAsStringList(keys_);
00119 }
00120 
00121 Property::ListData::ListData(const QValueList<QVariant> keys_, const QStringList& names_)
00122  : keys(keys_), names(names_)
00123 // , fixed(true)
00124 {
00125 }
00126 
00127 Property::ListData::ListData()
00128 // : fixed(true)
00129 {
00130 }
00131 
00132 Property::ListData::~ListData()
00133 {
00134 }
00135 
00136 void Property::ListData::setKeysAsStringList(const QStringList& list)
00137 {
00138     keys.clear();
00139     for (QStringList::ConstIterator it = list.constBegin(); it!=list.constEnd(); ++it) {
00140         keys.append(*it);
00141     }
00142 }
00143 
00144 QStringList Property::ListData::keysAsStringList() const
00145 {
00146     QStringList result;
00147     for (QValueList<QVariant>::ConstIterator it = keys.constBegin(); it!=keys.constEnd(); ++it) {
00148         result.append((*it).toString());
00149     }
00150     return result;
00151 }
00152 
00154 
00155 /*
00156 KOPROPERTY_EXPORT QMap<QString, QVariant>
00157 KoProperty::createValueListFromStringLists(const QStringList &keys, const QStringList &values)
00158 {
00159     QMap<QString, QVariant> map;
00160     if(keys.count() != values.count())
00161         return map;
00162 
00163     QStringList::ConstIterator valueIt = values.begin();
00164     QStringList::ConstIterator endIt = keys.constEnd();
00165     for(QStringList::ConstIterator it = keys.begin(); it != endIt; ++it, ++valueIt)
00166         map.insert( *it, *valueIt);
00167 
00168     return map;
00169 }
00170 */
00171 
00172 
00173 Property::Property(const QCString &name, const QVariant &value,
00174     const QString &caption, const QString &description,
00175     int type, Property* parent)
00176  : d( new PropertyPrivate() )
00177 {
00178     d->name = name;
00179     d->setCaptionForDisplaying(caption);
00180     d->description = description;
00181 
00182     if(type == Auto)
00183         d->type = value.type();
00184     else
00185         d->type = type;
00186 
00187     d->custom = FactoryManager::self()->createCustomProperty(this);
00188 
00189     if (parent)
00190         parent->addChild(this);
00191     setValue(value, false);
00192 }
00193 
00194 Property::Property(const QCString &name, const QStringList &keys, const QStringList &strings,
00195     const QVariant &value, const QString &caption, const QString &description, 
00196     int type, Property* parent)
00197  : d( new PropertyPrivate() )
00198 {
00199     d->name = name;
00200     d->setCaptionForDisplaying(caption);
00201     d->description = description;
00202     d->type = type;
00203     setListData(keys, strings);
00204 
00205     d->custom = FactoryManager::self()->createCustomProperty(this);
00206 
00207     if (parent)
00208         parent->addChild(this);
00209     setValue(value, false);
00210 }
00211 
00212 Property::Property(const QCString &name, ListData* listData, 
00213     const QVariant &value, const QString &caption, const QString &description, 
00214     int type, Property* parent)
00215  : d( new PropertyPrivate() )
00216 {
00217     d->name = name;
00218     d->setCaptionForDisplaying(caption);
00219     d->description = description;
00220     d->type = type;
00221     d->listData = listData;
00222 
00223     d->custom = FactoryManager::self()->createCustomProperty(this);
00224 
00225     if (parent)
00226         parent->addChild(this);
00227     setValue(value, false);
00228 }
00229 
00230 Property::Property()
00231  : d( new PropertyPrivate() )
00232 {
00233 }
00234 
00235 Property::Property(const Property &prop)
00236  : d( new PropertyPrivate() )
00237 {
00238     *this = prop;
00239 }
00240 
00241 Property::~Property()
00242 {
00243     delete d;
00244     d = 0;
00245 }
00246 
00247 QCString
00248 Property::name() const
00249 {
00250     return d->name;
00251 }
00252 
00253 void
00254 Property::setName(const QCString &name)
00255 {
00256     d->name = name;
00257 }
00258 
00259 QString
00260 Property::caption() const
00261 {
00262     return d->caption ? *d->caption : d->captionForDisplaying;
00263 }
00264 
00265 QString
00266 Property::captionForDisplaying() const
00267 {
00268     return d->captionForDisplaying;
00269 }
00270 
00271 void
00272 Property::setCaption(const QString &caption)
00273 {
00274     d->setCaptionForDisplaying(caption);
00275 }
00276 
00277 QString
00278 Property::description() const
00279 {
00280     return d->description;
00281 }
00282 
00283 void
00284 Property::setDescription(const QString &desc)
00285 {
00286     d->description = desc;
00287 }
00288 
00289 int
00290 Property::type() const
00291 {
00292     return d->type;
00293 }
00294 
00295 void
00296 Property::setType(int type)
00297 {
00298     d->type = type;
00299 }
00300 
00301 QString
00302 Property::icon() const
00303 {
00304     return d->icon;
00305 }
00306 
00307 void
00308 Property::setIcon(const QString &icon)
00309 {
00310     d->icon = icon;
00311 }
00312 
00313 QVariant
00314 Property::value() const
00315 {
00316     if(d->custom && d->custom->handleValue())
00317         return d->custom->value();
00318     return d->value;
00319 }
00320 
00321 QVariant
00322 Property::oldValue() const
00323 {
00324 /*  if(d->oldValue.isNull())
00325         return value();
00326     else*/
00327         return d->oldValue;
00328 }
00329 
00330 void
00331 Property::setValue(const QVariant &value, bool rememberOldValue, bool useCustomProperty)
00332 {
00333     if (d->name.isEmpty()) {
00334         kopropertywarn << "Property::setValue(): COULD NOT SET value to a null property" << endl;
00335         return;
00336     }
00337     QVariant currentValue = this->value();
00338     const QVariant::Type t = currentValue.type();
00339     const QVariant::Type newt = value.type();
00340 //  kopropertydbg << d->name << " : setValue('" << value.toString() << "' type=" << type() << ")" << endl;
00341     if (t != newt && !currentValue.isNull() && !value.isNull()
00342          && !( (t==QVariant::Int && newt==QVariant::UInt)
00343                || (t==QVariant::UInt && newt==QVariant::Int)
00344                || (t==QVariant::CString && newt==QVariant::String)
00345                || (t==QVariant::String && newt==QVariant::CString)
00346                || (t==QVariant::ULongLong && newt==QVariant::LongLong)
00347                || (t==QVariant::LongLong && newt==QVariant::ULongLong)
00348          )) {
00349         kopropertywarn << "Property::setValue(): INCOMPATIBLE TYPES! old=" << currentValue 
00350             << " new=" << value << endl;
00351     }
00352 
00353     //1. Check if the value should be changed
00354     bool ch;
00355     if (t == QVariant::DateTime
00356         || t == QVariant::Time) {
00357         //for date and datetime types: compare with strings, because there
00358         //can be miliseconds difference
00359         ch = (currentValue.toString() != value.toString());
00360     }
00361     else if (t == QVariant::String || t==QVariant::CString) {
00362         //property is changed for string type,
00363         //if one of value is empty and other isn't..
00364         ch = ( (currentValue.toString().isEmpty() != value.toString().isEmpty())
00365         //..or both are not empty and values differ
00366             || (!currentValue.toString().isEmpty() && !value.toString().isEmpty() && currentValue != value) );
00367     }
00368     else if (t == QVariant::Invalid && newt == QVariant::Invalid)
00369         ch = false;
00370     else
00371         ch = (currentValue != value);
00372 
00373     if (!ch)
00374         return;
00375 
00376     //2. Then change it, and store old value if necessary
00377     if(rememberOldValue) {
00378         if(!d->changed)
00379             d->oldValue = currentValue;
00380         d->changed = true;
00381     }
00382     else {
00383         d->oldValue = QVariant(); // clear old value
00384         d->changed = false;
00385     }
00386     QVariant prevValue;
00387     if(d->custom && useCustomProperty) {
00388         d->custom->setValue(value, rememberOldValue);
00389         prevValue = d->custom->value();
00390     }
00391     else
00392         prevValue = currentValue;
00393 
00394     if (!d->custom || !useCustomProperty || !d->custom->handleValue())
00395         d->value = value;
00396 
00397     emitPropertyChanged(); // called as last step in this method!
00398 }
00399 
00400 void
00401 Property::resetValue()
00402 {
00403     d->changed = false;
00404     bool cleared = false;
00405     if (d->set)
00406         d->set->informAboutClearing(cleared); //inform me about possibly clearing the property sets
00407     setValue(oldValue(), false);
00408     if (cleared)
00409         return; //property set has been cleared: no further actions make sense as 'this' is dead
00410 
00411     // maybe parent  prop is also unchanged now
00412     if(d->parent && d->parent->value() == d->parent->oldValue())
00413         d->parent->d->changed = false;
00414 
00415     if (d->sets) {
00416         for (QPtrDictIterator< QGuardedPtr<Set> > it(*d->sets); it.current(); ++it) {
00417             if (it.current()) //may be destroyed in the meantime
00418                 emit (*it.current())->propertyReset(**it.current(), *this);
00419         }
00420     }
00421     else if (d->set) {
00422         emit d->set->propertyReset(*d->set, *this);
00423     }
00424 }
00425 
00426 //const QMap<QString, QVariant>*
00427 Property::ListData*
00428 Property::listData() const
00429 {
00430     return d->listData;
00431 }
00432 
00433 void
00434 Property::setListData(ListData* list) //const QMap<QString, QVariant> &list)
00435 {
00436 //  if(!d->valueList)
00437 //      d->valueList = new QMap<QString, QVariant>();
00438     if (list == d->listData)
00439         return;
00440     delete d->listData;
00441     d->listData = list;
00442 }
00443 
00444 void
00445 Property::setListData(const QStringList &keys, const QStringList &names)
00446 {
00447     ListData* list = new ListData(keys, names);
00448     setListData(list);
00449 
00450 //  if(!d->valueList)
00451 //      d->valueList = new QMap<QString, QVariant>();
00452 //  *(d->valueList) = createValueListFromStringLists(keys, values);
00453 }
00454 
00456 
00457 bool
00458 Property::isNull() const
00459 {
00460     return d->name.isEmpty();
00461 }
00462 
00463 bool
00464 Property::isModified() const
00465 {
00466     return d->changed;
00467 }
00468 
00469 void
00470 Property::clearModifiedFlag()
00471 {
00472     d->changed = false;
00473 }
00474 
00475 bool
00476 Property::isReadOnly() const
00477 {
00478     return d->readOnly;
00479 }
00480 
00481 void
00482 Property::setReadOnly(bool readOnly)
00483 {
00484     d->readOnly = readOnly;
00485 }
00486 
00487 bool
00488 Property::isVisible() const
00489 {
00490     return d->visible;
00491 }
00492 
00493 void
00494 Property::setVisible(bool visible)
00495 {
00496     d->visible = visible;
00497 }
00498 
00499 int
00500 Property::autoSync() const
00501 {
00502     return d->autosync;
00503 }
00504 
00505 void
00506 Property::setAutoSync(int sync)
00507 {
00508     d->autosync = sync;
00509 }
00510 
00511 bool
00512 Property::isStorable() const
00513 {
00514     return d->storable;
00515 }
00516 
00517 void
00518 Property::setStorable(bool storable)
00519 {
00520     d->storable = storable;
00521 }
00522 
00523 void
00524 Property::setOption(const char* name, const QVariant& val)
00525 {
00526     d->options[name] = val;
00527 }
00528 
00529 QVariant
00530 Property::option(const char* name) const
00531 {
00532     if (d->options.contains(name))
00533         return d->options[name];
00534     return QVariant();
00535 }
00536 
00537 bool
00538 Property::hasOptions() const
00539 {
00540     return !d->options.isEmpty();
00541 }
00542 
00544 
00545 Property::operator bool () const
00546 {
00547     return !isNull();
00548 }
00549 
00550 const Property&
00551 Property::operator= (const QVariant& val)
00552 {
00553     setValue(val);
00554     return *this;
00555 }
00556 
00557 const Property&
00558 Property::operator= (const Property &property)
00559 {
00560     if(&property == this)
00561         return *this;
00562 
00563     if(d->listData) {
00564         delete d->listData;
00565         d->listData = 0;
00566     }
00567     if(d->children) {
00568         delete d->children;
00569         d->children = 0;
00570     }
00571     if(d->relatedProperties) {
00572         delete d->relatedProperties;
00573         d->relatedProperties = 0;
00574     }
00575     if(d->custom) {
00576         delete d->custom;
00577         d->custom = 0;
00578     }
00579 
00580     d->name = property.d->name;
00581     d->setCaptionForDisplaying(property.captionForDisplaying());
00582     d->description = property.d->description;
00583     d->type = property.d->type;
00584 
00585     d->icon = property.d->icon;
00586     d->autosync = property.d->autosync;
00587     d->visible = property.d->visible;
00588     d->storable = property.d->storable;
00589     d->readOnly = property.d->readOnly;
00590     d->options = property.d->options;
00591 
00592     if(property.d->listData) {
00593         d->listData = new ListData(*property.d->listData); //QMap<QString, QVariant>(*(property.d->valueList));
00594     }
00595     if(property.d->custom) {
00596         d->custom = FactoryManager::self()->createCustomProperty(this);
00597         // updates all children value, using CustomProperty
00598         setValue(property.value());
00599     }
00600     else {
00601         d->value = property.d->value;
00602         if(property.d->children) {
00603             // no CustomProperty (should never happen), simply copy all children
00604             d->children = new QValueList<Property*>();
00605             QValueList<Property*>::ConstIterator endIt = property.d->children->constEnd();
00606             for(QValueList<Property*>::ConstIterator it = property.d->children->constBegin(); it != endIt; ++it) {
00607                 Property *child = new Property( *(*it) );
00608                 addChild(child);
00609             }
00610         }
00611     }
00612 
00613     if(property.d->relatedProperties) {
00614         d->relatedProperties = new QValueList<Property*>( *(property.d->relatedProperties));
00615     }
00616 
00617     // update these later because they may have been changed when creating children
00618     d->oldValue = property.d->oldValue;
00619     d->changed = property.d->changed;
00620     d->sortingKey = property.d->sortingKey;
00621 
00622     return *this;
00623 }
00624 
00625 bool
00626 Property::operator ==(const Property &prop) const
00627 {
00628     return ((d->name == prop.d->name) && (value() == prop.value()));
00629 }
00630 
00632 
00633 const QValueList<Property*>*
00634 Property::children() const
00635 {
00636     return d->children;
00637 }
00638 
00639 Property*
00640 Property::child(const QCString &name)
00641 {
00642     QValueList<Property*>::ConstIterator endIt = d->children->constEnd();
00643     for(QValueList<Property*>::ConstIterator it = d->children->constBegin(); it != endIt; ++it) {
00644         if((*it)->name() == name)
00645             return *it;
00646     }
00647     return 0;
00648 }
00649 
00650 Property*
00651 Property::parent() const
00652 {
00653     return d->parent;
00654 }
00655 
00656 void
00657 Property::addChild(Property *prop)
00658 {
00659     if (!prop)
00660         return;
00661 
00662     if(!d->children || qFind( d->children->begin(), d->children->end(), prop) == d->children->end()) { // not in our list
00663         if(!d->children)
00664             d->children = new QValueList<Property*>();
00665         d->children->append(prop);
00666         prop->setSortingKey(d->children->count());
00667         prop->d->parent = this;
00668     }
00669     else {
00670         kopropertywarn << "Property::addChild(): property \"" << name() 
00671             << "\": child property \"" << prop->name() << "\" already added" << endl;
00672         return;
00673     }
00674 }
00675 
00676 void
00677 Property::addSet(Set *set)
00678 {
00679     if (!set)
00680         return;
00681 
00682     if (!d->set) {//simple case
00683         d->set = set;
00684         return;
00685     }
00686     if ((Set*)d->set==set)
00687         return;
00688     QGuardedPtr<Set> *pset = d->sets ? d->sets->find(set) : 0;
00689     if (pset && (Set*)*pset == set)
00690         return;
00691     if (!d->sets) {
00692         d->sets = new QPtrDict< QGuardedPtr<Set> >( 101 );
00693         d->sets->setAutoDelete(true);
00694     }
00695 
00696     d->sets->replace(set, new QGuardedPtr<Set>( set ));
00697 
00698 //  QValueList<Set*>::iterator it = qFind( d->sets.begin(), d->sets.end(), set);
00699 //  if(it == d->sets.end()) // not in our list
00700 //      d->sets.append(set);
00701 }
00702 
00703 const QValueList<Property*>*
00704 Property::related() const
00705 {
00706     return d->relatedProperties;
00707 }
00708 
00709 void
00710 Property::addRelatedProperty(Property *property)
00711 {
00712     if(!d->relatedProperties)
00713         d->relatedProperties = new QValueList<Property*>();
00714 
00715     QValueList<Property*>::iterator it = qFind( d->relatedProperties->begin(), d->relatedProperties->end(), property);
00716     if(it == d->relatedProperties->end()) // not in our list
00717         d->relatedProperties->append(property);
00718 }
00719 
00720 CustomProperty*
00721 Property::customProperty() const
00722 {
00723     return d->custom;
00724 }
00725 
00726 void
00727 Property::setCustomProperty(CustomProperty *prop)
00728 {
00729     d->custom = prop;
00730 }
00731 
00732 int Property::sortingKey() const
00733 {
00734     return d->sortingKey;
00735 }
00736 
00737 void Property::setSortingKey(int key)
00738 {
00739     d->sortingKey = key;
00740 }
00741 
00742 void Property::emitPropertyChanged()
00743 {
00744     if (d->sets) {
00745         for (QPtrDictIterator< QGuardedPtr<Set> > it(*d->sets); it.current(); ++it) {
00746             if (it.current()) {//may be destroyed in the meantime
00747                 emit (*it.current())->propertyChangedInternal(**it.current(), *this);
00748                 emit (*it.current())->propertyChanged(**it.current(), *this);
00749             }
00750         }
00751     }
00752     else if (d->set) {
00753         //if the slot connect with that signal may call set->clear() - that's
00754         //the case e.g. at kexi/plugins/{macros|scripting}/* -  this Property
00755         //may got destroyed ( see Set::removeProperty(Property*) ) while we are
00756         //still on it. So, if we try to access ourself/this once the signal
00757         //got emitted we may end in a very hard to reproduce crash. So, the
00758         //emit should happen as last step in this method!
00759         emit d->set->propertyChangedInternal(*d->set, *this);
00760         emit d->set->propertyChanged(*d->set, *this);
00761     }
00762 }
00763 
00765 
00766 void
00767 Property::debug()
00768 {
00769     QString dbg = "Property( name='" + QString(d->name) + "' desc='" + d->description
00770         + "' val=" + (value().isValid() ? value().toString() : "<INVALID>");
00771     if (!d->oldValue.isValid())
00772         dbg += (", oldVal='" + d->oldValue.toString() + '\'');
00773     dbg += (QString(d->changed ? " " : " un") + "changed");
00774     dbg += (d->visible ? " visible" : " hidden");
00775     dbg+=" )";
00776 
00777     kopropertydbg << dbg << endl;
00778 }
KDE Home | KDE Accessibility Home | Description of Access Keys