1 /****************************************************************************************
2  * Copyright (c) 2013 Anmol Ahuja <darthcodus@gmail.com>                                *
3  *                                                                                      *
4  * This program is free software; you can redistribute it and/or modify it under        *
5  * the terms of the GNU General Public License as published by the Free Software        *
6  * Foundation; either version 2 of the License, or (at your option) any later           *
7  * version.                                                                             *
8  *                                                                                      *
9  * This program is distributed in the hope that it will be useful, but WITHOUT ANY      *
10  * WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A      *
11  * PARTICULAR PURPOSE. See the GNU General Public License for more details.             *
12  *                                                                                      *
13  * You should have received a copy of the GNU General Public License along with         *
14  * this program.  If not, see <http://www.gnu.org/licenses/>.                           *
15  ****************************************************************************************/
16 
17 #ifndef AMAROKSCRIPT_SCRIPTING_DEFINES_H
18 #define AMAROKSCRIPT_SCRIPTING_DEFINES_H
19 
20 #include <QHash>
21 #include <QObject>
22 #include <QJSEngine>
23 #include <QJSValue>
24 #include <QJSValueIterator>
25 
26 class QMetaEnum;
27 
28 namespace AmarokScript
29 {
30     template <class type, class WrapperType>
fromScriptValue(const QJSValue & obj,type & object)31     void fromScriptValue( const QJSValue &obj, type &object )
32     {
33         const WrapperType *wrapper = dynamic_cast<WrapperType*>( obj.toQObject() );
34         if( wrapper )
35             object = wrapper->data();
36         else
37             object = 0;
38     }
39 
40     template <class type, class WrapperType>
toScriptValue(QJSEngine * engine,type const & object)41     QJSValue toScriptValue( QJSEngine *engine, type const &object )
42     {
43         WrapperType *wrapper = new WrapperType( object );
44         return engine->newQObject( wrapper );
45     }
46 
47     template <class Container>
toScriptArray(QJSEngine * engine,const Container & container)48     QJSValue toScriptArray( QJSEngine *engine, const Container &container )
49     {
50         QJSValue scriptArray = engine->newArray();
51         typename Container::const_iterator begin = container.begin();
52         typename Container::const_iterator end = container.end();
53         typename Container::const_iterator it;
54         for( it = begin; it != end; ++it )
55             scriptArray.setProperty( quint32(it - begin), engine->toScriptValue(*it) );
56         return scriptArray;
57     }
58 
59     template <class Container>
fromScriptArray(const QJSValue & value,Container & container)60     void fromScriptArray( const QJSValue &value, Container &container )
61     {
62         quint32 len = value.property( QStringLiteral("length") ).toUInt();
63         for( quint32 i = 0; i < len; ++i )
64         {
65             QJSValue item = value.property( i );
66             typedef typename Container::value_type ContainerValue;
67             container.push_back( qjsvalue_cast<ContainerValue>(item) );
68         }
69     }
70 
71     template <class Map>
toScriptMap(QJSEngine * engine,const Map & map)72     QJSValue toScriptMap( QJSEngine *engine, const Map &map )
73     {
74         QJSValue scriptMap = engine->newObject();
75         for( typename Map::const_iterator it( map.begin() ); it != map.end(); ++it )
76             scriptMap.setProperty( it.key(), engine->toScriptValue( it.value() ) );
77         return scriptMap;
78     }
79 
80     template <class Map>
fromScriptMap(const QJSValue & value,Map & map)81     void fromScriptMap( const QJSValue &value, Map &map )
82     {
83         QJSValueIterator it( value );
84         while( it.hasNext() )
85         {
86             it.next();
87             map[it.name()] = qjsvalue_cast<typename Map::mapped_type>( it.value() );
88         }
89     }
90 
91     /**
92      * SCRIPTDOX _
93      */
94     class AmarokScriptEngine : public QJSEngine
95     {
96         Q_OBJECT
97 
98         public:
99             explicit AmarokScriptEngine( QObject *parent );
100             ~AmarokScriptEngine() override;
101 
102             void setDeprecatedProperty( const QString &parent, const QString &name, const QJSValue &property );
103             // exposing the metaobject directly also exposes >900 other values
104             QJSValue enumObject( const QMetaEnum &metaEnum );
105 
106             template <class T>
registerArrayType()107             void registerArrayType()
108             {
109                 qRegisterMetaType<T>();
110                 QMetaType::registerConverter<QJSValue,T>( [] (QJSValue scriptObj) {
111                     T arrayObj;
112                     fromScriptArray( scriptObj, arrayObj );
113                     return arrayObj;
114                 });
115                 QMetaType::registerConverter<T,QJSValue>( [this] (T arrayObj) { return toScriptArray( this, arrayObj ); } );
116             }
117             template <class Map>
registerMapType()118             void registerMapType()
119             {
120                 qRegisterMetaType<Map>();
121                 QMetaType::registerConverter<QJSValue,Map>( [] (QJSValue scriptObj) {
122                     Map mapObj;
123                     fromScriptMap( scriptObj, mapObj );
124                     return mapObj;
125                 });
126                 QMetaType::registerConverter<Map,QJSValue>( [this] (Map mapObj) { return toScriptMap( this, mapObj ); } );
127             }
128 
129             // SCRIPTDOX exclude
130             Q_INVOKABLE void invokableDeprecatedCall( const QString &call );
131 
132             /**
133              * @param function The function to invoke after time @param time in milliseconds.
134              * @param thisObject [Optional] The this object this function is invoked with.
135              * @param args [Optional] An array containing arguments this function is to be invoked with.
136              */
137             Q_INVOKABLE void setTimeout( const QJSValue &function, int time,
138                              const QJSValue &thisObject = QJSValue(),
139                              const QJSValue &args = QJSValue() );
140 
141         private Q_SLOTS:
142             void slotTimeout();
143 
144         Q_SIGNALS:
145             void deprecatedCall(const QString &);
146 
147         private:
148             const QString internalObject;
149             QHash<QObject*, QJSValueList> m_callbacks;
150     };
151 }
152 
153 #endif // AMAROKSCRIPT_SCRIPTING_DEFINES_H
154