You can not select more than 25 topics
Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.
1860 lines
51 KiB
1860 lines
51 KiB
/*
|
|
* This file is part of the KDE libraries
|
|
* Copyright (C) 2001-2002 Rolf Magnus <ramagnus@kde.org>
|
|
* Copyright (C) 2001-2002 Carsten Pfeiffer <pfeiffer@kde.org>
|
|
*
|
|
* This library is free software; you can redistribute it and/or
|
|
* modify it under the terms of the GNU Library General Public
|
|
* License as published by the Free Software Foundation version 2.0.
|
|
*
|
|
* This library is distributed in the hope that it will be useful,
|
|
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
|
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
|
|
* Library General Public License for more details.
|
|
*
|
|
* You should have received a copy of the GNU Library General Public License
|
|
* along with this library; see the file COPYING.LIB. If not, write to
|
|
* the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor,
|
|
* Boston, MA 02110-1301, USA.
|
|
*
|
|
* $Id$
|
|
*/
|
|
|
|
#include <assert.h>
|
|
|
|
#include <tqshared.h>
|
|
#include <tqdict.h>
|
|
|
|
#include <ktrader.h>
|
|
#include <kstaticdeleter.h>
|
|
#include <kparts/componentfactory.h>
|
|
#include <kuserprofile.h>
|
|
#include <kdebug.h>
|
|
#include <kmimetype.h>
|
|
#include <kdatastream.h> // needed for serialization of bool
|
|
#include <klocale.h>
|
|
#include <kio/global.h>
|
|
|
|
#include "kfilemetainfo.h"
|
|
|
|
// shared data of a KFileMetaInfoItem
|
|
class KFileMetaInfoItem::Data : public TQShared
|
|
{
|
|
public:
|
|
Data( const KFileMimeTypeInfo::ItemInfo* mti, const TQString& _key,
|
|
const TQVariant& _value )
|
|
: TQShared(),
|
|
mimeTypeInfo( mti ),
|
|
key( _key ),
|
|
value( _value ),
|
|
dirty( false ),
|
|
added( false ),
|
|
removed( false )
|
|
{}
|
|
|
|
// we use this one for the streaming operators
|
|
Data() : mimeTypeInfo( 0L )
|
|
{}
|
|
|
|
~Data()
|
|
{
|
|
if ( this == null ) // only the null item owns its mimeTypeInfo
|
|
delete mimeTypeInfo;
|
|
}
|
|
|
|
const KFileMimeTypeInfo::ItemInfo* mimeTypeInfo;
|
|
// mimeTypeInfo has the key, too, but only for non-variable ones
|
|
TQString key;
|
|
TQVariant value;
|
|
bool dirty :1;
|
|
bool added :1;
|
|
bool removed :1;
|
|
|
|
static Data* null;
|
|
static Data* makeNull();
|
|
};
|
|
|
|
//this is our null data
|
|
KFileMetaInfoItem::Data* KFileMetaInfoItem::Data::null = 0L;
|
|
static KStaticDeleter<KFileMetaInfoItem::Data> sd_KFileMetaInfoItemData;
|
|
|
|
KFileMetaInfoItem::Data* KFileMetaInfoItem::Data::makeNull()
|
|
{
|
|
if (!null)
|
|
{
|
|
// We deliberately do not reset "null" after it has been destroyed!
|
|
// Otherwise we will run into problems later in ~KFileMetaInfoItem
|
|
// where the d-pointer is compared against null.
|
|
|
|
KFileMimeTypeInfo::ItemInfo* info = new KFileMimeTypeInfo::ItemInfo();
|
|
null = new Data(info, TQString::null, TQVariant());
|
|
sd_KFileMetaInfoItemData.setObject( null );
|
|
}
|
|
return null;
|
|
}
|
|
|
|
KFileMetaInfoItem::KFileMetaInfoItem( const KFileMimeTypeInfo::ItemInfo* mti,
|
|
const TQString& key, const TQVariant& value )
|
|
: d( new Data( mti, key, value ) )
|
|
{
|
|
}
|
|
|
|
KFileMetaInfoItem::KFileMetaInfoItem( const KFileMetaInfoItem& item )
|
|
{
|
|
// operator= does everything that's necessary
|
|
d = Data::makeNull();
|
|
*this = item;
|
|
}
|
|
|
|
KFileMetaInfoItem::KFileMetaInfoItem()
|
|
{
|
|
d = Data::makeNull();
|
|
}
|
|
|
|
KFileMetaInfoItem::~KFileMetaInfoItem()
|
|
{
|
|
deref();
|
|
}
|
|
|
|
const KFileMetaInfoItem& KFileMetaInfoItem::operator=
|
|
(const KFileMetaInfoItem & item )
|
|
{
|
|
if (d != item.d)
|
|
{
|
|
// first deref the old one
|
|
deref();
|
|
d = item.d;
|
|
// and now ref the new one
|
|
ref();
|
|
}
|
|
|
|
return *this;
|
|
}
|
|
|
|
bool KFileMetaInfoItem::setValue( const TQVariant& value )
|
|
{
|
|
// We don't call makeNull here since it isn't necassery, see deref()
|
|
if ( d == Data::null ) return false;
|
|
|
|
if ( ! (d->mimeTypeInfo->attributes() & KFileMimeTypeInfo::Modifiable ) ||
|
|
! (value.canCast(d->mimeTypeInfo->type())))
|
|
{
|
|
kdDebug(7033) << "setting the value of " << key() << "failed\n";
|
|
return false;
|
|
}
|
|
|
|
// kdDebug(7033) << key() << ".setValue()\n";
|
|
|
|
if ( d->value == value )
|
|
return true;
|
|
|
|
d->dirty = true;
|
|
d->value = value;
|
|
// If we don't cast (and test for canCast in the above if), TQVariant is
|
|
// very picky about types (e.g. TQString vs. TQCString or int vs. uint)
|
|
d->value.cast(d->mimeTypeInfo->type());
|
|
|
|
return true;
|
|
}
|
|
|
|
bool KFileMetaInfoItem::isRemoved() const
|
|
{
|
|
return d->removed;
|
|
}
|
|
|
|
TQString KFileMetaInfoItem::key() const
|
|
{
|
|
return d->key;
|
|
}
|
|
|
|
TQString KFileMetaInfoItem::translatedKey() const
|
|
{
|
|
// are we a variable key?
|
|
if (d->mimeTypeInfo->key().isNull())
|
|
{
|
|
// then try if we have luck with i18n()
|
|
return i18n(d->key.utf8());
|
|
}
|
|
|
|
return d->mimeTypeInfo->translatedKey();
|
|
}
|
|
|
|
const TQVariant& KFileMetaInfoItem::value() const
|
|
{
|
|
return d->value;
|
|
}
|
|
|
|
TQString KFileMetaInfoItem::string( bool mangle ) const
|
|
{
|
|
return d->mimeTypeInfo->string(d->value, mangle);
|
|
}
|
|
|
|
TQVariant::Type KFileMetaInfoItem::type() const
|
|
{
|
|
return d->mimeTypeInfo->type();
|
|
}
|
|
|
|
uint KFileMetaInfoItem::unit() const
|
|
{
|
|
return d->mimeTypeInfo->unit();
|
|
}
|
|
|
|
bool KFileMetaInfoItem::isModified() const
|
|
{
|
|
return d->dirty;
|
|
}
|
|
|
|
TQString KFileMetaInfoItem::prefix() const
|
|
{
|
|
return d->mimeTypeInfo->prefix();
|
|
}
|
|
|
|
TQString KFileMetaInfoItem::suffix() const
|
|
{
|
|
return d->mimeTypeInfo->suffix();
|
|
}
|
|
|
|
uint KFileMetaInfoItem::hint() const
|
|
{
|
|
return d->mimeTypeInfo->hint();
|
|
}
|
|
|
|
uint KFileMetaInfoItem::attributes() const
|
|
{
|
|
return d->mimeTypeInfo->attributes();
|
|
}
|
|
|
|
bool KFileMetaInfoItem::isEditable() const
|
|
{
|
|
return d->mimeTypeInfo->attributes() & KFileMimeTypeInfo::Modifiable;
|
|
}
|
|
|
|
bool KFileMetaInfoItem::isValid() const
|
|
{
|
|
// We don't call makeNull here since it isn't necassery:
|
|
// If d is equal to null it means that null is initialized already.
|
|
// null is 0L when it hasn't been initialized and d is never 0L.
|
|
return d != Data::null;
|
|
}
|
|
|
|
void KFileMetaInfoItem::setAdded()
|
|
{
|
|
d->added = true;
|
|
}
|
|
|
|
void KFileMetaInfoItem::setRemoved()
|
|
{
|
|
d->removed = true;
|
|
}
|
|
|
|
void KFileMetaInfoItem::ref()
|
|
{
|
|
if (d != Data::null) d->ref();
|
|
}
|
|
|
|
void KFileMetaInfoItem::deref()
|
|
{
|
|
// We don't call makeNull here since it isn't necassery:
|
|
// If d is equal to null it means that null is initialized already.
|
|
// null is 0L when it hasn't been initialized and d is never 0L.
|
|
if ((d != Data::null) && d->deref())
|
|
{
|
|
// kdDebug(7033) << "item " << d->key
|
|
// << " is finally deleted\n";
|
|
delete d;
|
|
d = 0;
|
|
}
|
|
}
|
|
|
|
///////////////////////////////////////////////////////////////////
|
|
///////////////////////////////////////////////////////////////////
|
|
|
|
// shared data of a KFileMetaInfo
|
|
class KFileMetaInfo::Data : public TQShared
|
|
{
|
|
public:
|
|
Data(const KURL& _url, uint _what)
|
|
: TQShared(),
|
|
url(_url),
|
|
what(_what),
|
|
mimeTypeInfo( 0L )
|
|
{}
|
|
|
|
// wee use this one for the streaming operators
|
|
Data() {};
|
|
|
|
KURL url;
|
|
uint what;
|
|
TQMap<TQString, KFileMetaInfoGroup> groups;
|
|
const KFileMimeTypeInfo* mimeTypeInfo;
|
|
TQStringList removedGroups;
|
|
|
|
static Data* null;
|
|
static Data* makeNull();
|
|
|
|
};
|
|
|
|
KFileMetaInfo::KFileMetaInfo( const TQString& path, const TQString& mimeType,
|
|
uint what )
|
|
{
|
|
KURL u;
|
|
|
|
u.setPath(path);
|
|
init(u, mimeType, what);
|
|
}
|
|
|
|
KFileMetaInfo::KFileMetaInfo( const KURL& url, const TQString& mimeType,
|
|
uint what )
|
|
{
|
|
init(url, mimeType, what);
|
|
}
|
|
|
|
void KFileMetaInfo::init( const KURL& url, const TQString& mimeType,
|
|
uint what )
|
|
{
|
|
d = new Data( url, what );
|
|
|
|
TQString mT;
|
|
if (mimeType.isEmpty())
|
|
mT = KMimeType::findByURL(url)->name();
|
|
else
|
|
mT = mimeType;
|
|
|
|
// let's "share our property"
|
|
KFileMetaInfo item(*this);
|
|
|
|
//kdDebug() << k_funcinfo << mT << " " << url << endl;
|
|
|
|
d->mimeTypeInfo = KFileMetaInfoProvider::self()->mimeTypeInfo( mT, url.protocol() );
|
|
if ( d->mimeTypeInfo )
|
|
{
|
|
//kdDebug(7033) << "Found mimetype info for " << mT /* or protocol*/ << endl;
|
|
KFilePlugin *p = plugin();
|
|
Q_ASSERT( p );
|
|
if ( p && !p->readInfo( item, what) )
|
|
{
|
|
deref();
|
|
d = Data::makeNull();
|
|
}
|
|
}
|
|
else
|
|
{
|
|
// kdDebug(7033) << "No mimetype info for " << mimeType << endl;
|
|
deref();
|
|
d = Data::makeNull();
|
|
}
|
|
}
|
|
|
|
KFileMetaInfo::KFileMetaInfo( const KFileMetaInfo& original )
|
|
{
|
|
// operator= does everything that's necessary
|
|
d = Data::makeNull();
|
|
*this = original;
|
|
}
|
|
|
|
KFileMetaInfo::KFileMetaInfo()
|
|
{
|
|
d = Data::makeNull();
|
|
}
|
|
|
|
KFileMetaInfo::~KFileMetaInfo()
|
|
{
|
|
deref();
|
|
}
|
|
|
|
TQStringList KFileMetaInfo::supportedGroups() const
|
|
{
|
|
assert(isValid());
|
|
return d->mimeTypeInfo->supportedGroups();
|
|
}
|
|
|
|
TQStringList KFileMetaInfo::supportedKeys() const
|
|
{
|
|
assert(isValid());
|
|
return d->mimeTypeInfo->supportedKeys();
|
|
}
|
|
|
|
TQStringList KFileMetaInfo::groups() const
|
|
{
|
|
TQStringList list;
|
|
TQMapConstIterator<TQString, KFileMetaInfoGroup> it = d->groups.begin();
|
|
for ( ; it != d->groups.end(); ++it )
|
|
list += (*it).name();
|
|
|
|
return list;
|
|
}
|
|
|
|
TQStringList KFileMetaInfo::editableGroups() const
|
|
{
|
|
TQStringList list;
|
|
TQStringList supported = supportedGroups();
|
|
TQStringList::ConstIterator it = supported.begin();
|
|
for ( ; it != supported.end(); ++it ) {
|
|
const KFileMimeTypeInfo::GroupInfo * groupInfo = d->mimeTypeInfo->groupInfo( *it );
|
|
if ( groupInfo && groupInfo->attributes() &
|
|
(KFileMimeTypeInfo::Addable | KFileMimeTypeInfo::Removable) )
|
|
list.append( *it );
|
|
}
|
|
|
|
return list;
|
|
}
|
|
|
|
TQStringList KFileMetaInfo::preferredGroups() const
|
|
{
|
|
assert(isValid());
|
|
TQStringList list = groups();
|
|
TQStringList newlist;
|
|
TQStringList preferred = d->mimeTypeInfo->preferredGroups();
|
|
TQStringList::Iterator pref;
|
|
|
|
// move all keys from the preferred groups that are in our list to a new list
|
|
for ( pref = preferred.begin(); pref != preferred.end(); ++pref )
|
|
{
|
|
TQStringList::Iterator group = list.find(*pref);
|
|
if ( group != list.end() )
|
|
{
|
|
newlist.append( *group );
|
|
list.remove(group);
|
|
}
|
|
}
|
|
|
|
// now the old list only contains the non-preferred items, so we
|
|
// add the remaining ones to newlist
|
|
newlist += list;
|
|
|
|
return newlist;
|
|
}
|
|
|
|
TQStringList KFileMetaInfo::preferredKeys() const
|
|
{
|
|
TQStringList newlist;
|
|
|
|
TQStringList list = preferredGroups();
|
|
for (TQStringList::Iterator git = list.begin(); git != list.end(); ++git)
|
|
{
|
|
newlist += d->groups[*git].preferredKeys();
|
|
}
|
|
|
|
return newlist;
|
|
}
|
|
|
|
KFileMetaInfoGroup KFileMetaInfo::group(const TQString& key) const
|
|
{
|
|
TQMapIterator<TQString,KFileMetaInfoGroup> it = d->groups.find( key );
|
|
if ( it != d->groups.end() )
|
|
return it.data();
|
|
else
|
|
return KFileMetaInfoGroup();
|
|
}
|
|
|
|
bool KFileMetaInfo::addGroup( const TQString& name )
|
|
{
|
|
assert(isValid());
|
|
if ( d->mimeTypeInfo->supportedGroups().contains(name) &&
|
|
! d->groups.contains(name) )
|
|
{
|
|
KFileMetaInfoGroup group( name, d->mimeTypeInfo );
|
|
|
|
// add all the items that can't be added by the user later
|
|
const KFileMimeTypeInfo::GroupInfo* ginfo = d->mimeTypeInfo->groupInfo(name);
|
|
Q_ASSERT(ginfo);
|
|
if (!ginfo) return false;
|
|
|
|
TQStringList keys = ginfo->supportedKeys();
|
|
for (TQStringList::Iterator it = keys.begin(); it != keys.end(); ++it)
|
|
{
|
|
const KFileMimeTypeInfo::ItemInfo* iteminfo = ginfo->itemInfo(*it);
|
|
Q_ASSERT(ginfo);
|
|
if (!iteminfo) return false;
|
|
|
|
if ( !(iteminfo->attributes() & KFileMimeTypeInfo::Addable) &&
|
|
(iteminfo->attributes() & KFileMimeTypeInfo::Modifiable))
|
|
{
|
|
// append it now or never
|
|
group.appendItem(iteminfo->key(), TQVariant());
|
|
}
|
|
|
|
}
|
|
|
|
d->groups.insert(name, group);
|
|
group.setAdded();
|
|
return true;
|
|
}
|
|
|
|
return false;
|
|
}
|
|
|
|
bool KFileMetaInfo::removeGroup( const TQString& name )
|
|
{
|
|
TQMapIterator<TQString, KFileMetaInfoGroup> it = d->groups.find(name);
|
|
if ( (it==d->groups.end()) ||
|
|
!((*it).attributes() & KFileMimeTypeInfo::Removable))
|
|
return false;
|
|
|
|
d->groups.remove(it);
|
|
d->removedGroups.append(name);
|
|
return true;
|
|
}
|
|
|
|
TQStringList KFileMetaInfo::removedGroups()
|
|
{
|
|
return d->removedGroups;
|
|
}
|
|
|
|
const KFileMetaInfo& KFileMetaInfo::operator= (const KFileMetaInfo& info )
|
|
{
|
|
if (d != info.d)
|
|
{
|
|
deref();
|
|
// first deref the old one
|
|
d = info.d;
|
|
// and now ref the new one
|
|
ref();
|
|
}
|
|
return *this;
|
|
}
|
|
|
|
bool KFileMetaInfo::isValid() const
|
|
{
|
|
// We don't call makeNull here since it isn't necassery, see deref()
|
|
return d != Data::null;
|
|
}
|
|
|
|
bool KFileMetaInfo::isEmpty() const
|
|
{
|
|
for (TQMapIterator<TQString, KFileMetaInfoGroup> it = d->groups.begin();
|
|
it!=d->groups.end(); ++it)
|
|
if (!(*it).isEmpty())
|
|
return false;
|
|
return true;
|
|
}
|
|
|
|
bool KFileMetaInfo::applyChanges()
|
|
{
|
|
return applyChanges( path() );
|
|
}
|
|
|
|
bool KFileMetaInfo::applyChanges( const TQString& path )
|
|
{
|
|
bool doit = false;
|
|
|
|
// kdDebug(7033) << "KFileMetaInfo::applyChanges()\n";
|
|
|
|
// look up if we need to write to the file
|
|
TQMapConstIterator<TQString, KFileMetaInfoGroup> it;
|
|
for (it = d->groups.begin(); it!=d->groups.end() && !doit; ++it)
|
|
{
|
|
if ( (*it).isModified() )
|
|
doit = true;
|
|
|
|
else
|
|
{
|
|
TQStringList keys = it.data().keys();
|
|
for (TQStringList::Iterator it2 = keys.begin(); it2!=keys.end(); ++it2)
|
|
{
|
|
if ( (*it)[*it2].isModified() )
|
|
{
|
|
doit = true;
|
|
break;
|
|
}
|
|
}
|
|
}
|
|
}
|
|
|
|
if (!doit)
|
|
{
|
|
kdDebug(7033) << "Don't need to write, nothing changed\n";
|
|
return true;
|
|
}
|
|
|
|
KFilePlugin* p = plugin();
|
|
if (!p) return false;
|
|
|
|
// kdDebug(7033) << "Ok, trying to write the info\n";
|
|
|
|
KURL savedURL = url();
|
|
d->url = KURL();
|
|
d->url.setPath( path );
|
|
|
|
bool ret = p->writeInfo(*this);
|
|
|
|
d->url = savedURL;
|
|
return ret;
|
|
}
|
|
|
|
KFilePlugin * const KFileMetaInfo::plugin() const
|
|
{
|
|
assert(isValid());
|
|
KFileMetaInfoProvider* prov = KFileMetaInfoProvider::self();
|
|
return prov->plugin( d->mimeTypeInfo->mimeType(), d->url.protocol() );
|
|
}
|
|
|
|
TQString KFileMetaInfo::mimeType() const
|
|
{
|
|
assert(isValid());
|
|
return d->mimeTypeInfo->mimeType();
|
|
}
|
|
|
|
bool KFileMetaInfo::contains(const TQString& key) const
|
|
{
|
|
TQStringList glist = groups();
|
|
for (TQStringList::Iterator it = glist.begin(); it != glist.end(); ++it)
|
|
{
|
|
KFileMetaInfoGroup g = d->groups[*it];
|
|
if (g.contains(key)) return true;
|
|
}
|
|
return false;
|
|
}
|
|
|
|
bool KFileMetaInfo::containsGroup(const TQString& key) const
|
|
{
|
|
return groups().contains(key);
|
|
}
|
|
|
|
KFileMetaInfoItem KFileMetaInfo::item( const TQString& key) const
|
|
{
|
|
TQStringList groups = preferredGroups();
|
|
for (TQStringList::Iterator it = groups.begin(); it != groups.end(); ++it)
|
|
{
|
|
KFileMetaInfoItem i = d->groups[*it][key];
|
|
if (i.isValid()) return i;
|
|
}
|
|
return KFileMetaInfoItem();
|
|
}
|
|
|
|
KFileMetaInfoItem KFileMetaInfo::item(const KFileMetaInfoItem::Hint hint) const
|
|
{
|
|
TQStringList groups = preferredGroups();
|
|
TQStringList::ConstIterator it;
|
|
for (it = groups.begin(); it != groups.end(); ++it)
|
|
{
|
|
KFileMetaInfoItem i = d->groups[*it].item(hint);
|
|
if (i.isValid()) return i;
|
|
}
|
|
return KFileMetaInfoItem();
|
|
}
|
|
|
|
KFileMetaInfoItem KFileMetaInfo::saveItem( const TQString& key,
|
|
const TQString& preferredGroup,
|
|
bool createGroup )
|
|
{
|
|
assert(isValid());
|
|
// try the preferred groups first
|
|
if ( !preferredGroup.isEmpty() ) {
|
|
TQMapIterator<TQString,KFileMetaInfoGroup> it =
|
|
d->groups.find( preferredGroup );
|
|
|
|
// try to create the preferred group, if necessary
|
|
if ( it == d->groups.end() && createGroup ) {
|
|
const KFileMimeTypeInfo::GroupInfo *groupInfo =
|
|
d->mimeTypeInfo->groupInfo( preferredGroup );
|
|
if ( groupInfo && groupInfo->supportedKeys().contains( key ) ) {
|
|
if ( addGroup( preferredGroup ) )
|
|
it = d->groups.find( preferredGroup );
|
|
}
|
|
}
|
|
|
|
if ( it != d->groups.end() ) {
|
|
KFileMetaInfoItem item = it.data().addItem( key );
|
|
if ( item.isValid() )
|
|
return item;
|
|
}
|
|
}
|
|
|
|
TQStringList groups = preferredGroups();
|
|
|
|
KFileMetaInfoItem item;
|
|
|
|
TQStringList::ConstIterator groupIt = groups.begin();
|
|
for ( ; groupIt != groups.end(); ++groupIt )
|
|
{
|
|
TQMapIterator<TQString,KFileMetaInfoGroup> it = d->groups.find( *groupIt );
|
|
if ( it != d->groups.end() )
|
|
{
|
|
KFileMetaInfoGroup group = it.data();
|
|
item = findEditableItem( group, key );
|
|
if ( item.isValid() )
|
|
return item;
|
|
}
|
|
else // not existant -- try to create the group
|
|
{
|
|
const KFileMimeTypeInfo::GroupInfo *groupInfo =
|
|
d->mimeTypeInfo->groupInfo( *groupIt );
|
|
if ( groupInfo && groupInfo->supportedKeys().contains( key ) )
|
|
{
|
|
if ( addGroup( *groupIt ) )
|
|
{
|
|
KFileMetaInfoGroup group = d->groups[*groupIt];
|
|
KFileMetaInfoItem item = group.addItem( key );
|
|
if ( item.isValid() )
|
|
return item;
|
|
// else ### add when removeGroup() is implemented :)
|
|
// removeGroup( *groupIt ); // couldn't add item -> remove
|
|
}
|
|
}
|
|
}
|
|
}
|
|
|
|
// finally check for variable items
|
|
|
|
return item;
|
|
}
|
|
|
|
KFileMetaInfoItem KFileMetaInfo::findEditableItem( KFileMetaInfoGroup& group,
|
|
const TQString& key )
|
|
{
|
|
assert(isValid());
|
|
KFileMetaInfoItem item = group.addItem( key );
|
|
if ( item.isValid() && item.isEditable() )
|
|
return item;
|
|
|
|
if ( (d->mimeTypeInfo->groupInfo( group.name() )->attributes() & KFileMimeTypeInfo::Addable) )
|
|
return item;
|
|
|
|
return KFileMetaInfoItem();
|
|
}
|
|
|
|
KFileMetaInfoGroup KFileMetaInfo::appendGroup(const TQString& name)
|
|
{
|
|
assert(isValid());
|
|
if ( d->mimeTypeInfo->supportedGroups().contains(name) &&
|
|
! d->groups.contains(name) )
|
|
{
|
|
KFileMetaInfoGroup group( name, d->mimeTypeInfo );
|
|
d->groups.insert(name, group);
|
|
return group;
|
|
}
|
|
|
|
else {
|
|
kdWarning(7033) << "Someone's trying to add a KFileMetaInfoGroup which is not supported or already existing: " << name << endl;
|
|
return KFileMetaInfoGroup();
|
|
}
|
|
}
|
|
|
|
TQString KFileMetaInfo::path() const
|
|
{
|
|
return d->url.isLocalFile() ? d->url.path() : TQString::null;
|
|
}
|
|
|
|
KURL KFileMetaInfo::url() const
|
|
{
|
|
return d->url;
|
|
}
|
|
|
|
void KFileMetaInfo::ref()
|
|
{
|
|
if (d != Data::null) d->ref();
|
|
|
|
}
|
|
|
|
void KFileMetaInfo::deref()
|
|
{
|
|
// We don't call makeNull here since it isn't necassery:
|
|
// If d is equal to null it means that null is initialized already.
|
|
// null is 0L when it hasn't been initialized and d is never 0L.
|
|
if ((d != Data::null) && d->deref())
|
|
{
|
|
// kdDebug(7033) << "metainfo object for " << d->url.path << " is finally deleted\n";
|
|
delete d;
|
|
d = 0;
|
|
}
|
|
|
|
}
|
|
|
|
|
|
KFileMetaInfo::Data* KFileMetaInfo::Data::null = 0L;
|
|
static KStaticDeleter<KFileMetaInfo::Data> sd_KFileMetaInfoData;
|
|
|
|
KFileMetaInfo::Data* KFileMetaInfo::Data::makeNull()
|
|
{
|
|
if (!null)
|
|
// We deliberately do not reset "null" after it has been destroyed!
|
|
// Otherwise we will run into problems later in ~KFileMetaInfoItem
|
|
// where the d-pointer is compared against null.
|
|
null = sd_KFileMetaInfoData.setObject( new KFileMetaInfo::Data(KURL(), 0) );
|
|
return null;
|
|
}
|
|
|
|
///////////////////////////////////////////////////////////////////
|
|
///////////////////////////////////////////////////////////////////
|
|
|
|
KFilePlugin::KFilePlugin( TQObject *parent, const char *name,
|
|
const TQStringList& /*args*/)
|
|
: TQObject( parent, name )
|
|
{
|
|
// kdDebug(7033) << "loaded a plugin for " << name << endl;
|
|
}
|
|
|
|
KFilePlugin::~KFilePlugin()
|
|
{
|
|
// kdDebug(7033) << "unloaded a plugin for " << name() << endl;
|
|
}
|
|
|
|
KFileMimeTypeInfo * KFilePlugin::addMimeTypeInfo( const TQString& mimeType )
|
|
{
|
|
return KFileMetaInfoProvider::self()->addMimeTypeInfo( mimeType );
|
|
}
|
|
|
|
void KFilePlugin::virtual_hook( int, void* )
|
|
{ /*BASE::virtual_hook( id, data );*/ }
|
|
|
|
|
|
KFileMimeTypeInfo::GroupInfo* KFilePlugin::addGroupInfo(KFileMimeTypeInfo* info,
|
|
const TQString& key, const TQString& translatedKey) const
|
|
{
|
|
return info->addGroupInfo(key, translatedKey);
|
|
}
|
|
|
|
void KFilePlugin::setAttributes(KFileMimeTypeInfo::GroupInfo* gi, uint attr) const
|
|
{
|
|
gi->m_attr = attr;
|
|
}
|
|
|
|
void KFilePlugin::addVariableInfo(KFileMimeTypeInfo::GroupInfo* gi,
|
|
TQVariant::Type type, uint attr) const
|
|
{
|
|
gi->addVariableInfo(type, attr);
|
|
}
|
|
|
|
KFileMimeTypeInfo::ItemInfo* KFilePlugin::addItemInfo(KFileMimeTypeInfo::GroupInfo* gi,
|
|
const TQString& key,
|
|
const TQString& translatedKey,
|
|
TQVariant::Type type)
|
|
{
|
|
return gi->addItemInfo(key, translatedKey, type);
|
|
}
|
|
|
|
void KFilePlugin::setAttributes(KFileMimeTypeInfo::ItemInfo* item, uint attr)
|
|
{
|
|
item->m_attr = attr;
|
|
}
|
|
|
|
void KFilePlugin::setHint(KFileMimeTypeInfo::ItemInfo* item, uint hint)
|
|
{
|
|
item->m_hint = hint;
|
|
}
|
|
|
|
void KFilePlugin::setUnit(KFileMimeTypeInfo::ItemInfo* item, uint unit)
|
|
{
|
|
item->m_unit = unit;
|
|
// set prefix and suffix
|
|
switch (unit)
|
|
{
|
|
case KFileMimeTypeInfo::Seconds:
|
|
item->m_suffix = i18n("s"); break;
|
|
|
|
case KFileMimeTypeInfo::MilliSeconds:
|
|
item->m_suffix = i18n("ms"); break;
|
|
|
|
case KFileMimeTypeInfo::BitsPerSecond:
|
|
item->m_suffix = i18n("bps"); break;
|
|
|
|
case KFileMimeTypeInfo::Pixels:
|
|
item->m_suffix = i18n("pixels"); break;
|
|
|
|
case KFileMimeTypeInfo::Inches:
|
|
item->m_suffix = i18n("in"); break;
|
|
|
|
case KFileMimeTypeInfo::Centimeters:
|
|
item->m_suffix = i18n("cm"); break;
|
|
|
|
case KFileMimeTypeInfo::Bytes:
|
|
item->m_suffix = i18n("B"); break;
|
|
|
|
case KFileMimeTypeInfo::KiloBytes:
|
|
item->m_suffix = i18n("KB"); break;
|
|
|
|
case KFileMimeTypeInfo::FramesPerSecond:
|
|
item->m_suffix = i18n("fps"); break;
|
|
|
|
case KFileMimeTypeInfo::DotsPerInch:
|
|
item->m_suffix = i18n("dpi"); break;
|
|
|
|
case KFileMimeTypeInfo::BitsPerPixel:
|
|
item->m_suffix = i18n("bpp"); break;
|
|
|
|
case KFileMimeTypeInfo::Hertz:
|
|
item->m_suffix = i18n("Hz"); break;
|
|
|
|
case KFileMimeTypeInfo::Millimeters:
|
|
item->m_suffix = i18n("mm");
|
|
}
|
|
}
|
|
|
|
void KFilePlugin::setPrefix(KFileMimeTypeInfo::ItemInfo* item, const TQString& prefix)
|
|
{
|
|
item->m_prefix = prefix;
|
|
}
|
|
|
|
void KFilePlugin::setSuffix(KFileMimeTypeInfo::ItemInfo* item, const TQString& suffix)
|
|
{
|
|
item->m_suffix = suffix;
|
|
}
|
|
|
|
KFileMetaInfoGroup KFilePlugin::appendGroup(KFileMetaInfo& info, const TQString& key)
|
|
{
|
|
return info.appendGroup(key);
|
|
}
|
|
|
|
void KFilePlugin::appendItem(KFileMetaInfoGroup& group, const TQString& key, TQVariant value)
|
|
{
|
|
group.appendItem(key, value);
|
|
}
|
|
|
|
///////////////////////////////////////////////////////////////////
|
|
///////////////////////////////////////////////////////////////////
|
|
|
|
|
|
KFileMetaInfoProvider * KFileMetaInfoProvider::s_self;
|
|
static KStaticDeleter<KFileMetaInfoProvider> sd;
|
|
|
|
KFileMetaInfoProvider * KFileMetaInfoProvider::self()
|
|
{
|
|
if ( !s_self )
|
|
s_self = sd.setObject( s_self, new KFileMetaInfoProvider() );
|
|
|
|
return s_self;
|
|
}
|
|
|
|
KFileMetaInfoProvider::KFileMetaInfoProvider()
|
|
{
|
|
m_plugins.setAutoDelete( true );
|
|
}
|
|
|
|
KFileMetaInfoProvider::~KFileMetaInfoProvider()
|
|
{
|
|
m_plugins.clear();
|
|
sd.setObject( 0 );
|
|
}
|
|
|
|
KFilePlugin* KFileMetaInfoProvider::loadPlugin( const TQString& mimeType, const TQString& protocol )
|
|
{
|
|
//kdDebug() << "loadPlugin: mimeType=" << mimeType << " protocol=" << protocol << endl;
|
|
// Currently the idea is: either the mimetype is set or the protocol, but not both.
|
|
// We need PNG fileinfo, and trash: fileinfo, but not "PNG in the trash".
|
|
TQString queryMimeType, query;
|
|
if ( !mimeType.isEmpty() ) {
|
|
query = "(not exist [X-KDE-Protocol])";
|
|
queryMimeType = mimeType;
|
|
} else {
|
|
query = TQString::fromLatin1( "[X-KDE-Protocol] == '%1'" ).arg(protocol);
|
|
// querying for a protocol: we have no mimetype, so we need to use KFilePlugin as one
|
|
queryMimeType = "KFilePlugin";
|
|
// hopefully using KFilePlugin as genericMimeType too isn't a problem
|
|
}
|
|
const KTrader::OfferList offers = KTrader::self()->query( queryMimeType, "KFilePlugin", query, TQString::null );
|
|
if ( offers.isEmpty() )
|
|
return 0;
|
|
KService::Ptr service = *(offers.begin());
|
|
Q_ASSERT( service && service->isValid() );
|
|
if ( !service || !service->isValid() )
|
|
return 0;
|
|
|
|
KFilePlugin* plugin = KParts::ComponentFactory::createInstanceFromService<KFilePlugin>
|
|
( service, TQT_TQOBJECT(this), mimeType.local8Bit() );
|
|
if (!plugin)
|
|
kdWarning(7033) << "error loading the plugin from " << service->desktopEntryPath() << endl;
|
|
|
|
return plugin;
|
|
}
|
|
|
|
KFilePlugin* KFileMetaInfoProvider::loadAndRegisterPlugin( const TQString& mimeType, const TQString& protocol )
|
|
{
|
|
Q_ASSERT( m_pendingMimetypeInfos.isEmpty() );
|
|
m_pendingMimetypeInfos.clear();
|
|
|
|
KFilePlugin* plugin = loadPlugin( mimeType, protocol );
|
|
if ( !plugin ) {
|
|
// No plugin found. Remember that, to save time.
|
|
m_plugins.insert( protocol.isEmpty() ? mimeType : protocol, new CachedPluginInfo );
|
|
return 0;
|
|
}
|
|
|
|
if ( !protocol.isEmpty() ) {
|
|
// Protocol-metainfo: only one entry
|
|
Q_ASSERT( m_pendingMimetypeInfos.count() == 1 );
|
|
KFileMimeTypeInfo* info = m_pendingMimetypeInfos[ protocol ];
|
|
Q_ASSERT( info );
|
|
m_plugins.insert( protocol, new CachedPluginInfo( plugin, info, true ) );
|
|
} else {
|
|
// Mimetype-metainfo: the plugin can register itself for multiple mimetypes, remember them all
|
|
bool first = true;
|
|
TQDictIterator<KFileMimeTypeInfo> it( m_pendingMimetypeInfos );
|
|
for( ; it.current(); ++it ) {
|
|
KFileMimeTypeInfo* info = it.current();
|
|
m_plugins.insert( it.currentKey(), new CachedPluginInfo( plugin, info, first ) );
|
|
first = false;
|
|
}
|
|
// Hopefully the above includes the mimetype we asked for!
|
|
if ( m_pendingMimetypeInfos.find( mimeType ) == 0 )
|
|
kdWarning(7033) << plugin->className() << " was created for " << mimeType << " but doesn't call addMimeTypeInfo for it!" << endl;
|
|
}
|
|
m_pendingMimetypeInfos.clear();
|
|
return plugin;
|
|
}
|
|
|
|
KFilePlugin * KFileMetaInfoProvider::plugin(const TQString& mimeType)
|
|
{
|
|
return plugin( mimeType, TQString::null );
|
|
}
|
|
|
|
KFilePlugin * KFileMetaInfoProvider::plugin(const TQString& mimeType, const TQString& protocol)
|
|
{
|
|
//kdDebug(7033) << "plugin() : looking for plugin for protocol=" << protocol << " mimeType=" << mimeType << endl;
|
|
|
|
if ( !protocol.isEmpty() ) {
|
|
CachedPluginInfo *cache = m_plugins.find( protocol );
|
|
if ( cache && cache->plugin ) {
|
|
return cache->plugin;
|
|
}
|
|
if ( !cache ) {
|
|
KFilePlugin* plugin = loadAndRegisterPlugin( TQString::null, protocol );
|
|
if ( plugin )
|
|
return plugin;
|
|
}
|
|
}
|
|
|
|
CachedPluginInfo *cache = m_plugins.find( mimeType );
|
|
if ( cache ) {
|
|
return cache->plugin;
|
|
}
|
|
|
|
KFilePlugin* plugin = loadAndRegisterPlugin( mimeType, TQString::null );
|
|
|
|
#if 0
|
|
kdDebug(7033) << "currently loaded plugins:\n";
|
|
|
|
TQDictIterator<CachedPluginInfo> it( m_plugins );
|
|
for( ; it.current(); ++it ) {
|
|
CachedPluginInfo* cache = it.current();
|
|
kdDebug(7033)
|
|
<< it.currentKey() // mimetype or protocol
|
|
<< " : " << (cache->plugin ? cache->plugin->className() : "(no plugin)") << endl; // plugin
|
|
// TODO print cache->mimeTypeInfo
|
|
}
|
|
#endif
|
|
|
|
return plugin;
|
|
}
|
|
|
|
TQStringList KFileMetaInfoProvider::preferredKeys( const TQString& mimeType ) const
|
|
{
|
|
KService::Ptr service =
|
|
KServiceTypeProfile::preferredService( mimeType, "KFilePlugin");
|
|
|
|
if ( !service || !service->isValid() )
|
|
{
|
|
// kdDebug(7033) << "no valid service found\n";
|
|
return TQStringList();
|
|
}
|
|
return service->property("PreferredItems").toStringList();
|
|
}
|
|
|
|
TQStringList KFileMetaInfoProvider::preferredGroups( const TQString& mimeType ) const
|
|
{
|
|
KService::Ptr service =
|
|
KServiceTypeProfile::preferredService( mimeType, "KFilePlugin");
|
|
|
|
if ( !service || !service->isValid() )
|
|
{
|
|
// kdDebug(7033) << "no valid service found\n";
|
|
return TQStringList();
|
|
}
|
|
return service->property("PreferredGroups").toStringList();
|
|
}
|
|
|
|
const KFileMimeTypeInfo * KFileMetaInfoProvider::mimeTypeInfo( const TQString& mimeType )
|
|
{
|
|
return mimeTypeInfo( mimeType, TQString::null );
|
|
}
|
|
|
|
const KFileMimeTypeInfo * KFileMetaInfoProvider::mimeTypeInfo( const TQString& mimeType, const TQString& protocol )
|
|
{
|
|
//kdDebug(7033) << "mimeTypeInfo() : looking for plugin for protocol=" << protocol << " mimeType=" << mimeType << endl;
|
|
if ( !protocol.isEmpty() ) {
|
|
CachedPluginInfo *cache = m_plugins.find( protocol );
|
|
if ( cache && cache->mimeTypeInfo ) {
|
|
return cache->mimeTypeInfo;
|
|
}
|
|
|
|
if ( !cache ) {
|
|
loadAndRegisterPlugin( TQString::null, protocol );
|
|
cache = m_plugins.find( protocol );
|
|
if ( cache && cache->mimeTypeInfo ) {
|
|
return cache->mimeTypeInfo;
|
|
}
|
|
}
|
|
}
|
|
|
|
CachedPluginInfo *cache = m_plugins.find( mimeType );
|
|
if ( cache ) {
|
|
return cache->mimeTypeInfo;
|
|
}
|
|
|
|
loadAndRegisterPlugin( mimeType, TQString::null );
|
|
cache = m_plugins.find( mimeType );
|
|
if ( cache ) {
|
|
return cache->mimeTypeInfo;
|
|
}
|
|
return 0;
|
|
}
|
|
|
|
KFileMimeTypeInfo * KFileMetaInfoProvider::addMimeTypeInfo(
|
|
const TQString& mimeType )
|
|
{
|
|
|
|
KFileMimeTypeInfo *info = m_pendingMimetypeInfos.find( mimeType );
|
|
Q_ASSERT( !info );
|
|
if ( !info )
|
|
{
|
|
info = new KFileMimeTypeInfo( mimeType );
|
|
m_pendingMimetypeInfos.insert( mimeType, info );
|
|
}
|
|
|
|
info->m_preferredKeys = preferredKeys( mimeType );
|
|
info->m_preferredGroups = preferredGroups( mimeType );
|
|
|
|
return info;
|
|
}
|
|
|
|
TQStringList KFileMetaInfoProvider::supportedMimeTypes() const
|
|
{
|
|
TQStringList allMimeTypes;
|
|
TQString kfilePlugin = "KFilePlugin";
|
|
|
|
KTrader::OfferList offers = KTrader::self()->query( "KFilePlugin" );
|
|
KTrader::OfferListIterator it = offers.begin();
|
|
for ( ; it != offers.end(); ++it )
|
|
{
|
|
const TQStringList mimeTypes = (*it)->serviceTypes();
|
|
TQStringList::ConstIterator it2 = mimeTypes.begin();
|
|
for ( ; it2 != mimeTypes.end(); ++it2 )
|
|
if ( allMimeTypes.find( *it2 ) == allMimeTypes.end() &&
|
|
*it2 != kfilePlugin ) // also in serviceTypes()
|
|
allMimeTypes.append( *it2 );
|
|
}
|
|
|
|
return allMimeTypes;
|
|
}
|
|
|
|
///////////////////////////////////////////////////////////////////
|
|
///////////////////////////////////////////////////////////////////
|
|
///////////////////////////////////////////////////////////////////
|
|
///////////////////////////////////////////////////////////////////
|
|
|
|
|
|
// shared data of a KFileMetaInfoGroup
|
|
class KFileMetaInfoGroup::Data : public TQShared
|
|
{
|
|
public:
|
|
Data(const TQString& _name)
|
|
: TQShared(),
|
|
name(_name),
|
|
mimeTypeInfo(0L),
|
|
dirty( false ),
|
|
added( false )
|
|
{}
|
|
|
|
// we use this one for the streaming operators
|
|
Data() : mimeTypeInfo(0L) {}
|
|
~Data() {
|
|
if ( this == null )
|
|
delete mimeTypeInfo;
|
|
};
|
|
|
|
TQString name;
|
|
TQMap<TQString, KFileMetaInfoItem> items;
|
|
const KFileMimeTypeInfo* mimeTypeInfo;
|
|
TQStringList removedItems;
|
|
bool dirty :1;
|
|
bool added :1;
|
|
|
|
static Data* null;
|
|
static Data* makeNull();
|
|
|
|
};
|
|
|
|
KFileMetaInfoGroup::KFileMetaInfoGroup( const TQString& name,
|
|
const KFileMimeTypeInfo* info )
|
|
: d(new Data( name ) )
|
|
{
|
|
d->mimeTypeInfo = info;
|
|
}
|
|
|
|
KFileMetaInfoGroup::KFileMetaInfoGroup( const KFileMetaInfoGroup& original )
|
|
{
|
|
// operator= does everything that's necessary
|
|
d = Data::makeNull();
|
|
*this = original;
|
|
}
|
|
|
|
KFileMetaInfoGroup::KFileMetaInfoGroup()
|
|
{
|
|
d = Data::makeNull();
|
|
}
|
|
|
|
KFileMetaInfoGroup::~KFileMetaInfoGroup()
|
|
{
|
|
deref();
|
|
}
|
|
|
|
const KFileMetaInfoGroup& KFileMetaInfoGroup::operator= (const KFileMetaInfoGroup& info )
|
|
{
|
|
if (d != info.d)
|
|
{
|
|
deref();
|
|
// first deref the old one
|
|
d = info.d;
|
|
// and now ref the new one
|
|
ref();
|
|
}
|
|
return *this;
|
|
}
|
|
|
|
bool KFileMetaInfoGroup::isValid() const
|
|
{
|
|
// We don't call makeNull here since it isn't necassery, see deref()
|
|
return d != Data::null;
|
|
}
|
|
|
|
bool KFileMetaInfoGroup::isEmpty() const
|
|
{
|
|
return d->items.isEmpty();
|
|
}
|
|
|
|
TQStringList KFileMetaInfoGroup::preferredKeys() const
|
|
{
|
|
assert(isValid());
|
|
TQStringList list = keys();
|
|
TQStringList newlist;
|
|
TQStringList preferredKeys = d->mimeTypeInfo->preferredKeys();
|
|
TQStringList::Iterator pref;
|
|
TQStringList::Iterator begin = preferredKeys.begin();
|
|
TQStringList::Iterator end = preferredKeys.end();
|
|
|
|
// move all keys from the preferred keys that are in our list to a new list
|
|
for ( pref = begin; pref!=end; ++pref )
|
|
{
|
|
TQStringList::Iterator item = list.find(*pref);
|
|
if ( item != list.end() )
|
|
{
|
|
newlist.append( *item );
|
|
list.remove(item);
|
|
}
|
|
}
|
|
|
|
// now the old list only contains the non-preferred items, so we
|
|
// add the remaining ones to newlist
|
|
newlist += list;
|
|
|
|
return newlist;
|
|
}
|
|
|
|
TQStringList KFileMetaInfoGroup::keys() const
|
|
{
|
|
if (d == Data::makeNull())
|
|
kdWarning(7033) << "attempt to get the keys of "
|
|
"an invalid metainfo group";
|
|
|
|
TQStringList list;
|
|
|
|
// make a TQStringList with all available keys
|
|
TQMapConstIterator<TQString, KFileMetaInfoItem> it;
|
|
for (it = d->items.begin(); it!=d->items.end(); ++it)
|
|
{
|
|
list.append(it.data().key());
|
|
// kdDebug(7033) << "Item " << it.data().key() << endl;
|
|
}
|
|
return list;
|
|
}
|
|
|
|
TQString KFileMetaInfoGroup::translatedName() const
|
|
{
|
|
assert(isValid());
|
|
return d->mimeTypeInfo->groupInfo(d->name)->translatedName();
|
|
}
|
|
|
|
TQStringList KFileMetaInfoGroup::supportedKeys() const
|
|
{
|
|
assert(isValid());
|
|
return d->mimeTypeInfo->groupInfo(d->name)->supportedKeys();
|
|
}
|
|
|
|
bool KFileMetaInfoGroup::supportsVariableKeys() const
|
|
{
|
|
assert(isValid());
|
|
return d->mimeTypeInfo->groupInfo(d->name)->supportsVariableKeys();
|
|
}
|
|
|
|
bool KFileMetaInfoGroup::contains( const TQString& key ) const
|
|
{
|
|
return d->items.contains(key);
|
|
}
|
|
|
|
KFileMetaInfoItem KFileMetaInfoGroup::item( const TQString& key) const
|
|
{
|
|
TQMapIterator<TQString,KFileMetaInfoItem> it = d->items.find( key );
|
|
if ( it != d->items.end() )
|
|
return it.data();
|
|
|
|
return KFileMetaInfoItem();
|
|
}
|
|
|
|
KFileMetaInfoItem KFileMetaInfoGroup::item(uint hint) const
|
|
{
|
|
TQMapIterator<TQString, KFileMetaInfoItem> it;
|
|
|
|
for (it = d->items.begin(); it!=d->items.end(); ++it)
|
|
if (it.data().hint() == hint)
|
|
return it.data();
|
|
|
|
return KFileMetaInfoItem();
|
|
}
|
|
|
|
TQString KFileMetaInfoGroup::name() const
|
|
{
|
|
return d->name;
|
|
}
|
|
|
|
uint KFileMetaInfoGroup::attributes() const
|
|
{
|
|
assert(isValid());
|
|
return d->mimeTypeInfo->groupInfo(d->name)->attributes();
|
|
}
|
|
|
|
void KFileMetaInfoGroup::setAdded()
|
|
{
|
|
d->added = true;
|
|
}
|
|
|
|
bool KFileMetaInfoGroup::isModified() const
|
|
{
|
|
return d->dirty;
|
|
}
|
|
|
|
void KFileMetaInfoGroup::ref()
|
|
{
|
|
if (d != Data::null) d->ref();
|
|
|
|
}
|
|
|
|
void KFileMetaInfoGroup::deref()
|
|
{
|
|
// We don't call makeNull here since it isn't necassery:
|
|
// If d is equal to null it means that null is initialized already.
|
|
// null is 0L when it hasn't been initialized and d is never 0L.
|
|
if ((d != Data::null) && d->deref())
|
|
{
|
|
// kdDebug(7033) << "metainfo group " << d->name
|
|
// << " is finally deleted\n";
|
|
delete d;
|
|
d = 0;
|
|
}
|
|
|
|
}
|
|
|
|
KFileMetaInfoItem KFileMetaInfoGroup::addItem( const TQString& key )
|
|
{
|
|
assert(isValid());
|
|
TQMapIterator<TQString,KFileMetaInfoItem> it = d->items.find( key );
|
|
if ( it != d->items.end() )
|
|
return it.data();
|
|
|
|
const KFileMimeTypeInfo::GroupInfo* ginfo = d->mimeTypeInfo->groupInfo(d->name);
|
|
|
|
if ( !ginfo ) {
|
|
Q_ASSERT( ginfo );
|
|
return KFileMetaInfoItem();
|
|
}
|
|
|
|
const KFileMimeTypeInfo::ItemInfo* info = ginfo->itemInfo(key);
|
|
|
|
if ( !info ) {
|
|
Q_ASSERT( info );
|
|
return KFileMetaInfoItem();
|
|
}
|
|
|
|
KFileMetaInfoItem item;
|
|
|
|
if (info->isVariableItem())
|
|
item = KFileMetaInfoItem(ginfo->variableItemInfo(), key, TQVariant());
|
|
else
|
|
item = KFileMetaInfoItem(info, key, TQVariant());
|
|
|
|
d->items.insert(key, item);
|
|
item.setAdded(); // mark as added
|
|
d->dirty = true; // mark ourself as dirty, too
|
|
return item;
|
|
}
|
|
|
|
bool KFileMetaInfoGroup::removeItem( const TQString& key )
|
|
{
|
|
if (!isValid())
|
|
{
|
|
kdDebug(7033) << "trying to remove an item from an invalid group\n";
|
|
return false;
|
|
}
|
|
|
|
TQMapIterator<TQString, KFileMetaInfoItem> it = d->items.find(key);
|
|
if ( it==d->items.end() )
|
|
{
|
|
kdDebug(7033) << "trying to remove the non existant item " << key << "\n";
|
|
return false;
|
|
}
|
|
|
|
if (!((*it).attributes() & KFileMimeTypeInfo::Removable))
|
|
{
|
|
kdDebug(7033) << "trying to remove a non removable item\n";
|
|
return false;
|
|
}
|
|
|
|
(*it).setRemoved();
|
|
d->items.remove(it);
|
|
d->removedItems.append(key);
|
|
d->dirty = true;
|
|
return true;
|
|
}
|
|
|
|
TQStringList KFileMetaInfoGroup::removedItems()
|
|
{
|
|
return d->removedItems;
|
|
}
|
|
|
|
KFileMetaInfoItem KFileMetaInfoGroup::appendItem(const TQString& key,
|
|
const TQVariant& value)
|
|
{
|
|
//KDE4 enforce (value.type() == d->mimeTypeInfo->type())
|
|
assert(isValid());
|
|
const KFileMimeTypeInfo::GroupInfo* ginfo = d->mimeTypeInfo->groupInfo(d->name);
|
|
if ( !ginfo ) {
|
|
kdWarning() << "Trying to append a Metadata item for a non-existant group:" << d->name << endl;
|
|
return KFileMetaInfoItem();
|
|
}
|
|
const KFileMimeTypeInfo::ItemInfo* info = ginfo->itemInfo(key);
|
|
if ( !info ) {
|
|
kdWarning() << "Trying to append a Metadata item for an unknown key (no ItemInfo): " << key << endl;
|
|
return KFileMetaInfoItem();
|
|
}
|
|
|
|
KFileMetaInfoItem item;
|
|
|
|
if (info->key().isNull())
|
|
item = KFileMetaInfoItem(ginfo->variableItemInfo(), key, value);
|
|
else
|
|
item = KFileMetaInfoItem(info, key, value);
|
|
|
|
kdDebug(7033) << "KFileMetaInfogroup inserting a " << key << endl;
|
|
|
|
d->items.insert(key, item);
|
|
return item;
|
|
}
|
|
|
|
KFileMetaInfoGroup::Data* KFileMetaInfoGroup::Data::null = 0L;
|
|
static KStaticDeleter<KFileMetaInfoGroup::Data> sd_KFileMetaInfoGroupData;
|
|
|
|
KFileMetaInfoGroup::Data* KFileMetaInfoGroup::Data::makeNull()
|
|
{
|
|
if (!null)
|
|
{
|
|
// We deliberately do not reset "null" after it has been destroyed!
|
|
// Otherwise we will run into problems later in ~KFileMetaInfoItem
|
|
// where the d-pointer is compared against null.
|
|
null = new Data(TQString::null);
|
|
null->mimeTypeInfo = new KFileMimeTypeInfo();
|
|
sd_KFileMetaInfoGroupData.setObject( null );
|
|
}
|
|
return null;
|
|
}
|
|
|
|
|
|
///////////////////////////////////////////////////////////////////
|
|
///////////////////////////////////////////////////////////////////
|
|
|
|
KFileMimeTypeInfo::KFileMimeTypeInfo( const TQString& mimeType )
|
|
: m_mimeType( mimeType )
|
|
{
|
|
m_groups.setAutoDelete( true );
|
|
}
|
|
|
|
KFileMimeTypeInfo::~KFileMimeTypeInfo()
|
|
{
|
|
}
|
|
|
|
const KFileMimeTypeInfo::GroupInfo * KFileMimeTypeInfo::groupInfo( const TQString& group ) const
|
|
{
|
|
return m_groups.find( group );
|
|
}
|
|
|
|
KFileMimeTypeInfo::GroupInfo * KFileMimeTypeInfo::addGroupInfo(
|
|
const TQString& name, const TQString& translatedName )
|
|
{
|
|
GroupInfo* group = new GroupInfo( name, translatedName );
|
|
m_groups.insert(name, group);
|
|
return group;
|
|
}
|
|
|
|
TQStringList KFileMimeTypeInfo::supportedGroups() const
|
|
{
|
|
TQStringList list;
|
|
TQDictIterator<GroupInfo> it( m_groups );
|
|
for ( ; it.current(); ++it )
|
|
list.append( it.current()->name() );
|
|
|
|
return list;
|
|
}
|
|
|
|
TQStringList KFileMimeTypeInfo::translatedGroups() const
|
|
{
|
|
TQStringList list;
|
|
TQDictIterator<GroupInfo> it( m_groups );
|
|
for ( ; it.current(); ++it )
|
|
list.append( it.current()->translatedName() );
|
|
|
|
return list;
|
|
}
|
|
|
|
TQStringList KFileMimeTypeInfo::supportedKeys() const
|
|
{
|
|
// not really efficient, but not those are not large lists, probably.
|
|
// maybe cache the result?
|
|
TQStringList keys;
|
|
TQStringList::ConstIterator lit;
|
|
TQDictIterator<GroupInfo> it( m_groups );
|
|
for ( ; it.current(); ++it ) { // need to nuke dupes
|
|
TQStringList list = it.current()->supportedKeys();
|
|
for ( lit = list.begin(); lit != list.end(); ++lit ) {
|
|
if ( keys.find( *lit ) == keys.end() )
|
|
keys.append( *lit );
|
|
}
|
|
}
|
|
|
|
return keys;
|
|
}
|
|
|
|
TQValidator * KFileMimeTypeInfo::createValidator(const TQString& group,
|
|
const TQString& key,
|
|
TQObject *parent,
|
|
const char *name) const
|
|
{
|
|
KFilePlugin* plugin = KFileMetaInfoProvider::self()->plugin(m_mimeType);
|
|
if (plugin) return plugin->createValidator(mimeType(), group, key,
|
|
parent, name);
|
|
return 0;
|
|
}
|
|
|
|
|
|
///////////////////////////////////////////////////////////////////
|
|
///////////////////////////////////////////////////////////////////
|
|
|
|
KFileMimeTypeInfo::GroupInfo::GroupInfo( const TQString& name,
|
|
const TQString& translatedName )
|
|
: m_name( name ),
|
|
m_translatedName( translatedName ),
|
|
m_attr( 0 ),
|
|
m_variableItemInfo( 0 )
|
|
|
|
{
|
|
m_itemDict.setAutoDelete( true );
|
|
}
|
|
|
|
KFileMimeTypeInfo::GroupInfo::~GroupInfo()
|
|
{
|
|
delete m_variableItemInfo;
|
|
}
|
|
|
|
const KFileMimeTypeInfo::ItemInfo * KFileMimeTypeInfo::GroupInfo::itemInfo( const TQString& key ) const
|
|
{
|
|
ItemInfo* item = m_itemDict.find( key );
|
|
|
|
// if we the item isn't found and variable keys are supported, we need to
|
|
// return the default variable key iteminfo.
|
|
if (!item && m_variableItemInfo)
|
|
{
|
|
return m_variableItemInfo;
|
|
}
|
|
return item;
|
|
}
|
|
|
|
KFileMimeTypeInfo::ItemInfo* KFileMimeTypeInfo::GroupInfo::addItemInfo(
|
|
const TQString& key, const TQString& translatedKey,
|
|
TQVariant::Type type)
|
|
{
|
|
// kdDebug(7034) << key << "(" << translatedKey << ") -> " << TQVariant::typeToName(type) << endl;
|
|
|
|
ItemInfo* item = new ItemInfo(key, translatedKey, type);
|
|
m_supportedKeys.append(key);
|
|
m_itemDict.insert(key, item);
|
|
return item;
|
|
}
|
|
|
|
|
|
void KFileMimeTypeInfo::GroupInfo::addVariableInfo( TQVariant::Type type,
|
|
uint attr )
|
|
{
|
|
// just make sure that it's not already there
|
|
delete m_variableItemInfo;
|
|
m_variableItemInfo = new ItemInfo(TQString::null, TQString::null, type);
|
|
m_variableItemInfo->m_attr = attr;
|
|
}
|
|
|
|
///////////////////////////////////////////////////////////////////
|
|
///////////////////////////////////////////////////////////////////
|
|
|
|
TQString KFileMimeTypeInfo::ItemInfo::string(const TQVariant& value, bool mangle) const
|
|
{
|
|
TQString s;
|
|
|
|
switch (value.type())
|
|
{
|
|
case TQVariant::Invalid :
|
|
return "---";
|
|
|
|
case TQVariant::Bool :
|
|
s = value.toBool() ? i18n("Yes") : i18n("No");
|
|
break;
|
|
|
|
case TQVariant::Int :
|
|
if (unit() == KFileMimeTypeInfo::Seconds)
|
|
{
|
|
int seconds = value.toInt() % 60;
|
|
int minutes = value.toInt() / 60 % 60;
|
|
int hours = value.toInt() / 3600;
|
|
s = hours ? TQString().sprintf("%d:%02d:%02d",hours, minutes, seconds)
|
|
: TQString().sprintf("%02d:%02d", minutes, seconds);
|
|
return s; // no suffix wanted
|
|
}
|
|
else if (unit() == KFileMimeTypeInfo::Bytes)
|
|
{
|
|
// convertSize already adds the correct suffix
|
|
return KIO::convertSize(value.toInt());
|
|
}
|
|
else if (unit() == KFileMimeTypeInfo::KiloBytes)
|
|
{
|
|
// convertSizeFromKB already adds the correct suffix
|
|
return KIO::convertSizeFromKB(value.toInt());
|
|
}
|
|
else
|
|
s = KGlobal::locale()->formatNumber( value.toInt() , 0);
|
|
break;
|
|
|
|
case TQVariant::LongLong :
|
|
s = KGlobal::locale()->formatNumber( value.toLongLong(), 0 );
|
|
break;
|
|
|
|
case TQVariant::ULongLong :
|
|
if ( unit() == KFileMimeTypeInfo::Bytes )
|
|
return KIO::convertSize( value.toULongLong() );
|
|
else if ( unit() == KFileMimeTypeInfo::KiloBytes )
|
|
return KIO::convertSizeFromKB( value.toULongLong() );
|
|
else
|
|
s = KGlobal::locale()->formatNumber( value.toULongLong(), 0 );
|
|
break;
|
|
|
|
case TQVariant::UInt :
|
|
s = KGlobal::locale()->formatNumber( value.toUInt() , 0);
|
|
break;
|
|
|
|
case TQVariant::Double :
|
|
s = KGlobal::locale()->formatNumber( value.toDouble(), 3);
|
|
break;
|
|
|
|
case TQVariant::Date :
|
|
s = KGlobal::locale()->formatDate( value.toDate(), true );
|
|
break;
|
|
|
|
case TQVariant::Time :
|
|
s = KGlobal::locale()->formatTime( value.toTime(), true );
|
|
break;
|
|
|
|
case TQVariant::DateTime :
|
|
s = KGlobal::locale()->formatDateTime( value.toDateTime(),
|
|
true, true );
|
|
break;
|
|
|
|
case TQVariant::Size :
|
|
s = TQString("%1 x %2").arg(value.toSize().width())
|
|
.arg(value.toSize().height());
|
|
break;
|
|
|
|
case TQVariant::Point :
|
|
s = TQString("%1/%2").arg(value.toSize().width())
|
|
.arg(value.toSize().height());
|
|
break;
|
|
|
|
default:
|
|
s = value.toString();
|
|
}
|
|
|
|
if (mangle && !s.isNull())
|
|
{
|
|
s.prepend(prefix());
|
|
s.append(" " + suffix());
|
|
}
|
|
return s;
|
|
}
|
|
|
|
|
|
///////////////////////////////////////////////////////////////////
|
|
///////////////////////////////////////////////////////////////////
|
|
|
|
|
|
|
|
// stream operators
|
|
|
|
/* serialization of a KFileMetaInfoItem:
|
|
first a bool that says if the items is valid, and if yes,
|
|
all the elements of the Data
|
|
*/
|
|
KIO_EXPORT TQDataStream& operator <<(TQDataStream& s, const KFileMetaInfoItem& item )
|
|
{
|
|
|
|
KFileMetaInfoItem::Data* d = item.d;
|
|
|
|
// if the object is invalid, put only a char in the stream
|
|
bool isValid = item.isValid();
|
|
s << isValid;
|
|
// ### what do about mimetypeInfo ?
|
|
if (isValid)
|
|
s << d->key
|
|
<< d->value
|
|
<< d->dirty
|
|
<< d->added
|
|
<< d->removed;
|
|
|
|
return s;
|
|
}
|
|
|
|
|
|
KIO_EXPORT TQDataStream& operator >>(TQDataStream& s, KFileMetaInfoItem& item )
|
|
{
|
|
bool isValid;
|
|
s >> isValid;
|
|
|
|
if (!isValid)
|
|
{
|
|
item = KFileMetaInfoItem();
|
|
return s;
|
|
}
|
|
|
|
// we need a new object for our data
|
|
item.deref();
|
|
item.d = new KFileMetaInfoItem::Data();
|
|
|
|
// ### what do about mimetypeInfo ?
|
|
bool dirty, added, removed;
|
|
s >> item.d->key
|
|
>> item.d->value
|
|
>> dirty
|
|
>> added
|
|
>> removed;
|
|
item.d->dirty = dirty;
|
|
item.d->added = added;
|
|
item.d->removed = removed;
|
|
|
|
return s;
|
|
}
|
|
|
|
|
|
// serialization of a KFileMetaInfoGroup
|
|
// we serialize the name of the mimetype here instead of the mimetype info
|
|
// on the other side, we can simply use this to ask the provider for the info
|
|
KIO_EXPORT TQDataStream& operator <<(TQDataStream& s, const KFileMetaInfoGroup& group )
|
|
{
|
|
KFileMetaInfoGroup::Data* d = group.d;
|
|
|
|
// if the object is invalid, put only a byte in the stream
|
|
bool isValid = group.isValid();
|
|
|
|
s << isValid;
|
|
if (isValid)
|
|
{
|
|
s << d->name
|
|
<< d->items
|
|
<< d->mimeTypeInfo->mimeType();
|
|
}
|
|
return s;
|
|
}
|
|
|
|
KIO_EXPORT TQDataStream& operator >>(TQDataStream& s, KFileMetaInfoGroup& group )
|
|
{
|
|
TQString mimeType;
|
|
bool isValid;
|
|
s >> isValid;
|
|
|
|
// if it's invalid, there is not much to do
|
|
if (!isValid)
|
|
{
|
|
group = KFileMetaInfoGroup();
|
|
return s;
|
|
}
|
|
|
|
// we need a new object for our data
|
|
group.deref();
|
|
group.d = new KFileMetaInfoGroup::Data();
|
|
|
|
s >> group.d->name
|
|
>> group.d->items
|
|
>> mimeType;
|
|
|
|
group.d->mimeTypeInfo = KFileMetaInfoProvider::self()->mimeTypeInfo(mimeType);
|
|
|
|
// we need to set the item info for the items here
|
|
TQMapIterator<TQString, KFileMetaInfoItem> it = group.d->items.begin();
|
|
for ( ; it != group.d->items.end(); ++it)
|
|
{
|
|
(*it).d->mimeTypeInfo = group.d->mimeTypeInfo->groupInfo(group.d->name)
|
|
->itemInfo((*it).key());
|
|
}
|
|
|
|
return s;
|
|
}
|
|
|
|
// serialization of a KFileMetaInfo object
|
|
// we serialize the name of the mimetype here instead of the mimetype info
|
|
// on the other side, we can simply use this to ask the provider for the info
|
|
KIO_EXPORT TQDataStream& operator <<(TQDataStream& s, const KFileMetaInfo& info )
|
|
{
|
|
KFileMetaInfo::Data* d = info.d;
|
|
|
|
// if the object is invalid, put only a byte that tells this
|
|
bool isValid = info.isValid();
|
|
|
|
s << isValid;
|
|
if (isValid)
|
|
{
|
|
s << d->url
|
|
<< d->what
|
|
<< d->groups
|
|
<< d->mimeTypeInfo->mimeType();
|
|
}
|
|
return s;
|
|
}
|
|
|
|
KIO_EXPORT TQDataStream& operator >>(TQDataStream& s, KFileMetaInfo& info )
|
|
{
|
|
TQString mimeType;
|
|
bool isValid;
|
|
s >> isValid;
|
|
|
|
// if it's invalid, there is not much to do
|
|
if (!isValid)
|
|
{
|
|
info = KFileMetaInfo();
|
|
return s;
|
|
}
|
|
|
|
// we need a new object for our data
|
|
info.deref();
|
|
info.d = new KFileMetaInfo::Data();
|
|
|
|
s >> info.d->url
|
|
>> info.d->what
|
|
>> info.d->groups
|
|
>> mimeType;
|
|
info.d->mimeTypeInfo = KFileMetaInfoProvider::self()->mimeTypeInfo(mimeType);
|
|
|
|
return s;
|
|
}
|
|
|
|
#include "kfilemetainfo.moc"
|