1/*
2 * Copyright 2011 Marco Martin <mart@kde.org>
3 *
4 * This program is free software; you can redistribute it and/or modify
5 * it under the terms of the GNU Library General Public License as
6 * published by the Free Software Foundation; either version 2, or
7 * (at your option) any later version.
8 *
9 * This program is distributed in the hope that it will be useful,
10 * but WITHOUT ANY WARRANTY; without even the implied warranty of
11 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
12 * GNU General Public License for more details
13 *
14 * You should have received a copy of the GNU Library General Public
15 * License along with this program; if not, write to the
16 * Free Software Foundation, Inc.,
17 * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
18 */
19
20#include "kdeclarative.h"
21#include "bindings/i18n_p.h"
22#include "private/kdeclarative_p.h"
23#include "private/engineaccess_p.h"
24#include "private/kiconprovider_p.h"
25
26#include <QtDeclarative/QDeclarativeComponent>
27#include <QtDeclarative/QDeclarativeContext>
28#include <QtDeclarative/QDeclarativeEngine>
29#include <QtDeclarative/QDeclarativeExpression>
30#include <QtDeclarative/qdeclarativedebug.h>
31#include <QtScript/QScriptEngine>
32#include <QtScript/QScriptValueIterator>
33#include <QtCore/QWeakPointer>
34
35#include <kcmdlineargs.h>
36#include <kdebug.h>
37#include <kglobal.h>
38#include <kstandarddirs.h>
39#include <kurl.h>
40#include <kconfiggroup.h>
41#include <ksharedconfig.h>
42
43void registerNonGuiMetaTypes(QScriptEngine *engine);
44QScriptValue constructIconClass(QScriptEngine *engine);
45QScriptValue constructKUrlClass(QScriptEngine *engine);
46
47KDeclarativePrivate::KDeclarativePrivate()
48 : initialized(false)
49{
50}
51
52KDeclarative::KDeclarative()
53 : d(new KDeclarativePrivate)
54{
55}
56
57KDeclarative::~KDeclarative()
58{
59 delete d;
60}
61
62
63void KDeclarative::setDeclarativeEngine(QDeclarativeEngine *engine)
64{
65 if (d->declarativeEngine.data() == engine) {
66 return;
67 }
68 d->initialized = false;
69 d->declarativeEngine = engine;
70}
71
72QDeclarativeEngine *KDeclarative::declarativeEngine() const
73{
74 return d->declarativeEngine.data();
75}
76
77void KDeclarative::initialize()
78{
79 //Glorious hack:steal the engine
80 //create the access object
81 EngineAccess *engineAccess = new EngineAccess(this);
82 d->declarativeEngine.data()->rootContext()->setContextProperty("__engineAccess", engineAccess);
83
84 //make engineaccess set our d->scriptengine
85 QDeclarativeExpression *expr = new QDeclarativeExpression(d->declarativeEngine.data()->rootContext(), d->declarativeEngine.data()->rootContext()->contextObject(), "__engineAccess.setEngine(this)");
86 expr->evaluate();
87 delete expr;
88
89 //we don't need engineaccess anymore
90 d->declarativeEngine.data()->rootContext()->setContextProperty("__engineAccess", 0);
91 engineAccess->deleteLater();
92
93 //fail?
94 if (!d->scriptEngine) {
95 kWarning() << "Failed to get the script engine";
96 return;
97 }
98
99 //change the old globalobject with a new read/write copy
100 QScriptValue originalGlobalObject = d->scriptEngine.data()->globalObject();
101
102 QScriptValue newGlobalObject = d->scriptEngine.data()->newObject();
103
104 QString eval = QLatin1String("eval");
105 QString version = QLatin1String("version");
106
107 {
108 QScriptValueIterator iter(originalGlobalObject);
109 QVector<QString> names;
110 QVector<QScriptValue> values;
111 QVector<QScriptValue::PropertyFlags> flags;
112 while (iter.hasNext()) {
113 iter.next();
114
115 QString name = iter.name();
116
117 if (name == version) {
118 continue;
119 }
120
121 if (name != eval) {
122 names.append(name);
123 values.append(iter.value());
124 flags.append(iter.flags() | QScriptValue::Undeletable);
125 }
126 newGlobalObject.setProperty(iter.scriptName(), iter.value());
127
128 // m_illegalNames.insert(name);
129 }
130
131 }
132
133 d->scriptEngine.data()->setGlobalObject(newGlobalObject);
134
135 d->initialized = true;
136}
137
138void KDeclarative::setupBindings()
139{
140 QScriptEngine *engine = d->scriptEngine.data();
141 if (!engine) {
142 return;
143 }
144
145 /*tell the engine to search for import in the kde4 plugin dirs.
146 addImportPath adds the path at the beginning, so to honour user's
147 paths we need to traverse the list in reverse order*/
148
149 const QStringList importPathList = KGlobal::dirs()->findDirs("module", "imports");
150 QStringListIterator importPathIterator(importPathList);
151 importPathIterator.toBack();
152 while (importPathIterator.hasPrevious()) {
153 d->declarativeEngine.data()->addImportPath(importPathIterator.previous());
154 }
155
156 const QString target = componentsTarget();
157 if (target != defaultComponentsTarget()) {
158 const QStringList paths = KGlobal::dirs()->findDirs("module", "platformimports/" % target);
159 QStringListIterator it(paths);
160 it.toBack();
161 while (it.hasPrevious()) {
162 d->declarativeEngine.data()->addImportPath(it.previous());
163 }
164 }
165
166 QScriptValue global = engine->globalObject();
167
168 //KConfig and KJob
169 registerNonGuiMetaTypes(d->scriptEngine.data());
170
171 // Stuff from Qt
172 global.setProperty("QIcon", constructIconClass(engine));
173
174 // Add stuff from KDE libs
175 bindI18N(engine);
176 qScriptRegisterSequenceMetaType<KUrl::List>(engine);
177 global.setProperty("Url", constructKUrlClass(engine));
178
179 // setup ImageProvider for KDE icons
180 d->declarativeEngine.data()->addImageProvider(QString("icon"), new KIconProvider);
181}
182
183QScriptEngine *KDeclarative::scriptEngine() const
184{
185 return d->scriptEngine.data();
186}
187
188void KDeclarative::setupQmlJsDebugger()
189{
190 if (KCmdLineArgs::parsedArgs("qt")->isSet("qmljsdebugger")) {
191 QDeclarativeDebuggingEnabler enabler;
192 }
193}
194
195QString KDeclarative::defaultComponentsTarget()
196{
197 return QLatin1String("desktop");
198}
199
200QString KDeclarative::componentsTarget()
201{
202 const QStringList platform = runtimePlatform();
203 if (platform.isEmpty()) {
204 return defaultComponentsTarget();
205 }
206
207 return platform.last();
208}
209
210QStringList KDeclarative::runtimePlatform()
211{
212 static QStringList *runtimePlatform = 0;
213 if (!runtimePlatform) {
214 const QString env = getenv("PLASMA_PLATFORM");
215 runtimePlatform = new QStringList(env.split(":", QString::SkipEmptyParts));
216 if (runtimePlatform->isEmpty()) {
217 KConfigGroup cg(KGlobal::config(), "General");
218 *runtimePlatform = cg.readEntry("runtimePlatform", *runtimePlatform);
219 }
220 }
221
222 return *runtimePlatform;
223}
224
225