00001
00002
00003
00004
00005
00006
00007
00008
00009
00010
00011
00012
00013
00014
00015
00016
00017
00018
00019
00020
00021
00022
00023 #include <qshared.h>
00024 #include <qdict.h>
00025
00026 #include <ktrader.h>
00027 #include <kstaticdeleter.h>
00028 #include <kparts/componentfactory.h>
00029 #include <kuserprofile.h>
00030 #include <kdebug.h>
00031 #include <kmimetype.h>
00032 #include <kdatastream.h>
00033 #include <klocale.h>
00034 #include <kio/global.h>
00035
00036 #include "kfilemetainfo.h"
00037
00038
00039 class KFileMetaInfoItem::Data : public QShared
00040 {
00041 public:
00042 Data( const KFileMimeTypeInfo::ItemInfo* mti, const QString& _key,
00043 const QVariant& _value )
00044 : QShared(),
00045 mimeTypeInfo( mti ),
00046 key( _key ),
00047 value( _value ),
00048 dirty( false ),
00049 added( false ),
00050 removed( false )
00051 {}
00052
00053
00054 Data() : mimeTypeInfo( 0L )
00055 {}
00056
00057 ~Data()
00058 {
00059 if ( this == null )
00060 delete const_cast<KFileMimeTypeInfo::ItemInfo*>( mimeTypeInfo );
00061 }
00062
00063 const KFileMimeTypeInfo::ItemInfo* mimeTypeInfo;
00064
00065 QString key;
00066 QVariant value;
00067 bool dirty :1;
00068 bool added :1;
00069 bool removed :1;
00070
00071 static Data* null;
00072 static Data* makeNull();
00073 };
00074
00075
00076 KFileMetaInfoItem::Data* KFileMetaInfoItem::Data::null = 0L;
00077 static KStaticDeleter<KFileMetaInfoItem::Data> sd_KFileMetaInfoItemData;
00078
00079 KFileMetaInfoItem::Data* KFileMetaInfoItem::Data::makeNull()
00080 {
00081 if (!null)
00082 {
00083
00084
00085
00086
00087 KFileMimeTypeInfo::ItemInfo* info = new KFileMimeTypeInfo::ItemInfo();
00088 null = new Data(info, QString::null, QVariant());
00089 sd_KFileMetaInfoItemData.setObject( null );
00090 }
00091 return null;
00092 }
00093
00094 KFileMetaInfoItem::KFileMetaInfoItem( const KFileMimeTypeInfo::ItemInfo* mti,
00095 const QString& key, const QVariant& value )
00096 : d( new Data( mti, key, value ) )
00097 {
00098 }
00099
00100 KFileMetaInfoItem::KFileMetaInfoItem( const KFileMetaInfoItem& item )
00101 {
00102
00103 d = Data::makeNull();
00104 *this = item;
00105 }
00106
00107 KFileMetaInfoItem::KFileMetaInfoItem()
00108 {
00109 d = Data::makeNull();
00110 }
00111
00112 KFileMetaInfoItem::~KFileMetaInfoItem()
00113 {
00114 deref();
00115 }
00116
00117 const KFileMetaInfoItem& KFileMetaInfoItem::operator=
00118 (const KFileMetaInfoItem & item )
00119 {
00120 if (d != item.d)
00121 {
00122
00123 deref();
00124 d = item.d;
00125
00126 ref();
00127 }
00128
00129 return *this;
00130 }
00131
00132 bool KFileMetaInfoItem::setValue( const QVariant& value )
00133 {
00134
00135 if ( d == Data::null ) return false;
00136
00137 if ( ! (d->mimeTypeInfo->attributes() & KFileMimeTypeInfo::Modifiable ) ||
00138 ! (value.canCast(d->mimeTypeInfo->type())))
00139 {
00140 kdDebug(7033) << "setting the value of " << key() << "failed\n";
00141 return false;
00142 }
00143
00144
00145
00146 if ( d->value == value )
00147 return true;
00148
00149 d->dirty = true;
00150 d->value = value;
00151
00152
00153 d->value.cast(d->mimeTypeInfo->type());
00154
00155 return true;
00156 }
00157
00158 bool KFileMetaInfoItem::isRemoved() const
00159 {
00160 return d->removed;
00161 }
00162
00163 QString KFileMetaInfoItem::key() const
00164 {
00165 return d->key;
00166 }
00167
00168 QString KFileMetaInfoItem::translatedKey() const
00169 {
00170
00171 if (d->mimeTypeInfo->key().isNull())
00172 {
00173
00174 return i18n(d->key.utf8());
00175 }
00176
00177 return d->mimeTypeInfo->translatedKey();
00178 }
00179
00180 const QVariant& KFileMetaInfoItem::value() const
00181 {
00182 return d->value;
00183 }
00184
00185 QString KFileMetaInfoItem::string( bool mangle ) const
00186 {
00187 return d->mimeTypeInfo->string(d->value, mangle);
00188 }
00189
00190 QVariant::Type KFileMetaInfoItem::type() const
00191 {
00192 return d->mimeTypeInfo->type();
00193 }
00194
00195 bool KFileMetaInfoItem::isModified() const
00196 {
00197 return d->dirty;
00198 }
00199
00200 QString KFileMetaInfoItem::prefix() const
00201 {
00202 return d->mimeTypeInfo->prefix();
00203 }
00204
00205 QString KFileMetaInfoItem::suffix() const
00206 {
00207 return d->mimeTypeInfo->suffix();
00208 }
00209
00210 uint KFileMetaInfoItem::hint() const
00211 {
00212 return d->mimeTypeInfo->hint();
00213 }
00214
00215 uint KFileMetaInfoItem::attributes() const
00216 {
00217 return d->mimeTypeInfo->attributes();
00218 }
00219
00220 bool KFileMetaInfoItem::isEditable() const
00221 {
00222 return d->mimeTypeInfo->attributes() & KFileMimeTypeInfo::Modifiable;
00223 }
00224
00225 bool KFileMetaInfoItem::isValid() const
00226 {
00227
00228
00229
00230 return d != Data::null;
00231 }
00232
00233 void KFileMetaInfoItem::setAdded()
00234 {
00235 d->added = true;
00236 }
00237
00238 void KFileMetaInfoItem::setRemoved()
00239 {
00240 d->removed = true;
00241 }
00242
00243 void KFileMetaInfoItem::ref()
00244 {
00245 if (d != Data::null) d->ref();
00246 }
00247
00248 void KFileMetaInfoItem::deref()
00249 {
00250
00251
00252
00253 if ((d != Data::null) && d->deref())
00254 {
00255
00256
00257 delete d;
00258 }
00259 }
00260
00263
00264
00265 class KFileMetaInfo::Data : public QShared
00266 {
00267 public:
00268 Data(const QString& _path, uint _what)
00269 : QShared(),
00270 path(_path),
00271 what(_what)
00272 {}
00273
00274
00275 Data() {};
00276
00277 QString path;
00278 uint what;
00279 QMap<QString, KFileMetaInfoGroup> groups;
00280 const KFileMimeTypeInfo* mimeTypeInfo;
00281 QStringList removedGroups;
00282
00283 static Data* null;
00284 static Data* makeNull();
00285
00286 };
00287
00288 KFileMetaInfo::KFileMetaInfo( const QString& path, const QString& mimeType,
00289 uint what )
00290 : d(new Data( path, what ) )
00291 {
00292
00293
00294 QString mT;
00295 if (mimeType.isEmpty())
00296 mT = KMimeType::findByPath(path)->name();
00297 else
00298 mT = mimeType;
00299
00300
00301 KFileMetaInfo item(*this);
00302
00303 d->mimeTypeInfo = KFileMetaInfoProvider::self()->mimeTypeInfo(mT);
00304 if ( d->mimeTypeInfo )
00305 {
00306
00307 KFilePlugin *p = plugin();
00308 if (p && !p->readInfo( item, what))
00309 *this=KFileMetaInfo();
00310 }
00311 else
00312 {
00313
00314 d = Data::makeNull();
00315 }
00316 }
00317
00318 KFileMetaInfo::KFileMetaInfo( const KFileMetaInfo& original )
00319 {
00320
00321 d = Data::makeNull();
00322 *this = original;
00323 }
00324
00325 KFileMetaInfo::KFileMetaInfo()
00326 {
00327 d = Data::makeNull();
00328 }
00329
00330 KFileMetaInfo::~KFileMetaInfo()
00331 {
00332 deref();
00333 }
00334
00335 QStringList KFileMetaInfo::supportedGroups() const
00336 {
00337 return d->mimeTypeInfo->supportedGroups();
00338 }
00339
00340 QStringList KFileMetaInfo::supportedKeys() const
00341 {
00342 return d->mimeTypeInfo->supportedKeys();
00343 }
00344
00345 QStringList KFileMetaInfo::groups() const
00346 {
00347 QStringList list;
00348 QMapConstIterator<QString, KFileMetaInfoGroup> it = d->groups.begin();
00349 for ( ; it != d->groups.end(); ++it )
00350 list += (*it).name();
00351
00352 return list;
00353 }
00354
00355 QStringList KFileMetaInfo::editableGroups() const
00356 {
00357 QStringList list;
00358 QStringList supported = supportedGroups();
00359 QStringList::ConstIterator it = supported.begin();
00360 for ( ; it != supported.end(); ++it ) {
00361 const KFileMimeTypeInfo::GroupInfo * groupInfo = d->mimeTypeInfo->groupInfo( *it );
00362 if ( groupInfo && groupInfo->attributes() &
00363 (KFileMimeTypeInfo::Addable | KFileMimeTypeInfo::Removable) )
00364 list.append( *it );
00365 }
00366
00367 return list;
00368 }
00369
00370 QStringList KFileMetaInfo::preferredGroups() const
00371 {
00372 QStringList list = groups();
00373 QStringList newlist;
00374 QStringList preferred = d->mimeTypeInfo->preferredGroups();
00375 QStringList::Iterator pref;
00376
00377
00378 for ( pref = preferred.begin(); pref != preferred.end(); pref++ )
00379 {
00380 QStringList::Iterator group = list.find(*pref);
00381 if ( group != list.end() )
00382 {
00383 newlist.append( *group );
00384 list.remove(group);
00385 }
00386 }
00387
00388
00389
00390 newlist += list;
00391
00392 return newlist;
00393 }
00394
00395 QStringList KFileMetaInfo::preferredKeys() const
00396 {
00397 QStringList newlist;
00398
00399 QStringList list = preferredGroups();
00400 for (QStringList::Iterator git = list.begin(); git != list.end(); ++git)
00401 {
00402 newlist += d->groups[*git].preferredKeys();
00403 }
00404
00405 return newlist;
00406 }
00407
00408 KFileMetaInfoGroup KFileMetaInfo::group(const QString& key) const
00409 {
00410 QMapIterator<QString,KFileMetaInfoGroup> it = d->groups.find( key );
00411 if ( it != d->groups.end() )
00412 return it.data();
00413 else
00414 return KFileMetaInfoGroup();
00415 }
00416
00417 bool KFileMetaInfo::addGroup( const QString& name )
00418 {
00419 if ( d->mimeTypeInfo->supportedGroups().contains(name) &&
00420 ! d->groups.contains(name) )
00421 {
00422 KFileMetaInfoGroup group( name, d->mimeTypeInfo );
00423
00424
00425 const KFileMimeTypeInfo::GroupInfo* ginfo = d->mimeTypeInfo->groupInfo(name);
00426 Q_ASSERT(ginfo);
00427 if (!ginfo) return false;
00428
00429 QStringList keys = ginfo->supportedKeys();
00430 for (QStringList::Iterator it = keys.begin(); it != keys.end(); ++it)
00431 {
00432 const KFileMimeTypeInfo::ItemInfo* iteminfo = ginfo->itemInfo(*it);
00433 Q_ASSERT(ginfo);
00434 if (!iteminfo) return false;
00435
00436 if ( !(iteminfo->attributes() & KFileMimeTypeInfo::Addable) &&
00437 (iteminfo->attributes() & KFileMimeTypeInfo::Modifiable))
00438 {
00439
00440 group.appendItem(iteminfo->key(), QVariant());
00441 }
00442
00443 }
00444
00445 d->groups.insert(name, group);
00446 group.setAdded();
00447 return true;
00448 }
00449
00450 return false;
00451 }
00452
00453 bool KFileMetaInfo::removeGroup( const QString& name )
00454 {
00455 QMapIterator<QString, KFileMetaInfoGroup> it = d->groups.find(name);
00456 if ( (it==d->groups.end()) ||
00457 !((*it).attributes() & KFileMimeTypeInfo::Removable))
00458 return false;
00459
00460 d->groups.remove(it);
00461 d->removedGroups.append(name);
00462 return true;
00463 }
00464
00465 QStringList KFileMetaInfo::removedGroups()
00466 {
00467 return d->removedGroups;
00468 }
00469
00470 const KFileMetaInfo& KFileMetaInfo::operator= (const KFileMetaInfo& info )
00471 {
00472 if (d != info.d)
00473 {
00474 deref();
00475
00476 d = info.d;
00477
00478 ref();
00479 }
00480 return *this;
00481 }
00482
00483 bool KFileMetaInfo::isValid() const
00484 {
00485
00486 return d != Data::null;
00487 }
00488
00489 bool KFileMetaInfo::isEmpty() const
00490 {
00491 for (QMapIterator<QString, KFileMetaInfoGroup> it = d->groups.begin();
00492 it!=d->groups.end(); ++it)
00493 if (!(*it).isEmpty())
00494 return false;
00495 return true;
00496 }
00497
00498 bool KFileMetaInfo::applyChanges()
00499 {
00500 bool doit = false;
00501
00502
00503
00504
00505 QMapConstIterator<QString, KFileMetaInfoGroup> it;
00506 for (it = d->groups.begin(); it!=d->groups.end() && !doit; ++it)
00507 {
00508 if ( (*it).isModified() )
00509 doit = true;
00510
00511 else
00512 {
00513 QStringList keys = it.data().keys();
00514 for (QStringList::Iterator it2 = keys.begin(); it2!=keys.end(); ++it2)
00515 {
00516 if ( (*it)[*it2].isModified() )
00517 {
00518 doit = true;
00519 break;
00520 }
00521 }
00522 }
00523 }
00524
00525 if (!doit)
00526 {
00527 kdDebug(7033) << "Don't need to write, nothing changed\n";
00528 return true;
00529 }
00530
00531 KFilePlugin* p = plugin();
00532 if (!p) return false;
00533
00534
00535
00536 return p->writeInfo(*this);
00537 }
00538
00539 KFilePlugin * const KFileMetaInfo::plugin() const
00540 {
00541 KFileMetaInfoProvider* prov = KFileMetaInfoProvider::self();
00542 return prov->plugin( d->mimeTypeInfo->mimeType() );
00543 }
00544
00545 QString KFileMetaInfo::mimeType() const
00546 {
00547 return d->mimeTypeInfo->mimeType();
00548 }
00549
00550 bool KFileMetaInfo::contains(const QString& key) const
00551 {
00552 QStringList glist = groups();
00553 for (QStringList::Iterator it = glist.begin(); it != glist.end(); ++it)
00554 {
00555 KFileMetaInfoGroup g = d->groups[*it];
00556 if (g.contains(key)) return true;
00557 }
00558 return false;
00559 }
00560
00561 bool KFileMetaInfo::containsGroup(const QString& key) const
00562 {
00563 return groups().contains(key);
00564 }
00565
00566 KFileMetaInfoItem KFileMetaInfo::item( const QString& key) const
00567 {
00568 QStringList groups = preferredGroups();
00569 for (QStringList::Iterator it = groups.begin(); it != groups.end(); ++it)
00570 {
00571 KFileMetaInfoItem i = d->groups[*it][key];
00572 if (i.isValid()) return i;
00573 }
00574 return KFileMetaInfoItem();
00575 }
00576
00577 KFileMetaInfoItem KFileMetaInfo::item(const KFileMetaInfoItem::Hint hint) const
00578 {
00579 QStringList groups = preferredGroups();
00580 QStringList::ConstIterator it;
00581 for (it = groups.begin(); it != groups.end(); ++it)
00582 {
00583 KFileMetaInfoItem i = d->groups[*it].item(hint);
00584 if (i.isValid()) return i;
00585 }
00586 return KFileMetaInfoItem();
00587 }
00588
00589 KFileMetaInfoItem KFileMetaInfo::saveItem( const QString& key,
00590 const QString& preferredGroup,
00591 bool createGroup )
00592 {
00593
00594 if ( !preferredGroup.isEmpty() ) {
00595 QMapIterator<QString,KFileMetaInfoGroup> it =
00596 d->groups.find( preferredGroup );
00597
00598
00599 if ( it == d->groups.end() && createGroup ) {
00600 const KFileMimeTypeInfo::GroupInfo *groupInfo =
00601 d->mimeTypeInfo->groupInfo( preferredGroup );
00602 if ( groupInfo && groupInfo->supportedKeys().contains( key ) ) {
00603 if ( addGroup( preferredGroup ) )
00604 it = d->groups.find( preferredGroup );
00605 }
00606 }
00607
00608 if ( it != d->groups.end() ) {
00609 KFileMetaInfoItem item = it.data().addItem( key );
00610 if ( item.isValid() )
00611 return item;
00612 }
00613 }
00614
00615 QStringList groups = preferredGroups();
00616
00617 KFileMetaInfoItem item;
00618
00619 QStringList::ConstIterator groupIt = groups.begin();
00620 for ( ; groupIt != groups.end(); ++groupIt )
00621 {
00622 QMapIterator<QString,KFileMetaInfoGroup> it = d->groups.find( *groupIt );
00623 if ( it != d->groups.end() )
00624 {
00625 KFileMetaInfoGroup group = it.data();
00626 item = findEditableItem( group, key );
00627 if ( item.isValid() )
00628 return item;
00629 }
00630 else
00631 {
00632 const KFileMimeTypeInfo::GroupInfo *groupInfo =
00633 d->mimeTypeInfo->groupInfo( *groupIt );
00634 if ( groupInfo && groupInfo->supportedKeys().contains( key ) )
00635 {
00636 if ( addGroup( *groupIt ) )
00637 {
00638 KFileMetaInfoGroup group = d->groups[*groupIt];
00639 KFileMetaInfoItem item = group.addItem( key );
00640 if ( item.isValid() )
00641 return item;
00642
00643
00644 }
00645 }
00646 }
00647 }
00648
00649
00650
00651 return item;
00652 }
00653
00654 KFileMetaInfoItem KFileMetaInfo::findEditableItem( KFileMetaInfoGroup& group,
00655 const QString& key )
00656 {
00657 KFileMetaInfoItem item = group.addItem( key );
00658 if ( item.isValid() && item.isEditable() )
00659 return item;
00660
00661 if ( (d->mimeTypeInfo->groupInfo( group.name() )->attributes() & KFileMimeTypeInfo::Addable) )
00662 return item;
00663
00664 return KFileMetaInfoItem();
00665 }
00666
00667 KFileMetaInfoGroup KFileMetaInfo::appendGroup(const QString& name)
00668 {
00669 if ( d->mimeTypeInfo->supportedGroups().contains(name) &&
00670 ! d->groups.contains(name) )
00671 {
00672 KFileMetaInfoGroup group( name, d->mimeTypeInfo );
00673 d->groups.insert(name, group);
00674 return group;
00675 }
00676
00677 else {
00678 kdWarning(7033) << "Someone's trying to add a KFileMetaInfoGroup which is not supported or already existing: " << name << endl;
00679 return KFileMetaInfoGroup();
00680 }
00681 }
00682
00683 QString KFileMetaInfo::path() const
00684 {
00685 return d->path;
00686 }
00687
00688 void KFileMetaInfo::ref()
00689 {
00690 if (d != Data::null) d->ref();
00691
00692 }
00693
00694 void KFileMetaInfo::deref()
00695 {
00696
00697
00698
00699 if ((d != Data::null) && d->deref())
00700 {
00701
00702 delete d;
00703 }
00704
00705 }
00706
00707
00708 KFileMetaInfo::Data* KFileMetaInfo::Data::null = 0L;
00709 static KStaticDeleter<KFileMetaInfo::Data> sd_KFileMetaInfoData;
00710
00711 KFileMetaInfo::Data* KFileMetaInfo::Data::makeNull()
00712 {
00713 if (!null)
00714
00715
00716
00717 null = sd_KFileMetaInfoData.setObject( new KFileMetaInfo::Data(QString::null, 0) );
00718 return null;
00719 }
00720
00723
00724 KFilePlugin::KFilePlugin( QObject *parent, const char *name,
00725 const QStringList& )
00726 : QObject( parent, name )
00727 {
00728
00729 }
00730
00731 KFilePlugin::~KFilePlugin()
00732 {
00733 kdDebug(7033) << "unloaded a plugin for " << name() << endl;
00734 }
00735
00736 KFileMimeTypeInfo * KFilePlugin::addMimeTypeInfo( const QString& mimeType )
00737 {
00738 KFileMimeTypeInfo* info;
00739
00740 info = KFileMetaInfoProvider::self()-> addMimeTypeInfo( mimeType );
00741 return info;
00742 }
00743
00744 void KFilePlugin::virtual_hook( int, void* )
00745 { }
00746
00747
00748 KFileMimeTypeInfo::GroupInfo* KFilePlugin::addGroupInfo(KFileMimeTypeInfo* info,
00749 const QString& key, const QString& translatedKey) const
00750 {
00751 return info->addGroupInfo(key, translatedKey);
00752 }
00753
00754 void KFilePlugin::setAttributes(KFileMimeTypeInfo::GroupInfo* gi, uint attr) const
00755 {
00756 gi->m_attr = attr;
00757 }
00758
00759 void KFilePlugin::addVariableInfo(KFileMimeTypeInfo::GroupInfo* gi,
00760 QVariant::Type type, uint attr) const
00761 {
00762 gi->addVariableInfo(type, attr);
00763 }
00764
00765 KFileMimeTypeInfo::ItemInfo* KFilePlugin::addItemInfo(KFileMimeTypeInfo::GroupInfo* gi,
00766 const QString& key,
00767 const QString& translatedKey,
00768 QVariant::Type type)
00769 {
00770 return gi->addItemInfo(key, translatedKey, type);
00771 }
00772
00773 void KFilePlugin::setAttributes(KFileMimeTypeInfo::ItemInfo* item, uint attr)
00774 {
00775 item->m_attr = attr;
00776 }
00777
00778 void KFilePlugin::setHint(KFileMimeTypeInfo::ItemInfo* item, uint hint)
00779 {
00780 item->m_hint = hint;
00781 }
00782
00783 void KFilePlugin::setUnit(KFileMimeTypeInfo::ItemInfo* item, uint unit)
00784 {
00785 item->m_unit = unit;
00786
00787 switch (unit)
00788 {
00789 case KFileMimeTypeInfo::Seconds:
00790 item->m_suffix = i18n("s"); break;
00791
00792 case KFileMimeTypeInfo::MilliSeconds:
00793 item->m_suffix = i18n("ms"); break;
00794
00795 case KFileMimeTypeInfo::BitsPerSecond:
00796 item->m_suffix = i18n("bps"); break;
00797
00798 case KFileMimeTypeInfo::Pixels:
00799 item->m_suffix = i18n("pixels"); break;
00800
00801 case KFileMimeTypeInfo::Inches:
00802 item->m_suffix = i18n("in"); break;
00803
00804 case KFileMimeTypeInfo::Centimeters:
00805 item->m_suffix = i18n("cm"); break;
00806
00807 case KFileMimeTypeInfo::Bytes:
00808 item->m_suffix = i18n("B"); break;
00809
00810 case KFileMimeTypeInfo::KiloBytes:
00811 item->m_suffix = i18n("KB"); break;
00812
00813 case KFileMimeTypeInfo::FramesPerSecond:
00814 item->m_suffix = i18n("fps"); break;
00815
00816 case KFileMimeTypeInfo::DotsPerInch:
00817 item->m_suffix = i18n("dpi"); break;
00818
00819 case KFileMimeTypeInfo::BitsPerPixel:
00820 item->m_suffix = i18n("bpp"); break;
00821
00822 case KFileMimeTypeInfo::Hertz:
00823 item->m_suffix = i18n("Hz");
00824 }
00825 }
00826
00827 void KFilePlugin::setPrefix(KFileMimeTypeInfo::ItemInfo* item, const QString& prefix)
00828 {
00829 item->m_prefix = prefix;
00830 }
00831
00832 void KFilePlugin::setSuffix(KFileMimeTypeInfo::ItemInfo* item, const QString& suffix)
00833 {
00834 item->m_suffix = suffix;
00835 }
00836
00837 KFileMetaInfoGroup KFilePlugin::appendGroup(KFileMetaInfo& info, const QString& key)
00838 {
00839 return info.appendGroup(key);
00840 }
00841
00842 void KFilePlugin::appendItem(KFileMetaInfoGroup& group, const QString& key, QVariant value)
00843 {
00844 group.appendItem(key, value);
00845 }
00846
00849
00850
00851 KFileMetaInfoProvider * KFileMetaInfoProvider::s_self = 0;
00852 KStaticDeleter<KFileMetaInfoProvider> sd;
00853
00854 KFileMetaInfoProvider * KFileMetaInfoProvider::self()
00855 {
00856 if ( !s_self )
00857 s_self = sd.setObject( new KFileMetaInfoProvider() );
00858
00859 return s_self;
00860 }
00861
00862 KFileMetaInfoProvider::KFileMetaInfoProvider()
00863 {
00864 m_plugins.setAutoDelete( true );
00865 m_mimeTypeDict.setAutoDelete( true );
00866 }
00867
00868 KFileMetaInfoProvider::~KFileMetaInfoProvider()
00869 {
00870 s_self = 0;
00871 sd.setObject( 0 );
00872 }
00873
00874 KFilePlugin * KFileMetaInfoProvider::plugin(const QString& mimeType)
00875 {
00876 KFilePlugin *p = m_plugins.find( mimeType );
00877
00878
00879
00880 if ( !p )
00881 {
00882
00883
00884 KService::Ptr service =
00885 KServiceTypeProfile::preferredService( mimeType, "KFilePlugin");
00886
00887 if ( !service || !service->isValid() )
00888 {
00889
00890 return 0;
00891 }
00892
00893 p = KParts::ComponentFactory::createInstanceFromService<KFilePlugin>
00894 ( service, this, mimeType.local8Bit() );
00895
00896 if (!p)
00897 {
00898 kdWarning(7033) << "error loading the plugin\n";
00899 return 0;
00900 }
00901
00902
00903 m_plugins.insert( mimeType, p );
00904
00905 }
00906
00907
00908
00909
00910
00911
00912
00913
00914
00915 return p;
00916 }
00917
00918 QStringList KFileMetaInfoProvider::preferredKeys( const QString& mimeType ) const
00919 {
00920 KService::Ptr service =
00921 KServiceTypeProfile::preferredService( mimeType, "KFilePlugin");
00922
00923 if ( !service || !service->isValid() )
00924 {
00925
00926 return QStringList();
00927 }
00928 return service->property("PreferredItems").toStringList();
00929 }
00930
00931 QStringList KFileMetaInfoProvider::preferredGroups( const QString& mimeType ) const
00932 {
00933 KService::Ptr service =
00934 KServiceTypeProfile::preferredService( mimeType, "KFilePlugin");
00935
00936 if ( !service || !service->isValid() )
00937 {
00938
00939 return QStringList();
00940 }
00941 return service->property("PreferredGroups").toStringList();
00942 }
00943
00944 const KFileMimeTypeInfo * KFileMetaInfoProvider::mimeTypeInfo( const QString& mimeType )
00945 {
00946 KFileMimeTypeInfo *info = m_mimeTypeDict.find( mimeType );
00947 if ( !info ) {
00948
00949 KFilePlugin *p = plugin( mimeType );
00950 if ( p )
00951 info = m_mimeTypeDict.find( mimeType );
00952 }
00953
00954 return info;
00955 }
00956
00957 KFileMimeTypeInfo * KFileMetaInfoProvider::addMimeTypeInfo(
00958 const QString& mimeType )
00959 {
00960 KFileMimeTypeInfo *info = m_mimeTypeDict.find( mimeType );
00961 if ( !info )
00962 {
00963 info = new KFileMimeTypeInfo( mimeType );
00964 m_mimeTypeDict.replace( mimeType, info );
00965 }
00966
00967 info->m_preferredKeys = preferredKeys( mimeType );
00968 info->m_preferredGroups = preferredGroups( mimeType );
00969
00970 return info;
00971 }
00972
00973 QStringList KFileMetaInfoProvider::supportedMimeTypes() const
00974 {
00975 QStringList allMimeTypes;
00976 QString kfilePlugin = "KFilePlugin";
00977
00978 KTrader::OfferList offers = KTrader::self()->query( "KFilePlugin" );
00979 KTrader::OfferListIterator it = offers.begin();
00980 for ( ; it != offers.end(); ++it )
00981 {
00982 QStringList mimeTypes = (*it)->serviceTypes();
00983 QStringList::ConstIterator it2 = mimeTypes.begin();
00984 for ( ; it2 != mimeTypes.end(); ++it2 )
00985 if ( allMimeTypes.find( *it2 ) == allMimeTypes.end() &&
00986 *it2 != kfilePlugin )
00987 allMimeTypes.append( *it2 );
00988 }
00989
00990 return allMimeTypes;
00991 }
00992
00997
00998
00999
01000 class KFileMetaInfoGroup::Data : public QShared
01001 {
01002 public:
01003 Data(const QString& _name)
01004 : QShared(),
01005 name(_name),
01006 mimeTypeInfo(0L),
01007 dirty( false ),
01008 added( false )
01009 {}
01010
01011
01012 Data() : mimeTypeInfo(0L) {}
01013 ~Data() {
01014 if ( this == null )
01015 delete mimeTypeInfo;
01016 };
01017
01018 QString name;
01019 QMap<QString, KFileMetaInfoItem> items;
01020 const KFileMimeTypeInfo* mimeTypeInfo;
01021 QStringList removedItems;
01022 bool dirty :1;
01023 bool added :1;
01024
01025 static Data* null;
01026 static Data* makeNull();
01027
01028 };
01029
01030 KFileMetaInfoGroup::KFileMetaInfoGroup( const QString& name,
01031 const KFileMimeTypeInfo* info )
01032 : d(new Data( name ) )
01033 {
01034 d->mimeTypeInfo = info;
01035 }
01036
01037 KFileMetaInfoGroup::KFileMetaInfoGroup( const KFileMetaInfoGroup& original )
01038 {
01039
01040 d = Data::makeNull();
01041 *this = original;
01042 }
01043
01044 KFileMetaInfoGroup::KFileMetaInfoGroup()
01045 {
01046 d = Data::makeNull();
01047 }
01048
01049 KFileMetaInfoGroup::~KFileMetaInfoGroup()
01050 {
01051 deref();
01052 }
01053
01054 const KFileMetaInfoGroup& KFileMetaInfoGroup::operator= (const KFileMetaInfoGroup& info )
01055 {
01056 if (d != info.d)
01057 {
01058 deref();
01059
01060 d = info.d;
01061
01062 ref();
01063 }
01064 return *this;
01065 }
01066
01067 bool KFileMetaInfoGroup::isValid() const
01068 {
01069
01070 return d != Data::null;
01071 }
01072
01073 bool KFileMetaInfoGroup::isEmpty() const
01074 {
01075 return d->items.isEmpty();
01076 }
01077
01078 QStringList KFileMetaInfoGroup::preferredKeys() const
01079 {
01080 if (d == Data::makeNull())
01081 kdWarning(7033) << "attempt to get the preferredKeys of "
01082 "an invalid metainfo group";
01083
01084 QStringList list = keys();
01085 QStringList newlist;
01086 QStringList preferredKeys = d->mimeTypeInfo->preferredKeys();
01087 QStringList::Iterator pref;
01088 QStringList::Iterator begin = preferredKeys.begin();
01089 QStringList::Iterator end = preferredKeys.end();
01090
01091
01092 for ( pref = begin; pref!=end; pref++ )
01093 {
01094 QStringList::Iterator item = list.find(*pref);
01095 if ( item != list.end() )
01096 {
01097 newlist.append( *item );
01098 list.remove(item);
01099 }
01100 }
01101
01102
01103
01104 newlist += list;
01105
01106 return newlist;
01107 }
01108
01109 QStringList KFileMetaInfoGroup::keys() const
01110 {
01111 if (d == Data::makeNull())
01112 kdWarning(7033) << "attempt to get the keys of "
01113 "an invalid metainfo group";
01114
01115 QStringList list;
01116
01117
01118 QMapConstIterator<QString, KFileMetaInfoItem> it;
01119 for (it = d->items.begin(); it!=d->items.end(); ++it)
01120 {
01121 list.append(it.data().key());
01122
01123 }
01124 return list;
01125 }
01126
01127 QStringList KFileMetaInfoGroup::supportedKeys() const
01128 {
01129 return d->mimeTypeInfo->groupInfo(d->name)->supportedKeys();
01130 }
01131
01132 bool KFileMetaInfoGroup::supportsVariableKeys() const
01133 {
01134 return d->mimeTypeInfo->groupInfo(d->name)->supportsVariableKeys();
01135 }
01136
01137 bool KFileMetaInfoGroup::contains( const QString& key ) const
01138 {
01139 return d->items.contains(key);
01140 }
01141
01142 KFileMetaInfoItem KFileMetaInfoGroup::item( const QString& key) const
01143 {
01144 QMapIterator<QString,KFileMetaInfoItem> it = d->items.find( key );
01145 if ( it != d->items.end() )
01146 return it.data();
01147
01148 return KFileMetaInfoItem();
01149 }
01150
01151 KFileMetaInfoItem KFileMetaInfoGroup::item(uint hint) const
01152 {
01153 QMapIterator<QString, KFileMetaInfoItem> it;
01154
01155 for (it = d->items.begin(); it!=d->items.end(); ++it)
01156 if (it.data().hint() == hint)
01157 return it.data();
01158
01159 return KFileMetaInfoItem();
01160 }
01161
01162 QString KFileMetaInfoGroup::name() const
01163 {
01164 return d->name;
01165 }
01166
01167 uint KFileMetaInfoGroup::attributes() const
01168 {
01169 return d->mimeTypeInfo->groupInfo(d->name)->attributes();
01170 }
01171
01172 void KFileMetaInfoGroup::setAdded()
01173 {
01174 d->added = true;
01175 }
01176
01177 bool KFileMetaInfoGroup::isModified() const
01178 {
01179 return d->dirty;
01180 }
01181
01182 void KFileMetaInfoGroup::ref()
01183 {
01184 if (d != Data::null) d->ref();
01185
01186 }
01187
01188 void KFileMetaInfoGroup::deref()
01189 {
01190
01191
01192
01193 if ((d != Data::null) && d->deref())
01194 {
01195
01196
01197 delete d;
01198 }
01199
01200 }
01201
01202 KFileMetaInfoItem KFileMetaInfoGroup::addItem( const QString& key )
01203 {
01204 QMapIterator<QString,KFileMetaInfoItem> it = d->items.find( key );
01205 if ( it != d->items.end() )
01206 return it.data();
01207
01208 const KFileMimeTypeInfo::GroupInfo* ginfo = d->mimeTypeInfo->groupInfo(d->name);
01209
01210 if ( !ginfo ) {
01211 Q_ASSERT( ginfo );
01212 return KFileMetaInfoItem();
01213 }
01214
01215 const KFileMimeTypeInfo::ItemInfo* info = ginfo->itemInfo(key);
01216
01217 if ( !info ) {
01218 Q_ASSERT( info );
01219 return KFileMetaInfoItem();
01220 }
01221
01222 KFileMetaInfoItem item;
01223
01224 if (info->isVariableItem())
01225 item = KFileMetaInfoItem(ginfo->variableItemInfo(), key, QVariant());
01226 else
01227 item = KFileMetaInfoItem(info, key, QVariant());
01228
01229 d->items.insert(key, item);
01230 item.setAdded();
01231 d->dirty = true;
01232 return item;
01233 }
01234
01235 bool KFileMetaInfoGroup::removeItem( const QString& key )
01236 {
01237 if (!isValid())
01238 {
01239 kdDebug(7033) << "trying to remove an item from an invalid group\n";
01240 return false;
01241 }
01242
01243 QMapIterator<QString, KFileMetaInfoItem> it = d->items.find(key);
01244 if ( it==d->items.end() )
01245 {
01246 kdDebug(7033) << "trying to remove the non existant item " << key << "\n";
01247 return false;
01248 }
01249
01250 if (!((*it).attributes() & KFileMimeTypeInfo::Removable))
01251 {
01252 kdDebug(7033) << "trying to remove a non removable item\n";
01253 return false;
01254 }
01255
01256 (*it).setRemoved();
01257 d->items.remove(it);
01258 d->removedItems.append(key);
01259 d->dirty = true;
01260 return true;
01261 }
01262
01263 QStringList KFileMetaInfoGroup::removedItems()
01264 {
01265 return d->removedItems;
01266 }
01267
01268 KFileMetaInfoItem KFileMetaInfoGroup::appendItem(const QString& key,
01269 const QVariant& value)
01270 {
01271 const KFileMimeTypeInfo::GroupInfo* ginfo = d->mimeTypeInfo->groupInfo(d->name);
01272 if ( !ginfo ) {
01273 kdWarning() << "Trying to append a Metadata item for a non-existant group:" << d->name << endl;
01274 return KFileMetaInfoItem();
01275 }
01276 const KFileMimeTypeInfo::ItemInfo* info = ginfo->itemInfo(key);
01277 if ( !info ) {
01278 kdWarning() << "Trying to append a Metadata item for an unknown key (no ItemInfo): " << key << endl;
01279 return KFileMetaInfoItem();
01280 }
01281
01282 KFileMetaInfoItem item;
01283
01284 if (info->key().isNull())
01285 item = KFileMetaInfoItem(ginfo->variableItemInfo(), key, value);
01286 else
01287 item = KFileMetaInfoItem(info, key, value);
01288
01289 kdDebug(7033) << "KFileMetaInfogroup inserting a " << key << endl;
01290
01291 d->items.insert(key, item);
01292 return item;
01293 }
01294
01295 KFileMetaInfoGroup::Data* KFileMetaInfoGroup::Data::null = 0L;
01296 static KStaticDeleter<KFileMetaInfoGroup::Data> sd_KFileMetaInfoGroupData;
01297
01298 KFileMetaInfoGroup::Data* KFileMetaInfoGroup::Data::makeNull()
01299 {
01300 if (!null)
01301 {
01302
01303
01304
01305 null = new Data(QString::null);
01306 null->mimeTypeInfo = new KFileMimeTypeInfo();
01307 sd_KFileMetaInfoGroupData.setObject( null );
01308 }
01309 return null;
01310 }
01311
01312
01315
01316 KFileMimeTypeInfo::KFileMimeTypeInfo( const QString& mimeType )
01317 : m_mimeType( mimeType )
01318 {
01319 m_groups.setAutoDelete( true );
01320 }
01321
01322 KFileMimeTypeInfo::~KFileMimeTypeInfo()
01323 {
01324 }
01325
01326 const KFileMimeTypeInfo::GroupInfo * KFileMimeTypeInfo::groupInfo( const QString& group ) const
01327 {
01328 return m_groups.find( group );
01329 }
01330
01331 KFileMimeTypeInfo::GroupInfo * KFileMimeTypeInfo::addGroupInfo(
01332 const QString& name, const QString& translatedName )
01333 {
01334 GroupInfo* group = new GroupInfo( name, translatedName );
01335 m_groups.insert(name, group);
01336 return group;
01337 }
01338
01339 QStringList KFileMimeTypeInfo::supportedGroups() const
01340 {
01341 QStringList list;
01342 QDictIterator<GroupInfo> it( m_groups );
01343 for ( ; it.current(); ++it )
01344 list.append( it.current()->name() );
01345
01346 return list;
01347 }
01348
01349 QStringList KFileMimeTypeInfo::translatedGroups() const
01350 {
01351 QStringList list;
01352 QDictIterator<GroupInfo> it( m_groups );
01353 for ( ; it.current(); ++it )
01354 list.append( it.current()->translatedName() );
01355
01356 return list;
01357 }
01358
01359 QStringList KFileMimeTypeInfo::supportedKeys() const
01360 {
01361
01362
01363 QStringList keys;
01364 QStringList::ConstIterator lit;
01365 QDictIterator<GroupInfo> it( m_groups );
01366 for ( ; it.current(); ++it ) {
01367 QStringList list = it.current()->supportedKeys();
01368 for ( lit = list.begin(); lit != list.end(); ++lit ) {
01369 if ( keys.find( *lit ) == keys.end() )
01370 keys.append( *lit );
01371 }
01372 }
01373
01374 return keys;
01375 }
01376
01377 QValidator * KFileMimeTypeInfo::createValidator(const QString& group,
01378 const QString& key,
01379 QObject *parent,
01380 const char *name) const
01381 {
01382 KFilePlugin* plugin = KFileMetaInfoProvider::self()->plugin(m_mimeType);
01383 if (plugin) return plugin->createValidator(mimeType(), group, key,
01384 parent, name);
01385 return 0;
01386 }
01387
01388
01391
01392 KFileMimeTypeInfo::GroupInfo::GroupInfo( const QString& name,
01393 const QString& translatedName )
01394 : m_name( name ),
01395 m_translatedName( translatedName ),
01396 m_attr( 0 ),
01397 m_variableItemInfo( 0 )
01398
01399 {
01400 m_itemDict.setAutoDelete( true );
01401 }
01402
01403 const KFileMimeTypeInfo::ItemInfo * KFileMimeTypeInfo::GroupInfo::itemInfo( const QString& key ) const
01404 {
01405 ItemInfo* item = m_itemDict.find( key );
01406
01407
01408
01409 if (!item && m_variableItemInfo)
01410 {
01411 return m_variableItemInfo;
01412 }
01413 return item;
01414 }
01415
01416 KFileMimeTypeInfo::ItemInfo* KFileMimeTypeInfo::GroupInfo::addItemInfo(
01417 const QString& key, const QString& translatedKey,
01418 QVariant::Type type)
01419 {
01420
01421
01422 ItemInfo* item = new ItemInfo(key, translatedKey, type);
01423 m_supportedKeys.append(key);
01424 m_itemDict.insert(key, item);
01425 return item;
01426 }
01427
01428
01429 void KFileMimeTypeInfo::GroupInfo::addVariableInfo( QVariant::Type type,
01430 uint attr )
01431 {
01432
01433 delete m_variableItemInfo;
01434 m_variableItemInfo = new ItemInfo(QString::null, QString::null, type);
01435 m_variableItemInfo->m_attr = attr;
01436 }
01437
01440
01441 QString KFileMimeTypeInfo::ItemInfo::string(const QVariant& value, bool mangle) const
01442 {
01443 QString s;
01444
01445 switch (value.type())
01446 {
01447 case QVariant::Invalid :
01448 return "---";
01449
01450 case QVariant::Bool :
01451 s = value.toBool() ? i18n("Yes") : i18n("No");
01452 break;
01453
01454 case QVariant::Int :
01455 if (unit() == KFileMimeTypeInfo::Seconds)
01456 {
01457 int seconds = value.toInt() % 60;
01458 int minutes = value.toInt() / 60 % 60;
01459 int hours = value.toInt() / 3600;
01460 s = hours ? QString().sprintf("%d:%02d:%02d",hours, minutes, seconds)
01461 : QString().sprintf("%02d:%02d", minutes, seconds);
01462 return s;
01463 }
01464 else if (unit() == KFileMimeTypeInfo::Bytes)
01465 {
01466
01467 return KIO::convertSize(value.toInt());
01468 }
01469 else if (unit() == KFileMimeTypeInfo::KiloBytes)
01470 {
01471
01472 return KIO::convertSizeFromKB(value.toInt());
01473 }
01474 else
01475 s = KGlobal::locale()->formatNumber( value.toInt() , 0);
01476 break;
01477
01478 case QVariant::UInt :
01479 s = KGlobal::locale()->formatNumber( value.toUInt() , 0);
01480 break;
01481
01482 case QVariant::Double :
01483 s = KGlobal::locale()->formatNumber( value.toDouble(), 3);
01484 break;
01485
01486 case QVariant::Date :
01487 s = KGlobal::locale()->formatDate( value.toDate(), true );
01488 break;
01489
01490 case QVariant::Time :
01491 s = KGlobal::locale()->formatTime( value.toTime(), true );
01492 break;
01493
01494 case QVariant::DateTime :
01495 s = KGlobal::locale()->formatDateTime( value.toDateTime(),
01496 true, true );
01497 break;
01498
01499 case QVariant::Size :
01500 s = QString("%1 x %2").arg(value.toSize().width())
01501 .arg(value.toSize().height());
01502 break;
01503
01504 case QVariant::Point :
01505 s = QString("%1/%2").arg(value.toSize().width())
01506 .arg(value.toSize().height());
01507 break;
01508
01509 default:
01510 s = value.toString();
01511 }
01512
01513 if (mangle && !s.isNull())
01514 {
01515 s.prepend(prefix());
01516 s.append(" " + suffix());
01517 }
01518 return s;
01519 }
01520
01521
01524
01525
01526
01527
01528
01529
01530
01531
01532
01533 QDataStream& operator <<(QDataStream& s, const KFileMetaInfoItem& item )
01534 {
01535
01536 KFileMetaInfoItem::Data* d = item.d;
01537
01538
01539 bool isValid = item.isValid();
01540 s << isValid;
01541
01542 if (isValid)
01543 s << d->key
01544 << d->value
01545 << d->dirty
01546 << d->added
01547 << d->removed;
01548
01549 return s;
01550 }
01551
01552
01553 QDataStream& operator >>(QDataStream& s, KFileMetaInfoItem& item )
01554 {
01555 bool isValid;
01556 s >> isValid;
01557
01558 if (!isValid)
01559 {
01560 item = KFileMetaInfoItem();
01561 return s;
01562 }
01563
01564
01565 item.deref();
01566 item.d = new KFileMetaInfoItem::Data();
01567
01568
01569 bool dirty, added, removed;
01570 s >> item.d->key
01571 >> item.d->value
01572 >> dirty
01573 >> added
01574 >> removed;
01575 item.d->dirty = dirty;
01576 item.d->added = added;
01577 item.d->removed = removed;
01578
01579 return s;
01580 }
01581
01582
01583
01584
01585
01586 QDataStream& operator <<(QDataStream& s, const KFileMetaInfoGroup& group )
01587 {
01588 KFileMetaInfoGroup::Data* d = group.d;
01589
01590
01591 bool isValid = group.isValid();
01592
01593 s << isValid;
01594 if (isValid)
01595 {
01596 s << d->name
01597 << d->items
01598 << d->mimeTypeInfo->mimeType();
01599 }
01600 return s;
01601 }
01602
01603 QDataStream& operator >>(QDataStream& s, KFileMetaInfoGroup& group )
01604 {
01605 QString mimeType;
01606 bool isValid;
01607 s >> isValid;
01608
01609
01610 if (!isValid)
01611 {
01612 group = KFileMetaInfoGroup();
01613 return s;
01614 }
01615
01616
01617 group.deref();
01618 group.d = new KFileMetaInfoGroup::Data();
01619 group.ref();
01620
01621 s >> group.d->name
01622 >> group.d->items
01623 >> mimeType;
01624
01625 group.d->mimeTypeInfo = KFileMetaInfoProvider::self()->mimeTypeInfo(mimeType);
01626
01627
01628 QMapIterator<QString, KFileMetaInfoItem> it = group.d->items.begin();
01629 for ( ; it != group.d->items.end(); ++it)
01630 {
01631 (*it).d->mimeTypeInfo = group.d->mimeTypeInfo->groupInfo(group.d->name)
01632 ->itemInfo((*it).key());
01633 }
01634
01635 return s;
01636 }
01637
01638
01639
01640
01641 QDataStream& operator <<(QDataStream& s, const KFileMetaInfo& info )
01642 {
01643 KFileMetaInfo::Data* d = info.d;
01644
01645
01646 bool isValid = info.isValid();
01647
01648 s << isValid;
01649 if (isValid)
01650 {
01651 s << d->path
01652 << d->what
01653 << d->groups
01654 << d->mimeTypeInfo->mimeType();
01655 }
01656 return s;
01657 }
01658
01659 QDataStream& operator >>(QDataStream& s, KFileMetaInfo& info )
01660 {
01661 QString mimeType;
01662 bool isValid;
01663 s >> isValid;
01664
01665
01666 if (!isValid)
01667 {
01668 info = KFileMetaInfo();
01669 return s;
01670 }
01671
01672
01673 info.deref();
01674 info.d = new KFileMetaInfo::Data();
01675 info.ref();
01676
01677 s >> info.d->path
01678 >> info.d->what
01679 >> info.d->groups
01680 >> mimeType;
01681 info.d->mimeTypeInfo = KFileMetaInfoProvider::self()->mimeTypeInfo(mimeType);
01682
01683 return s;
01684 }
01685
01686
01687
01688
01689 #include "kfilemetainfo.moc"