F:/KPlato/koffice/libs/koproperty/property.cpp

Aller à la documentation de ce fichier.
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>
00030 #include <q3ptrdict.h>
00031 #include <q3asciidict.h>
00032 #include <QPointer>
00033 #include <QByteArray>
00034 #include <QStringList>
00035 namespace KoProperty {
00036 
00037 QT_STATIC_CONST_IMPL Property Property::null;
00038 
00040 class PropertyPrivate
00041 {
00042         public:
00043                 PropertyPrivate()
00044                 : caption(0), listData(0), changed(false), storable(true), 
00045                  readOnly(false), visible(true),
00046                  autosync(-1), custom(0), useCustomProperty(true),
00047                  sets(0), parent(0), children(0), relatedProperties(0),
00048                  sortingKey(0)
00049                 {
00050                 }
00051 
00052                 inline void setCaptionForDisplaying(const QString& captionForDisplaying)
00053                 {
00054                         delete caption;
00055                         if (captionForDisplaying.simplified()!=captionForDisplaying)
00056                                 caption = new QString(captionForDisplaying.simplified());
00057                         else
00058                                 caption = 0;
00059                         this->captionForDisplaying = captionForDisplaying;
00060                 }
00061 
00062                 ~PropertyPrivate()
00063                 {
00064                         delete caption;
00065                         caption = 0;
00066                         delete listData;
00067                         delete children;
00068                         delete relatedProperties;
00069                         delete custom;
00070                         delete sets;
00071                 }
00072 
00073         int type;
00074         QByteArray name;
00075         QString captionForDisplaying;
00076         QString* caption;
00077         QString description;
00078         QVariant value;
00079         QVariant oldValue;
00081         Property::ListData* listData;
00082 //      QMap<QString, QVariant> *valueList;
00083         QString icon;
00084 
00085         bool changed : 1;
00086         bool storable : 1;
00087         bool readOnly : 1;
00088         bool visible : 1;
00089         int autosync;
00090         QMap<QByteArray, QVariant> options;
00091 
00092         CustomProperty *custom;
00094         bool useCustomProperty;
00095 
00097         QPointer<Set> set;
00099         Q3PtrDict< QPointer<Set> > *sets;
00100 //      QValueList<Set*>  sets;
00101 
00102         Property  *parent;
00103         QList<Property*>  *children;
00105         QList<Property*>  *relatedProperties;
00106 
00107         int sortingKey;
00108 };
00109 }
00110 
00111 using namespace KoProperty;
00112 
00114 
00115 Property::ListData::ListData(const QStringList& keys_, const QStringList& names_)
00116  : names(names_)
00117 // , fixed(true)
00118 {
00119         setKeysAsStringList(keys_);
00120 }
00121 
00122 Property::ListData::ListData(const QList<QVariant> keys_, const QStringList& names_)
00123  : keys(keys_), names(names_)
00124 // , fixed(true)
00125 {
00126 }
00127 
00128 Property::ListData::ListData()
00129 // : fixed(true)
00130 {
00131 }
00132 
00133 Property::ListData::~ListData()
00134 {
00135 }
00136 
00137 void Property::ListData::setKeysAsStringList(const QStringList& list)
00138 {
00139         keys.clear();
00140         for (QStringList::ConstIterator it = list.constBegin(); it!=list.constEnd(); ++it) {
00141                 keys.append(*it);
00142         }
00143 }
00144 
00145 QStringList Property::ListData::keysAsStringList() const
00146 {
00147         QStringList result;
00148         for (QList<QVariant>::ConstIterator it = keys.constBegin(); it!=keys.constEnd(); ++it) {
00149                 result.append((*it).toString());
00150         }
00151         return result;
00152 }
00153 
00155 
00156 /*
00157 KOPROPERTY_EXPORT QMap<QString, QVariant>
00158 KoProperty::createValueListFromStringLists(const QStringList &keys, const QStringList &values)
00159 {
00160         QMap<QString, QVariant> map;
00161         if(keys.count() != values.count())
00162                 return map;
00163 
00164         QStringList::ConstIterator valueIt = values.begin();
00165         QStringList::ConstIterator endIt = keys.constEnd();
00166         for(QStringList::ConstIterator it = keys.begin(); it != endIt; ++it, ++valueIt)
00167                 map.insert( *it, *valueIt);
00168 
00169         return map;
00170 }
00171 */
00172 
00173 
00174 Property::Property(const QByteArray &name, const QVariant &value,
00175         const QString &caption, const QString &description,
00176         int type, Property* parent)
00177  : d( new PropertyPrivate() )
00178 {
00179         d->name = name;
00180         d->setCaptionForDisplaying(caption);
00181         d->description = description;
00182 
00183         if(type == (int)Auto)
00184                 d->type = value.type();
00185         else
00186                 d->type = type;
00187 
00188         d->custom = FactoryManager::self()->createCustomProperty(this);
00189 
00190         if (parent)
00191                 parent->addChild(this);
00192         setValue(value, false);
00193 }
00194 
00195 Property::Property(const QByteArray &name, const QStringList &keys, const QStringList &strings,
00196         const QVariant &value, const QString &caption, const QString &description, 
00197         int type, Property* parent)
00198  : d( new PropertyPrivate() )
00199 {
00200         d->name = name;
00201         d->setCaptionForDisplaying(caption);
00202         d->description = description;
00203         d->type = type;
00204         setListData(keys, strings);
00205 
00206         d->custom = FactoryManager::self()->createCustomProperty(this);
00207 
00208         if (parent)
00209                 parent->addChild(this);
00210         setValue(value, false);
00211 }
00212 
00213 Property::Property(const QByteArray &name, ListData* listData, 
00214         const QVariant &value, const QString &caption, const QString &description, 
00215         int type, Property* parent)
00216  : d( new PropertyPrivate() )
00217 {
00218         d->name = name;
00219         d->setCaptionForDisplaying(caption);
00220         d->description = description;
00221         d->type = type;
00222         d->listData = listData;
00223 
00224         d->custom = FactoryManager::self()->createCustomProperty(this);
00225 
00226         if (parent)
00227                 parent->addChild(this);
00228         setValue(value, false);
00229 }
00230 
00231 Property::Property()
00232  : d( new PropertyPrivate() )
00233 {
00234 }
00235 
00236 Property::Property(const Property &prop)
00237  : d( new PropertyPrivate() )
00238 {
00239         *this = prop;
00240 }
00241 
00242 Property::~Property()
00243 {
00244         delete d;
00245         d = 0;
00246 }
00247 
00248 QByteArray
00249 Property::name() const
00250 {
00251         return d->name;
00252 }
00253 
00254 void
00255 Property::setName(const QByteArray &name)
00256 {
00257         d->name = name;
00258 }
00259 
00260 QString
00261 Property::caption() const
00262 {
00263         return d->caption ? *d->caption : d->captionForDisplaying;
00264 }
00265 
00266 QString
00267 Property::captionForDisplaying() const
00268 {
00269         return d->captionForDisplaying;
00270 }
00271 
00272 void
00273 Property::setCaption(const QString &caption)
00274 {
00275         d->setCaptionForDisplaying(caption);
00276 }
00277 
00278 QString
00279 Property::description() const
00280 {
00281         return d->description;
00282 }
00283 
00284 void
00285 Property::setDescription(const QString &desc)
00286 {
00287         d->description = desc;
00288 }
00289 
00290 int
00291 Property::type() const
00292 {
00293         return d->type;
00294 }
00295 
00296 void
00297 Property::setType(int type)
00298 {
00299         d->type = type;
00300 }
00301 
00302 QString
00303 Property::icon() const
00304 {
00305         return d->icon;
00306 }
00307 
00308 void
00309 Property::setIcon(const QString &icon)
00310 {
00311         d->icon = icon;
00312 }
00313 
00314 QVariant
00315 Property::value() const
00316 {
00317         if(d->custom && d->custom->handleValue())
00318                 return d->custom->value();
00319         return d->value;
00320 }
00321 
00322 QVariant
00323 Property::oldValue() const
00324 {
00325 /*      if(d->oldValue.isNull())
00326                 return value();
00327         else*/
00328                 return d->oldValue;
00329 }
00330 
00331 void
00332 Property::setValue(const QVariant &value, bool rememberOldValue, bool useCustomProperty)
00333 {
00334         if (d->name.isEmpty()) {
00335                 kopropertywarn << "Property::setValue(): COULD NOT SET value to a null property" << endl;
00336                 return;
00337         }
00338         QVariant currentValue = this->value();
00339         const QVariant::Type t = currentValue.type();
00340         const QVariant::Type newt = value.type();
00341 //      kopropertydbg << d->name << " : setValue('" << value.toString() << "' type=" << type() << ")" << endl;
00342         if (t != newt && !currentValue.isNull() && !value.isNull()
00343                  && !( (t==QVariant::Int && newt==QVariant::UInt)
00344                            || (t==QVariant::UInt && newt==QVariant::Int)
00345                            || (t==QVariant::CString && newt==QVariant::String)
00346                            || (t==QVariant::String && newt==QVariant::CString)
00347                            || (t==QVariant::ULongLong && newt==QVariant::LongLong)
00348                            || (t==QVariant::LongLong && newt==QVariant::ULongLong)
00349                  )) {
00350                 kopropertywarn << "Property::setValue(): INCOMPATIBLE TYPES! old=" << currentValue 
00351                         << " new=" << value << endl;
00352         }
00353 
00354         //1. Check if the value should be changed
00355         bool ch;
00356         if (t == QVariant::DateTime
00357                 || t == QVariant::Time) {
00358                 //for date and datetime types: compare with strings, because there
00359                 //can be miliseconds difference
00360                 ch = (currentValue.toString() != value.toString());
00361         }
00362         else if (t == QVariant::String || t==QVariant::CString) {
00363                 //property is changed for string type,
00364                 //if one of value is empty and other isn't..
00365                 ch = ( (currentValue.toString().isEmpty() != value.toString().isEmpty())
00366                 //..or both are not empty and values differ
00367                         || (!currentValue.toString().isEmpty() && !value.toString().isEmpty() && currentValue != value) );
00368         }
00369         else if (t == QVariant::Invalid && newt == QVariant::Invalid)
00370                 ch = false;
00371         else
00372                 ch = (currentValue != value);
00373 
00374         if (!ch)
00375                 return;
00376 
00377         //2. Then change it, and store old value if necessary
00378         if(rememberOldValue) {
00379                 if(!d->changed)
00380                         d->oldValue = currentValue;
00381                 d->changed = true;
00382         }
00383         else {
00384                 d->oldValue = QVariant(); // clear old value
00385                 d->changed = false;
00386         }
00387         QVariant prevValue;
00388         if(d->custom && useCustomProperty) {
00389                 d->custom->setValue(value, rememberOldValue);
00390                 prevValue = d->custom->value();
00391         }
00392         else
00393                 prevValue = currentValue;
00394 
00395         if (!d->custom || !useCustomProperty || !d->custom->handleValue())
00396                 d->value = value;
00397 
00398         emitPropertyChanged(); // called as last step in this method!
00399 }
00400 
00401 void
00402 Property::resetValue()
00403 {
00404         d->changed = false;
00405         bool cleared = false;
00406         if (d->set)
00407                 d->set->informAboutClearing(cleared); //inform me about possibly clearing the property sets
00408         setValue(oldValue(), false);
00409         if (cleared)
00410                 return; //property set has been cleared: no further actions make sense as 'this' is dead
00411 
00412         // maybe parent  prop is also unchanged now
00413         if(d->parent && d->parent->value() == d->parent->oldValue())
00414                 d->parent->d->changed = false;
00415 
00416         if (d->sets) {
00417                 for (Q3PtrDictIterator< QPointer<Set> > it(*d->sets); it.current(); ++it) {
00418                         if (it.current()) //may be destroyed in the meantime
00419                                 emit (*it.current())->propertyReset(**it.current(), *this);
00420                 }
00421         }
00422         else if (d->set) {
00423                 emit d->set->propertyReset(*d->set, *this);
00424         }
00425 }
00426 
00427 //const QMap<QString, QVariant>*
00428 Property::ListData*
00429 Property::listData() const
00430 {
00431         return d->listData;
00432 }
00433 
00434 void
00435 Property::setListData(ListData* list) //const QMap<QString, QVariant> &list)
00436 {
00437 //      if(!d->valueList)
00438 //              d->valueList = new QMap<QString, QVariant>();
00439         if (list == d->listData)
00440                 return;
00441         delete d->listData;
00442         d->listData = list;
00443 }
00444 
00445 void
00446 Property::setListData(const QStringList &keys, const QStringList &names)
00447 {
00448         ListData* list = new ListData(keys, names);
00449         setListData(list);
00450 
00451 //      if(!d->valueList)
00452 //              d->valueList = new QMap<QString, QVariant>();
00453 //      *(d->valueList) = createValueListFromStringLists(keys, values);
00454 }
00455 
00457 
00458 bool
00459 Property::isNull() const
00460 {
00461         return d->name.isEmpty();
00462 }
00463 
00464 bool
00465 Property::isModified() const
00466 {
00467         return d->changed;
00468 }
00469 
00470 void
00471 Property::clearModifiedFlag()
00472 {
00473         d->changed = false;
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 QList<Property*>();
00606                         QList<Property*>::ConstIterator endIt = property.d->children->constEnd();
00607                         for(QList<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 QList<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 QList<Property*>*
00635 Property::children() const
00636 {
00637         return d->children;
00638 }
00639 
00640 Property*
00641 Property::child(const QByteArray &name)
00642 {
00643         QList<Property*>::ConstIterator endIt = d->children->constEnd();
00644         for(QList<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 QList<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         QPointer<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 Q3PtrDict< QPointer<Set> >( 101 );
00694                 d->sets->setAutoDelete(true);
00695         }
00696 
00697         d->sets->replace(set, new QPointer<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 QList<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 QList<Property*>();
00715 
00716         QList<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 CustomProperty*
00722 Property::customProperty() const
00723 {
00724         return d->custom;
00725 }
00726 
00727 void
00728 Property::setCustomProperty(CustomProperty *prop)
00729 {
00730         d->custom = prop;
00731 }
00732 
00733 int Property::sortingKey() const
00734 {
00735         return d->sortingKey;
00736 }
00737 
00738 void Property::setSortingKey(int key)
00739 {
00740         d->sortingKey = key;
00741 }
00742 
00743 void Property::emitPropertyChanged()
00744 {
00745         if (d->sets) {
00746                 for (Q3PtrDictIterator< QPointer<Set> > it(*d->sets); it.current(); ++it) {
00747                         if (it.current()) {//may be destroyed in the meantime
00748                                 emit (*it.current())->propertyChangedInternal(**it.current(), *this);
00749                                 emit (*it.current())->propertyChanged(**it.current(), *this);
00750                         }
00751                 }
00752         }
00753         else if (d->set) {
00754                 //if the slot connect with that signal may call set->clear() - that's
00755                 //the case e.g. at kexi/plugins/{macros|scripting}/* -  this Property
00756                 //may got destroyed ( see Set::removeProperty(Property*) ) while we are
00757                 //still on it. So, if we try to access ourself/this once the signal
00758                 //got emitted we may end in a very hard to reproduce crash. So, the
00759                 //emit should happen as last step in this method!
00760                 //emit d->set->propertyChangedInternal(*d->set, *this);
00761                 emit d->set->propertyChanged(*d->set, *this);
00762         }
00763 }
00764 
00766 
00767 void
00768 Property::debug()
00769 {
00770         QString dbg = "Property( name='" + QString(d->name) + "' desc='" + d->description
00771                 + "' val=" + (value().isValid() ? value().toString() : "<INVALID>");
00772         if (!d->oldValue.isValid())
00773                 dbg += (", oldVal='" + d->oldValue.toString() + '\'');
00774         dbg += (QString(d->changed ? " " : " un") + "changed");
00775         dbg += (d->visible ? " visible" : " hidden");
00776         dbg+=" )";
00777 
00778         kopropertydbg << dbg << endl;
00779 }

Généré le Wed Nov 22 23:41:07 2006 pour KPlato par  doxygen 1.5.1-p1