mirror of
				https://github.com/arcan1s/awesome-widgets.git
				synced 2025-10-31 05:13:40 +00:00 
			
		
		
		
	initial implementation of custom keys
This commit is contained in:
		
							
								
								
									
										127
									
								
								sources/awesome-widget/plugin/awcustomkeyshelper.cpp
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										127
									
								
								sources/awesome-widget/plugin/awcustomkeyshelper.cpp
									
									
									
									
									
										Normal file
									
								
							| @ -0,0 +1,127 @@ | ||||
| /*************************************************************************** | ||||
|  *   This file is part of awesome-widgets                                  * | ||||
|  *                                                                         * | ||||
|  *   awesome-widgets is free software: you can redistribute it and/or      * | ||||
|  *   modify it under the terms of the GNU General Public License as        * | ||||
|  *   published by the Free Software Foundation, either version 3 of the    * | ||||
|  *   License, or (at your option) any later version.                       * | ||||
|  *                                                                         * | ||||
|  *   awesome-widgets 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 awesome-widgets. If not, see http://www.gnu.org/licenses/  * | ||||
|  ***************************************************************************/ | ||||
|  | ||||
| #include "awcustomkeyshelper.h" | ||||
|  | ||||
| #include <QSet> | ||||
| #include <QSettings> | ||||
| #include <QStandardPaths> | ||||
|  | ||||
| #include "awdebug.h" | ||||
|  | ||||
|  | ||||
| AWCustomKeysHelper::AWCustomKeysHelper(QObject *_parent) | ||||
|     : QObject(_parent) | ||||
| { | ||||
|     qCDebug(LOG_AW) << __PRETTY_FUNCTION__; | ||||
|  | ||||
|     m_filePath = "awesomewidgets/custom.ini"; | ||||
|     initKeys(); | ||||
| } | ||||
|  | ||||
|  | ||||
| AWCustomKeysHelper::~AWCustomKeysHelper() | ||||
| { | ||||
|     qCDebug(LOG_AW) << __PRETTY_FUNCTION__; | ||||
| } | ||||
|  | ||||
|  | ||||
| void AWCustomKeysHelper::initKeys() | ||||
| { | ||||
|     m_keys.clear(); | ||||
|  | ||||
|     QStringList configs = QStandardPaths::locateAll( | ||||
|         QStandardPaths::GenericDataLocation, m_filePath); | ||||
|  | ||||
|     for (auto &fileName : configs) { | ||||
|         QSettings settings(fileName, QSettings::IniFormat); | ||||
|         qCInfo(LOG_AW) << "Configuration file" << settings.fileName(); | ||||
|  | ||||
|         settings.beginGroup("Custom"); | ||||
|         QStringList keys = settings.childKeys(); | ||||
|         for (auto &key : keys) { | ||||
|             QString source = settings.value(key).toString(); | ||||
|             qCInfo(LOG_AW) << "Found custom key" << key << "for source" | ||||
|                            << source << "in" << settings.fileName(); | ||||
|             if (source.isEmpty()) { | ||||
|                 qCInfo(LOG_AW) << "Skip empty source for" << key; | ||||
|                 continue; | ||||
|             } | ||||
|             m_keys[key] = source; | ||||
|         } | ||||
|         settings.endGroup(); | ||||
|     } | ||||
| } | ||||
|  | ||||
|  | ||||
| bool AWCustomKeysHelper::writeKeys( | ||||
|     const QHash<QString, QString> &_configuration) const | ||||
| { | ||||
|     qCDebug(LOG_AW) << "Write configuration" << _configuration; | ||||
|  | ||||
|     QString fileName = QString("%1/%2") | ||||
|                            .arg(QStandardPaths::writableLocation( | ||||
|                                QStandardPaths::GenericDataLocation)) | ||||
|                            .arg(m_filePath); | ||||
|     QSettings settings(fileName, QSettings::IniFormat); | ||||
|     qCInfo(LOG_AW) << "Configuration file" << fileName; | ||||
|  | ||||
|     settings.beginGroup("Custom"); | ||||
|     for (auto &key : _configuration.keys()) | ||||
|         settings.setValue(key, _configuration[key]); | ||||
|     settings.endGroup(); | ||||
|  | ||||
|     settings.sync(); | ||||
|  | ||||
|     return (settings.status() == QSettings::NoError); | ||||
| } | ||||
|  | ||||
|  | ||||
| QStringList AWCustomKeysHelper::keys() const | ||||
| { | ||||
|     return m_keys.keys(); | ||||
| } | ||||
|  | ||||
|  | ||||
| QString AWCustomKeysHelper::source(const QString &_key) const | ||||
| { | ||||
|     qCDebug(LOG_AW) << "Get source by key" << _key; | ||||
|  | ||||
|     return m_keys[_key]; | ||||
| } | ||||
|  | ||||
|  | ||||
| QStringList AWCustomKeysHelper::sources() const | ||||
| { | ||||
|     return QSet<QString>::fromList(m_keys.values()).toList(); | ||||
| } | ||||
|  | ||||
|  | ||||
| QStringList AWCustomKeysHelper::refinedSources() const | ||||
| { | ||||
|     auto allSources = QSet<QString>::fromList(m_keys.values()); | ||||
|     QSet<QString> output; | ||||
|  | ||||
|     while (output != allSources) { | ||||
|         output.clear(); | ||||
|         for (auto &src : allSources) | ||||
|             output.insert(m_keys.contains(src) ? source(src) : src); | ||||
|         allSources = output; | ||||
|     } | ||||
|  | ||||
|     return output.toList(); | ||||
| } | ||||
							
								
								
									
										48
									
								
								sources/awesome-widget/plugin/awcustomkeyshelper.h
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										48
									
								
								sources/awesome-widget/plugin/awcustomkeyshelper.h
									
									
									
									
									
										Normal file
									
								
							| @ -0,0 +1,48 @@ | ||||
