source: trunk/examples/script/context2d/environment.cpp@ 651

Last change on this file since 651 was 651, checked in by Dmitry A. Kuminov, 15 years ago

trunk: Merged in qt 4.6.2 sources.

File size: 17.3 KB
Line 
1/****************************************************************************
2**
3** Copyright (C) 2010 Nokia Corporation and/or its subsidiary(-ies).
4** All rights reserved.
5** Contact: Nokia Corporation ([email protected])
6**
7** This file is part of the examples of the Qt Toolkit.
8**
9** $QT_BEGIN_LICENSE:LGPL$
10** Commercial Usage
11** Licensees holding valid Qt Commercial licenses may use this file in
12** accordance with the Qt Commercial License Agreement provided with the
13** Software or, alternatively, in accordance with the terms contained in
14** a written agreement between you and Nokia.
15**
16** GNU Lesser General Public License Usage
17** Alternatively, this file may be used under the terms of the GNU Lesser
18** General Public License version 2.1 as published by the Free Software
19** Foundation and appearing in the file LICENSE.LGPL included in the
20** packaging of this file. Please review the following information to
21** ensure the GNU Lesser General Public License version 2.1 requirements
22** will be met: http://www.gnu.org/licenses/old-licenses/lgpl-2.1.html.
23**
24** In addition, as a special exception, Nokia gives you certain additional
25** rights. These rights are described in the Nokia Qt LGPL Exception
26** version 1.1, included in the file LGPL_EXCEPTION.txt in this package.
27**
28** GNU General Public License Usage
29** Alternatively, this file may be used under the terms of the GNU
30** General Public License version 3.0 as published by the Free Software
31** Foundation and appearing in the file LICENSE.GPL included in the
32** packaging of this file. Please review the following information to
33** ensure the GNU General Public License version 3.0 requirements will be
34** met: http://www.gnu.org/copyleft/gpl.html.
35**
36** If you have questions regarding the use of this file, please contact
37** Nokia at [email protected].
38** $QT_END_LICENSE$
39**
40****************************************************************************/
41
42#include "environment.h"
43#include "qcontext2dcanvas.h"
44#include "context2d.h"
45#include <QScriptValueIterator>
46#include <QDateTime>
47
48struct FakeDomEvent
49{
50 enum KeyCodes {
51 DOM_VK_UNDEFINED = 0x0,
52 DOM_VK_RIGHT_ALT = 0x12,
53 DOM_VK_LEFT_ALT = 0x12,
54 DOM_VK_LEFT_CONTROL = 0x11,
55 DOM_VK_RIGHT_CONTROL = 0x11,
56 DOM_VK_LEFT_SHIFT = 0x10,
57 DOM_VK_RIGHT_SHIFT = 0x10,
58 DOM_VK_META = 0x9D,
59 DOM_VK_BACK_SPACE = 0x08,
60 DOM_VK_CAPS_LOCK = 0x14,
61 DOM_VK_DELETE = 0x7F,
62 DOM_VK_END = 0x23,
63 DOM_VK_ENTER = 0x0D,
64 DOM_VK_ESCAPE = 0x1B,
65 DOM_VK_HOME = 0x24,
66 DOM_VK_NUM_LOCK = 0x90,
67 DOM_VK_PAUSE = 0x13,
68 DOM_VK_PRINTSCREEN = 0x9A,
69 DOM_VK_SCROLL_LOCK = 0x91,
70 DOM_VK_SPACE = 0x20,
71 DOM_VK_TAB = 0x09,
72 DOM_VK_LEFT = 0x25,
73 DOM_VK_RIGHT = 0x27,
74 DOM_VK_UP = 0x26,
75 DOM_VK_DOWN = 0x28,
76 DOM_VK_PAGE_DOWN = 0x22,
77 DOM_VK_PAGE_UP = 0x21,
78 DOM_VK_F1 = 0x70,
79 DOM_VK_F2 = 0x71,
80 DOM_VK_F3 = 0x72,
81 DOM_VK_F4 = 0x73,
82 DOM_VK_F5 = 0x74,
83 DOM_VK_F6 = 0x75,
84 DOM_VK_F7 = 0x76,
85 DOM_VK_F8 = 0x77,
86 DOM_VK_F9 = 0x78,
87 DOM_VK_F10 = 0x79,
88 DOM_VK_F11 = 0x7A,
89 DOM_VK_F12 = 0x7B,
90 DOM_VK_F13 = 0xF000,
91 DOM_VK_F14 = 0xF001,
92 DOM_VK_F15 = 0xF002,
93 DOM_VK_F16 = 0xF003,
94 DOM_VK_F17 = 0xF004,
95 DOM_VK_F18 = 0xF005,
96 DOM_VK_F19 = 0xF006,
97 DOM_VK_F20 = 0xF007,
98 DOM_VK_F21 = 0xF008,
99 DOM_VK_F22 = 0xF009,
100 DOM_VK_F23 = 0xF00A,
101 DOM_VK_F24 = 0xF00B
102 };
103
104 static int qtToDomKey(int keyCode);
105};
106
107int FakeDomEvent::qtToDomKey(int keyCode)
108{
109 switch (keyCode) {
110 case Qt::Key_Backspace:
111 return DOM_VK_BACK_SPACE;
112 case Qt::Key_Enter:
113 return DOM_VK_ENTER;
114 case Qt::Key_Return:
115 return DOM_VK_ENTER;
116 case Qt::Key_NumLock:
117 return DOM_VK_NUM_LOCK;
118 case Qt::Key_Alt:
119 return DOM_VK_RIGHT_ALT;
120 case Qt::Key_Control:
121 return DOM_VK_LEFT_CONTROL;
122 case Qt::Key_Shift:
123 return DOM_VK_LEFT_SHIFT;
124 case Qt::Key_Meta:
125 return DOM_VK_META;
126 case Qt::Key_CapsLock:
127 return DOM_VK_CAPS_LOCK;
128 case Qt::Key_Delete:
129 return DOM_VK_DELETE;
130 case Qt::Key_End:
131 return DOM_VK_END;
132 case Qt::Key_Escape:
133 return DOM_VK_ESCAPE;
134 case Qt::Key_Home:
135 return DOM_VK_HOME;
136 case Qt::Key_Pause:
137 return DOM_VK_PAUSE;
138 case Qt::Key_Print:
139 return DOM_VK_PRINTSCREEN;
140 case Qt::Key_ScrollLock:
141 return DOM_VK_SCROLL_LOCK;
142 case Qt::Key_Left:
143 return DOM_VK_LEFT;
144 case Qt::Key_Right:
145 return DOM_VK_RIGHT;
146 case Qt::Key_Up:
147 return DOM_VK_UP;
148 case Qt::Key_Down:
149 return DOM_VK_DOWN;
150 case Qt::Key_PageDown:
151 return DOM_VK_PAGE_DOWN;
152 case Qt::Key_PageUp:
153 return DOM_VK_PAGE_UP;
154 case Qt::Key_F1:
155 return DOM_VK_F1;
156 case Qt::Key_F2:
157 return DOM_VK_F2;
158 case Qt::Key_F3:
159 return DOM_VK_F3;
160 case Qt::Key_F4:
161 return DOM_VK_F4;
162 case Qt::Key_F5:
163 return DOM_VK_F5;
164 case Qt::Key_F6:
165 return DOM_VK_F6;
166 case Qt::Key_F7:
167 return DOM_VK_F7;
168 case Qt::Key_F8:
169 return DOM_VK_F8;
170 case Qt::Key_F9:
171 return DOM_VK_F9;
172 case Qt::Key_F10:
173 return DOM_VK_F10;
174 case Qt::Key_F11:
175 return DOM_VK_F11;
176 case Qt::Key_F12:
177 return DOM_VK_F12;
178 case Qt::Key_F13:
179 return DOM_VK_F13;
180 case Qt::Key_F14:
181 return DOM_VK_F14;
182 case Qt::Key_F15:
183 return DOM_VK_F15;
184 case Qt::Key_F16:
185 return DOM_VK_F16;
186 case Qt::Key_F17:
187 return DOM_VK_F17;
188 case Qt::Key_F18:
189 return DOM_VK_F18;
190 case Qt::Key_F19:
191 return DOM_VK_F19;
192 case Qt::Key_F20:
193 return DOM_VK_F20;
194 case Qt::Key_F21:
195 return DOM_VK_F21;
196 case Qt::Key_F22:
197 return DOM_VK_F22;
198 case Qt::Key_F23:
199 return DOM_VK_F23;
200 case Qt::Key_F24:
201 return DOM_VK_F24;
202 }
203 return keyCode;
204}
205
206//! [0]
207Environment::Environment(QObject *parent)
208 : QObject(parent)
209{
210 m_engine = new QScriptEngine(this);
211
212 m_document = m_engine->newQObject(
213 new Document(this), QScriptEngine::QtOwnership,
214 QScriptEngine::ExcludeSuperClassContents);
215
216 CanvasGradientPrototype::setup(m_engine);
217
218 m_originalGlobalObject = m_engine->globalObject();
219 reset();
220}
221//! [0]
222
223Environment::~Environment()
224{
225}
226
227QScriptEngine *Environment::engine() const
228{
229 return m_engine;
230}
231
232QScriptValue Environment::document() const
233{
234 return m_document;
235}
236
237int Environment::setTimeout(const QScriptValue &expression, int delay)
238{
239 if (expression.isString() || expression.isFunction()) {
240 int timerId = startTimer(delay);
241 m_timeoutHash.insert(timerId, expression);
242 return timerId;
243 }
244 return -1;
245}
246
247void Environment::clearTimeout(int timerId)
248{
249 killTimer(timerId);
250 m_timeoutHash.remove(timerId);
251}
252
253//! [1]
254int Environment::setInterval(const QScriptValue &expression, int delay)
255{
256 if (expression.isString() || expression.isFunction()) {
257 int timerId = startTimer(delay);
258 m_intervalHash.insert(timerId, expression);
259 return timerId;
260 }
261 return -1;
262}
263
264void Environment::clearInterval(int timerId)
265{
266 killTimer(timerId);
267 m_intervalHash.remove(timerId);
268}
269
270void Environment::timerEvent(QTimerEvent *event)
271{
272 int id = event->timerId();
273 QScriptValue expression = m_intervalHash.value(id);
274 if (!expression.isValid()) {
275 expression = m_timeoutHash.value(id);
276 if (expression.isValid())
277 killTimer(id);
278 }
279 if (expression.isString()) {
280 evaluate(expression.toString());
281 } else if (expression.isFunction()) {
282 expression.call();
283 }
284 maybeEmitScriptError();
285}
286//! [1]
287
288//! [5]
289void Environment::addCanvas(QContext2DCanvas *canvas)
290{
291 m_canvases.append(canvas);
292}
293
294QContext2DCanvas *Environment::canvasByName(const QString &name) const
295{
296 for (int i = 0; i < m_canvases.size(); ++i) {
297 QContext2DCanvas *canvas = m_canvases.at(i);
298 if (canvas->objectName() == name)
299 return canvas;
300 }
301 return 0;
302}
303//! [5]
304
305QList<QContext2DCanvas*> Environment::canvases() const
306{
307 return m_canvases;
308}
309
310void Environment::reset()
311{
312 if (m_engine->isEvaluating())
313 m_engine->abortEvaluation();
314
315 {
316 QHash<int, QScriptValue>::const_iterator it;
317 for (it = m_intervalHash.constBegin(); it != m_intervalHash.constEnd(); ++it)
318 killTimer(it.key());
319 m_intervalHash.clear();
320 for (it = m_timeoutHash.constBegin(); it != m_timeoutHash.constEnd(); ++it)
321 killTimer(it.key());
322 m_timeoutHash.clear();
323 }
324
325 for (int i = 0; i < m_canvases.size(); ++i)
326 m_canvases.at(i)->reset();
327
328 QScriptValue self = m_engine->newQObject(
329 this, QScriptEngine::QtOwnership,
330 QScriptEngine::ExcludeSuperClassContents);
331
332 {
333 QScriptValueIterator it(m_originalGlobalObject);
334 while (it.hasNext()) {
335 it.next();
336 self.setProperty(it.scriptName(), it.value(), it.flags());
337 }
338 }
339
340 self.setProperty("self", self);
341 self.setProperty("window", self);
342
343 QScriptValue navigator = m_engine->newObject();
344 navigator.setProperty("appCodeName", "context2d");
345 navigator.setProperty("appMinorVersion", 1);
346 navigator.setProperty("appVersion", 1);
347 navigator.setProperty("browserLanguage", "en_US");
348 navigator.setProperty("cookieEnabled", false);
349 navigator.setProperty("cpuClass", "i686");
350 navigator.setProperty("onLine", false);
351 navigator.setProperty("platform", "bogus OS");
352 navigator.setProperty("systemLanguage", "en_US");
353 navigator.setProperty("userAgent", "Context2D/1.1");
354 navigator.setProperty("userLanguage", "en_US");
355 self.setProperty("navigator", navigator);
356
357 m_engine->setGlobalObject(self);
358
359 m_engine->collectGarbage();
360}
361
362QScriptValue Environment::evaluate(const QString &code, const QString &fileName)
363{
364 return m_engine->evaluate(code, fileName);
365}
366
367//! [2]
368QScriptValue Environment::toWrapper(QObject *object)
369{
370 return m_engine->newQObject(object, QScriptEngine::QtOwnership,
371 QScriptEngine::PreferExistingWrapperObject
372 | QScriptEngine::ExcludeSuperClassContents);
373}
374//! [2]
375
376//! [3]
377void Environment::handleEvent(QContext2DCanvas *canvas, QMouseEvent *e)
378{
379 QString type;
380 switch (e->type()) {
381 case QEvent::MouseButtonPress:
382 type = "mousedown"; break;
383 case QEvent::MouseButtonRelease:
384 type = "mouseup"; break;
385 case QEvent::MouseMove:
386 type = "mousemove"; break;
387 default: break;
388 }
389 if (type.isEmpty())
390 return;
391
392 QScriptValue handlerObject;
393 QScriptValue handler = eventHandler(canvas, type, &handlerObject);
394 if (!handler.isFunction())
395 return;
396
397 QScriptValue scriptEvent = newFakeDomEvent(type, toWrapper(canvas));
398 // MouseEvent
399 scriptEvent.setProperty("screenX", e->globalX(), QScriptValue::ReadOnly);
400 scriptEvent.setProperty("screenY", e->globalY(), QScriptValue::ReadOnly);
401 scriptEvent.setProperty("clientX", e->x(), QScriptValue::ReadOnly);
402 scriptEvent.setProperty("clientY", e->y(), QScriptValue::ReadOnly);
403 scriptEvent.setProperty("layerX", e->x(), QScriptValue::ReadOnly);
404 scriptEvent.setProperty("layerY", e->y(), QScriptValue::ReadOnly);
405 scriptEvent.setProperty("pageX", e->x(), QScriptValue::ReadOnly);
406 scriptEvent.setProperty("pageY", e->y(), QScriptValue::ReadOnly);
407 scriptEvent.setProperty("altKey", (e->modifiers() & Qt::AltModifier) != 0,
408 QScriptValue::ReadOnly);
409 scriptEvent.setProperty("ctrlKey", (e->modifiers() & Qt::ControlModifier) != 0,
410 QScriptValue::ReadOnly);
411 scriptEvent.setProperty("metaKey", (e->modifiers() & Qt::MetaModifier) != 0,
412 QScriptValue::ReadOnly);
413 scriptEvent.setProperty("shiftKey", (e->modifiers() & Qt::ShiftModifier) != 0,
414 QScriptValue::ReadOnly);
415 int button = 0;
416 if (e->button() == Qt::RightButton)
417 button = 2;
418 else if (e->button() == Qt::MidButton)
419 button = 1;
420 scriptEvent.setProperty("button", button);
421 scriptEvent.setProperty("relatedTarget", m_engine->nullValue(),
422 QScriptValue::ReadOnly);
423 handler.call(handlerObject, QScriptValueList() << scriptEvent);
424 maybeEmitScriptError();
425}
426//! [3]
427
428void Environment::handleEvent(QContext2DCanvas *canvas, QKeyEvent *e)
429{
430 QString type;
431 switch (e->type()) {
432 case QEvent::KeyPress:
433 type = "keydown"; break;
434 case QEvent::KeyRelease:
435 type = "keyup"; break;
436 default: break;
437 }
438 if (type.isEmpty())
439 return;
440
441 QScriptValue handlerObject;
442 QScriptValue handler = eventHandler(canvas, type, &handlerObject);
443 if (!handler.isFunction())
444 return;
445
446 QScriptValue scriptEvent = newFakeDomEvent(type, toWrapper(canvas));
447 // KeyEvent
448 scriptEvent.setProperty("isChar", !e->text().isEmpty());
449 scriptEvent.setProperty("charCode", e->text());
450 scriptEvent.setProperty("keyCode", FakeDomEvent::qtToDomKey(e->key()));
451 scriptEvent.setProperty("which", e->key());
452
453 handler.call(handlerObject, QScriptValueList() << scriptEvent);
454 maybeEmitScriptError();
455}
456
457QScriptValue Environment::eventHandler(QContext2DCanvas *canvas, const QString &type,
458 QScriptValue *who)
459{
460 QString handlerName = "on" + type;
461 QScriptValue obj = toWrapper(canvas);
462 QScriptValue handler = obj.property(handlerName);
463 if (!handler.isValid()) {
464 obj = m_document;
465 handler = obj.property(handlerName);
466 }
467 if (who && handler.isFunction())
468 *who = obj;
469 return handler;
470}
471
472//! [4]
473QScriptValue Environment::newFakeDomEvent(const QString &type, const QScriptValue &target)
474{
475 QScriptValue e = m_engine->newObject();
476 // Event
477 e.setProperty("type", type, QScriptValue::ReadOnly);
478 e.setProperty("bubbles", true, QScriptValue::ReadOnly);
479 e.setProperty("cancelable", false, QScriptValue::ReadOnly);
480 e.setProperty("target", target, QScriptValue::ReadOnly);
481 e.setProperty("currentTarget", target, QScriptValue::ReadOnly);
482 e.setProperty("eventPhase", 3); // bubbling
483 e.setProperty("timeStamp", QDateTime::currentDateTime().toTime_t());
484 // UIEvent
485 e.setProperty("detail", 0, QScriptValue::ReadOnly);
486 e.setProperty("view", m_engine->globalObject(), QScriptValue::ReadOnly);
487 return e;
488}
489//! [4]
490
491void Environment::maybeEmitScriptError()
492{
493 if (m_engine->hasUncaughtException())
494 emit scriptError(m_engine->uncaughtException());
495}
496
497
498Document::Document(Environment *env)
499 : QObject(env)
500{
501}
502
503Document::~Document()
504{
505}
506
507QScriptValue Document::getElementById(const QString &id) const
508{
509 Environment *env = qobject_cast<Environment*>(parent());
510 QContext2DCanvas *canvas = env->canvasByName(id);
511 if (!canvas)
512 return QScriptValue();
513 return env->toWrapper(canvas);
514}
515
516QScriptValue Document::getElementsByTagName(const QString &name) const
517{
518 if (name != "canvas")
519 return QScriptValue();
520 Environment *env = qobject_cast<Environment*>(parent());
521 QList<QContext2DCanvas*> list = env->canvases();
522 QScriptValue result = env->engine()->newArray(list.size());
523 for (int i = 0; i < list.size(); ++i)
524 result.setProperty(i, env->toWrapper(list.at(i)));
525 return result;
526}
527
528void Document::addEventListener(const QString &type, const QScriptValue &listener,
529 bool useCapture)
530{
531 Q_UNUSED(useCapture);
532 if (listener.isFunction()) {
533 Environment *env = qobject_cast<Environment*>(parent());
534 QScriptValue self = env->toWrapper(this);
535 self.setProperty("on" + type, listener);
536 }
537}
538
539
540QColor colorFromString(const QString &name);
541
542CanvasGradientPrototype::CanvasGradientPrototype(QObject *parent)
543 : QObject(parent)
544{
545}
546
547void CanvasGradientPrototype::addColorStop(qreal offset, const QString &color)
548{
549 CanvasGradient *self = qscriptvalue_cast<CanvasGradient*>(thisObject());
550 if (!self || (self->value.type() == QGradient::NoGradient))
551 return;
552 self->value.setColorAt(offset, colorFromString(color));
553}
554
555void CanvasGradientPrototype::setup(QScriptEngine *engine)
556{
557 CanvasGradientPrototype *proto = new CanvasGradientPrototype();
558 engine->setDefaultPrototype(qMetaTypeId<CanvasGradient>(),
559 engine->newQObject(proto, QScriptEngine::ScriptOwnership,
560 QScriptEngine::ExcludeSuperClassContents));
561}
Note: See TracBrowser for help on using the repository browser.