File indexing completed on 2024-12-08 09:42:37

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     Copyright (C) 2007, 2008 Sebastian Sauer <mail@dipe.org>
0007 
0008     This library is free software; you can redistribute it and/or
0009     modify it under the terms of the GNU Library General Public
0010     License as published by the Free Software Foundation; either
0011     version 2 of the License, or (at your option) any later version.
0012 
0013     This library is distributed in the hope that it will be useful,
0014     but WITHOUT ANY WARRANTY; without even the implied warranty of
0015     MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
0016     Library General Public License for more details.
0017 
0018     You should have received a copy of the GNU Library General Public License
0019     along with this library; see the file COPYING.LIB.  If not, write to
0020     the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor,
0021     Boston, MA 02110-1301, USA.
0022 */
0023 
0024 #ifndef QOBJECT_BINDING_H
0025 #define QOBJECT_BINDING_H
0026 
0027 #include <QObjectCleanupHandler>
0028 #include <QDebug>
0029 
0030 #include <kjs/function.h>
0031 
0032 #include "binding_support.h"
0033 #include "object_binding.h"
0034 
0035 /**
0036 * A simple pointer style method.
0037 * This will extract the pointer, cast it to the native type and place it in "value".
0038 * Any data that should be returned from this method should be placed into "result";
0039 *
0040 */
0041 #define START_QOBJECT_METHOD( METHODNAME, TYPE) \
0042     KJS::JSValue *METHODNAME( KJS::ExecState *exec, KJS::JSObject *self, const KJS::List &args ) \
0043     { \
0044         Q_UNUSED( args ); \
0045         KJS::JSValue *result = KJS::jsNull(); \
0046         KJSEmbed::QObjectBinding *imp = KJSEmbed::extractBindingImp<KJSEmbed::QObjectBinding>(exec, self ); \
0047         if( imp ) \
0048         { \
0049             TYPE *object = imp->qobject<TYPE>(); \
0050             if( object ) \
0051             {
0052 
0053 /**
0054 * End a variant method started by START_QOBJECT_METHOD
0055 */
0056 #define END_QOBJECT_METHOD \
0057     } \
0058     else \
0059         KJS::throwError(exec, KJS::ReferenceError, QString("QO: The internal object died %1:%2.").arg(__FILE__).arg(__LINE__));\
0060     } \
0061     else \
0062         KJS::throwError(exec, KJS::ReferenceError, QString("QObject died."));\
0063     return result; \
0064     }
0065 
0066 class QObject;
0067 class QMetaMethod;
0068 
0069 namespace KJSEmbed
0070 {
0071 
0072 KJS_BINDING(QObjectFactory)
0073 
0074 class EventProxy;
0075 
0076 class KJSEMBED_EXPORT QObjectBinding : public ObjectBinding
0077 {
0078 public:
0079 
0080     QObjectBinding(KJS::ExecState *exec, QObject *object);
0081     ~QObjectBinding() override;
0082 
0083     static void publishQObject(KJS::ExecState *exec, KJS::JSObject *target, QObject *object);
0084 
0085     /**
0086     * Enumeration of access-flags that could be OR-combined to define
0087     * what parts of the QObject should be published.
0088     * Default is AllSlots|AllSignals|AllProperties|AllObjects what
0089     * means that everything got published, even e.g. private slots.
0090     */
0091     enum Access {
0092         None = 0x00, ///< Don't publish anything.
0093 
0094         ScriptableSlots = 0x01, ///< Publish slots that have Q_SCRIPTABLE defined.
0095         NonScriptableSlots = 0x02, ///< Publish slots that don't have Q_SCRIPTABLE defined.
0096         PrivateSlots = 0x04, ///< Publish private slots.
0097         ProtectedSlots = 0x08, ///< Publish protected slots.
0098         PublicSlots = 0x10, ///< Publish public slots.
0099         AllSlots = ScriptableSlots | NonScriptableSlots | PrivateSlots | ProtectedSlots | PublicSlots,
0100 
0101         ScriptableSignals = 0x100, ///< Publish signals that have Q_SCRIPTABLE defined.
0102         NonScriptableSignals = 0x200, ///< Publish signals that don't have Q_SCRIPTABLE defined.
0103         PrivateSignals = 0x400, ///< Publish private signals.
0104         ProtectedSignals = 0x800, ///< Publish protected signals.
0105         PublicSignals = 0x1000, ///< Publish public signals.
0106         AllSignals = ScriptableSignals | NonScriptableSignals | PrivateSignals | ProtectedSignals | PublicSignals,
0107 
0108         ScriptableProperties = 0x10000, ///< Publish properties that have Q_SCRIPTABLE defined.
0109         NonScriptableProperties = 0x20000, ///< Publish properties that don't have Q_SCRIPTABLE defined.
0110         AllProperties = ScriptableProperties | NonScriptableProperties,
0111 
0112         GetParentObject = 0x100000, ///< Provide access to the parent QObject the QObject has.
0113         SetParentObject = 0x200000, ///< Be able to set the parent QObject the QObject has.
0114         ChildObjects = 0x400000, ///< Provide access to the child QObject's the QObject has.
0115         AllObjects = GetParentObject | SetParentObject | ChildObjects
0116     };
0117 
0118     Q_DECLARE_FLAGS(AccessFlags, Access)
0119 
0120     /**
0121     * \return the defined \a Access flags.
0122     */
0123     AccessFlags access() const;
0124 
0125     /**
0126     * Set the defined \a Access flags to \p access .
0127     */
0128     void setAccess(AccessFlags access);
0129 
0130     /**
0131     * Set the value \p value of the property \p propertyName .
0132     */
0133     void put(KJS::ExecState *exec, const KJS::Identifier &propertyName, KJS::JSValue *value,
0134              int attr = KJS::None) override;
0135     using JSObject::put;
0136 
0137     /**
0138     * \return true if the property \p propertyName can be changed else false is returned.
0139     */
0140     bool canPut(KJS::ExecState *exec, const KJS::Identifier &propertyName) const override;
0141 
0142     /**
0143     * Called to ask if we have a callback for the named property.
0144     * We return the callback in the property slot.
0145     */
0146     bool getOwnPropertySlot(KJS::ExecState *exec, const KJS::Identifier &propertyName,
0147                             KJS::PropertySlot &slot) override;
0148     using JSObject::getOwnPropertySlot;
0149 
0150     /**
0151     * Callback used to get properties.
0152     */
0153     static KJS::JSValue *propertyGetter(KJS::ExecState *exec, KJS::JSObject *, const KJS::Identifier &name, const KJS::PropertySlot &);
0154 
0155     /**
0156     * \return a string-representation of the QObject. For example for a QWidget-instance that
0157     * has the QObject::objectName "mywidget" the string "mywidget (QWidget)" is returned.
0158     */
0159     KJS::UString toString(KJS::ExecState *exec) const override;
0160 
0161     /**
0162     * \return the QObject's classname. For example for a QWidget-instance the string "QWidget"
0163     * is returned.
0164     */
0165     KJS::UString className() const override;
0166 
0167     /**
0168     * Add the QObject \p object to the internal QObjectCleanupHandler to watch the
0169     * lifetime of the QObject to know when the QObject got deleted.
0170     */
0171     void watchObject(QObject *object);
0172 
0173     /**
0174      * \return the internal object as a pointer to type T to the
0175      * internal object that is derived from QObject.
0176      */
0177     template <typename T>
0178     T *qobject() const
0179     {
0180         QObject *object = QObjectBinding::object<QObject>();
0181         if (object) {
0182             return qobject_cast<T *>(object);
0183         } else {
0184             return nullptr;
0185         }
0186     }
0187 
0188 private:
0189     EventProxy *m_evproxy;
0190     QObjectCleanupHandler *m_cleanupHandler;
0191     AccessFlags m_access;
0192 };
0193 
0194 Q_DECLARE_OPERATORS_FOR_FLAGS(QObjectBinding::AccessFlags)
0195 
0196 class KJSEMBED_EXPORT SlotBinding : public KJS::InternalFunctionImp
0197 {
0198 public:
0199     SlotBinding(KJS::ExecState *exec, const QMetaMethod &memberName);
0200     KJS::JSValue *callAsFunction(KJS::ExecState *exec, KJS::JSObject *self, const KJS::List &args) override;
0201     bool implementsCall() const override
0202     {
0203         return true;
0204     }
0205     bool implementsConstruct() const override
0206     {
0207         return false;
0208     }
0209 
0210 protected:
0211     QByteArray m_memberName;
0212 };
0213 
0214 /**
0215 * Returns a binding object for the specified QObject. This method walks
0216 * up the meta objects in order to find the most specific binding it can.
0217 * There should always be some kind of binding possible even if it is just
0218 * the QObject binding.
0219 *
0220 * \param exec Represents the current state of script execution.
0221 * \param value The QObject or from it inherited instance we should return
0222 * a binding object for.
0223 * \param owner Defines who's the owner of the QObject. This could be;
0224 *     \li CPPOwned what means, that the QObject's lifetime is handled
0225 *         within C++ code. So, we just provide access to it and don't
0226 *         take any future actions.
0227 *     \li QObjOwned means that the QObject got deleted if the parent QObject
0228 *         is destroyed. If the QObject has no parent QObject, it behaves like
0229 *         JSOwned.
0230 *     \li JSOwned means, that the returned KJS::JSObject takes care of
0231 *         deleting the QObject. This means, that the QObject got deleted
0232 *         as soon as the KJS::JSObject got destroyed what happens if the
0233 *         KJS::JSObject is not needed / in use any longer.
0234 * \return the binding object instance that wraps the QObject instance or
0235 * a JSObject with a prototype of jsNull (that is, the ECMAScript "null" value,
0236 * not a null object pointer) if we failed to provide any binding for it.
0237 */
0238 KJSEMBED_EXPORT KJS::JSObject *createQObject(KJS::ExecState *exec, QObject *value, KJSEmbed::ObjectBinding::Ownership owner = KJSEmbed::ObjectBinding::JSOwned);
0239 
0240 }
0241 #endif
0242