File indexing completed on 2025-02-09 05:31:48
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