File indexing completed on 2024-04-14 04:38:25

0001 /*
0002     Copyright (C) 2011 Harald Sitter <sitter@kde.org>
0003 
0004     This library is free software; you can redistribute it and/or
0005     modify it under the terms of the GNU Lesser General Public
0006     License as published by the Free Software Foundation; either
0007     version 2.1 of the License, or (at your option) version 3, or any
0008     later version accepted by the membership of KDE e.V. (or its
0009     successor approved by the membership of KDE e.V.), Nokia Corporation
0010     (or its successors, if any) and the KDE Free Qt Foundation, which shall
0011     act as a proxy defined in Section 6 of version 3 of the license.
0012 
0013     This library is distributed in the hope that it will be useful,
0014     but WITHOUT ANY WARRANTY; without even the implied warranty of
0015     MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
0016     Lesser General Public License for more details.
0017 
0018     You should have received a copy of the GNU Lesser General Public
0019     License along with this library.  If not, see <http://www.gnu.org/licenses/>.
0020 */
0021 
0022 #ifndef PHONON_GLOBALDESCRIPTIONCONTAINER_H
0023 #define PHONON_GLOBALDESCRIPTIONCONTAINER_H
0024 
0025 #include <QMap>
0026 #include <QDebug>
0027 #include <QtGlobal>
0028 
0029 #include <phonon/objectdescription.h>
0030 
0031 namespace Phonon
0032 {
0033 
0034 class MediaController;
0035 
0036 /**
0037  * \internal
0038  *
0039  * A container for object descriptions.
0040  * The primary use of this container is to turn ObjectDescriptions with unique
0041  * id scope smaller than backend into globally unique ones.
0042  *
0043  * For example a MediaController enhances a MediaObject, you may have multiple
0044  * MediaObjects and thus MediaControllers in one application. The interface
0045  * to query all subtitles is only available on the backend class itself though,
0046  * so the index/id of the descriptions handed to a Phonon API user must be
0047  * unique with global scope.
0048  * This is where the GlobalDescriptionContainer comes in. It allows arbitrary
0049  * objects to register (using object address) with the container (which is a
0050  * singleton).
0051  * The object hands its locally unique ObjectDescriptions to the container, which
0052  * turns it into a globally unique description and maps the global id to the
0053  * local id.
0054  *
0055  * That way it is possible to easily map local to global description objects.
0056  *
0057  * \author Harald Sitter <sitter@kde.org>
0058  */
0059 template <typename D>
0060 class GlobalDescriptionContainer
0061 {
0062 public:
0063     typedef int global_id_t;
0064     typedef int local_id_t;
0065 
0066     typedef QMap<global_id_t, D> GlobalDescriptorMap;
0067     typedef QMapIterator<global_id_t, D> GlobalDescriptorMapIterator;
0068 
0069     typedef QMap<global_id_t, local_id_t> LocalIdMap;
0070     typedef QMapIterator<global_id_t, local_id_t> LocaIdMapIterator;
0071 
0072 public:
0073     static GlobalDescriptionContainer *self;
0074 
0075     static GlobalDescriptionContainer *instance()
0076     {
0077         if (!self)
0078             self = new GlobalDescriptionContainer;
0079         return self;
0080     }
0081 
0082     virtual ~GlobalDescriptionContainer() {}
0083 
0084     /**
0085      * \returns a list of all global unique IDs of all stored ObjectDescriptions
0086      */
0087     QList<int> globalIndexes()
0088     {
0089         QList<int> list;
0090         GlobalDescriptorMapIterator it(m_globalDescriptors);
0091         while (it.hasNext()) {
0092             it.next();
0093             list << it.key();
0094         }
0095         return list;
0096     }
0097 
0098     /**
0099      * \param key the global ID of the ObjectDescription
0100      *
0101      * \returns ObjectDescriptions associated with a given ID
0102      */
0103     D fromIndex(global_id_t key)
0104     {
0105         return m_globalDescriptors.value(key, D());
0106     }
0107 
0108     // ----------- MediaController Specific ----------- //
0109 
0110     /**
0111      * Registers a new object within the container.
0112      * This essentially creates a new empty ID map.
0113      *
0114      * \param obj The reference object
0115      */
0116     void register_(void *obj)
0117     {
0118         Q_ASSERT(obj);
0119         Q_ASSERT(m_localIds.find(obj) == m_localIds.end());
0120         m_localIds[obj] = LocalIdMap();
0121     }
0122 
0123     /**
0124      * Unregisters a object from the container.
0125      * This essentially clears the ID map and removes all traces of the
0126      * object.
0127      *
0128      * \param obj The object
0129      */
0130     void unregister_(void *obj)
0131     {
0132         // TODO: remove all descriptions that are *only* associated with this MC
0133         Q_ASSERT(obj);
0134         Q_ASSERT(m_localIds.find(obj) != m_localIds.end());
0135         m_localIds[obj].clear();
0136         m_localIds.remove(obj);
0137     }
0138 
0139     /**
0140      * Clear the internal mapping of global to local id for a given object.
0141      *
0142      * \param obj The object
0143      */
0144     void clearListFor(void *obj)
0145     {
0146         Q_ASSERT(obj);
0147         Q_ASSERT_X(m_localIds.find(obj) != m_localIds.end(),
0148                    "clearing list",
0149                    "the object is not registered!");
0150         m_localIds[obj].clear();
0151     }
0152 
0153     /**
0154      * Adds a new description object for a specific object.
0155      * A description object *must* have a global unique id, which is ensured
0156      * by using this function, which will either reuse an existing equal
0157      * ObjectDescription or use the next free unique ID.
0158      * Using the provided index the unique ID is then mapped to the one of the
0159      * specific object.
0160      *
0161      * \param obj The object
0162      * \param index local ID (i.e. within the object @obj)
0163      * \param name Name of the description
0164      * \param type Type of the description (e.g. file)
0165      */
0166     void add(void *obj,
0167              local_id_t index, const QString &name, const QString &type = QString())
0168     {
0169         Q_ASSERT(obj);
0170         Q_ASSERT(m_localIds.find(obj) != m_localIds.end());
0171 
0172         QHash<QByteArray, QVariant> properties;
0173         properties.insert("name", name);
0174         properties.insert("description", "");
0175         properties.insert("type", type);
0176 
0177         // Empty lists will start at 0.
0178         global_id_t id = 0;
0179         {
0180             // Find id, either a descriptor with name and type is already present
0181             // or get the next available index.
0182             GlobalDescriptorMapIterator it(m_globalDescriptors);
0183             while (it.hasNext()) {
0184                 it.next();
0185                 if (it.value().property("name") == name &&
0186                         it.value().property("type") == type) {
0187                     id = it.value().index();
0188                 }
0189             }
0190             if (id == 0)
0191                 id = nextFreeIndex();
0192         }
0193         D descriptor = D(id, properties);
0194 
0195         m_globalDescriptors.insert(id, descriptor);
0196         m_localIds[obj].insert(id, index);
0197     }
0198 
0199     /**
0200      * Overload function.
0201      * The index of the provided descriptor *must* be unique within the
0202      * context of the container.
0203      *
0204      * \param obj The object
0205      * \param descriptor the DescriptionObject with unique index
0206      */
0207     void add(void *obj,
0208              D descriptor)
0209     {
0210         Q_ASSERT(obj);
0211         Q_ASSERT(m_localIds.find(obj) != m_localIds.end());
0212         Q_ASSERT(m_globalDescriptors.find(descriptor.index()) == m_globalDescriptors.end());
0213 
0214         m_globalDescriptors.insert(descriptor.index(), descriptor);
0215         m_localIds[obj].insert(descriptor.index(), descriptor.index());
0216     }
0217 
0218     /**
0219      * List of ObjectDescriptions for a given object, the
0220      * descriptions are limied by the scope of the type (obviously), so you only
0221      * get ObjectDescription from the container.
0222      *
0223      * \param obj The object
0224      *
0225      * \returns the list of ObjectDescriptions for a given object, the
0226      * descriptions are limied by the scope of the type (obviously), so you only
0227      * get subtitle descriptions from a subtitle container.
0228      */
0229     QList<D> listFor(const void *obj) const
0230     {
0231         Q_ASSERT(obj);
0232         Q_ASSERT(m_localIds.find(obj) != m_localIds.end());
0233 
0234         QList<D> list;
0235         LocaIdMapIterator it(m_localIds.value(obj));
0236         while (it.hasNext()) {
0237             it.next();
0238             Q_ASSERT(m_globalDescriptors.find(it.key()) != m_globalDescriptors.end());
0239             list << m_globalDescriptors[it.key()];
0240         }
0241         return list;
0242     }
0243 
0244     /**
0245      * \param obj The object
0246      * \param key the global ID (i.e. index of an ObjectDescription)
0247      *
0248      * \returns the local ID associated with the description object
0249      */
0250     int localIdFor(const void *obj, global_id_t key) const
0251     {
0252         Q_ASSERT(obj);
0253         Q_ASSERT(m_localIds.find(obj) != m_localIds.end());
0254         if (m_localIds[obj].find(key) == m_localIds[obj].end())
0255             qWarning() << "WARNING:" << Q_FUNC_INFO
0256                        << ": supplied global ID is unknown for the object ("
0257                        << obj << ")";
0258         return m_localIds[obj].value(key, 0);
0259     }
0260 
0261 protected:
0262     GlobalDescriptionContainer() :
0263         m_peak(0)
0264     {
0265     }
0266 
0267     /**
0268      * \returns next free unique index to be used as global ID for an ObjectDescription
0269      */
0270     global_id_t nextFreeIndex()
0271     {
0272         return ++m_peak;
0273     }
0274 
0275     GlobalDescriptorMap m_globalDescriptors;
0276     QMap<const void *, LocalIdMap> m_localIds;
0277 
0278     global_id_t m_peak;
0279 };
0280 
0281 template <typename D>
0282 GlobalDescriptionContainer<D> *GlobalDescriptionContainer<D>::self = 0;
0283 
0284 typedef GlobalDescriptionContainer<AudioChannelDescription> GlobalAudioChannels;
0285 typedef GlobalDescriptionContainer<SubtitleDescription> GlobalSubtitles;
0286 
0287 } // Namespace Phonon
0288 
0289 #endif // PHONON_GLOBALDESCRIPTIONCONTAINER_H