File indexing completed on 2024-04-28 15:28:45

0001 /* This file is part of the KDE libraries
0002     Copyright (C) 2005, 2006 Ian Reinhart Geiser <geiseri@kde.org>
0003     Copyright (C) 2005, 2006 Matt Broadstone <mbroadst@gmail.com>
0004     Copyright (C) 2005, 2006 Richard J. Moore <rich@kde.org>
0005     Copyright (C) 2005, 2006 Erik L. Bunce <kde@bunce.us>
0006 
0007     This library is free software; you can redistribute it and/or
0008     modify it under the terms of the GNU Library General Public
0009     License as published by the Free Software Foundation; either
0010     version 2 of the License, or (at your option) any later version.
0011 
0012     This library is distributed in the hope that it will be useful,
0013     but WITHOUT ANY WARRANTY; without even the implied warranty of
0014     MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
0015     Library General Public License for more details.
0016 
0017     You should have received a copy of the GNU Library General Public License
0018     along with this library; see the file COPYING.LIB.  If not, write to
0019     the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor,
0020     Boston, MA 02110-1301, USA.
0021 */
0022 #include "kjsembed.h"
0023 #include "binding_support.h"
0024 
0025 #include "qobject_binding.h"
0026 #include "variant_binding.h"
0027 #include "static_binding.h"
0028 
0029 #include "iosupport.h"
0030 #include "quiloader_binding.h"
0031 #ifdef KJSEMBED_FORMBUILDER_BINDING
0032 #include "qformbuilder_binding.h"
0033 #endif
0034 #include "qpainter_binding.h"
0035 #include "qwidget_binding.h"
0036 #include "qaction_binding.h"
0037 #include "qlayout_binding.h"
0038 #include "svg_binding.h"
0039 #include "filedialog_binding.h"
0040 #include "settings.h"
0041 #include "fileio.h"
0042 #include "color.h"
0043 #include "rect.h"
0044 #include "size.h"
0045 #include "point.h"
0046 #include "image.h"
0047 #include "pixmap.h"
0048 #include "brush.h"
0049 #include "pen.h"
0050 #include "font.h"
0051 #include "dom.h"
0052 #include "url.h"
0053 #include "application.h"
0054 
0055 #include "builtins.h"
0056 
0057 #include <kjs/interpreter.h>
0058 #include <kjs/completion.h>
0059 
0060 #include <QFile>
0061 #include <QTextStream>
0062 #include <QObject>
0063 
0064 #include <QDebug>
0065 
0066 /**
0067 * Implement QString-KJS::UString conversion methods. These methods are declared
0068 * by KJS, but libkjs doesn't actually contain their implementations.
0069 * because we link against khtml , those functions are already implemented there.
0070 *
0071 */
0072 namespace KJS
0073 {
0074 #ifndef QTONLY_WEBKIT
0075 UString::UString(const QString &d)
0076 {
0077     uint len = d.length();
0078     UChar *dat = static_cast<UChar *>(fastMalloc(sizeof(UChar) * len));
0079     memcpy(dat, d.unicode(), len * sizeof(UChar));
0080     m_rep = UString::Rep::create(dat, len);
0081 }
0082 
0083 QString UString::qstring() const
0084 {
0085     return QString((QChar *) data(), size());
0086 }
0087 
0088 QString Identifier::qstring() const
0089 {
0090     return QString((QChar *) data(), size());
0091 }
0092 #endif
0093 }
0094 
0095 namespace KJSEmbed
0096 {
0097 
0098 class EnginePrivate
0099 {
0100 public:
0101     EnginePrivate()
0102     {
0103         m_interpreter = new KJS::Interpreter();
0104         m_interpreter->initGlobalObject();
0105         m_interpreter->ref();
0106     }
0107     ~EnginePrivate()
0108     {
0109         m_interpreter->deref();
0110     }
0111     KJS::Interpreter *m_interpreter;
0112     KJS::Completion m_currentResult;
0113     bool m_bindingsEnabled;
0114 };
0115 
0116 void setup(KJS::ExecState *exec, KJS::JSObject *parent)
0117 {
0118     StaticBinding::publish(exec, parent, IoFactory::methods());   // Global methods
0119     StaticBinding::publish(exec, parent, FileDialog::methods());   // Global methods
0120     StaticBinding::publish(exec, parent, BuiltinsFactory::methods());   // Global methods
0121     StaticConstructor::add(exec, parent, FileIO::constructor());   // Ctor
0122     StaticConstructor::add(exec, parent, DomNode::constructor());   // Ctor
0123     StaticConstructor::add(exec, parent, DomDocument::constructor());   // Ctor
0124     StaticConstructor::add(exec, parent, DomElement::constructor());   // Ctor
0125     StaticConstructor::add(exec, parent, DomAttr::constructor());   // Ctor
0126     StaticConstructor::add(exec, parent, DomDocumentType::constructor());   // Ctor
0127     StaticConstructor::add(exec, parent, DomNodeList::constructor());   // Ctor
0128     StaticConstructor::add(exec, parent, DomNamedNodeMap::constructor());   // Ctor
0129     StaticConstructor::add(exec, parent, DomText::constructor());   // Ctor
0130     StaticConstructor::add(exec, parent, Url::constructor());   // Ctor
0131     StaticConstructor::add(exec, parent, SettingsBinding::constructor());   // Ctor
0132     StaticConstructor::add(exec, parent, CoreApplicationBinding::constructor());
0133     StaticConstructor::add(exec, parent, Point::constructor());   // Ctor
0134     StaticConstructor::add(exec, parent, Size::constructor());   // Ctor
0135     StaticConstructor::add(exec, parent, Rect::constructor());   // Ctor
0136     StaticConstructor::add(exec, parent, Color::constructor());   // Ctor
0137 
0138     // check if this is a GUI application
0139     QApplication *app = ::qobject_cast<QApplication *>(QCoreApplication::instance());
0140     if (app) {
0141         //qDebug("Loading GUI Bindings");
0142 
0143 #ifdef KJSEMBED_FORMBUILDER_BINDING
0144         StaticConstructor::add(exec, parent, FormBuilder::constructor());   // Ctor
0145 #endif
0146         StaticConstructor::add(exec, parent, UiLoaderBinding::constructor());   // Ctor
0147         StaticConstructor::add(exec, parent, QWidgetBinding::constructor());   // Ctor
0148         StaticConstructor::add(exec, parent, Layout::constructor());   // Ctor
0149         StaticConstructor::add(exec, parent, Action::constructor());   // Ctor
0150         StaticConstructor::add(exec, parent, ActionGroup::constructor());   // Ctor
0151         StaticConstructor::add(exec, parent, Font::constructor());   // Ctor
0152         StaticConstructor::add(exec, parent, Pen::constructor());   // Ctor
0153         StaticConstructor::add(exec, parent, Brush::constructor());   // Ctor
0154         StaticConstructor::add(exec, parent, Image::constructor());   // Ctor
0155         StaticConstructor::add(exec, parent, Pixmap::constructor());   // Ctor
0156         StaticConstructor::add(exec, parent, Painter::constructor());   // Ctor
0157         StaticConstructor::add(exec, parent, SvgRenderer::constructor());   // Ctor
0158         StaticConstructor::add(exec, parent, SvgWidget::constructor());   // Ctor
0159         StaticConstructor::add(exec, parent, ApplicationBinding::constructor());
0160     }
0161 }
0162 
0163 Engine::Engine(bool enableBindings)
0164 {
0165     dptr = new EnginePrivate();
0166     if (enableBindings) {
0167         setup(dptr->m_interpreter->globalExec(), dptr->m_interpreter->globalObject());
0168     }
0169     dptr->m_bindingsEnabled =  enableBindings;
0170 }
0171 
0172 Engine::~Engine()
0173 {
0174     delete dptr;
0175 }
0176 
0177 bool Engine::isBindingsEnabled() const
0178 {
0179     return dptr->m_bindingsEnabled;
0180 }
0181 
0182 KJS::JSObject *Engine::addObject(QObject *obj, KJS::JSObject *parent, const KJS::UString &name) const
0183 {
0184     KJS::ExecState *exec = dptr->m_interpreter->globalExec();
0185     KJS::JSObject *returnObject = KJSEmbed::createQObject(exec, obj, KJSEmbed::ObjectBinding::CPPOwned);
0186     KJS::Identifier jsName(!name.isEmpty() ? name : toUString(obj->objectName()));
0187 
0188     parent->putDirect(jsName, returnObject, KJS::DontDelete | KJS::ReadOnly);
0189     return returnObject;
0190 }
0191 
0192 KJS::JSObject *Engine::addObject(QObject *obj, const KJS::UString &name) const
0193 {
0194     return addObject(obj, dptr->m_interpreter->globalObject(), name);
0195 }
0196 
0197 KJS::Completion Engine::completion() const
0198 {
0199     return dptr->m_currentResult;
0200 }
0201 
0202 KJS::Interpreter *Engine::interpreter() const
0203 {
0204     return dptr->m_interpreter;
0205 }
0206 
0207 KJS::Completion Engine::runFile(KJS::Interpreter *interpreter, const KJS::UString &fileName)
0208 {
0209 //    qDebug() << "runFile: " << toQString(fileName);
0210     KJS::UString code;
0211     QFile file(toQString(fileName));
0212     if (file.open(QFile::ReadOnly)) {
0213         QTextStream ts(&file);
0214 
0215         QString line;
0216         while (!ts.atEnd()) {
0217             line = ts.readLine();
0218             if (line[0] != '#') {
0219                 code += toUString(line + '\n');
0220             }
0221         }
0222         file.close();
0223     } else {
0224         code = "println('Could not open file.');";
0225         qWarning() << "Could not open file " << toQString(fileName);
0226     }
0227 
0228 //    qDebug() << "Loaded code: " << toQString(code);
0229 
0230     return interpreter->evaluate(fileName, 0, code, nullptr);
0231 }
0232 
0233 Engine::ExitStatus Engine::runFile(const KJS::UString &fileName)
0234 {
0235     dptr->m_currentResult = runFile(dptr->m_interpreter, fileName);
0236 
0237     if (dptr->m_currentResult.complType() == KJS::Normal) {
0238         return Engine::Success;
0239     } else if (dptr->m_currentResult.complType() == KJS::ReturnValue) {
0240         return Engine::Success;
0241     } else {
0242         return Engine::Failure;
0243     }
0244 }
0245 
0246 Engine::ExitStatus Engine::execute(const KJS::UString &code)
0247 {
0248     dptr->m_currentResult = dptr->m_interpreter->evaluate(KJS::UString(""), 0, code, nullptr);
0249     if (dptr->m_currentResult.complType() == KJS::Normal) {
0250         return Engine::Success;
0251     } else if (dptr->m_currentResult.complType() == KJS::ReturnValue) {
0252         return Engine::Success;
0253     } else {
0254         return Engine::Failure;
0255     }
0256 }
0257 
0258 KJS::JSObject *Engine::construct(const KJS::UString &className, const KJS::List &args) const
0259 {
0260     KJS::JSObject *global = dptr->m_interpreter->globalObject();
0261     KJS::ExecState *exec = dptr->m_interpreter->globalExec();
0262     return StaticConstructor::construct(exec, global, className, args);
0263 }
0264 
0265 KJS::JSValue *Engine::callMethod(const KJS::UString &methodName, const KJS::List &args)
0266 {
0267     KJS::JSObject *global = dptr->m_interpreter->globalObject();
0268     KJS::ExecState *exec = dptr->m_interpreter->globalExec();
0269 
0270     KJS::Identifier id = KJS::Identifier(KJS::UString(methodName));
0271     KJS::JSObject *fun = global->get(exec, id)->toObject(exec);
0272     KJS::JSValue *retValue;
0273 
0274     if (!fun->implementsCall()) {
0275         QString msg = i18n("%1 is not a function and cannot be called.", toQString(methodName));
0276         return throwError(exec, KJS::TypeError, msg);
0277     }
0278 
0279     retValue = fun->call(exec, global, args);
0280 
0281     if (exec->hadException()) {
0282         return exec->exception();
0283     }
0284 
0285     return retValue;
0286 }
0287 
0288 KJS::JSValue *Engine::callMethod(KJS::JSObject *parent,
0289                                  const KJS::UString &methodName, const KJS::List &args)
0290 {
0291     KJS::ExecState *exec = dptr->m_interpreter->globalExec();
0292 
0293     KJS::Identifier id = KJS::Identifier(methodName);
0294     KJS::JSObject *fun = parent->get(exec, id)->toObject(exec);
0295     KJS::JSValue *retValue;
0296 
0297     if (!fun->implementsCall()) {
0298         QString msg = i18n("%1 is not a function and cannot be called.", toQString(methodName));
0299         return throwError(exec, KJS::TypeError, msg);
0300     }
0301 
0302     retValue = fun->call(exec, parent, args);
0303 
0304     if (exec->hadException()) {
0305         return exec->exception();
0306     }
0307 
0308     return retValue;
0309 }
0310 
0311 } // namespace KJS
0312