| /*************************************************************************** | ||||
|  *   This file is part of awesome-widgets                                  * | ||||
|  *                                                                         * | ||||
|  *   awesome-widgets is free software: you can redistribute it and/or      * | ||||
|  *   modify it under the terms of the GNU General Public License as        * | ||||
|  *   published by the Free Software Foundation, either version 3 of the    * | ||||
|  *   License, or (at your option) any later version.                       * | ||||
|  *                                                                         * | ||||
|  *   awesome-widgets 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 awesome-widgets. If not, see http://www.gnu.org/licenses/  * | ||||
|  ***************************************************************************/ | ||||
|  | ||||
|  | ||||
| #ifndef AWCUSTOMKEYSHELPER_H | ||||
| #define AWCUSTOMKEYSHELPER_H | ||||
|  | ||||
| #include <QHash> | ||||
| #include <QObject> | ||||
|  | ||||
|  | ||||
| class AWCustomKeysHelper : public QObject | ||||
| { | ||||
|     Q_OBJECT | ||||
|  | ||||
| public: | ||||
|     explicit AWCustomKeysHelper(QObject *_parent = nullptr); | ||||
|     virtual ~AWCustomKeysHelper(); | ||||
|     void initKeys(); | ||||
|     bool writeKeys(const QHash<QString, QString> &_configuration) const; | ||||
|     // get | ||||
|     QStringList keys() const; | ||||
|     QString source(const QString &_key) const; | ||||
|     QStringList sources() const; | ||||
|     QStringList refinedSources() const; | ||||
|  | ||||
| private: | ||||
|     // properties | ||||
|     QString m_filePath; | ||||
|     QHash<QString, QString> m_keys; | ||||
| }; | ||||
|  | ||||
|  | ||||
| #endif /* AWCUSTOMKEYSHELPER_H */ | ||||
| @ -44,8 +44,6 @@ AWDataAggregator::AWDataAggregator(QObject *_parent) | ||||
|     m_boundaries["batTooltip"] = 100.0; | ||||
|  | ||||
|     initScene(); | ||||
|     connect(this, SIGNAL(updateData(const QVariantHash &)), this, | ||||
|             SLOT(dataUpdate(const QVariantHash &))); | ||||
| } | ||||
|  | ||||
|  | ||||
|  | ||||
| @ -40,13 +40,12 @@ public: | ||||
|     void setParameters(const QVariantMap &_settings); | ||||
|     QPixmap tooltipImage(); | ||||
|  | ||||
| signals: | ||||
|     void updateData(const QVariantHash &_values); | ||||
|     void toolTipPainted(const QString &_image) const; | ||||
|  | ||||
| private slots: | ||||
| public slots: | ||||
|     void dataUpdate(const QVariantHash &_values); | ||||
|  | ||||
| signals: | ||||
|     void toolTipPainted(const QString &_image) const; | ||||
|  | ||||
| private: | ||||
|     // ui | ||||
|     QGraphicsScene *m_toolTipScene = nullptr; | ||||
|  | ||||
| @ -78,6 +78,14 @@ QHash<QString, QString> AWFormatterHelper::getFormatters() const | ||||
| } | ||||
|  | ||||
|  | ||||
| void AWFormatterHelper::initItems() | ||||
| { | ||||
|     installDirectories(); | ||||
|     initFormatters(); | ||||
|     initKeys(); | ||||
| } | ||||
|  | ||||
|  | ||||
| QList<AbstractExtItem *> AWFormatterHelper::items() const | ||||
| { | ||||
|     QList<AbstractExtItem *> converted; | ||||
| @ -333,11 +341,3 @@ void AWFormatterHelper::doCreateItem() | ||||
|         return createItem<AWNoFormatter>(); | ||||
|     } | ||||
| } | ||||
|  | ||||
|  | ||||
| void AWFormatterHelper::initItems() | ||||
| { | ||||
|     installDirectories(); | ||||
|     initFormatters(); | ||||
|     initKeys(); | ||||
| } | ||||
|  | ||||
| @ -24,8 +24,6 @@ | ||||
| #include "awabstractformatter.h" | ||||
|  | ||||
|  | ||||
| class AWAbstractFormatter; | ||||
|  | ||||
| class AWFormatterHelper : public AbstractExtItemAggregator | ||||
| { | ||||
|     Q_OBJECT | ||||
| @ -36,6 +34,7 @@ public: | ||||
|     QString convert(const QVariant &_value, const QString &_name) const; | ||||
|     QStringList definedFormatters() const; | ||||
|     QHash<QString, QString> getFormatters() const; | ||||
|     void initItems(); | ||||
|     QList<AbstractExtItem *> items() const; | ||||
|     QStringList knownFormatters() const; | ||||
|     bool removeUnusedFormatters(const QStringList &_keys) const; | ||||
| @ -55,7 +54,6 @@ private: | ||||
|     readMetadata(const QString &_filePath) const; | ||||
|     // parent methods | ||||
|     void doCreateItem(); | ||||
|     void initItems(); | ||||
|     // properties | ||||
|     QStringList m_directories; | ||||
|     QString m_filePath; | ||||
|  | ||||
| @ -86,6 +86,7 @@ bool AWKeyCache::addKeyToCache(const QString &_type, const QString &_key) | ||||
| QStringList AWKeyCache::getRequiredKeys(const QStringList &_keys, | ||||
|                                         const QStringList &_bars, | ||||
|                                         const QVariantMap &_tooltip, | ||||
|                                         const QStringList &_userKeys, | ||||
|                                         const QStringList &_allKeys) | ||||
| { | ||||
|     qCDebug(LOG_AW) << "Looking for required keys in" << _keys << _bars | ||||
| @ -94,6 +95,7 @@ QStringList AWKeyCache::getRequiredKeys(const QStringList &_keys, | ||||
|     // initial copy | ||||
|     QSet<QString> used = QSet<QString>::fromList(_keys); | ||||
|     used.unite(QSet<QString>::fromList(_bars)); | ||||
|     used.unite(QSet<QString>::fromList(_userKeys)); | ||||
|     // insert keys from tooltip | ||||
|     for (auto &key : _tooltip.keys()) { | ||||
|         if ((key.endsWith("Tooltip")) && (_tooltip[key].toBool())) { | ||||
|  | ||||
| @ -29,6 +29,7 @@ namespace AWKeyCache | ||||
| bool addKeyToCache(const QString &_type, const QString &_key = ""); | ||||
| QStringList getRequiredKeys(const QStringList &_keys, const QStringList &_bars, | ||||
|                             const QVariantMap &_tooltip, | ||||
|                             const QStringList &_userKeys, | ||||
|                             const QStringList &_allKeys); | ||||
| QHash<QString, QStringList> loadKeysFromCache(); | ||||
| }; | ||||
|  | ||||
| @ -22,6 +22,7 @@ | ||||
| #include <QRegExp> | ||||
| #include <QThread> | ||||
|  | ||||
| #include "awcustomkeyshelper.h" | ||||
| #include "awdebug.h" | ||||
| #include "awkeycache.h" | ||||
| #include "awpatternfunctions.h" | ||||
| @ -38,6 +39,16 @@ AWKeyOperations::AWKeyOperations(QObject *_parent) | ||||
|     : QObject(_parent) | ||||
| { | ||||
|     qCDebug(LOG_AW) << __PRETTY_FUNCTION__; | ||||
|  | ||||
|     m_customKeys = new AWCustomKeysHelper(this); | ||||
|     m_graphicalItems | ||||
|         = new ExtItemAggregator<GraphicalItem>(nullptr, "desktops"); | ||||
|     m_extNetRequest | ||||
|         = new ExtItemAggregator<ExtNetworkRequest>(nullptr, "requests"); | ||||
|     m_extQuotes = new ExtItemAggregator<ExtQuotes>(nullptr, "quotes"); | ||||
|     m_extScripts = new ExtItemAggregator<ExtScript>(nullptr, "scripts"); | ||||
|     m_extUpgrade = new ExtItemAggregator<ExtUpgrade>(nullptr, "upgrade"); | ||||
|     m_extWeather = new ExtItemAggregator<ExtWeather>(nullptr, "weather"); | ||||
| } | ||||
|  | ||||
|  | ||||
| @ -46,6 +57,7 @@ AWKeyOperations::~AWKeyOperations() | ||||
|     qCDebug(LOG_AW) << __PRETTY_FUNCTION__; | ||||
|  | ||||
|     // extensions | ||||
|     delete m_customKeys; | ||||
|     delete m_graphicalItems; | ||||
|     delete m_extNetRequest; | ||||
|     delete m_extQuotes; | ||||
| @ -159,6 +171,8 @@ QStringList AWKeyOperations::dictKeys() const | ||||
|     // bars | ||||
|     for (auto &item : m_graphicalItems->activeItems()) | ||||
|         allKeys.append(item->tag("bar")); | ||||
|     // user defined keys | ||||
|     allKeys.append(m_customKeys->keys()); | ||||
|     // static keys | ||||
|     allKeys.append(QString(STATIC_KEYS).split(',')); | ||||
|  | ||||
| @ -180,6 +194,24 @@ GraphicalItem *AWKeyOperations::giByKey(const QString &_key) const | ||||
| } | ||||
|  | ||||
|  | ||||
| QStringList AWKeyOperations::requiredUserKeys() const | ||||
| { | ||||
|     return m_customKeys->refinedSources(); | ||||
| } | ||||
|  | ||||
|  | ||||
| QStringList AWKeyOperations::userKeys() const | ||||
| { | ||||
|     return m_customKeys->keys(); | ||||
| } | ||||
|  | ||||
|  | ||||
| QString AWKeyOperations::userKeySource(const QString &_key) const | ||||
| { | ||||
|     return m_customKeys->source(_key); | ||||
| } | ||||
|  | ||||
|  | ||||
| QString AWKeyOperations::infoByKey(const QString &_key) const | ||||
| { | ||||
|     qCDebug(LOG_AW) << "Requested key" << _key; | ||||
| @ -314,29 +346,13 @@ void AWKeyOperations::addKeyToCache(const QString &_type, const QString &_key) | ||||
|  | ||||
| void AWKeyOperations::reinitKeys() | ||||
| { | ||||
|     // renew extensions | ||||
|     // delete them if any | ||||
|     delete m_graphicalItems; | ||||
|     m_graphicalItems = nullptr; | ||||
|     delete m_extNetRequest; | ||||
|     m_extNetRequest = nullptr; | ||||
|     delete m_extQuotes; | ||||
|     m_extQuotes = nullptr; | ||||
|     delete m_extScripts; | ||||
|     m_extScripts = nullptr; | ||||
|     delete m_extUpgrade; | ||||
|     m_extUpgrade = nullptr; | ||||
|     delete m_extWeather; | ||||
|     m_extWeather = nullptr; | ||||
|     // create | ||||
|     m_graphicalItems | ||||
|         = new ExtItemAggregator<GraphicalItem>(nullptr, "desktops"); | ||||
|     m_extNetRequest | ||||
|         = new ExtItemAggregator<ExtNetworkRequest>(nullptr, "requests"); | ||||
|     m_extQuotes = new ExtItemAggregator<ExtQuotes>(nullptr, "quotes"); | ||||
|     m_extScripts = new ExtItemAggregator<ExtScript>(nullptr, "scripts"); | ||||
|     m_extUpgrade = new ExtItemAggregator<ExtUpgrade>(nullptr, "upgrade"); | ||||
|     m_extWeather = new ExtItemAggregator<ExtWeather>(nullptr, "weather"); | ||||
|     m_customKeys->initKeys(); | ||||
|     m_graphicalItems->initItems(); | ||||
|     m_extNetRequest->initItems(); | ||||
|     m_extQuotes->initItems(); | ||||
|     m_extScripts->initItems(); | ||||
|     m_extUpgrade->initItems(); | ||||
|     m_extWeather->initItems(); | ||||
|  | ||||
|     // init | ||||
|     QStringList allKeys = dictKeys(); | ||||
|  | ||||
| @ -27,6 +27,7 @@ | ||||
| #include "extitemaggregator.h" | ||||
|  | ||||
|  | ||||
| class AWCustomKeysHelper; | ||||
| class AWDataAggregator; | ||||
| class AWDataEngineAggregator; | ||||
| class AWKeysAggregator; | ||||
| @ -52,6 +53,9 @@ public: | ||||
|     // keys | ||||
|     QStringList dictKeys() const; | ||||
|     GraphicalItem *giByKey(const QString &_key) const; | ||||
|     QStringList requiredUserKeys() const; | ||||
|     QStringList userKeys() const; | ||||
|     QString userKeySource(const QString &_key) const; | ||||
|     // values | ||||
|     QString infoByKey(const QString &_key) const; | ||||
|     QString pattern() const; | ||||
| @ -70,6 +74,7 @@ private: | ||||
|     void addKeyToCache(const QString &_type, const QString &_key = ""); | ||||
|     void reinitKeys(); | ||||
|     // objects | ||||
|     AWCustomKeysHelper *m_customKeys = nullptr; | ||||
|     ExtItemAggregator<GraphicalItem> *m_graphicalItems = nullptr; | ||||
|     ExtItemAggregator<ExtNetworkRequest> *m_extNetRequest = nullptr; | ||||
|     ExtItemAggregator<ExtQuotes> *m_extQuotes = nullptr; | ||||
|  | ||||
| @ -250,9 +250,10 @@ void AWKeys::reinitKeys(const QStringList &_currentKeys) | ||||
|         barKeys.append(item->usedKeys()); | ||||
|     } | ||||
|     // get required keys | ||||
|     m_requiredKeys | ||||
|         = m_optimize ? AWKeyCache::getRequiredKeys( | ||||
|                            m_foundKeys, barKeys, m_tooltipParams, _currentKeys) | ||||
|     m_requiredKeys = m_optimize | ||||
|                          ? AWKeyCache::getRequiredKeys( | ||||
|                                m_foundKeys, barKeys, m_tooltipParams, | ||||
|                                m_keyOperator->requiredUserKeys(), _currentKeys) | ||||
|                          : QStringList(); | ||||
|  | ||||
|     // set key data to m_aggregator | ||||
| @ -266,10 +267,11 @@ void AWKeys::updateTextData() | ||||
|     m_mutex.lock(); | ||||
|     calculateValues(); | ||||
|     QString text = parsePattern(m_keyOperator->pattern()); | ||||
|     // update tooltip values under lock | ||||
|     m_dataAggregator->dataUpdate(m_values); | ||||
|     m_mutex.unlock(); | ||||
|  | ||||
|     emit(needTextToBeUpdated(text)); | ||||
|     emit(m_dataAggregator->updateData(m_values)); | ||||
| } | ||||
|  | ||||
|  | ||||
| @ -321,6 +323,10 @@ void AWKeys::calculateValues() | ||||
|     m_values["swap"] = 100.0f * m_values["swapmb"].toFloat() | ||||
|                        / m_values["swaptotmb"].toFloat(); | ||||
|  | ||||
|     // user defined keys | ||||
|     for (auto &key : m_keyOperator->userKeys()) | ||||
|         m_values[key] = m_values[m_keyOperator->userKeySource(key)]; | ||||
|  | ||||
|     // lambdas | ||||
|     for (auto &key : m_foundLambdas) | ||||
|         m_values[key] = AWPatternFunctions::expandLambdas( | ||||
|  | ||||
| @ -25,6 +25,7 @@ | ||||
| #include <QObject> | ||||
|  | ||||
|  | ||||
| class AWCustomKeysHelper; | ||||
| class AWDataAggregator; | ||||
| class AWDataEngineAggregator; | ||||
| class AWKeyOperations; | ||||
| @ -46,7 +47,7 @@ public: | ||||
|                               const bool _optimize); | ||||
|     Q_INVOKABLE void setAggregatorProperty(const QString &_key, | ||||
|                                            const QVariant &_value); | ||||
|     Q_INVOKABLE void setWrapNewLines(const bool _wrap = false); | ||||
|     Q_INVOKABLE void setWrapNewLines(const bool _wrap); | ||||
|     // additional method to force load keys from Qml UI. Used in some | ||||
|     // configuration pages | ||||
|     Q_INVOKABLE void updateCache(); | ||||
|  | ||||
| @ -32,6 +32,8 @@ AWKeysAggregator::AWKeysAggregator(QObject *_parent) | ||||
| { | ||||
|     qCDebug(LOG_AW) << __PRETTY_FUNCTION__; | ||||
|  | ||||
|     m_customFormatters = new AWFormatterHelper(nullptr); | ||||
|  | ||||
|     // sort time keys | ||||
|     m_timeKeys.sort(); | ||||
|     std::reverse(m_timeKeys.begin(), m_timeKeys.end()); | ||||
| @ -65,9 +67,7 @@ AWKeysAggregator::~AWKeysAggregator() | ||||
|  | ||||
| void AWKeysAggregator::initFormatters() | ||||
| { | ||||
|     if (m_customFormatters) | ||||
|         delete m_customFormatters; | ||||
|     m_customFormatters = new AWFormatterHelper(nullptr); | ||||
|     m_customFormatters->initItems(); | ||||
| } | ||||
|  | ||||
|  | ||||
|  | ||||
| @ -61,6 +61,19 @@ public: | ||||
|         qCInfo(LOG_LIB) << "Dialog returns" << ret; | ||||
|     }; | ||||
|  | ||||
|     void initItems() | ||||
|     { | ||||
|         m_items.clear(); | ||||
|         m_activeItems.clear(); | ||||
|  | ||||
|         m_items = getItems(); | ||||
|         for (auto &item : m_items) { | ||||
|             if (!item->isActive()) | ||||
|                 continue; | ||||
|             m_activeItems.append(static_cast<T *>(item)); | ||||
|         } | ||||
|     }; | ||||
|  | ||||
|     void initSockets() | ||||
|     { | ||||
|         // HACK as soon as per one widget instance we have two objects each of | ||||
| @ -148,19 +161,6 @@ private: | ||||
|                   }); | ||||
|         return items; | ||||
|     }; | ||||
|  | ||||
|     void initItems() | ||||
|     { | ||||
|         m_items.clear(); | ||||
|         m_activeItems.clear(); | ||||
|  | ||||
|         m_items = getItems(); | ||||
|         for (auto &item : m_items) { | ||||
|             if (!item->isActive()) | ||||
|                 continue; | ||||
|             m_activeItems.append(static_cast<T *>(item)); | ||||
|         } | ||||
|     }; | ||||
| }; | ||||
|  | ||||
|  | ||||
|  | ||||
		Reference in New Issue
	
	Block a user