kfilemetainfo.cpp

00001 /*
00002  *  This file is part of the KDE libraries
00003  *  Copyright (C) 2001-2002 Rolf Magnus <ramagnus@kde.org>
00004  *  Copyright (C) 2001-2002 Carsten Pfeiffer <pfeiffer@kde.org>
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 version 2.0.
00009  *
00010  *  This library is distributed in the hope that it will be useful,
00011  *  but WITHOUT ANY WARRANTY; without even the implied warranty of
00012  *  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
00013  *  Library General Public License for more details.
00014  *
00015  *  You should have received a copy of the GNU Library General Public License
00016  *  along with this library; see the file COPYING.LIB.  If not, write to
00017  *  the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor,
00018  *  Boston, MA 02110-1301, USA.
00019  *
00020  *  $Id: kfilemetainfo.cpp 532794 2006-04-22 20:33:21Z pfeiffer $
00021  */
00022 
00023 #include <assert.h>
00024 
00025 #include <qshared.h>
00026 #include <qdict.h>
00027 
00028 #include <ktrader.h>
00029 #include <kstaticdeleter.h>
00030 #include <kparts/componentfactory.h>
00031 #include <kuserprofile.h>
00032 #include <kdebug.h>
00033 #include <kmimetype.h>
00034 #include <kdatastream.h> // needed for serialization of bool
00035 #include <klocale.h>
00036 #include <kio/global.h>
00037 
00038 #include "kfilemetainfo.h"
00039 
00040 // shared data of a KFileMetaInfoItem
00041 class KFileMetaInfoItem::Data : public QShared
00042 {
00043 public:
00044     Data( const KFileMimeTypeInfo::ItemInfo* mti, const QString& _key,
00045           const QVariant& _value )
00046         : QShared(),
00047           mimeTypeInfo( mti ),
00048           key( _key ),
00049           value( _value ),
00050           dirty( false ),
00051           added( false ),
00052           removed( false )
00053     {}
00054 
00055     // we use this one for the streaming operators
00056     Data() : mimeTypeInfo( 0L )
00057     {}
00058 
00059     ~Data()
00060     {
00061         if ( this == null ) // only the null item owns its mimeTypeInfo
00062             delete mimeTypeInfo;
00063     }
00064 
00065     const KFileMimeTypeInfo::ItemInfo*  mimeTypeInfo;
00066     // mimeTypeInfo has the key, too, but only for non-variable ones
00067     QString                             key;
00068     QVariant                            value;
00069     bool                                dirty    :1;
00070     bool                                added    :1;
00071     bool                                removed  :1;
00072 
00073     static Data* null;
00074     static Data* makeNull();
00075 };
00076 
00077 //this is our null data
00078 KFileMetaInfoItem::Data* KFileMetaInfoItem::Data::null = 0L;
00079 static KStaticDeleter<KFileMetaInfoItem::Data> sd_KFileMetaInfoItemData;
00080 
00081 KFileMetaInfoItem::Data* KFileMetaInfoItem::Data::makeNull()
00082 {
00083     if (!null)
00084     {
00085         // We deliberately do not reset "null" after it has been destroyed!
00086         // Otherwise we will run into problems later in ~KFileMetaInfoItem
00087         // where the d-pointer is compared against null.
00088 
00089         KFileMimeTypeInfo::ItemInfo* info = new KFileMimeTypeInfo::ItemInfo();
00090         null = new Data(info, QString::null, QVariant());
00091         sd_KFileMetaInfoItemData.setObject( null );
00092     }
00093     return null;
00094 }
00095 
00096 KFileMetaInfoItem::KFileMetaInfoItem( const KFileMimeTypeInfo::ItemInfo* mti,
00097                                       const QString& key, const QVariant& value )
00098     : d( new Data( mti, key, value ) )
00099 {
00100 }
00101 
00102 KFileMetaInfoItem::KFileMetaInfoItem( const KFileMetaInfoItem& item )
00103 {
00104     // operator= does everything that's necessary
00105     d = Data::makeNull();
00106     *this = item;
00107 }
00108 
00109 KFileMetaInfoItem::KFileMetaInfoItem()
00110 {
00111     d = Data::makeNull();
00112 }
00113 
00114 KFileMetaInfoItem::~KFileMetaInfoItem()
00115 {
00116     deref();
00117 }
00118 
00119 const KFileMetaInfoItem& KFileMetaInfoItem::operator=
00120                                               (const KFileMetaInfoItem & item )
00121 {
00122     if (d != item.d)
00123     {
00124         // first deref the old one
00125         deref();
00126         d = item.d;
00127         // and now ref the new one
00128         ref();
00129     }
00130 
00131     return *this;
00132 }
00133 
00134 bool KFileMetaInfoItem::setValue( const QVariant& value )
00135 {
00136     // We don't call makeNull here since it isn't necassery, see deref()
00137     if ( d == Data::null ) return false;
00138 
00139     if ( ! (d->mimeTypeInfo->attributes() & KFileMimeTypeInfo::Modifiable ) ||
00140          ! (value.canCast(d->mimeTypeInfo->type())))
00141     {
00142         kdDebug(7033) << "setting the value of " << key() << "failed\n";
00143         return false;
00144     }
00145 
00146 //    kdDebug(7033) << key() << ".setValue()\n";
00147 
00148     if ( d->value == value )
00149         return true;
00150 
00151     d->dirty = true;
00152     d->value = value;
00153     // If we don't cast (and test for canCast in the above if), QVariant is
00154     // very picky about types (e.g. QString vs. QCString or int vs. uint)
00155     d->value.cast(d->mimeTypeInfo->type());
00156 
00157     return true;
00158 }
00159 
00160 bool KFileMetaInfoItem::isRemoved() const
00161 {
00162     return d->removed;
00163 }
00164 
00165 QString KFileMetaInfoItem::key() const
00166 {
00167     return d->key;
00168 }
00169 
00170 QString KFileMetaInfoItem::translatedKey() const
00171 {
00172     // are we a variable key?
00173     if (d->mimeTypeInfo->key().isNull())
00174     {
00175         // then try if we have luck with i18n()
00176         return i18n(d->key.utf8());
00177     }
00178 
00179     return d->mimeTypeInfo->translatedKey();
00180 }
00181 
00182 const QVariant& KFileMetaInfoItem::value() const
00183 {
00184     return d->value;
00185 }
00186 
00187 QString KFileMetaInfoItem::string( bool mangle ) const
00188 {
00189     return d->mimeTypeInfo->string(d->value, mangle);
00190 }
00191 
00192 QVariant::Type KFileMetaInfoItem::type() const
00193 {
00194     return d->mimeTypeInfo->type();
00195 }
00196 
00197 uint KFileMetaInfoItem::unit() const
00198 {
00199     return d->mimeTypeInfo->unit();
00200 }
00201 
00202 bool KFileMetaInfoItem::isModified() const
00203 {
00204     return d->dirty;
00205 }
00206 
00207 QString KFileMetaInfoItem::prefix() const
00208 {
00209     return d->mimeTypeInfo->prefix();
00210 }
00211 
00212 QString KFileMetaInfoItem::suffix() const
00213 {
00214     return d->mimeTypeInfo->suffix();
00215 }
00216 
00217 uint KFileMetaInfoItem::hint() const
00218 {
00219     return d->mimeTypeInfo->hint();
00220 }
00221 
00222 uint KFileMetaInfoItem::attributes() const
00223 {
00224     return d->mimeTypeInfo->attributes();
00225 }
00226 
00227 bool KFileMetaInfoItem::isEditable() const
00228 {
00229     return d->mimeTypeInfo->attributes() & KFileMimeTypeInfo::Modifiable;
00230 }
00231 
00232 bool KFileMetaInfoItem::isValid() const
00233 {
00234     // We don't call makeNull here since it isn't necassery:
00235     // If d is equal to null it means that null is initialized already.
00236     // null is 0L when it hasn't been initialized and d is never 0L.
00237     return d != Data::null;
00238 }
00239 
00240 void KFileMetaInfoItem::setAdded()
00241 {
00242     d->added = true;
00243 }
00244 
00245 void KFileMetaInfoItem::setRemoved()
00246 {
00247     d->removed = true;
00248 }
00249 
00250 void KFileMetaInfoItem::ref()
00251 {
00252     if (d != Data::null) d->ref();
00253 }
00254 
00255 void KFileMetaInfoItem::deref()
00256 {
00257     // We don't call makeNull here since it isn't necassery:
00258     // If d is equal to null it means that null is initialized already.
00259     // null is 0L when it hasn't been initialized and d is never 0L.
00260     if ((d != Data::null) && d->deref())
00261     {
00262 //        kdDebug(7033) << "item " << d->key
00263 //                      << " is finally deleted\n";
00264         delete d;
00265         d = 0;
00266     }
00267 }
00268 
00271 
00272 // shared data of a KFileMetaInfo
00273 class KFileMetaInfo::Data : public QShared
00274 {
00275 public:
00276     Data(const KURL& _url, uint _what)
00277         : QShared(),
00278           url(_url),
00279           what(_what),
00280           mimeTypeInfo( 0L )
00281     {}
00282 
00283     // wee use this one for the streaming operators
00284     Data() {};
00285 
00286     KURL                              url;
00287     uint                              what;
00288     QMap<QString, KFileMetaInfoGroup> groups;
00289     const KFileMimeTypeInfo*          mimeTypeInfo;
00290     QStringList                       removedGroups;
00291 
00292     static Data* null;
00293     static Data* makeNull();
00294 
00295 };
00296 
00297 KFileMetaInfo::KFileMetaInfo( const QString& path, const QString& mimeType,
00298                               uint what )
00299 {
00300     KURL u;
00301 
00302     u.setPath(path);
00303     init(u, mimeType, what);
00304 }
00305 
00306 KFileMetaInfo::KFileMetaInfo( const KURL& url, const QString& mimeType,
00307                               uint what )
00308 {
00309     init(url, mimeType, what);
00310 }
00311 
00312 void KFileMetaInfo::init( const KURL& url, const QString& mimeType,
00313                           uint what )
00314 {
00315     d = new Data( url, what );
00316 
00317     QString mT;
00318     if (mimeType.isEmpty())
00319         mT = KMimeType::findByURL(url)->name();
00320     else
00321         mT = mimeType;
00322 
00323     // let's "share our property"
00324     KFileMetaInfo item(*this);
00325 
00326     //kdDebug() << k_funcinfo << mT << " " << url << endl;
00327 
00328     d->mimeTypeInfo = KFileMetaInfoProvider::self()->mimeTypeInfo( mT, url.protocol() );
00329     if ( d->mimeTypeInfo )
00330     {
00331         //kdDebug(7033) << "Found mimetype info for " << mT /* or protocol*/ << endl;
00332         KFilePlugin *p = plugin();
00333         Q_ASSERT( p );
00334         if ( p && !p->readInfo( item, what) )
00335             d = Data::makeNull();
00336     }
00337     else
00338     {
00339 //        kdDebug(7033) << "No mimetype info for " << mimeType << endl;
00340         d = Data::makeNull();
00341     }
00342 }
00343 
00344 KFileMetaInfo::KFileMetaInfo( const KFileMetaInfo& original )
00345 {
00346     // operator= does everything that's necessary
00347     d = Data::makeNull();
00348     *this = original;
00349 }
00350 
00351 KFileMetaInfo::KFileMetaInfo()
00352 {
00353     d = Data::makeNull();
00354 }
00355 
00356 KFileMetaInfo::~KFileMetaInfo()
00357 {
00358     deref();
00359 }
00360 
00361 QStringList KFileMetaInfo::supportedGroups() const
00362 {
00363     assert(isValid());
00364     return d->mimeTypeInfo->supportedGroups();
00365 }
00366 
00367 QStringList KFileMetaInfo::supportedKeys() const
00368 {
00369     assert(isValid());
00370     return d->mimeTypeInfo->supportedKeys();
00371 }
00372 
00373 QStringList KFileMetaInfo::groups() const
00374 {
00375     QStringList list;
00376     QMapConstIterator<QString, KFileMetaInfoGroup> it = d->groups.begin();
00377     for ( ; it != d->groups.end(); ++it )
00378         list += (*it).name();
00379 
00380     return list;
00381 }
00382 
00383 QStringList KFileMetaInfo::editableGroups() const
00384 {
00385     QStringList list;
00386     QStringList supported = supportedGroups();
00387     QStringList::ConstIterator it = supported.begin();
00388     for ( ; it != supported.end(); ++it ) {
00389         const KFileMimeTypeInfo::GroupInfo * groupInfo = d->mimeTypeInfo->groupInfo( *it );
00390         if ( groupInfo && groupInfo->attributes() &
00391              (KFileMimeTypeInfo::Addable | KFileMimeTypeInfo::Removable) )
00392             list.append( *it );
00393     }
00394 
00395     return list;
00396 }
00397 
00398 QStringList KFileMetaInfo::preferredGroups() const
00399 {
00400     assert(isValid());
00401     QStringList list = groups();
00402     QStringList newlist;
00403     QStringList preferred = d->mimeTypeInfo->preferredGroups();
00404     QStringList::Iterator pref;
00405 
00406     // move all keys from the preferred groups that are in our list to a new list
00407     for ( pref = preferred.begin(); pref != preferred.end(); ++pref )
00408     {
00409         QStringList::Iterator group = list.find(*pref);
00410         if ( group != list.end() )
00411         {
00412              newlist.append( *group );
00413              list.remove(group);
00414         }
00415     }
00416 
00417     // now the old list only contains the non-preferred items, so we
00418     // add the remaining ones to newlist
00419     newlist += list;
00420 
00421     return newlist;
00422 }
00423 
00424 QStringList KFileMetaInfo::preferredKeys() const
00425 {
00426     QStringList newlist;
00427 
00428     QStringList list = preferredGroups();
00429     for (QStringList::Iterator git = list.begin(); git != list.end(); ++git)
00430     {
00431         newlist += d->groups[*git].preferredKeys();
00432     }
00433 
00434     return newlist;
00435 }
00436 
00437 KFileMetaInfoGroup KFileMetaInfo::group(const QString& key) const
00438 {
00439     QMapIterator<QString,KFileMetaInfoGroup> it = d->groups.find( key );
00440     if ( it != d->groups.end() )
00441         return it.data();
00442     else
00443         return KFileMetaInfoGroup();
00444 }
00445 
00446 bool KFileMetaInfo::addGroup( const QString& name )
00447 {
00448     assert(isValid());
00449     if ( d->mimeTypeInfo->supportedGroups().contains(name) &&
00450          ! d->groups.contains(name) )
00451     {
00452         KFileMetaInfoGroup group( name, d->mimeTypeInfo );
00453 
00454         // add all the items that can't be added by the user later
00455         const KFileMimeTypeInfo::GroupInfo* ginfo = d->mimeTypeInfo->groupInfo(name);
00456         Q_ASSERT(ginfo);
00457         if (!ginfo) return false;
00458 
00459         QStringList keys = ginfo->supportedKeys();
00460         for (QStringList::Iterator it = keys.begin(); it != keys.end(); ++it)
00461         {
00462             const KFileMimeTypeInfo::ItemInfo* iteminfo = ginfo->itemInfo(*it);
00463             Q_ASSERT(ginfo);
00464             if (!iteminfo) return false;
00465 
00466             if ( !(iteminfo->attributes() & KFileMimeTypeInfo::Addable) &&
00467                   (iteminfo->attributes() & KFileMimeTypeInfo::Modifiable))
00468             {
00469                 // append it now or never
00470                 group.appendItem(iteminfo->key(), QVariant());
00471             }
00472 
00473         }
00474 
00475         d->groups.insert(name, group);
00476         group.setAdded();
00477         return true;
00478     }
00479 
00480     return false;
00481 }
00482 
00483 bool KFileMetaInfo::removeGroup( const QString& name )
00484 {
00485     QMapIterator<QString, KFileMetaInfoGroup> it = d->groups.find(name);
00486     if ( (it==d->groups.end()) ||
00487         !((*it).attributes() & KFileMimeTypeInfo::Removable))
00488         return false;
00489 
00490     d->groups.remove(it);
00491     d->removedGroups.append(name);
00492     return true;
00493 }
00494 
00495 QStringList KFileMetaInfo::removedGroups()
00496 {
00497     return d->removedGroups;
00498 }
00499 
00500 const KFileMetaInfo& KFileMetaInfo::operator= (const KFileMetaInfo& info )
00501 {
00502     if (d != info.d)
00503     {
00504         deref();
00505         // first deref the old one
00506         d = info.d;
00507         // and now ref the new one
00508         ref();
00509     }
00510     return *this;
00511 }
00512 
00513 bool KFileMetaInfo::isValid() const
00514 {
00515     // We don't call makeNull here since it isn't necassery, see deref()
00516     return d != Data::null;
00517 }
00518 
00519 bool KFileMetaInfo::isEmpty() const
00520 {
00521     for (QMapIterator<QString, KFileMetaInfoGroup> it = d->groups.begin();
00522          it!=d->groups.end(); ++it)
00523         if (!(*it).isEmpty())
00524             return false;
00525     return true;
00526 }
00527 
00528 bool KFileMetaInfo::applyChanges()
00529 {
00530     return applyChanges( path() );
00531 }
00532 
00533 bool KFileMetaInfo::applyChanges( const QString& path )
00534 {
00535     bool doit = false;
00536 
00537 //    kdDebug(7033) << "KFileMetaInfo::applyChanges()\n";
00538 
00539     // look up if we need to write to the file
00540     QMapConstIterator<QString, KFileMetaInfoGroup> it;
00541     for (it = d->groups.begin(); it!=d->groups.end() && !doit; ++it)
00542     {
00543         if ( (*it).isModified() )
00544             doit = true;
00545 
00546         else
00547         {
00548             QStringList keys = it.data().keys();
00549             for (QStringList::Iterator it2 = keys.begin(); it2!=keys.end(); ++it2)
00550             {
00551                 if ( (*it)[*it2].isModified() )
00552                 {
00553                     doit = true;
00554                     break;
00555                 }
00556             }
00557         }
00558     }
00559 
00560     if (!doit)
00561     {
00562         kdDebug(7033) << "Don't need to write, nothing changed\n";
00563         return true;
00564     }
00565 
00566     KFilePlugin* p = plugin();
00567     if (!p) return false;
00568 
00569 //    kdDebug(7033) << "Ok, trying to write the info\n";
00570 
00571     KURL savedURL = url();
00572     d->url = KURL();
00573     d->url.setPath( path );
00574     
00575     bool ret = p->writeInfo(*this);
00576     
00577     d->url = savedURL;
00578     return ret;
00579 }
00580 
00581 KFilePlugin * const KFileMetaInfo::plugin() const
00582 {
00583     assert(isValid());
00584     KFileMetaInfoProvider* prov = KFileMetaInfoProvider::self();
00585     return prov->plugin( d->mimeTypeInfo->mimeType(), d->url.protocol() );
00586 }
00587 
00588 QString KFileMetaInfo::mimeType() const
00589 {
00590     assert(isValid());
00591     return d->mimeTypeInfo->mimeType();
00592 }
00593 
00594 bool KFileMetaInfo::contains(const QString& key) const
00595 {
00596     QStringList glist = groups();
00597     for (QStringList::Iterator it = glist.begin(); it != glist.end(); ++it)
00598     {
00599         KFileMetaInfoGroup g = d->groups[*it];
00600         if (g.contains(key)) return true;
00601     }
00602     return false;
00603 }
00604 
00605 bool KFileMetaInfo::containsGroup(const QString& key) const
00606 {
00607     return groups().contains(key);
00608 }
00609 
00610 KFileMetaInfoItem KFileMetaInfo::item( const QString& key) const
00611 {
00612     QStringList groups = preferredGroups();
00613     for (QStringList::Iterator it = groups.begin(); it != groups.end(); ++it)
00614     {
00615         KFileMetaInfoItem i = d->groups[*it][key];
00616         if (i.isValid()) return i;
00617     }
00618     return KFileMetaInfoItem();
00619 }
00620 
00621 KFileMetaInfoItem KFileMetaInfo::item(const KFileMetaInfoItem::Hint hint) const
00622 {
00623     QStringList groups = preferredGroups();
00624     QStringList::ConstIterator it;
00625     for (it = groups.begin(); it != groups.end(); ++it)
00626     {
00627         KFileMetaInfoItem i = d->groups[*it].item(hint);
00628         if (i.isValid()) return i;
00629     }
00630     return KFileMetaInfoItem();
00631 }
00632 
00633 KFileMetaInfoItem KFileMetaInfo::saveItem( const QString& key,
00634                                            const QString& preferredGroup,
00635                                            bool createGroup )
00636 {
00637     assert(isValid());
00638     // try the preferred groups first
00639     if ( !preferredGroup.isEmpty() ) {
00640         QMapIterator<QString,KFileMetaInfoGroup> it =
00641             d->groups.find( preferredGroup );
00642 
00643         // try to create the preferred group, if necessary
00644         if ( it == d->groups.end() && createGroup ) {
00645             const KFileMimeTypeInfo::GroupInfo *groupInfo =
00646                 d->mimeTypeInfo->groupInfo( preferredGroup );
00647             if ( groupInfo && groupInfo->supportedKeys().contains( key ) ) {
00648                 if ( addGroup( preferredGroup ) )
00649                     it = d->groups.find( preferredGroup );
00650             }
00651         }
00652 
00653         if ( it != d->groups.end() ) {
00654             KFileMetaInfoItem item = it.data().addItem( key );
00655             if ( item.isValid() )
00656                 return item;
00657         }
00658     }
00659 
00660     QStringList groups = preferredGroups();
00661 
00662     KFileMetaInfoItem item;
00663 
00664     QStringList::ConstIterator groupIt = groups.begin();
00665     for ( ; groupIt != groups.end(); ++groupIt )
00666     {
00667         QMapIterator<QString,KFileMetaInfoGroup> it = d->groups.find( *groupIt );
00668         if ( it != d->groups.end() )
00669         {
00670             KFileMetaInfoGroup group = it.data();
00671             item = findEditableItem( group, key );
00672             if ( item.isValid() )
00673                 return item;
00674         }
00675         else // not existant -- try to create the group
00676         {
00677             const KFileMimeTypeInfo::GroupInfo *groupInfo =
00678                 d->mimeTypeInfo->groupInfo( *groupIt );
00679             if ( groupInfo && groupInfo->supportedKeys().contains( key ) )
00680             {
00681                 if ( addGroup( *groupIt ) )
00682                 {
00683                     KFileMetaInfoGroup group = d->groups[*groupIt];
00684                     KFileMetaInfoItem item = group.addItem( key );
00685                     if ( item.isValid() )
00686                         return item;
00687 //                     else ### add when removeGroup() is implemented :)
00688 //                         removeGroup( *groupIt ); // couldn't add item -> remove
00689                 }
00690             }
00691         }
00692     }
00693 
00694     // finally check for variable items
00695 
00696     return item;
00697 }
00698 
00699 KFileMetaInfoItem KFileMetaInfo::findEditableItem( KFileMetaInfoGroup& group,
00700                                                    const QString& key )
00701 {
00702     assert(isValid());
00703     KFileMetaInfoItem item = group.addItem( key );
00704     if ( item.isValid() && item.isEditable() )
00705          return item;
00706 
00707     if ( (d->mimeTypeInfo->groupInfo( group.name() )->attributes() & KFileMimeTypeInfo::Addable) )
00708         return item;
00709 
00710     return KFileMetaInfoItem();
00711 }
00712 
00713 KFileMetaInfoGroup KFileMetaInfo::appendGroup(const QString& name)
00714 {
00715     assert(isValid());
00716     if ( d->mimeTypeInfo->supportedGroups().contains(name) &&
00717          ! d->groups.contains(name) )
00718     {
00719         KFileMetaInfoGroup group( name, d->mimeTypeInfo );
00720         d->groups.insert(name, group);
00721         return group;
00722     }
00723 
00724     else {
00725         kdWarning(7033) << "Someone's trying to add a KFileMetaInfoGroup which is not supported or already existing: " << name << endl;
00726         return KFileMetaInfoGroup();
00727     }
00728 }
00729 
00730 QString KFileMetaInfo::path() const
00731 {
00732     return d->url.isLocalFile() ? d->url.path() : QString::null;
00733 }
00734 
00735 KURL KFileMetaInfo::url() const
00736 {
00737     return d->url;
00738 }
00739 
00740 void KFileMetaInfo::ref()
00741 {
00742     if (d != Data::null) d->ref();
00743 
00744 }
00745 
00746 void KFileMetaInfo::deref()
00747 {
00748     // We don't call makeNull here since it isn't necassery:
00749     // If d is equal to null it means that null is initialized already.
00750     // null is 0L when it hasn't been initialized and d is never 0L.
00751     if ((d != Data::null) && d->deref())
00752     {
00753 //        kdDebug(7033) << "metainfo object for " << d->url.path << " is finally deleted\n";
00754         delete d;
00755         d = 0;
00756     }
00757 
00758 }
00759 
00760 
00761 KFileMetaInfo::Data* KFileMetaInfo::Data::null = 0L;
00762 static KStaticDeleter<KFileMetaInfo::Data> sd_KFileMetaInfoData;
00763 
00764 KFileMetaInfo::Data* KFileMetaInfo::Data::makeNull()
00765 {
00766     if (!null)
00767         // We deliberately do not reset "null" after it has been destroyed!
00768         // Otherwise we will run into problems later in ~KFileMetaInfoItem
00769         // where the d-pointer is compared against null.
00770     null = sd_KFileMetaInfoData.setObject( new KFileMetaInfo::Data(KURL(), 0) );
00771     return null;
00772 }
00773 
00776 
00777 KFilePlugin::KFilePlugin( QObject *parent, const char *name,
00778                           const QStringList& /*args*/)
00779     : QObject( parent, name )
00780 {
00781 //    kdDebug(7033) << "loaded a plugin for " << name << endl;
00782 }
00783 
00784 KFilePlugin::~KFilePlugin()
00785 {
00786 //    kdDebug(7033) << "unloaded a plugin for " << name() << endl;
00787 }
00788 
00789 KFileMimeTypeInfo * KFilePlugin::addMimeTypeInfo( const QString& mimeType )
00790 {
00791     return KFileMetaInfoProvider::self()->addMimeTypeInfo( mimeType );
00792 }
00793 
00794 void KFilePlugin::virtual_hook( int, void* )
00795 { /*BASE::virtual_hook( id, data );*/ }
00796 
00797 
00798 KFileMimeTypeInfo::GroupInfo*  KFilePlugin::addGroupInfo(KFileMimeTypeInfo* info,
00799                   const QString& key, const QString& translatedKey) const
00800 {
00801     return info->addGroupInfo(key, translatedKey);
00802 }
00803 
00804 void KFilePlugin::setAttributes(KFileMimeTypeInfo::GroupInfo* gi, uint attr) const
00805 {
00806     gi->m_attr = attr;
00807 }
00808 
00809 void KFilePlugin::addVariableInfo(KFileMimeTypeInfo::GroupInfo* gi,
00810                                   QVariant::Type type, uint attr) const
00811 {
00812     gi->addVariableInfo(type, attr);
00813 }
00814 
00815 KFileMimeTypeInfo::ItemInfo* KFilePlugin::addItemInfo(KFileMimeTypeInfo::GroupInfo* gi,
00816                                                      const QString& key,
00817                                                      const QString& translatedKey,
00818                                                      QVariant::Type type)
00819 {
00820     return gi->addItemInfo(key, translatedKey, type);
00821 }
00822 
00823 void KFilePlugin::setAttributes(KFileMimeTypeInfo::ItemInfo* item, uint attr)
00824 {
00825     item->m_attr = attr;
00826 }
00827 
00828 void KFilePlugin::setHint(KFileMimeTypeInfo::ItemInfo* item, uint hint)
00829 {
00830     item->m_hint = hint;
00831 }
00832 
00833 void KFilePlugin::setUnit(KFileMimeTypeInfo::ItemInfo* item, uint unit)
00834 {
00835     item->m_unit = unit;
00836     // set prefix and suffix
00837     switch (unit)
00838     {
00839         case KFileMimeTypeInfo::Seconds:
00840             item->m_suffix = i18n("s"); break;
00841 
00842         case KFileMimeTypeInfo::MilliSeconds:
00843             item->m_suffix = i18n("ms"); break;
00844 
00845         case KFileMimeTypeInfo::BitsPerSecond:
00846             item->m_suffix = i18n("bps"); break;
00847 
00848         case KFileMimeTypeInfo::Pixels:
00849             item->m_suffix = i18n("pixels"); break;
00850 
00851         case KFileMimeTypeInfo::Inches:
00852             item->m_suffix = i18n("in"); break;
00853 
00854         case KFileMimeTypeInfo::Centimeters:
00855             item->m_suffix = i18n("cm"); break;
00856 
00857         case KFileMimeTypeInfo::Bytes:
00858             item->m_suffix = i18n("B"); break;
00859 
00860         case KFileMimeTypeInfo::KiloBytes:
00861             item->m_suffix = i18n("KB"); break;
00862 
00863         case KFileMimeTypeInfo::FramesPerSecond:
00864             item->m_suffix = i18n("fps"); break;
00865 
00866         case KFileMimeTypeInfo::DotsPerInch:
00867             item->m_suffix = i18n("dpi"); break;
00868 
00869         case KFileMimeTypeInfo::BitsPerPixel:
00870             item->m_suffix = i18n("bpp"); break;
00871 
00872         case KFileMimeTypeInfo::Hertz:
00873             item->m_suffix = i18n("Hz"); break;
00874 
00875         case KFileMimeTypeInfo::Millimeters:
00876             item->m_suffix = i18n("mm");
00877     }
00878 }
00879 
00880 void KFilePlugin::setPrefix(KFileMimeTypeInfo::ItemInfo* item, const QString& prefix)
00881 {
00882     item->m_prefix = prefix;
00883 }
00884 
00885 void KFilePlugin::setSuffix(KFileMimeTypeInfo::ItemInfo* item, const QString& suffix)
00886 {
00887     item->m_suffix = suffix;
00888 }
00889 
00890 KFileMetaInfoGroup KFilePlugin::appendGroup(KFileMetaInfo& info, const QString& key)
00891 {
00892     return info.appendGroup(key);
00893 }
00894 
00895 void KFilePlugin::appendItem(KFileMetaInfoGroup& group, const QString& key, QVariant value)
00896 {
00897     group.appendItem(key, value);
00898 }
00899 
00902 
00903 
00904 KFileMetaInfoProvider * KFileMetaInfoProvider::s_self;
00905 static KStaticDeleter<KFileMetaInfoProvider> sd;
00906 
00907 KFileMetaInfoProvider * KFileMetaInfoProvider::self()
00908 {
00909     if ( !s_self )
00910         s_self = sd.setObject( s_self, new KFileMetaInfoProvider() );
00911 
00912     return s_self;
00913 }
00914 
00915 KFileMetaInfoProvider::KFileMetaInfoProvider()
00916 {
00917     m_plugins.setAutoDelete( true );
00918 }
00919 
00920 KFileMetaInfoProvider::~KFileMetaInfoProvider()
00921 {
00922     m_plugins.clear();
00923     sd.setObject( 0 );
00924 }
00925 
00926 KFilePlugin* KFileMetaInfoProvider::loadPlugin( const QString& mimeType, const QString& protocol )
00927 {
00928     //kdDebug() << "loadPlugin: mimeType=" << mimeType << " protocol=" << protocol << endl;
00929     // Currently the idea is: either the mimetype is set or the protocol, but not both.
00930     // We need PNG fileinfo, and trash: fileinfo, but not "PNG in the trash".
00931     QString queryMimeType, query;
00932     if ( !mimeType.isEmpty() ) {
00933         query = "(not exist [X-KDE-Protocol])";
00934         queryMimeType = mimeType;
00935     } else {
00936         query = QString::fromLatin1( "[X-KDE-Protocol] == '%1'" ).arg(protocol);
00937         // querying for a protocol: we have no mimetype, so we need to use KFilePlugin as one
00938         queryMimeType = "KFilePlugin";
00939         // hopefully using KFilePlugin as genericMimeType too isn't a problem
00940     }
00941     const KTrader::OfferList offers = KTrader::self()->query( queryMimeType, "KFilePlugin", query, QString::null );
00942     if ( offers.isEmpty() )
00943         return 0;
00944     KService::Ptr service = *(offers.begin());
00945     Q_ASSERT( service && service->isValid() );
00946     if ( !service || !service->isValid() )
00947         return 0;
00948 
00949     KFilePlugin* plugin = KParts::ComponentFactory::createInstanceFromService<KFilePlugin>
00950                           ( service, this, mimeType.local8Bit() );
00951     if (!plugin)
00952         kdWarning(7033) << "error loading the plugin from " << service->desktopEntryPath() << endl;
00953 
00954     return plugin;
00955 }
00956 
00957 KFilePlugin* KFileMetaInfoProvider::loadAndRegisterPlugin( const QString& mimeType, const QString& protocol )
00958 {
00959     Q_ASSERT( m_pendingMimetypeInfos.isEmpty() );
00960     m_pendingMimetypeInfos.clear();
00961 
00962     KFilePlugin* plugin = loadPlugin( mimeType, protocol );
00963     if ( !plugin ) {
00964         // No plugin found. Remember that, to save time.
00965         m_plugins.insert( protocol.isEmpty() ? mimeType : protocol, new CachedPluginInfo );
00966         return 0;
00967     }
00968 
00969     if ( !protocol.isEmpty() ) {
00970         // Protocol-metainfo: only one entry
00971         Q_ASSERT( m_pendingMimetypeInfos.count() == 1 );
00972         KFileMimeTypeInfo* info = m_pendingMimetypeInfos[ protocol ];
00973         Q_ASSERT( info );
00974         m_plugins.insert( protocol, new CachedPluginInfo( plugin, info, true ) );
00975     } else {
00976         // Mimetype-metainfo: the plugin can register itself for multiple mimetypes, remember them all
00977         bool first = true;
00978         QDictIterator<KFileMimeTypeInfo> it( m_pendingMimetypeInfos );
00979         for( ; it.current(); ++it ) {
00980             KFileMimeTypeInfo* info = it.current();
00981             m_plugins.insert( it.currentKey(), new CachedPluginInfo( plugin, info, first ) );
00982             first = false;
00983         }
00984         // Hopefully the above includes the mimetype we asked for!
00985         if ( m_pendingMimetypeInfos.find( mimeType ) == 0 )
00986             kdWarning(7033) << plugin->className() << " was created for " << mimeType << " but doesn't call addMimeTypeInfo for it!" << endl;
00987     }
00988     m_pendingMimetypeInfos.clear();
00989     return plugin;
00990 }
00991 
00992 KFilePlugin * KFileMetaInfoProvider::plugin(const QString& mimeType)
00993 {
00994     return plugin( mimeType, QString::null );
00995 }
00996 
00997 KFilePlugin * KFileMetaInfoProvider::plugin(const QString& mimeType, const QString& protocol)
00998 {
00999     //kdDebug(7033) << "plugin() : looking for plugin for protocol=" << protocol << " mimeType=" << mimeType << endl;
01000 
01001     if ( !protocol.isEmpty() ) {
01002         CachedPluginInfo *cache = m_plugins.find( protocol );
01003         if ( cache && cache->plugin ) {
01004             return cache->plugin;
01005         }
01006         if ( !cache ) {
01007             KFilePlugin* plugin = loadAndRegisterPlugin( QString::null, protocol );
01008             if ( plugin )
01009                 return plugin;
01010         }
01011     }
01012 
01013     CachedPluginInfo *cache = m_plugins.find( mimeType );
01014     if ( cache ) {
01015         return cache->plugin;
01016     }
01017 
01018     KFilePlugin* plugin = loadAndRegisterPlugin( mimeType, QString::null );
01019 
01020 #if 0
01021     kdDebug(7033) << "currently loaded plugins:\n";
01022 
01023     QDictIterator<CachedPluginInfo> it( m_plugins );
01024     for( ; it.current(); ++it ) {
01025         CachedPluginInfo* cache = it.current();
01026         kdDebug(7033)
01027             << it.currentKey() // mimetype or protocol
01028             << " : " << (cache->plugin ? cache->plugin->className() : "(no plugin)") << endl; // plugin
01029         // TODO print cache->mimeTypeInfo
01030     }
01031 #endif
01032 
01033     return plugin;
01034 }
01035 
01036 QStringList KFileMetaInfoProvider::preferredKeys( const QString& mimeType ) const
01037 {
01038     KService::Ptr service =
01039         KServiceTypeProfile::preferredService( mimeType, "KFilePlugin");
01040 
01041     if ( !service || !service->isValid() )
01042     {
01043 //        kdDebug(7033) << "no valid service found\n";
01044         return QStringList();
01045     }
01046     return service->property("PreferredItems").toStringList();
01047 }
01048 
01049 QStringList KFileMetaInfoProvider::preferredGroups( const QString& mimeType ) const
01050 {
01051     KService::Ptr service =
01052         KServiceTypeProfile::preferredService( mimeType, "KFilePlugin");
01053 
01054     if ( !service || !service->isValid() )
01055     {
01056 //        kdDebug(7033) << "no valid service found\n";
01057         return QStringList();
01058     }
01059     return service->property("PreferredGroups").toStringList();
01060 }
01061 
01062 const KFileMimeTypeInfo * KFileMetaInfoProvider::mimeTypeInfo( const QString& mimeType )
01063 {
01064     return mimeTypeInfo( mimeType, QString::null );
01065 }
01066 
01067 const KFileMimeTypeInfo * KFileMetaInfoProvider::mimeTypeInfo( const QString& mimeType, const QString& protocol )
01068 {
01069     //kdDebug(7033) << "mimeTypeInfo() : looking for plugin for protocol=" << protocol << " mimeType=" << mimeType << endl;
01070     if ( !protocol.isEmpty() ) {
01071         CachedPluginInfo *cache = m_plugins.find( protocol );
01072         if ( cache && cache->mimeTypeInfo ) {
01073             return cache->mimeTypeInfo;
01074         }
01075 
01076         if ( !cache ) {
01077             loadAndRegisterPlugin( QString::null, protocol );
01078             cache = m_plugins.find( protocol );
01079             if ( cache && cache->mimeTypeInfo ) {
01080                 return cache->mimeTypeInfo;
01081             }
01082         }
01083     }
01084 
01085     CachedPluginInfo *cache = m_plugins.find( mimeType );
01086     if ( cache ) {
01087         return cache->mimeTypeInfo;
01088     }
01089 
01090     loadAndRegisterPlugin( mimeType, QString::null );
01091     cache = m_plugins.find( mimeType );
01092     if ( cache ) {
01093         return cache->mimeTypeInfo;
01094     }
01095     return 0;
01096 }
01097 
01098 KFileMimeTypeInfo * KFileMetaInfoProvider::addMimeTypeInfo(
01099     const QString& mimeType )
01100 {
01101 
01102     KFileMimeTypeInfo *info = m_pendingMimetypeInfos.find( mimeType );
01103     Q_ASSERT( !info );
01104     if ( !info )
01105     {
01106         info = new KFileMimeTypeInfo( mimeType );
01107         m_pendingMimetypeInfos.insert( mimeType, info );
01108     }
01109 
01110     info->m_preferredKeys    = preferredKeys( mimeType );
01111     info->m_preferredGroups  = preferredGroups( mimeType );
01112 
01113     return info;
01114 }
01115 
01116 QStringList KFileMetaInfoProvider::supportedMimeTypes() const
01117 {
01118     QStringList allMimeTypes;
01119     QString kfilePlugin = "KFilePlugin";
01120 
01121     KTrader::OfferList offers = KTrader::self()->query( "KFilePlugin" );
01122     KTrader::OfferListIterator it = offers.begin();
01123     for ( ; it != offers.end(); ++it )
01124     {
01125         const QStringList mimeTypes = (*it)->serviceTypes();
01126         QStringList::ConstIterator it2 = mimeTypes.begin();
01127         for ( ; it2 != mimeTypes.end(); ++it2 )
01128             if ( allMimeTypes.find( *it2 ) == allMimeTypes.end() &&
01129                  *it2 != kfilePlugin ) // also in serviceTypes()
01130                 allMimeTypes.append( *it2 );
01131     }
01132 
01133     return allMimeTypes;
01134 }
01135 
01140 
01141 
01142 // shared data of a KFileMetaInfoGroup
01143 class KFileMetaInfoGroup::Data : public QShared
01144 {
01145 public:
01146     Data(const QString& _name)
01147         : QShared(),
01148           name(_name),
01149           mimeTypeInfo(0L),
01150           dirty( false ),
01151           added( false )
01152     {}
01153 
01154     // we use this one for the streaming operators
01155     Data() : mimeTypeInfo(0L) {}
01156     ~Data() {
01157         if ( this == null )
01158             delete mimeTypeInfo;
01159     };
01160 
01161     QString                             name;
01162     QMap<QString, KFileMetaInfoItem>    items;
01163     const KFileMimeTypeInfo*            mimeTypeInfo;
01164     QStringList                         removedItems;
01165     bool                                dirty   :1;
01166     bool                                added   :1;
01167 
01168     static Data* null;
01169     static Data* makeNull();
01170 
01171 };
01172 
01173 KFileMetaInfoGroup::KFileMetaInfoGroup( const QString& name,
01174                                         const KFileMimeTypeInfo* info )
01175     : d(new Data( name ) )
01176 {
01177       d->mimeTypeInfo = info;
01178 }
01179 
01180 KFileMetaInfoGroup::KFileMetaInfoGroup( const KFileMetaInfoGroup& original )
01181 {
01182     // operator= does everything that's necessary
01183     d = Data::makeNull();
01184     *this = original;
01185 }
01186 
01187 KFileMetaInfoGroup::KFileMetaInfoGroup()
01188 {
01189     d = Data::makeNull();
01190 }
01191 
01192 KFileMetaInfoGroup::~KFileMetaInfoGroup()
01193 {
01194     deref();
01195 }
01196 
01197 const KFileMetaInfoGroup& KFileMetaInfoGroup::operator= (const KFileMetaInfoGroup& info )
01198 {
01199     if (d != info.d)
01200     {
01201         deref();
01202         // first deref the old one
01203         d = info.d;
01204         // and now ref the new one
01205         ref();
01206     }
01207     return *this;
01208 }
01209 
01210 bool KFileMetaInfoGroup::isValid() const
01211 {
01212     // We don't call makeNull here since it isn't necassery, see deref()
01213     return d != Data::null;
01214 }
01215 
01216 bool KFileMetaInfoGroup::isEmpty() const
01217 {
01218     return d->items.isEmpty();
01219 }
01220 
01221 QStringList KFileMetaInfoGroup::preferredKeys() const
01222 {
01223     assert(isValid());
01224     QStringList list = keys();
01225     QStringList newlist;
01226     QStringList preferredKeys = d->mimeTypeInfo->preferredKeys();
01227     QStringList::Iterator pref;
01228     QStringList::Iterator begin = preferredKeys.begin();
01229     QStringList::Iterator end   = preferredKeys.end();
01230 
01231     // move all keys from the preferred keys that are in our list to a new list
01232     for ( pref = begin; pref!=end; ++pref )
01233     {
01234         QStringList::Iterator item = list.find(*pref);
01235         if ( item != list.end() )
01236         {
01237              newlist.append( *item );
01238              list.remove(item);
01239         }
01240     }
01241 
01242     // now the old list only contains the non-preferred items, so we
01243     // add the remaining ones to newlist
01244     newlist += list;
01245 
01246     return newlist;
01247 }
01248 
01249 QStringList KFileMetaInfoGroup::keys() const
01250 {
01251     if (d == Data::makeNull())
01252         kdWarning(7033) << "attempt to get the keys of "
01253                            "an invalid metainfo group";
01254 
01255     QStringList list;
01256 
01257     // make a QStringList with all available keys
01258     QMapConstIterator<QString, KFileMetaInfoItem> it;
01259     for (it = d->items.begin(); it!=d->items.end(); ++it)
01260     {
01261         list.append(it.data().key());
01262 //        kdDebug(7033) << "Item " << it.data().key() << endl;
01263     }
01264     return list;
01265 }
01266 
01267 QString KFileMetaInfoGroup::translatedName() const
01268 {
01269     assert(isValid());
01270     return d->mimeTypeInfo->groupInfo(d->name)->translatedName();
01271 }
01272 
01273 QStringList KFileMetaInfoGroup::supportedKeys() const
01274 {
01275     assert(isValid());
01276     return d->mimeTypeInfo->groupInfo(d->name)->supportedKeys();
01277 }
01278 
01279 bool KFileMetaInfoGroup::supportsVariableKeys() const
01280 {
01281     assert(isValid());
01282     return d->mimeTypeInfo->groupInfo(d->name)->supportsVariableKeys();
01283 }
01284 
01285 bool KFileMetaInfoGroup::contains( const QString& key ) const
01286 {
01287     return d->items.contains(key);
01288 }
01289 
01290 KFileMetaInfoItem KFileMetaInfoGroup::item( const QString& key) const
01291 {
01292     QMapIterator<QString,KFileMetaInfoItem> it = d->items.find( key );
01293     if ( it != d->items.end() )
01294         return it.data();
01295 
01296     return KFileMetaInfoItem();
01297 }
01298 
01299 KFileMetaInfoItem KFileMetaInfoGroup::item(uint hint) const
01300 {
01301     QMapIterator<QString, KFileMetaInfoItem> it;
01302 
01303     for (it = d->items.begin(); it!=d->items.end(); ++it)
01304         if (it.data().hint() == hint)
01305             return it.data();
01306 
01307     return KFileMetaInfoItem();
01308 }
01309 
01310 QString KFileMetaInfoGroup::name() const
01311 {
01312     return d->name;
01313 }
01314 
01315 uint KFileMetaInfoGroup::attributes() const
01316 {
01317     assert(isValid());
01318     return d->mimeTypeInfo->groupInfo(d->name)->attributes();
01319 }
01320 
01321 void KFileMetaInfoGroup::setAdded()
01322 {
01323     d->added = true;
01324 }
01325 
01326 bool KFileMetaInfoGroup::isModified() const
01327 {
01328     return d->dirty;
01329 }
01330 
01331 void KFileMetaInfoGroup::ref()
01332 {
01333     if (d != Data::null) d->ref();
01334 
01335 }
01336 
01337 void KFileMetaInfoGroup::deref()
01338 {
01339     // We don't call makeNull here since it isn't necassery:
01340     // If d is equal to null it means that null is initialized already.
01341     // null is 0L when it hasn't been initialized and d is never 0L.
01342     if ((d != Data::null) && d->deref())
01343     {
01344 //        kdDebug(7033) << "metainfo group " << d->name
01345 //                      << " is finally deleted\n";
01346         delete d;
01347         d = 0;
01348     }
01349 
01350 }
01351 
01352 KFileMetaInfoItem KFileMetaInfoGroup::addItem( const QString& key )
01353 {
01354     assert(isValid());
01355     QMapIterator<QString,KFileMetaInfoItem> it = d->items.find( key );
01356     if ( it != d->items.end() )
01357         return it.data();
01358 
01359     const KFileMimeTypeInfo::GroupInfo* ginfo = d->mimeTypeInfo->groupInfo(d->name);
01360 
01361     if ( !ginfo ) {
01362         Q_ASSERT( ginfo );
01363         return KFileMetaInfoItem();
01364     }
01365 
01366     const KFileMimeTypeInfo::ItemInfo* info = ginfo->itemInfo(key);
01367 
01368     if ( !info ) {
01369         Q_ASSERT( info );
01370         return KFileMetaInfoItem();
01371     }
01372 
01373     KFileMetaInfoItem item;
01374 
01375     if (info->isVariableItem())
01376         item = KFileMetaInfoItem(ginfo->variableItemInfo(), key, QVariant());
01377     else
01378         item = KFileMetaInfoItem(info, key, QVariant());
01379 
01380     d->items.insert(key, item);
01381     item.setAdded();           // mark as added
01382     d->dirty = true;           // mark ourself as dirty, too
01383     return item;
01384 }
01385 
01386 bool KFileMetaInfoGroup::removeItem( const QString& key )
01387 {
01388     if (!isValid())
01389     {
01390           kdDebug(7033) << "trying to remove an item from an invalid group\n";
01391           return false;
01392     }
01393 
01394     QMapIterator<QString, KFileMetaInfoItem> it = d->items.find(key);
01395     if ( it==d->items.end() )
01396     {
01397           kdDebug(7033) << "trying to remove the non existant item " << key << "\n";
01398           return false;
01399     }
01400 
01401     if (!((*it).attributes() & KFileMimeTypeInfo::Removable))
01402     {
01403         kdDebug(7033) << "trying to remove a non removable item\n";
01404         return false;
01405     }
01406 
01407     (*it).setRemoved();
01408     d->items.remove(it);
01409     d->removedItems.append(key);
01410     d->dirty = true;
01411     return true;
01412 }
01413 
01414 QStringList KFileMetaInfoGroup::removedItems()
01415 {
01416     return d->removedItems;
01417 }
01418 
01419 KFileMetaInfoItem KFileMetaInfoGroup::appendItem(const QString& key,
01420                                                  const QVariant& value)
01421 {
01422     //KDE4 enforce (value.type() == d->mimeTypeInfo->type())
01423     assert(isValid());
01424     const KFileMimeTypeInfo::GroupInfo* ginfo = d->mimeTypeInfo->groupInfo(d->name);
01425     if ( !ginfo ) {
01426         kdWarning() << "Trying to append a Metadata item for a non-existant group:" << d->name << endl;
01427         return KFileMetaInfoItem();
01428     }
01429     const KFileMimeTypeInfo::ItemInfo* info = ginfo->itemInfo(key);
01430     if ( !info ) {
01431         kdWarning() << "Trying to append a Metadata item for an unknown key (no ItemInfo): " << key << endl;
01432         return KFileMetaInfoItem();
01433     }
01434 
01435     KFileMetaInfoItem item;
01436 
01437     if (info->key().isNull())
01438         item = KFileMetaInfoItem(ginfo->variableItemInfo(), key, value);
01439     else
01440         item = KFileMetaInfoItem(info, key, value);
01441 
01442     kdDebug(7033) << "KFileMetaInfogroup inserting a " << key << endl;
01443 
01444     d->items.insert(key, item);
01445     return item;
01446 }
01447 
01448 KFileMetaInfoGroup::Data* KFileMetaInfoGroup::Data::null = 0L;
01449 static KStaticDeleter<KFileMetaInfoGroup::Data> sd_KFileMetaInfoGroupData;
01450 
01451 KFileMetaInfoGroup::Data* KFileMetaInfoGroup::Data::makeNull()
01452 {
01453     if (!null)
01454     {
01455         // We deliberately do not reset "null" after it has been destroyed!
01456         // Otherwise we will run into problems later in ~KFileMetaInfoItem
01457         // where the d-pointer is compared against null.
01458         null = new Data(QString::null);
01459         null->mimeTypeInfo = new KFileMimeTypeInfo();
01460         sd_KFileMetaInfoGroupData.setObject( null );
01461     }
01462     return null;
01463 }
01464 
01465 
01468 
01469 KFileMimeTypeInfo::KFileMimeTypeInfo( const QString& mimeType )
01470     : m_mimeType( mimeType )
01471 {
01472     m_groups.setAutoDelete( true );
01473 }
01474 
01475 KFileMimeTypeInfo::~KFileMimeTypeInfo()
01476 {
01477 }
01478 
01479 const KFileMimeTypeInfo::GroupInfo * KFileMimeTypeInfo::groupInfo( const QString& group ) const
01480 {
01481     return m_groups.find( group );
01482 }
01483 
01484 KFileMimeTypeInfo::GroupInfo * KFileMimeTypeInfo::addGroupInfo(
01485                            const QString& name, const QString& translatedName )
01486 {
01487     GroupInfo* group = new GroupInfo( name, translatedName );
01488     m_groups.insert(name, group);
01489     return group;
01490 }
01491 
01492 QStringList KFileMimeTypeInfo::supportedGroups() const
01493 {
01494     QStringList list;
01495     QDictIterator<GroupInfo> it( m_groups );
01496     for ( ; it.current(); ++it )
01497         list.append( it.current()->name() );
01498 
01499     return list;
01500 }
01501 
01502 QStringList KFileMimeTypeInfo::translatedGroups() const
01503 {
01504     QStringList list;
01505     QDictIterator<GroupInfo> it( m_groups );
01506     for ( ; it.current(); ++it )
01507         list.append( it.current()->translatedName() );
01508 
01509     return list;
01510 }
01511 
01512 QStringList KFileMimeTypeInfo::supportedKeys() const
01513 {
01514     // not really efficient, but not those are not large lists, probably.
01515     // maybe cache the result?
01516     QStringList keys;
01517     QStringList::ConstIterator lit;
01518     QDictIterator<GroupInfo> it( m_groups );
01519     for ( ; it.current(); ++it ) { // need to nuke dupes
01520         QStringList list = it.current()->supportedKeys();
01521         for ( lit = list.begin(); lit != list.end(); ++lit ) {
01522             if ( keys.find( *lit ) == keys.end() )
01523                 keys.append( *lit );
01524         }
01525     }
01526 
01527     return keys;
01528 }
01529 
01530 QValidator * KFileMimeTypeInfo::createValidator(const QString& group,
01531                                                 const QString& key,
01532                                                 QObject *parent,
01533                                                 const char *name) const
01534 {
01535     KFilePlugin* plugin = KFileMetaInfoProvider::self()->plugin(m_mimeType);
01536     if (plugin) return plugin->createValidator(mimeType(), group, key,
01537                                                parent, name);
01538     return 0;
01539 }
01540 
01541 
01544 
01545 KFileMimeTypeInfo::GroupInfo::GroupInfo( const QString& name,
01546                                          const QString& translatedName )
01547     : m_name( name ),
01548       m_translatedName( translatedName ),
01549       m_attr( 0 ),
01550       m_variableItemInfo( 0 )
01551 
01552 {
01553     m_itemDict.setAutoDelete( true );
01554 }
01555 
01556 KFileMimeTypeInfo::GroupInfo::~GroupInfo()
01557 {
01558     delete m_variableItemInfo;
01559 } 
01560 
01561 const KFileMimeTypeInfo::ItemInfo * KFileMimeTypeInfo::GroupInfo::itemInfo( const QString& key ) const
01562 {
01563     ItemInfo* item = m_itemDict.find( key );
01564 
01565     // if we the item isn't found and variable keys are supported, we need to
01566     // return the default variable key iteminfo.
01567     if (!item && m_variableItemInfo)
01568     {
01569         return m_variableItemInfo;
01570     }
01571     return item;
01572 }
01573 
01574 KFileMimeTypeInfo::ItemInfo* KFileMimeTypeInfo::GroupInfo::addItemInfo(
01575                   const QString& key, const QString& translatedKey,
01576                   QVariant::Type type)
01577 {
01578 //    kdDebug(7034) << key << "(" << translatedKey << ") -> " << QVariant::typeToName(type) << endl;
01579 
01580     ItemInfo* item = new ItemInfo(key, translatedKey, type);
01581     m_supportedKeys.append(key);
01582     m_itemDict.insert(key, item);
01583     return item;
01584 }
01585 
01586 
01587 void KFileMimeTypeInfo::GroupInfo::addVariableInfo( QVariant::Type type,
01588                                                    uint attr )
01589 {
01590     // just make sure that it's not already there
01591     delete m_variableItemInfo;
01592     m_variableItemInfo = new ItemInfo(QString::null, QString::null, type);
01593     m_variableItemInfo->m_attr = attr;
01594 }
01595 
01598 
01599 QString KFileMimeTypeInfo::ItemInfo::string(const QVariant& value, bool mangle) const
01600 {
01601     QString s;
01602 
01603     switch (value.type())
01604     {
01605         case QVariant::Invalid :
01606             return "---";
01607 
01608         case QVariant::Bool :
01609             s = value.toBool() ? i18n("Yes") : i18n("No");
01610             break;
01611 
01612         case QVariant::Int :
01613             if (unit() == KFileMimeTypeInfo::Seconds)
01614             {
01615               int seconds = value.toInt() % 60;
01616               int minutes = value.toInt() / 60 % 60;
01617               int hours   = value.toInt() / 3600;
01618               s = hours ? QString().sprintf("%d:%02d:%02d",hours, minutes, seconds)
01619                         : QString().sprintf("%02d:%02d", minutes, seconds);
01620               return s; // no suffix wanted
01621             }
01622             else if (unit() == KFileMimeTypeInfo::Bytes)
01623             {
01624                 // convertSize already adds the correct suffix
01625                 return KIO::convertSize(value.toInt());
01626             }
01627             else if (unit() == KFileMimeTypeInfo::KiloBytes)
01628             {
01629                 // convertSizeFromKB already adds the correct suffix
01630                 return KIO::convertSizeFromKB(value.toInt());
01631             }
01632             else
01633                 s = KGlobal::locale()->formatNumber( value.toInt() , 0);
01634             break;
01635 
01636         case QVariant::LongLong :
01637             s = KGlobal::locale()->formatNumber( value.toLongLong(), 0 );
01638             break;
01639 
01640     case QVariant::ULongLong :
01641             if ( unit() == KFileMimeTypeInfo::Bytes )
01642                 return KIO::convertSize( value.toULongLong() );
01643             else if ( unit() == KFileMimeTypeInfo::KiloBytes )
01644                 return KIO::convertSizeFromKB( value.toULongLong() );
01645             else
01646                 s = KGlobal::locale()->formatNumber( value.toULongLong(), 0 );
01647             break;
01648 
01649         case QVariant::UInt :
01650             s = KGlobal::locale()->formatNumber( value.toUInt() , 0);
01651             break;
01652 
01653         case QVariant::Double :
01654             s = KGlobal::locale()->formatNumber( value.toDouble(), 3);
01655             break;
01656 
01657         case QVariant::Date :
01658             s = KGlobal::locale()->formatDate( value.toDate(), true );
01659             break;
01660 
01661         case QVariant::Time :
01662             s = KGlobal::locale()->formatTime( value.toTime(), true );
01663             break;
01664 
01665         case QVariant::DateTime :
01666             s = KGlobal::locale()->formatDateTime( value.toDateTime(),
01667                                                    true, true );
01668             break;
01669 
01670         case QVariant::Size :
01671             s = QString("%1 x %2").arg(value.toSize().width())
01672                                 .arg(value.toSize().height());
01673             break;
01674 
01675         case QVariant::Point :
01676             s = QString("%1/%2").arg(value.toSize().width())
01677                                 .arg(value.toSize().height());
01678             break;
01679 
01680         default:
01681             s = value.toString();
01682     }
01683 
01684     if (mangle && !s.isNull())
01685     {
01686         s.prepend(prefix());
01687         s.append(" " + suffix());
01688     }
01689     return s;
01690 }
01691 
01692 
01695 
01696 
01697 
01698 // stream operators
01699 
01700 /* serialization of a KFileMetaInfoItem:
01701    first a bool that says if the items is valid, and if yes,
01702    all the elements of the Data
01703 */
01704 KIO_EXPORT QDataStream& operator <<(QDataStream& s, const KFileMetaInfoItem& item )
01705 {
01706 
01707      KFileMetaInfoItem::Data* d = item.d;
01708 
01709      // if the object is invalid, put only a char in the stream
01710      bool isValid = item.isValid();
01711      s << isValid;
01712      // ### what do about mimetypeInfo ?
01713      if (isValid)
01714          s << d->key
01715            << d->value
01716            << d->dirty
01717            << d->added
01718            << d->removed;
01719 
01720      return s;
01721 }
01722 
01723 
01724 KIO_EXPORT QDataStream& operator >>(QDataStream& s, KFileMetaInfoItem& item )
01725 {
01726      bool isValid;
01727      s >> isValid;
01728 
01729      if (!isValid)
01730      {
01731          item = KFileMetaInfoItem();
01732          return s;
01733      }
01734 
01735      // we need a new object for our data
01736      item.deref();
01737      item.d = new KFileMetaInfoItem::Data();
01738 
01739      // ### what do about mimetypeInfo ?
01740      bool dirty, added, removed;
01741      s >> item.d->key
01742        >> item.d->value
01743        >> dirty
01744        >> added
01745        >> removed;
01746      item.d->dirty = dirty;
01747      item.d->added = added;
01748      item.d->removed = removed;
01749 
01750     return s;
01751 }
01752 
01753 
01754 // serialization of a KFileMetaInfoGroup
01755 // we serialize the name of the mimetype here instead of the mimetype info
01756 // on the other side, we can simply use this to ask the provider for the info
01757 KIO_EXPORT QDataStream& operator <<(QDataStream& s, const KFileMetaInfoGroup& group )
01758 {
01759     KFileMetaInfoGroup::Data* d = group.d;
01760 
01761     // if the object is invalid, put only a byte in the stream
01762     bool isValid = group.isValid();
01763 
01764     s << isValid;
01765     if (isValid)
01766     {
01767         s << d->name
01768           << d->items
01769           << d->mimeTypeInfo->mimeType();
01770     }
01771     return s;
01772 }
01773 
01774 KIO_EXPORT QDataStream& operator >>(QDataStream& s, KFileMetaInfoGroup& group )
01775 {
01776     QString mimeType;
01777     bool isValid;
01778     s >> isValid;
01779 
01780     // if it's invalid, there is not much to do
01781     if (!isValid)
01782     {
01783         group = KFileMetaInfoGroup();
01784         return s;
01785     }
01786 
01787     // we need a new object for our data
01788     group.deref();
01789     group.d = new KFileMetaInfoGroup::Data();
01790 
01791     s >> group.d->name
01792       >> group.d->items
01793       >> mimeType;
01794 
01795     group.d->mimeTypeInfo = KFileMetaInfoProvider::self()->mimeTypeInfo(mimeType);
01796 
01797     // we need to set the item info for the items here
01798     QMapIterator<QString, KFileMetaInfoItem> it = group.d->items.begin();
01799     for ( ; it != group.d->items.end(); ++it)
01800     {
01801         (*it).d->mimeTypeInfo = group.d->mimeTypeInfo->groupInfo(group.d->name)
01802                                   ->itemInfo((*it).key());
01803     }
01804 
01805     return s;
01806 }
01807 
01808 // serialization of a KFileMetaInfo object
01809 // we serialize the name of the mimetype here instead of the mimetype info
01810 // on the other side, we can simply use this to ask the provider for the info
01811 KIO_EXPORT QDataStream& operator <<(QDataStream& s, const KFileMetaInfo& info )
01812 {
01813     KFileMetaInfo::Data* d = info.d;
01814 
01815     // if the object is invalid, put only a byte that tells this
01816     bool isValid = info.isValid();
01817 
01818     s << isValid;
01819     if (isValid)
01820     {
01821         s << d->url
01822           << d->what
01823           << d->groups
01824           << d->mimeTypeInfo->mimeType();
01825     }
01826     return s;
01827 }
01828 
01829 KIO_EXPORT QDataStream& operator >>(QDataStream& s, KFileMetaInfo& info )
01830 {
01831     QString mimeType;
01832     bool isValid;
01833     s >> isValid;
01834 
01835     // if it's invalid, there is not much to do
01836     if (!isValid)
01837     {
01838         info = KFileMetaInfo();
01839         return s;
01840     }
01841 
01842     // we need a new object for our data
01843     info.deref();
01844     info.d = new KFileMetaInfo::Data();
01845 
01846     s >> info.d->url
01847       >> info.d->what
01848       >> info.d->groups
01849       >> mimeType;
01850     info.d->mimeTypeInfo = KFileMetaInfoProvider::self()->mimeTypeInfo(mimeType);
01851 
01852     return s;
01853 }
01854 
01855 #include "kfilemetainfo.moc"
KDE Home | KDE Accessibility Home | Description of Access Keys