From 4aed2c8219774f5d797760606b8489a92ddc5163 Mon Sep 17 00:00:00 2001 From: toma Date: Wed, 25 Nov 2009 17:56:58 +0000 Subject: Copy the KDE 3.5 branch to branches/trinity for new KDE 3.5 features. BUG:215923 git-svn-id: svn://anonsvn.kde.org/home/kde/branches/trinity/kdebase@1054174 283d02a7-25f6-0310-bc7c-ecb5cbfe19da --- kcontrol/filetypes/typeslistitem.cpp | 579 +++++++++++++++++++++++++++++++++++ 1 file changed, 579 insertions(+) create mode 100644 kcontrol/filetypes/typeslistitem.cpp (limited to 'kcontrol/filetypes/typeslistitem.cpp') diff --git a/kcontrol/filetypes/typeslistitem.cpp b/kcontrol/filetypes/typeslistitem.cpp new file mode 100644 index 000000000..88f3c8035 --- /dev/null +++ b/kcontrol/filetypes/typeslistitem.cpp @@ -0,0 +1,579 @@ +/* This file is part of the KDE project + Copyright (C) 2003 Waldo Bastian + Copyright (C) 2003 David Faure + + This program is free software; you can redistribute it and/or + modify it under the terms of the GNU General Public + License version 2 as published by the Free Software Foundation. + + This program 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 + General Public License for more details. + + You should have received a copy of the GNU General Public License + along with this program; see the file COPYING. If not, write to + the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor, + Boston, MA 02110-1301, USA. +*/ + +#include +#include +#include +#include +#include +#include + +#include "typeslistitem.h" + +QMap< QString, QStringList >* TypesListItem::s_changedServices; +static KStaticDeleter< QMap< QString, QStringList > > deleter; + +TypesListItem::TypesListItem(QListView *parent, const QString & major) + : QListViewItem(parent), metaType(true), m_bNewItem(false), m_askSave(2) +{ + initMeta(major); + setText(0, majorType()); +} + +TypesListItem::TypesListItem(TypesListItem *parent, KMimeType::Ptr mimetype, bool newItem) + : QListViewItem(parent), metaType(false), m_bNewItem(newItem), m_askSave(2) +{ + init(mimetype); + setText(0, minorType()); +} + +TypesListItem::TypesListItem(QListView *parent, KMimeType::Ptr mimetype) + : QListViewItem(parent), metaType(false), m_bNewItem(false), m_askSave(2) +{ + init(mimetype); + setText(0, majorType()); +} + +TypesListItem::TypesListItem(QListView *parent, KMimeType::Ptr mimetype, bool newItem) + : QListViewItem(parent), metaType(false), m_bNewItem(newItem), m_askSave(2) +{ + init(mimetype); + setText(0, majorType()); +} + +TypesListItem::~TypesListItem() +{ +} + +void TypesListItem::initMeta( const QString & major ) +{ + m_bFullInit = true; + m_mimetype = 0L; + m_major = major; + KSharedConfig::Ptr config = KSharedConfig::openConfig("konquerorrc", false, false); + config->setGroup("EmbedSettings"); + bool defaultValue = defaultEmbeddingSetting( major ); + m_autoEmbed = config->readBoolEntry( QString::fromLatin1("embed-")+m_major, defaultValue ) ? 0 : 1; +} + +bool TypesListItem::defaultEmbeddingSetting( const QString& major ) +{ + // embedding is false by default except for image/* + return ( major=="image" ); +} + +void TypesListItem::setup() +{ + if (m_mimetype) + { + setPixmap(0, m_mimetype->pixmap(KIcon::Small, IconSize(KIcon::Small))); + } + QListViewItem::setup(); +} + +void TypesListItem::init(KMimeType::Ptr mimetype) +{ + m_bFullInit = false; + m_mimetype = mimetype; + + int index = mimetype->name().find("/"); + if (index != -1) { + m_major = mimetype->name().left(index); + m_minor = mimetype->name().right(mimetype->name().length() - + (index+1)); + } else { + m_major = mimetype->name(); + m_minor = ""; + } + m_comment = mimetype->comment(QString(), false); + m_icon = mimetype->icon(QString(), false); + m_patterns = mimetype->patterns(); + m_autoEmbed = readAutoEmbed( mimetype ); +} + +int TypesListItem::readAutoEmbed( KMimeType::Ptr mimetype ) +{ + QVariant v = mimetype->property( "X-KDE-AutoEmbed" ); + if ( v.isValid() ) + return (v.toBool() ? 0 : 1); + else if ( !mimetype->property( "X-KDE-LocalProtocol" ).toString().isEmpty() ) + return 0; // embed by default for zip, tar etc. + else + return 2; +} + +QStringList TypesListItem::appServices() const +{ + if (!m_bFullInit) + { + TypesListItem *that = const_cast(this); + that->getServiceOffers(that->m_appServices, that->m_embedServices); + that->m_bFullInit = true; + } + return m_appServices; +} + +QStringList TypesListItem::embedServices() const +{ + if (!m_bFullInit) + { + TypesListItem *that = const_cast(this); + that->getServiceOffers(that->m_appServices, that->m_embedServices); + that->m_bFullInit = true; + } + return m_embedServices; +} + +void TypesListItem::getServiceOffers( QStringList & appServices, QStringList & embedServices ) const +{ + KServiceTypeProfile::setConfigurationMode(); + + KServiceTypeProfile::OfferList offerList = + KServiceTypeProfile::offers(m_mimetype->name(), "Application"); + QValueListIterator it(offerList.begin()); + for (; it != offerList.end(); ++it) + if ((*it).allowAsDefault()) + appServices.append((*it).service()->desktopEntryPath()); + + offerList = KServiceTypeProfile::offers(m_mimetype->name(), "KParts/ReadOnlyPart"); + for ( it = offerList.begin(); it != offerList.end(); ++it) + embedServices.append((*it).service()->desktopEntryPath()); + + KServiceTypeProfile::unsetConfigurationMode(); +} + +bool TypesListItem::isMimeTypeDirty() const +{ + if ( m_bNewItem ) + return true; + if ((m_mimetype->name() != name()) && + (name() != "application/octet-stream")) + { + kdDebug() << "Mimetype Name Dirty: old=" << m_mimetype->name() << " name()=" << name() << endl; + return true; + } + if (m_mimetype->comment(QString(), false) != m_comment) + { + kdDebug() << "Mimetype Comment Dirty: old=" << m_mimetype->comment(QString(),false) << " m_comment=" << m_comment << endl; + return true; + } + if (m_mimetype->icon(QString(), false) != m_icon) + { + kdDebug() << "Mimetype Icon Dirty: old=" << m_mimetype->icon(QString(),false) << " m_icon=" << m_icon << endl; + return true; + } + + if (m_mimetype->patterns() != m_patterns) + { + kdDebug() << "Mimetype Patterns Dirty: old=" << m_mimetype->patterns().join(";") + << " m_patterns=" << m_patterns.join(";") << endl; + return true; + } + + if ( readAutoEmbed( m_mimetype ) != (int)m_autoEmbed ) + return true; + return false; +} + +bool TypesListItem::isDirty() const +{ + if ( !m_bFullInit) + { + return false; + } + + if ( m_bNewItem ) + { + kdDebug() << "New item, need to save it" << endl; + return true; + } + + if ( !isMeta() ) + { + QStringList oldAppServices; + QStringList oldEmbedServices; + getServiceOffers( oldAppServices, oldEmbedServices ); + + if (oldAppServices != m_appServices) + { + kdDebug() << "App Services Dirty: old=" << oldAppServices.join(";") + << " m_appServices=" << m_appServices.join(";") << endl; + return true; + } + if (oldEmbedServices != m_embedServices) + { + kdDebug() << "Embed Services Dirty: old=" << oldEmbedServices.join(";") + << " m_embedServices=" << m_embedServices.join(";") << endl; + return true; + } + if (isMimeTypeDirty()) + return true; + } + else + { + KSharedConfig::Ptr config = KSharedConfig::openConfig("konquerorrc", false, false); + config->setGroup("EmbedSettings"); + bool defaultValue = defaultEmbeddingSetting(m_major); + unsigned int oldAutoEmbed = config->readBoolEntry( QString::fromLatin1("embed-")+m_major, defaultValue ) ? 0 : 1; + if ( m_autoEmbed != oldAutoEmbed ) + return true; + } + + if (m_askSave != 2) + return true; + + // nothing seems to have changed, it's not dirty. + return false; +} + +void TypesListItem::sync() +{ + Q_ASSERT(m_bFullInit); + if ( isMeta() ) + { + KSharedConfig::Ptr config = KSharedConfig::openConfig("konquerorrc", false, false); + config->setGroup("EmbedSettings"); + config->writeEntry( QString::fromLatin1("embed-")+m_major, m_autoEmbed == 0 ); + return; + } + + if (m_askSave != 2) + { + KSharedConfig::Ptr config = KSharedConfig::openConfig("konquerorrc", false, false); + config->setGroup("Notification Messages"); + if (m_askSave == 0) + { + // Ask + config->deleteEntry("askSave"+name()); + config->deleteEntry("askEmbedOrSave"+name()); + } + else + { + // Do not ask, open + config->writeEntry("askSave"+name(), "no" ); + config->writeEntry("askEmbedOrSave"+name(), "no" ); + } + } + + if (isMimeTypeDirty()) + { + // We must use KConfig otherwise config.deleteEntry doesn't + // properly cancel out settings already present in system files. + KConfig config( m_mimetype->desktopEntryPath(), false, false, "mime" ); + config.setDesktopGroup(); + + config.writeEntry("Type", "MimeType"); + config.writeEntry("MimeType", name()); + config.writeEntry("Icon", m_icon); + config.writeEntry("Patterns", m_patterns, ';'); + config.writeEntry("Comment", m_comment); + config.writeEntry("Hidden", false); + + if ( m_autoEmbed == 2 ) + config.deleteEntry( QString::fromLatin1("X-KDE-AutoEmbed"), false ); + else + config.writeEntry( QString::fromLatin1("X-KDE-AutoEmbed"), m_autoEmbed == 0 ); + + m_bNewItem = false; + } + + KConfig profile("profilerc", false, false); + + // Deleting current contents in profilerc relating to + // this service type + // + QStringList groups = profile.groupList(); + + for (QStringList::Iterator it = groups.begin(); + it != groups.end(); it++ ) + { + profile.setGroup(*it); + + // Entries with Preference <= 0 or AllowAsDefault == false + // are not in m_services + if ( profile.readEntry( "ServiceType" ) == name() + && profile.readNumEntry( "Preference" ) > 0 + && profile.readBoolEntry( "AllowAsDefault" ) ) + { + profile.deleteGroup( *it ); + } + } + + // Save preferred services + // + + groupCount = 1; + + saveServices( profile, m_appServices, "Application" ); + saveServices( profile, m_embedServices, "KParts/ReadOnlyPart" ); + + // Handle removed services + + KServiceTypeProfile::setConfigurationMode(); + KServiceTypeProfile::OfferList offerList = + KServiceTypeProfile::offers(m_mimetype->name(), "Application"); + offerList += KServiceTypeProfile::offers(m_mimetype->name(), "KParts/ReadOnlyPart"); + KServiceTypeProfile::unsetConfigurationMode(); + + QValueListIterator it_srv(offerList.begin()); + + for (; it_srv != offerList.end(); ++it_srv) { + + + KService::Ptr pService = (*it_srv).service(); + + bool isApplication = pService->type() == "Application"; + if (isApplication && !pService->allowAsDefault()) + continue; // Only those which were added in init() + + // Look in the correct list... + if ( (isApplication && ! m_appServices.contains( pService->desktopEntryPath() )) + || (!isApplication && !m_embedServices.contains( pService->desktopEntryPath() )) + ) { + // The service was in m_appServices but has been removed + // create a new .desktop file without this mimetype + + if( s_changedServices == NULL ) + deleter.setObject( s_changedServices, new QMap< QString, QStringList > ); + QStringList mimeTypeList = s_changedServices->contains( pService->desktopEntryPath()) + ? (*s_changedServices)[ pService->desktopEntryPath() ] : pService->serviceTypes(); + + if ( mimeTypeList.contains( name() ) ) { + // The mimetype is listed explicitly in the .desktop files, so + // just remove it and we're done + KConfig *desktop; + if ( !isApplication ) + { + desktop = new KConfig(pService->desktopEntryPath(), false, false, "services"); + } + else + { + QString path = pService->locateLocal(); + KConfig orig(pService->desktopEntryPath(), true, false, "apps"); + desktop = orig.copyTo(path); + } + desktop->setDesktopGroup(); + + mimeTypeList = s_changedServices->contains( pService->desktopEntryPath()) + ? (*s_changedServices)[ pService->desktopEntryPath() ] : desktop->readListEntry("MimeType", ';'); + + // Remove entry and the number that might follow. + QStringList::Iterator it; + for(;(it = mimeTypeList.find(name())) != mimeTypeList.end();) + { + it = mimeTypeList.remove(it); + if (it != mimeTypeList.end()) + { + // Check next item + bool numeric; + (*it).toInt(&numeric); + if (numeric) + mimeTypeList.remove(it); + } + } + + desktop->writeEntry("MimeType", mimeTypeList, ';'); + + // if two or more types have been modified, and they use the same service, + // accumulate the changes + (*s_changedServices)[ pService->desktopEntryPath() ] = mimeTypeList; + + desktop->sync(); + delete desktop; + } + else { + // The mimetype is not listed explicitly so it can't + // be removed. Preference = 0 handles this. + + // Find a group header. The headers are just dummy names as far as + // KUserProfile is concerned, but using the mimetype makes it a + // bit more structured for "manual" reading + while ( profile.hasGroup( + name() + " - " + QString::number(groupCount) ) ) + groupCount++; + + profile.setGroup( name() + " - " + QString::number(groupCount) ); + + profile.writeEntry("Application", pService->storageId()); + profile.writeEntry("ServiceType", name()); + profile.writeEntry("AllowAsDefault", true); + profile.writeEntry("Preference", 0); + } + } + } +} + +static bool inheritsMimetype(KMimeType::Ptr m, const QStringList &mimeTypeList) +{ + for(QStringList::ConstIterator it = mimeTypeList.begin(); + it != mimeTypeList.end(); ++it) + { + if (m->is(*it)) + return true; + } + + return false; +} + +KMimeType::Ptr TypesListItem::findImplicitAssociation(const QString &desktop) +{ + KService::Ptr s = KService::serviceByDesktopPath(desktop); + if (!s) return 0; // Hey, where did that one go? + + if( s_changedServices == NULL ) + deleter.setObject( s_changedServices, new QMap< QString, QStringList > ); + QStringList mimeTypeList = s_changedServices->contains( s->desktopEntryPath()) + ? (*s_changedServices)[ s->desktopEntryPath() ] : s->serviceTypes(); + + for(QStringList::ConstIterator it = mimeTypeList.begin(); + it != mimeTypeList.end(); ++it) + { + if ((m_mimetype->name() != *it) && m_mimetype->is(*it)) + { + return KMimeType::mimeType(*it); + } + } + return 0; +} + +void TypesListItem::saveServices( KConfig & profile, QStringList services, const QString & genericServiceType ) +{ + QStringList::Iterator it(services.begin()); + for (int i = services.count(); it != services.end(); ++it, i--) { + + KService::Ptr pService = KService::serviceByDesktopPath(*it); + if (!pService) continue; // Where did that one go? + + // Find a group header. The headers are just dummy names as far as + // KUserProfile is concerned, but using the mimetype makes it a + // bit more structured for "manual" reading + while ( profile.hasGroup( name() + " - " + QString::number(groupCount) ) ) + groupCount++; + + profile.setGroup( name() + " - " + QString::number(groupCount) ); + + profile.writeEntry("ServiceType", name()); + profile.writeEntry("GenericServiceType", genericServiceType); + profile.writeEntry("Application", pService->storageId()); + profile.writeEntry("AllowAsDefault", true); + profile.writeEntry("Preference", i); + + // merge new mimetype + if( s_changedServices == NULL ) + deleter.setObject( s_changedServices, new QMap< QString, QStringList > ); + QStringList mimeTypeList = s_changedServices->contains( pService->desktopEntryPath()) + ? (*s_changedServices)[ pService->desktopEntryPath() ] : pService->serviceTypes(); + + if (!mimeTypeList.contains(name()) && !inheritsMimetype(m_mimetype, mimeTypeList)) + { + KConfig *desktop; + if ( pService->type() == QString("Service") ) + { + desktop = new KConfig(pService->desktopEntryPath(), false, false, "services"); + } + else + { + QString path = pService->locateLocal(); + KConfig orig(pService->desktopEntryPath(), true, false, "apps"); + desktop = orig.copyTo(path); + } + + desktop->setDesktopGroup(); + mimeTypeList = s_changedServices->contains( pService->desktopEntryPath()) + ? (*s_changedServices)[ pService->desktopEntryPath() ] : desktop->readListEntry("MimeType", ';'); + mimeTypeList.append(name()); + + desktop->writeEntry("MimeType", mimeTypeList, ';'); + desktop->sync(); + delete desktop; + + // if two or more types have been modified, and they use the same service, + // accumulate the changes + (*s_changedServices)[ pService->desktopEntryPath() ] = mimeTypeList; + } + } +} + +void TypesListItem::setIcon( const QString& icon ) +{ + m_icon = icon; + setPixmap( 0, SmallIcon( icon ) ); +} + +bool TypesListItem::isEssential() const +{ + QString n = name(); + if ( n == "application/octet-stream" ) + return true; + if ( n == "inode/directory" ) + return true; + if ( n == "inode/directory-locked" ) + return true; + if ( n == "inode/blockdevice" ) + return true; + if ( n == "inode/chardevice" ) + return true; + if ( n == "inode/socket" ) + return true; + if ( n == "inode/fifo" ) + return true; + if ( n == "application/x-shellscript" ) + return true; + if ( n == "application/x-executable" ) + return true; + if ( n == "application/x-desktop" ) + return true; + return false; +} + +void TypesListItem::refresh() +{ + kdDebug() << "TypesListItem refresh " << name() << endl; + m_mimetype = KMimeType::mimeType( name() ); +} + +void TypesListItem::reset() +{ + if( s_changedServices ) + s_changedServices->clear(); +} + +void TypesListItem::getAskSave(bool &_askSave) +{ + if (m_askSave == 0) + _askSave = true; + if (m_askSave == 1) + _askSave = false; +} + +void TypesListItem::setAskSave(bool _askSave) +{ + if (_askSave) + m_askSave = 0; + else + m_askSave = 1; +} + +bool TypesListItem::canUseGroupSetting() const +{ + // "Use group settings" isn't available for zip, tar etc.; those have a builtin default... + bool hasLocalProtocolRedirect = !m_mimetype->property( "X-KDE-LocalProtocol" ).toString().isEmpty(); + return !hasLocalProtocolRedirect; +} + -- cgit v1.2.3