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

Last change on this file since 983 was 846, checked in by Dmitry A. Kuminov, 14 years ago

trunk: Merged in qt 4.7.2 sources from branches/vendor/nokia/qt.

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