/* * This file is part of TelepathyQt4 * * Copyright (C) 2009-2010 Collabora Ltd. * Copyright (C) 2009-2010 Nokia Corporation * * This library is free software; you can redistribute it and/or * modify it under the terms of the GNU Lesser General Public * License as published by the Free Software Foundation; either * version 2.1 of the License, or (at your option) any later version. * * 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 * Lesser General Public License for more details. * * You should have received a copy of the GNU Lesser General Public * License along with this library; if not, write to the Free Software * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA */ #include #include "TelepathyQt4/_gen/future-constants.h" #include "TelepathyQt4/debug-internal.h" #include #include #include #include #include #include #include #include #include #include #include namespace Tp { struct ChannelFactory::Private { Private(); typedef QPair FeaturePair; QList features; typedef QPair CtorPair; QList ctors; }; ChannelFactory::Private::Private() { } /** * \class ChannelFactory * \ingroup clientchannel * \headerfile TelepathyQt4/channel-factory.h * * \brief Constructs Channel objects * * \todo This class is currently only a placeholder to enable using factories in general in other * classes. There is no actual configurability in the construction behavior, although a * factory-style construction API is provided. */ /** * Create a new ChannelFactory object for the given \a bus. * * The returned factory will construct channel subclasses provided by TelepathyQt4 as appropriate * for the channel immutable properties, but not make any features ready. * * \param bus The QDBusConnection the proxies constructed using this factory should use. * \return An ChannelFactoryPtr pointing to the newly created factory. */ ChannelFactoryPtr ChannelFactory::create(const QDBusConnection &bus) { return ChannelFactoryPtr(new ChannelFactory(bus)); } /** * Class constructor. * * The constructed factory will construct channel subclasses provided by TelepathyQt4 as appropriate * for the channel immutable properties, but not make any features ready. * * \param bus The QDBusConnection the proxies constructed using this factory should use. */ ChannelFactory::ChannelFactory(const QDBusConnection &bus) : DBusProxyFactory(bus), mPriv(new Private) { setSubclassForTextChats(); setSubclassForTextChatrooms(); setSubclassForStreamedMediaCalls(); setSubclassForRoomLists(); setSubclassForIncomingFileTransfers(); setSubclassForOutgoingFileTransfers(); setSubclassForContactSearches(); setFallbackSubclass(); } /** * Class destructor. */ ChannelFactory::~ChannelFactory() { delete mPriv; } Features ChannelFactory::featuresForTextChats(const QVariantMap &additionalProps) const { return featuresFor(ChannelClassSpec::textChat(additionalProps)); } void ChannelFactory::addFeaturesForTextChats(const Features &features, const QVariantMap &additionalProps) { addFeaturesFor(ChannelClassSpec::textChat(additionalProps), features); addFeaturesFor(ChannelClassSpec::unnamedTextChat(additionalProps), features); } ChannelFactory::ConstructorConstPtr ChannelFactory::constructorForTextChats( const QVariantMap &additionalProps) const { return constructorFor(ChannelClassSpec::textChat(additionalProps)); } void ChannelFactory::setConstructorForTextChats(const ConstructorConstPtr &ctor, const QVariantMap &additionalProps) { setConstructorFor(ChannelClassSpec::textChat(additionalProps), ctor); setConstructorFor(ChannelClassSpec::unnamedTextChat(additionalProps), ctor); } Features ChannelFactory::featuresForTextChatrooms(const QVariantMap &additionalProps) const { return featuresFor(ChannelClassSpec::textChatroom(additionalProps)); } void ChannelFactory::addFeaturesForTextChatrooms(const Features &features, const QVariantMap &additionalProps) { addFeaturesFor(ChannelClassSpec::textChatroom(additionalProps), features); } ChannelFactory::ConstructorConstPtr ChannelFactory::constructorForTextChatrooms( const QVariantMap &additionalProps) const { return constructorFor(ChannelClassSpec::textChatroom(additionalProps)); } void ChannelFactory::setConstructorForTextChatrooms(const ConstructorConstPtr &ctor, const QVariantMap &additionalProps) { setConstructorFor(ChannelClassSpec::textChatroom(additionalProps), ctor); } Features ChannelFactory::featuresForStreamedMediaCalls(const QVariantMap &additionalProps) const { return featuresFor(ChannelClassSpec::streamedMediaCall(additionalProps)); } void ChannelFactory::addFeaturesForStreamedMediaCalls(const Features &features, const QVariantMap &additionalProps) { ChannelClassSpec smSpec = ChannelClassSpec::streamedMediaCall(additionalProps); ChannelClassSpec unnamedSMSpec = ChannelClassSpec::unnamedStreamedMediaCall(additionalProps); addFeaturesFor(smSpec, features); addFeaturesFor(unnamedSMSpec, features); } ChannelFactory::ConstructorConstPtr ChannelFactory::constructorForStreamedMediaCalls( const QVariantMap &additionalProps) const { return constructorFor(ChannelClassSpec::streamedMediaCall(additionalProps)); } void ChannelFactory::setConstructorForStreamedMediaCalls(const ConstructorConstPtr &ctor, const QVariantMap &additionalProps) { ChannelClassSpec smSpec = ChannelClassSpec::streamedMediaCall(additionalProps); ChannelClassSpec unnamedSMSpec = ChannelClassSpec::unnamedStreamedMediaCall(additionalProps); setConstructorFor(smSpec, ctor); setConstructorFor(unnamedSMSpec, ctor); } Features ChannelFactory::featuresForRoomLists(const QVariantMap &additionalProps) const { return featuresFor(ChannelClassSpec::roomList(additionalProps)); } void ChannelFactory::addFeaturesForRoomLists(const Features &features, const QVariantMap &additionalProps) { addFeaturesFor(ChannelClassSpec::roomList(additionalProps), features); } ChannelFactory::ConstructorConstPtr ChannelFactory::constructorForRoomLists( const QVariantMap &additionalProps) const { return constructorFor(ChannelClassSpec::roomList(additionalProps)); } void ChannelFactory::setConstructorForRoomLists(const ConstructorConstPtr &ctor, const QVariantMap &additionalProps) { setConstructorFor(ChannelClassSpec::roomList(additionalProps), ctor); } Features ChannelFactory::featuresForOutgoingFileTransfers(const QVariantMap &additionalProps) const { return featuresFor(ChannelClassSpec::outgoingFileTransfer(additionalProps)); } void ChannelFactory::addFeaturesForOutgoingFileTransfers(const Features &features, const QVariantMap &additionalProps) { addFeaturesFor(ChannelClassSpec::outgoingFileTransfer(additionalProps), features); } ChannelFactory::ConstructorConstPtr ChannelFactory::constructorForOutgoingFileTransfers( const QVariantMap &additionalProps) const { return constructorFor(ChannelClassSpec::outgoingFileTransfer(additionalProps)); } void ChannelFactory::setConstructorForOutgoingFileTransfers(const ConstructorConstPtr &ctor, const QVariantMap &additionalProps) { setConstructorFor(ChannelClassSpec::outgoingFileTransfer(additionalProps), ctor); } Features ChannelFactory::featuresForIncomingFileTransfers(const QVariantMap &additionalProps) const { return featuresFor(ChannelClassSpec::incomingFileTransfer(additionalProps)); } void ChannelFactory::addFeaturesForIncomingFileTransfers(const Features &features, const QVariantMap &additionalProps) { addFeaturesFor(ChannelClassSpec::incomingFileTransfer(additionalProps), features); } ChannelFactory::ConstructorConstPtr ChannelFactory::constructorForIncomingFileTransfers( const QVariantMap &additionalProps) const { return constructorFor(ChannelClassSpec::incomingFileTransfer(additionalProps)); } void ChannelFactory::setConstructorForIncomingFileTransfers(const ConstructorConstPtr &ctor, const QVariantMap &additionalProps) { setConstructorFor(ChannelClassSpec::incomingFileTransfer(additionalProps), ctor); } Features ChannelFactory::featuresForContactSearches(const QVariantMap &additionalProps) const { return featuresFor(ChannelClassSpec::contactSearch(additionalProps)); } void ChannelFactory::addFeaturesForContactSearches(const Features &features, const QVariantMap &additionalProps) { addFeaturesFor(ChannelClassSpec::contactSearch(additionalProps), features); } ChannelFactory::ConstructorConstPtr ChannelFactory::constructorForContactSearches( const QVariantMap &additionalProps) const { return constructorFor(ChannelClassSpec::contactSearch(additionalProps)); } void ChannelFactory::setConstructorForContactSearches(const ConstructorConstPtr &ctor, const QVariantMap &additionalProps) { setConstructorFor(ChannelClassSpec::contactSearch(additionalProps), ctor); } Features ChannelFactory::commonFeatures() const { return featuresFor(ChannelClassSpec()); } void ChannelFactory::addCommonFeatures(const Features &features) { addFeaturesFor(ChannelClassSpec(), features); } ChannelFactory::ConstructorConstPtr ChannelFactory::fallbackConstructor() const { return constructorFor(ChannelClassSpec()); } void ChannelFactory::setFallbackConstructor(const ConstructorConstPtr &ctor) { setConstructorFor(ChannelClassSpec(), ctor); } Features ChannelFactory::featuresFor(const ChannelClassSpec &channelClass) const { Features features; foreach (const Private::FeaturePair &pair, mPriv->features) { if (pair.first.isSubsetOf(channelClass)) { features.unite(pair.second); } } return features; } void ChannelFactory::addFeaturesFor(const ChannelClassSpec &channelClass, const Features &features) { QList::iterator i; for (i = mPriv->features.begin(); i != mPriv->features.end(); ++i) { if (channelClass.allProperties().size() > i->first.allProperties().size()) { break; } if (i->first == channelClass) { i->second.unite(features); return; } } // We ran out of feature specifications (for the given size/specificity of a channel class) // before finding a matching one, so let's create a new entry mPriv->features.insert(i, qMakePair(channelClass, features)); } ChannelFactory::ConstructorConstPtr ChannelFactory::constructorFor(const ChannelClassSpec &cc) const { QList::iterator i; for (i = mPriv->ctors.begin(); i != mPriv->ctors.end(); ++i) { if (i->first.isSubsetOf(cc)) { return i->second; } } // If this is reached, we didn't have a proper fallback constructor Q_ASSERT(false); return ConstructorConstPtr(); } void ChannelFactory::setConstructorFor(const ChannelClassSpec &channelClass, const ConstructorConstPtr &ctor) { if (ctor.isNull()) { warning().nospace() << "Tried to set a NULL ctor for ChannelClass(" << channelClass.channelType() << ", " << channelClass.targetHandleType() << ", " << channelClass.allProperties().size() << "props in total)"; return; } QList::iterator i; for (i = mPriv->ctors.begin(); i != mPriv->ctors.end(); ++i) { if (channelClass.allProperties().size() > i->first.allProperties().size()) { break; } if (i->first == channelClass) { i->second = ctor; return; } } // We ran out of constructors (for the given size/specificity of a channel class) // before finding a matching one, so let's create a new entry mPriv->ctors.insert(i, qMakePair(channelClass, ctor)); } /** * Constructs a Channel proxy and begins making it ready. * * If a valid proxy already exists in the factory cache for the given combination of \a busName and * \a objectPath, it is returned instead. All newly created proxies are automatically cached until * they're either DBusProxy::invalidated() or the last reference to them outside the factory has * been dropped. * * The proxy can be accessed immediately after this function returns using PendingReady::proxy(). * * \todo Make it configurable which subclass is constructed. * * \param connection Proxy for the owning connection of the channel. * \param channelPath The object path of the channel. * \param immutableProperties The immutable properties of the channel. * \return A PendingReady operation with the proxy in PendingReady::proxy(). */ PendingReady *ChannelFactory::proxy(const ConnectionPtr &connection, const QString &channelPath, const QVariantMap &immutableProperties) const { DBusProxyPtr proxy = cachedProxy(connection->busName(), channelPath); if (proxy.isNull()) { proxy = constructorFor(ChannelClassSpec(immutableProperties))->construct(connection, channelPath, immutableProperties); } return nowHaveProxy(proxy); } /** * Transforms well-known names to the corresponding unique names, as is appropriate for Channel * * \param uniqueOrWellKnown The name to transform. * \return The unique name corresponding to \a uniqueOrWellKnown (which may be it itself). */ QString ChannelFactory::finalBusNameFrom(const QString &uniqueOrWellKnown) const { return StatefulDBusProxy::uniqueNameFrom(dbusConnection(), uniqueOrWellKnown); } /** * Returns features as configured for the channel class given by the Channel::immutableProperties() * of \a proxy. * * \todo Make the features configurable - currently an empty set is always returned. * * \param proxy The Channel proxy to determine the features for. * \return The channel class-specific features. */ Features ChannelFactory::featuresFor(const DBusProxyPtr &proxy) const { ChannelPtr chan = ChannelPtr::qObjectCast(proxy); Q_ASSERT(!chan.isNull()); return featuresFor(ChannelClassSpec(chan->immutableProperties())); } } // Tp