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