• Skip to content
  • Skip to link menu
KDE 3.5 API Reference
  • KDE API Reference
  • API Reference
  • Sitemap
  • Contact Us
 

kio

kfilemetainfo.cpp

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

kio

Skip menu "kio"
  • Main Page
  • Modules
  • Namespace List
  • Class Hierarchy
  • Alphabetical List
  • Class List
  • File List
  • Namespace Members
  • Class Members
  • Related Pages

API Reference

Skip menu "API Reference"
  • dcop
  • DNSSD
  • interfaces
  • Kate
  • kconf_update
  • KDECore
  • KDED
  • kdefx
  • KDEsu
  • kdeui
  • KDocTools
  • KHTML
  • KImgIO
  • KInit
  • kio
  • kioslave
  • KJS
  • KNewStuff
  • KParts
  • KUtils
Generated for API Reference by doxygen 1.5.9
This website is maintained by Adriaan de Groot and Allen Winter.
KDE® and the K Desktop Environment® logo are registered trademarks of KDE e.V. | Legal