update
|
@ -0,0 +1,4 @@
|
|||
*.json
|
||||
!WingHexPy.json
|
||||
**/*.pro.user
|
||||
push.sh
|
|
@ -0,0 +1,956 @@
|
|||
#ifndef PYTHONQT_H
|
||||
#define PYTHONQT_H
|
||||
|
||||
/*
|
||||
*
|
||||
* Copyright (C) 2010 MeVis Medical Solutions AG All Rights Reserved.
|
||||
*
|
||||
* This library is free software; you can redistribute it and/or
|
||||
* modify it under the terms of the GNU Lesser General Public
|
||||
* License as published by the Free Software Foundation; either
|
||||
* version 2.1 of the License, or (at your option) any later version.
|
||||
*
|
||||
* This library is distributed in the hope that it will be useful,
|
||||
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
|
||||
* Lesser General Public License for more details.
|
||||
*
|
||||
* Further, this software is distributed without any warranty that it is
|
||||
* free of the rightful claim of any third person regarding infringement
|
||||
* or the like. Any license provided herein, whether implied or
|
||||
* otherwise, applies only to this software file. Patent licenses, if
|
||||
* any, provided herein do not apply to combinations of this program with
|
||||
* other software, or any other product whatsoever.
|
||||
*
|
||||
* You should have received a copy of the GNU Lesser General Public
|
||||
* License along with this library; if not, write to the Free Software
|
||||
* Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
|
||||
*
|
||||
* Contact information: MeVis Medical Solutions AG, Universitaetsallee 29,
|
||||
* 28359 Bremen, Germany or:
|
||||
*
|
||||
* http://www.mevis.de
|
||||
*
|
||||
*/
|
||||
|
||||
//----------------------------------------------------------------------------------
|
||||
/*!
|
||||
// \file PythonQt.h
|
||||
// \author Florian Link
|
||||
// \author Last changed by $Author: florian $
|
||||
// \date 2006-05
|
||||
*/
|
||||
//----------------------------------------------------------------------------------
|
||||
|
||||
#include "PythonQtClassWrapper.h"
|
||||
#include "PythonQtInstanceWrapper.h"
|
||||
#include "PythonQtObjectPtr.h"
|
||||
#include "PythonQtSlot.h"
|
||||
#include "PythonQtStdIn.h"
|
||||
#include "PythonQtSystem.h"
|
||||
#include "PythonQtUtils.h"
|
||||
#include <QByteArray>
|
||||
#include <QHash>
|
||||
#include <QList>
|
||||
#include <QObject>
|
||||
#include <QStringList>
|
||||
#include <QVariant>
|
||||
#include <QtDebug>
|
||||
#include <iostream>
|
||||
|
||||
class PythonQtClassInfo;
|
||||
class PythonQtPrivate;
|
||||
class PythonQtMethodInfo;
|
||||
class PythonQtSignalReceiver;
|
||||
class PythonQtImportFileInterface;
|
||||
class PythonQtCppWrapperFactory;
|
||||
class PythonQtForeignWrapperFactory;
|
||||
class PythonQtQFileImporter;
|
||||
|
||||
typedef void PythonQtVoidPtrCB(void *object);
|
||||
typedef void PythonQtQObjectWrappedCB(QObject *object);
|
||||
typedef void PythonQtQObjectNoLongerWrappedCB(QObject *object);
|
||||
typedef void *PythonQtPolymorphicHandlerCB(const void *ptr,
|
||||
const char **class_name);
|
||||
|
||||
typedef void
|
||||
PythonQtShellSetInstanceWrapperCB(void *object,
|
||||
PythonQtInstanceWrapper *wrapper);
|
||||
|
||||
template <class T>
|
||||
void PythonQtSetInstanceWrapperOnShell(void *object,
|
||||
PythonQtInstanceWrapper *wrapper) {
|
||||
(reinterpret_cast<T *>(object))->_wrapper = wrapper;
|
||||
}
|
||||
|
||||
//! Helper template that allows to pass the ownership of a C++ instance between
|
||||
//! C++ and Python (it is used as a slot return type or parameter type so that
|
||||
//! it can be detected by the PythonQt
|
||||
//! slot calling code).
|
||||
template <class T> class PythonQtPassOwnershipToCPP {
|
||||
public:
|
||||
//! Allow conversion from T to PythonQtPassOwnershipToCPP<T>
|
||||
PythonQtPassOwnershipToCPP(const T &t) : _t(t) {}
|
||||
//! Allow conversion from PythonQtPassOwnershipToCPP<T> to T
|
||||
operator T() const { return _t; }
|
||||
|
||||
//! Stored value. This is important so that it has the same memory layout
|
||||
//! as a pointer if T is a pointer type (which is the typical use case for
|
||||
//! this class).
|
||||
T _t;
|
||||
};
|
||||
|
||||
//! Helper template that allows to pass the ownership of a C++ instance between
|
||||
//! C++ and Python (it is used as a slot return type or parameter type so that
|
||||
//! it can be detected by the PythonQt
|
||||
//! slot calling code).
|
||||
template <class T> class PythonQtPassOwnershipToPython {
|
||||
public:
|
||||
//! Allow conversion from T to PythonQtPassOwnershipToPython<T>
|
||||
PythonQtPassOwnershipToPython(const T &t) : _t(t) {}
|
||||
//! Allow conversion from PythonQtPassOwnershipToPython<T> to T
|
||||
operator T() const { return _t; }
|
||||
|
||||
//! Stored value. This is important so that it has the same memory layout
|
||||
//! as a pointer if T is a pointer type (which is the typical use case for
|
||||
//! this class).
|
||||
T _t;
|
||||
};
|
||||
|
||||
//! Helper template that allows to pass the ownership of a C++ instance between
|
||||
//! C++ and Python (it is used as a slot return type or parameter type so that
|
||||
//! it can be detected by the PythonQt
|
||||
//! slot calling code).
|
||||
template <class T> class PythonQtNewOwnerOfThis {
|
||||
public:
|
||||
//! Allow conversion from T to PythonQtNewOwnerOfThis<T>
|
||||
PythonQtNewOwnerOfThis(const T &t) : _t(t) {}
|
||||
//! Allow conversion from PythonQtNewOwnerOfThis<T> to T
|
||||
operator T() const { return _t; }
|
||||
|
||||
//! Stored value. This is important so that it has the same memory layout
|
||||
//! as a pointer if T is a pointer type (which is the typical use case for
|
||||
//! this class).
|
||||
T _t;
|
||||
};
|
||||
|
||||
//! returns the offset that needs to be added to upcast an object of type T1 to
|
||||
//! T2
|
||||
template <class T1, class T2> int PythonQtUpcastingOffset() {
|
||||
return ((reinterpret_cast<char *>(
|
||||
static_cast<T2 *>(reinterpret_cast<T1 *>(0x100)))) -
|
||||
(reinterpret_cast<char *>(reinterpret_cast<T1 *>(0x100))));
|
||||
}
|
||||
|
||||
//! callback to create a QObject lazily
|
||||
typedef QObject *PythonQtQObjectCreatorFunctionCB();
|
||||
|
||||
//! helper template to create a derived QObject class
|
||||
template <class T> QObject *PythonQtCreateObject() { return new T(); };
|
||||
|
||||
//! The main interface to the Python Qt binding, realized as a singleton
|
||||
/*!
|
||||
Use PythonQt::init() to initialize the singleton and PythonQt::self() to access
|
||||
it. While there can be only one PythonQt instance, you can have any number of
|
||||
Python context to do scripting in. One possibility is to use
|
||||
createModuleFromFile(), createModuleFromScript() or createUniqueModule() to get
|
||||
a context that is separated from the other contexts. Alternatively you can use
|
||||
Python dicts as contexts for script evaluation, but you will need to populate
|
||||
the dict with the __builtins__ instance to have all Pythons available when
|
||||
running code in the scope of a dict.
|
||||
*/
|
||||
class PYTHONQT_EXPORT PythonQt : public QObject {
|
||||
|
||||
Q_OBJECT
|
||||
|
||||
public:
|
||||
//! flags that can be passed to PythonQt::init()
|
||||
enum InitFlags {
|
||||
RedirectStdOut = 1, //!<< sets if the std out/err is redirected to
|
||||
//!< pythonStdOut() and pythonStdErr() signals
|
||||
IgnoreSiteModule = 2, //!<< sets if Python should ignore the site module
|
||||
ExternalHelp = 4, //!<< sets if help() calls on PythonQt modules are
|
||||
//!< forwarded to the pythonHelpRequest() signal
|
||||
PythonAlreadyInitialized = 8 //!<< sets that PythonQt should not can
|
||||
//!< PyInitialize, since it is already done
|
||||
};
|
||||
|
||||
//! flags that tell PythonQt which operators to expect on the registered type
|
||||
enum TypeSlots {
|
||||
Type_Add = 1,
|
||||
Type_Subtract = 1 << 1,
|
||||
Type_Multiply = 1 << 2,
|
||||
Type_Divide = 1 << 3,
|
||||
Type_Mod = 1 << 4,
|
||||
Type_And = 1 << 5,
|
||||
Type_Or = 1 << 6,
|
||||
Type_Xor = 1 << 7,
|
||||
Type_LShift = 1 << 8,
|
||||
Type_RShift = 1 << 9,
|
||||
|
||||
Type_InplaceAdd = 1 << 10,
|
||||
Type_InplaceSubtract = 1 << 11,
|
||||
Type_InplaceMultiply = 1 << 12,
|
||||
Type_InplaceDivide = 1 << 13,
|
||||
Type_InplaceMod = 1 << 14,
|
||||
Type_InplaceAnd = 1 << 15,
|
||||
Type_InplaceOr = 1 << 16,
|
||||
Type_InplaceXor = 1 << 17,
|
||||
Type_InplaceLShift = 1 << 18,
|
||||
Type_InplaceRShift = 1 << 19,
|
||||
|
||||
Type_Length = 1 << 20,
|
||||
Type_MappingSetItem = 1 << 21,
|
||||
Type_MappingGetItem = 1 << 22,
|
||||
|
||||
Type_Invert = 1 << 29,
|
||||
Type_RichCompare = 1 << 30,
|
||||
Type_NonZero = 1u << 31,
|
||||
};
|
||||
|
||||
//! enum for profiling callback
|
||||
enum ProfilingCallbackState { Enter = 1, Leave = 2 };
|
||||
|
||||
//! callback for profiling. className and methodName are only passed when
|
||||
//! state == Enter, otherwise they are NULL.
|
||||
typedef void ProfilingCB(ProfilingCallbackState state, const char *className,
|
||||
const char *methodName, PyObject *args);
|
||||
|
||||
//---------------------------------------------------------------------------
|
||||
//! \name Singleton Initialization
|
||||
//@{
|
||||
|
||||
//! initialize the python qt binding (flags are a or combination of
|
||||
//! PythonQt::InitFlags), if \c pythonQtModuleName is given it defines the
|
||||
//! name of the python module that PythonQt will add, otherwise "PythonQt" is
|
||||
//! used. This can be used to e.g. pass in PySide or PyQt4 to make it more
|
||||
//! compatible.
|
||||
static void init(int flags = IgnoreSiteModule | RedirectStdOut,
|
||||
const QByteArray &pythonQtModuleName = QByteArray());
|
||||
|
||||
//! cleanup of the singleton
|
||||
static void cleanup();
|
||||
|
||||
//! get the singleton instance
|
||||
static PythonQt *self();
|
||||
|
||||
//@}
|
||||
|
||||
//! defines the object types for introspection
|
||||
enum ObjectType {
|
||||
Class,
|
||||
Function,
|
||||
Variable,
|
||||
Module,
|
||||
Anything,
|
||||
CallOverloads
|
||||
};
|
||||
|
||||
//---------------------------------------------------------------------------
|
||||
//! \name Standard input handling
|
||||
//@{
|
||||
|
||||
//! Overwrite default handling of stdin using a custom callback. It internally
|
||||
//! backup the original 'sys.stdin' into 'sys.pythonqt_original_stdin'
|
||||
void setRedirectStdInCallback(PythonQtInputChangedCB *callback,
|
||||
void *callbackData = nullptr);
|
||||
|
||||
//! Enable or disable stdin custom callback. It resets 'sys.stdin' using
|
||||
//! either 'sys.pythonqt_stdin' or 'sys.pythonqt_original_stdin'
|
||||
void setRedirectStdInCallbackEnabled(bool enabled);
|
||||
|
||||
//@}
|
||||
|
||||
//---------------------------------------------------------------------------
|
||||
//! \name Modules
|
||||
//@{
|
||||
|
||||
//! get the __main__ module of python
|
||||
PythonQtObjectPtr getMainModule();
|
||||
|
||||
//! import the given module and return a reference to it (useful to import
|
||||
//! e.g. "sys" and call something on it) If a module is already imported, this
|
||||
//! returns the already imported module.
|
||||
PythonQtObjectPtr importModule(const QString &name);
|
||||
|
||||
//! creates the new module \c name and evaluates the given file in the context
|
||||
//! of that module If the \c script is empty, the module contains no initial
|
||||
//! code. You can use evalScript/evalCode to add code to a module later on.
|
||||
//! The user needs to make sure that the \c name is unique in the python
|
||||
//! module dictionary.
|
||||
PythonQtObjectPtr createModuleFromFile(const QString &name,
|
||||
const QString &filename);
|
||||
|
||||
//! creates the new module \c name and evaluates the given script in the
|
||||
//! context of that module. If the \c script is empty, the module contains no
|
||||
//! initial code. You can use evalScript/evalCode to add code to a module
|
||||
//! later on. The user needs to make sure that the \c name is unique in the
|
||||
//! python module dictionary.
|
||||
PythonQtObjectPtr createModuleFromScript(const QString &name,
|
||||
const QString &script = QString());
|
||||
|
||||
//! create a uniquely named module, you can use evalFile or evalScript to
|
||||
//! populate the module with script code
|
||||
PythonQtObjectPtr createUniqueModule();
|
||||
|
||||
//@}
|
||||
|
||||
//---------------------------------------------------------------------------
|
||||
//! \name Importing/Paths
|
||||
//@{
|
||||
|
||||
//! overwrite the python sys path (call this directly after PythonQt::init()
|
||||
//! if you want to change the std python sys path)
|
||||
void overwriteSysPath(const QStringList &paths);
|
||||
|
||||
//! prepend a path to sys.path to allow importing from it
|
||||
void addSysPath(const QString &path);
|
||||
|
||||
//! sets the __path__ list of a module to the given list (important for local
|
||||
//! imports)
|
||||
void setModuleImportPath(PyObject *module, const QStringList &paths);
|
||||
|
||||
//@}
|
||||
|
||||
//---------------------------------------------------------------------------
|
||||
//! \name Registering Classes
|
||||
//@{
|
||||
|
||||
//! registers a QObject derived class to PythonQt (this is implicitly called
|
||||
//! by addObject as well)
|
||||
/* Since Qt4 does not offer a way to detect if a given classname is derived
|
||||
from QObject and thus has a QMetaObject, you MUST register all your QObject
|
||||
derived classes here when you want them to be detected in signal and slot
|
||||
calls */
|
||||
void registerClass(const QMetaObject *metaobject,
|
||||
const char *package = nullptr,
|
||||
PythonQtQObjectCreatorFunctionCB *wrapperCreator = nullptr,
|
||||
PythonQtShellSetInstanceWrapperCB *shell = nullptr);
|
||||
|
||||
//! add a wrapper object for the given QMetaType typeName, also does an
|
||||
//! addClassDecorators() to add constructors for variants (ownership of
|
||||
//! wrapper is passed to PythonQt)
|
||||
/*! Make sure that you have done a qRegisterMetaType first, if typeName is a
|
||||
user type!
|
||||
|
||||
This will add a wrapper object that is used to make calls to the given
|
||||
classname \c typeName. All slots that take a pointer to typeName as the first
|
||||
argument will be callable from Python on a variant object that contains such
|
||||
a type.
|
||||
*/
|
||||
void
|
||||
registerCPPClass(const char *typeName, const char *parentTypeName = nullptr,
|
||||
const char *package = nullptr,
|
||||
PythonQtQObjectCreatorFunctionCB *wrapperCreator = nullptr,
|
||||
PythonQtShellSetInstanceWrapperCB *shell = nullptr);
|
||||
|
||||
//! as an alternative to registerClass, you can tell PythonQt the names of
|
||||
//! QObject derived classes and it will register the classes when it first
|
||||
//! sees a pointer to such a derived class
|
||||
void registerQObjectClassNames(const QStringList &names);
|
||||
|
||||
//! add a parent class relation to the \c given typeName, the upcastingOffset
|
||||
//! is needed for multiple inheritance and can be calculated using
|
||||
//! PythonQtUpcastingOffset<type,parentType>(), which also verifies that type
|
||||
//! is really derived from parentType. Returns false if the typeName was not
|
||||
//! yet registered.
|
||||
bool addParentClass(const char *typeName, const char *parentTypeName,
|
||||
int upcastingOffset = 0);
|
||||
|
||||
//! add a handler for polymorphic downcasting
|
||||
void addPolymorphicHandler(const char *typeName,
|
||||
PythonQtPolymorphicHandlerCB *cb);
|
||||
|
||||
//@}
|
||||
|
||||
//---------------------------------------------------------------------------
|
||||
//! \name Script Parsing and Evaluation
|
||||
//@{
|
||||
|
||||
//! parses the given file and returns the python code object, this can then be
|
||||
//! used to call evalCode()
|
||||
PythonQtObjectPtr parseFile(const QString &filename);
|
||||
|
||||
//! evaluates the given code and returns the result value (use Py_Compile etc.
|
||||
//! to create pycode from string) If pycode is NULL, a python error is
|
||||
//! printed.
|
||||
QVariant evalCode(PyObject *object, PyObject *pycode);
|
||||
|
||||
//! evaluates the given script code and returns the result value
|
||||
QVariant evalScript(PyObject *object, const QString &script,
|
||||
int start = Py_file_input);
|
||||
|
||||
//! evaluates the given script code from file
|
||||
void evalFile(PyObject *object, const QString &filename);
|
||||
|
||||
//@}
|
||||
|
||||
//---------------------------------------------------------------------------
|
||||
//! \name Signal Handlers
|
||||
//@{
|
||||
|
||||
//! add a signal handler to the given \c signal of \c obj and connect it to a
|
||||
//! callable \c objectname in module
|
||||
bool addSignalHandler(QObject *obj, const char *signal, PyObject *module,
|
||||
const QString &objectname);
|
||||
|
||||
//! remove a signal handler from the given \c signal of \c obj
|
||||
bool removeSignalHandler(QObject *obj, const char *signal, PyObject *module,
|
||||
const QString &objectname);
|
||||
|
||||
//! add a signal handler to the given \c signal of \c obj and connect it to a
|
||||
//! callable \c receiver
|
||||
bool addSignalHandler(QObject *obj, const char *signal, PyObject *receiver);
|
||||
|
||||
//! remove a signal handler from the given \c signal of \c obj
|
||||
bool removeSignalHandler(QObject *obj, const char *signal,
|
||||
PyObject *receiver);
|
||||
|
||||
//! globally removes all signal handlers (connections between QObjects and
|
||||
//! Python).
|
||||
void removeSignalHandlers();
|
||||
|
||||
//@}
|
||||
|
||||
//---------------------------------------------------------------------------
|
||||
//! \name Variable access
|
||||
//@{
|
||||
|
||||
//! add the given \c qObject to the python \c object as a variable with \c
|
||||
//! name (it can be removed via clearVariable)
|
||||
void addObject(PyObject *object, const QString &name, QObject *qObject);
|
||||
|
||||
//! add the given variable to the object
|
||||
void addVariable(PyObject *object, const QString &name, const QVariant &v);
|
||||
|
||||
//! remove the given variable
|
||||
void removeVariable(PyObject *module, const QString &name);
|
||||
|
||||
//! get the variable with the \c name of the \c object, returns an invalid
|
||||
//! QVariant on error
|
||||
QVariant getVariable(PyObject *object, const QString &name);
|
||||
|
||||
//! read vars etc. in scope of an \c object, optional looking inside of an
|
||||
//! object \c objectname
|
||||
QStringList introspection(PyObject *object, const QString &objectname,
|
||||
ObjectType type);
|
||||
//! read vars etc. in scope of the given \c object
|
||||
QStringList introspectObject(PyObject *object, ObjectType type);
|
||||
//! read vars etc. in scope of the type object called \c typename. First the
|
||||
//! typename of the form module.type is split into module and type. Then the
|
||||
//! module is looked up in sys.modules. If the module or type is not found
|
||||
//! there, then the type is looked up in the __builtin__ module.
|
||||
QStringList introspectType(const QString &typeName, ObjectType type);
|
||||
|
||||
//! returns the found callable object or NULL
|
||||
//! @return new reference
|
||||
PythonQtObjectPtr lookupCallable(PyObject *object, const QString &name);
|
||||
|
||||
//! returns the return type of the method of a wrapped c++ object referenced
|
||||
//! by \c objectname
|
||||
QString getReturnTypeOfWrappedMethod(PyObject *module,
|
||||
const QString &objectname);
|
||||
//! returns the return type of the method \c methodName of a wrapped c++ type
|
||||
//! referenced by \c typeName
|
||||
QString getReturnTypeOfWrappedMethod(const QString &typeName,
|
||||
const QString &methodName);
|
||||
//@}
|
||||
|
||||
//---------------------------------------------------------------------------
|
||||
//! \name Calling Python Objects
|
||||
//@{
|
||||
|
||||
//! call the given python \c callable in the scope of object, returns the
|
||||
//! result converted to a QVariant
|
||||
QVariant call(PyObject *object, const QString &callable,
|
||||
const QVariantList &args = QVariantList(),
|
||||
const QVariantMap &kwargs = QVariantMap());
|
||||
|
||||
//! call the given python object, returns the result converted to a QVariant
|
||||
QVariant call(PyObject *callable, const QVariantList &args = QVariantList(),
|
||||
const QVariantMap &kwargs = QVariantMap());
|
||||
|
||||
//! call the given python object, returns the result as new PyObject
|
||||
PyObject *callAndReturnPyObject(PyObject *callable,
|
||||
const QVariantList &args = QVariantList(),
|
||||
const QVariantMap &kwargs = QVariantMap());
|
||||
|
||||
//@}
|
||||
|
||||
//---------------------------------------------------------------------------
|
||||
//! \name Decorations, Constructors, Wrappers...
|
||||
//@{
|
||||
|
||||
//! add an object whose slots will be used as decorator slots for
|
||||
//! other QObjects or CPP classes. The slots need to follow the
|
||||
//! convention that the first argument is a pointer to the wrapped object.
|
||||
//! (ownership is passed to PythonQt)
|
||||
/*!
|
||||
Example:
|
||||
|
||||
A slot with the signature
|
||||
|
||||
\code
|
||||
bool doSomething(QWidget* w, int a)
|
||||
\endcode
|
||||
|
||||
will extend QWidget instances (and derived classes) with a "bool
|
||||
doSomething(int a)" slot that will be called with the concrete instance as
|
||||
first argument. So in Python you can now e.g. call
|
||||
|
||||
\code
|
||||
someWidget.doSomething(12)
|
||||
\endcode
|
||||
|
||||
without QWidget really having this method. This allows to easily make normal
|
||||
methods of Qt classes callable by forwarding them with such decorator slots or
|
||||
to make CPP classes (which are not derived from QObject) callable from Python.
|
||||
*/
|
||||
void addInstanceDecorators(QObject *o);
|
||||
|
||||
//! add an object whose slots will be used as decorator slots for
|
||||
//! class objects (ownership is passed to PythonQt)
|
||||
/*!
|
||||
The slots need to follow the following convention:
|
||||
- SomeClass* new_SomeClass(...)
|
||||
- QVariant new_SomeClass(...)
|
||||
- void delete_SomeClass(SomeClass*)
|
||||
- ... static_SomeClass_someName(...)
|
||||
|
||||
This will add:
|
||||
- a constructor
|
||||
- a constructor which generates a QVariant
|
||||
- a destructor (only useful for CPP objects)
|
||||
- a static decorator slot which will be available on the MetaObject (visible
|
||||
in PythonQt module)
|
||||
|
||||
*/
|
||||
void addClassDecorators(QObject *o);
|
||||
|
||||
//! this will add the object both as class and instance decorator (ownership
|
||||
//! is passed to PythonQt)
|
||||
void addDecorators(QObject *o);
|
||||
|
||||
//! add the given factory to PythonQt (ownership stays with caller)
|
||||
void addWrapperFactory(PythonQtCppWrapperFactory *factory);
|
||||
|
||||
//! add the given factory to PythonQt (ownership stays with caller)
|
||||
void addWrapperFactory(PythonQtForeignWrapperFactory *factory);
|
||||
|
||||
//! remove the wrapper factory
|
||||
void removeWrapperFactory(PythonQtCppWrapperFactory *factory);
|
||||
|
||||
//! remove the wrapper factory
|
||||
void removeWrapperFactory(PythonQtForeignWrapperFactory *factory);
|
||||
|
||||
//@}
|
||||
|
||||
//---------------------------------------------------------------------------
|
||||
//! \name Custom Importer
|
||||
//@{
|
||||
|
||||
//! replace the internal import implementation and use the supplied interface
|
||||
//! to load files (both py and pyc files) (this method should be called
|
||||
//! directly after initialization of init() and before calling
|
||||
//! overwriteSysPath(). On the first call to this method, it will install a
|
||||
//! generic PythonQt importer in Pythons "path_hooks". This is not reversible,
|
||||
//! so even setting setImporter(NULL) afterwards will keep the custom PythonQt
|
||||
//! importer with a QFile default import interface. Subsequent python import
|
||||
//! calls will make use of the passed importInterface which forwards all
|
||||
//! import calls to the given \c importInterface. Passing NULL will install a
|
||||
//! default QFile importer.
|
||||
//! (\c importInterface ownership stays with caller)
|
||||
void setImporter(PythonQtImportFileInterface *importInterface);
|
||||
|
||||
//! this installs the default QFile importer (which effectively does a
|
||||
//! setImporter(NULL)) (without calling setImporter or installDefaultImporter
|
||||
//! at least once, the default python import mechanism is in place) the
|
||||
//! default importer allows to import files from anywhere QFile can read from,
|
||||
//! including the Qt resource system using ":". Keep in mind that you need to
|
||||
//! extend "sys.path" with ":" to be able to import from the Qt resources.
|
||||
void installDefaultImporter() { setImporter(nullptr); }
|
||||
|
||||
//! set paths that the importer should ignore
|
||||
void setImporterIgnorePaths(const QStringList &paths);
|
||||
|
||||
//! get paths that the importer should ignore
|
||||
const QStringList &getImporterIgnorePaths();
|
||||
|
||||
//! get access to the file importer (if set)
|
||||
static PythonQtImportFileInterface *importInterface();
|
||||
|
||||
//@}
|
||||
|
||||
//---------------------------------------------------------------------------
|
||||
//! \name Other Stuff
|
||||
//@{
|
||||
|
||||
//! get access to internal data (should not be used on the public API, but is
|
||||
//! used by some C functions)
|
||||
static PythonQtPrivate *priv() { return _self->_p; }
|
||||
|
||||
//! clear all NotFound entries on all class infos, to ensure that
|
||||
//! newly loaded wrappers can add methods even when the object was wrapped by
|
||||
//! PythonQt before the wrapper was loaded
|
||||
void clearNotFoundCachedMembers();
|
||||
|
||||
//! handle a python error, call this when a python function fails. If no error
|
||||
//! occurred, it returns false. The error is currently just output to the
|
||||
//! python stderr, future version might implement better trace printing
|
||||
bool handleError();
|
||||
|
||||
//! return \a true if \a handleError() has been called and an error occurred.
|
||||
bool hadError() const;
|
||||
|
||||
//! reset error flag. After calling this, hadError() will return false.
|
||||
//! \sa hadError()
|
||||
void clearError();
|
||||
|
||||
//! if set to true, the systemExitExceptionRaised signal will be emitted if
|
||||
//! exception SystemExit is caught \sa handleError()
|
||||
void setSystemExitExceptionHandlerEnabled(bool value);
|
||||
|
||||
//! return \a true if SystemExit exception is handled by PythonQt
|
||||
//! \sa setSystemExitExceptionHandlerEnabled()
|
||||
bool systemExitExceptionHandlerEnabled() const;
|
||||
|
||||
//! set a callback that is called when a QObject with parent == NULL is
|
||||
//! wrapped by PythonQt
|
||||
void setQObjectWrappedCallback(PythonQtQObjectWrappedCB *cb);
|
||||
//! set a callback that is called when a QObject with parent == NULL is no
|
||||
//! longer wrapped by PythonQt
|
||||
void setQObjectNoLongerWrappedCallback(PythonQtQObjectNoLongerWrappedCB *cb);
|
||||
|
||||
//! call the callback if it is set
|
||||
static void qObjectNoLongerWrappedCB(QObject *o);
|
||||
|
||||
//! called by internal help methods
|
||||
PyObject *helpCalled(PythonQtClassInfo *info);
|
||||
|
||||
//! returns the found object or NULL
|
||||
//! @return new reference
|
||||
PythonQtObjectPtr lookupObject(PyObject *module, const QString &name);
|
||||
|
||||
//! sets a callback that is called before and after function calls for
|
||||
//! profiling
|
||||
void setProfilingCallback(ProfilingCB *cb);
|
||||
|
||||
//@}
|
||||
|
||||
Q_SIGNALS:
|
||||
//! emitted when python outputs something to stdout (and redirection is turned
|
||||
//! on)
|
||||
void pythonStdOut(const QString &str);
|
||||
//! emitted when python outputs something to stderr (and redirection is turned
|
||||
//! on)
|
||||
void pythonStdErr(const QString &str);
|
||||
|
||||
//! emitted when help() is called on a PythonQt object and \c ExternalHelp is
|
||||
//! enabled
|
||||
void pythonHelpRequest(const QByteArray &cppClassName);
|
||||
|
||||
//! emitted when both custom SystemExit exception handler is enabled and a
|
||||
//! SystemExit exception is raised. \sa
|
||||
//! setSystemExitExceptionHandlerEnabled(bool)
|
||||
void systemExitExceptionRaised(int exitCode);
|
||||
|
||||
private:
|
||||
void initPythonQtModule(bool redirectStdOut,
|
||||
const QByteArray &pythonQtModuleName);
|
||||
|
||||
QString
|
||||
getReturnTypeOfWrappedMethodHelper(const PythonQtObjectPtr &variableObject,
|
||||
const QString &methodName,
|
||||
const QString &context);
|
||||
|
||||
PyObject *getObjectByType(const QString &typeName);
|
||||
|
||||
//! callback for stdout redirection, emits pythonStdOut signal
|
||||
static void stdOutRedirectCB(const QString &str);
|
||||
//! callback for stderr redirection, emits pythonStdErr signal
|
||||
static void stdErrRedirectCB(const QString &str);
|
||||
|
||||
//! get (and create if not available) the signal receiver of that QObject,
|
||||
//! signal receiver is made child of the passed \c obj
|
||||
PythonQtSignalReceiver *getSignalReceiver(QObject *obj);
|
||||
|
||||
PythonQt(int flags, const QByteArray &pythonQtModuleName);
|
||||
~PythonQt();
|
||||
static PythonQt *_self;
|
||||
static int _uniqueModuleCount;
|
||||
|
||||
PythonQtPrivate *_p;
|
||||
};
|
||||
|
||||
class PythonQtDebugAPI;
|
||||
|
||||
//! internal PythonQt details
|
||||
class PYTHONQT_EXPORT PythonQtPrivate : public QObject {
|
||||
|
||||
Q_OBJECT
|
||||
|
||||
public:
|
||||
PythonQtPrivate();
|
||||
~PythonQtPrivate();
|
||||
|
||||
enum DecoratorTypes {
|
||||
StaticDecorator = 1,
|
||||
ConstructorDecorator = 2,
|
||||
DestructorDecorator = 4,
|
||||
InstanceDecorator = 8,
|
||||
AllDecorators = 0xffff
|
||||
};
|
||||
|
||||
//! get the suffixes that are used for shared libraries
|
||||
const QStringList &sharedLibrarySuffixes() { return _sharedLibrarySuffixes; }
|
||||
|
||||
//! returns if the id is the id for PythonQtObjectPtr
|
||||
bool isPythonQtObjectPtrMetaId(int id) {
|
||||
return _PythonQtObjectPtr_metaId == id;
|
||||
}
|
||||
|
||||
//! add the wrapper pointer (for reuse if the same obj appears while wrapper
|
||||
//! still exists)
|
||||
void addWrapperPointer(void *obj, PythonQtInstanceWrapper *wrapper);
|
||||
//! remove the wrapper ptr again
|
||||
void removeWrapperPointer(void *obj);
|
||||
|
||||
//! called by destructor of shells to allow invalidation of the Python wrapper
|
||||
void shellClassDeleted(void *shellClass);
|
||||
|
||||
//! try to unwrap the given object to a C++ pointer using the foreign wrapper
|
||||
//! factories
|
||||
void *unwrapForeignWrapper(const QByteArray &classname, PyObject *obj);
|
||||
|
||||
//! add parent class relation
|
||||
bool addParentClass(const char *typeName, const char *parentTypeName,
|
||||
int upcastingOffset);
|
||||
|
||||
//! add a handler for polymorphic downcasting
|
||||
void addPolymorphicHandler(const char *typeName,
|
||||
PythonQtPolymorphicHandlerCB *cb);
|
||||
|
||||
//! lookup existing classinfo and return new if not yet present
|
||||
PythonQtClassInfo *lookupClassInfoAndCreateIfNotPresent(const char *typeName);
|
||||
|
||||
//! called when a signal emitting QObject is destroyed to remove the signal
|
||||
//! handler from the hash map
|
||||
void removeSignalEmitter(QObject *obj);
|
||||
|
||||
//! wrap the given QObject into a Python object (or return existing wrapper!)
|
||||
PyObject *wrapQObject(QObject *obj);
|
||||
|
||||
//! wrap the given ptr into a Python object (or return existing wrapper!) if
|
||||
//! there is a known QObject of that name or a known wrapper in the factory.
|
||||
//! If passOwnership == true, the ownership is passed to PythonQt, so the
|
||||
//! object will be deleted by PythonQt when the Python wrapper goes away.
|
||||
PyObject *wrapPtr(void *ptr, const QByteArray &name,
|
||||
bool passOwnership = false);
|
||||
|
||||
//! create a read-only buffer object from the given memory
|
||||
static PyObject *wrapMemoryAsBuffer(const void *data, Py_ssize_t size);
|
||||
|
||||
//! create a read-write buffer object from the given memory
|
||||
static PyObject *wrapMemoryAsBuffer(void *data, Py_ssize_t size);
|
||||
|
||||
//! registers a QObject derived class to PythonQt (this is implicitly called
|
||||
//! by addObject as well)
|
||||
/* Since Qt4 does not offer a way to detect if a given classname is derived
|
||||
from QObject and thus has a QMetaObject,
|
||||
you MUST register all your QObject derived classes here when you want them
|
||||
to be detected in signal and slot calls */
|
||||
void registerClass(const QMetaObject *metaobject,
|
||||
const char *package = nullptr,
|
||||
PythonQtQObjectCreatorFunctionCB *wrapperCreator = nullptr,
|
||||
PythonQtShellSetInstanceWrapperCB *shell = nullptr,
|
||||
PyObject *module = nullptr, int typeSlots = 0);
|
||||
|
||||
//! add a wrapper object for the given QMetaType typeName, also does an
|
||||
//! addClassDecorators() to add constructors for variants (ownership of
|
||||
//! wrapper is passed to PythonQt)
|
||||
/*! Make sure that you have done a qRegisterMetaType first, if typeName is a
|
||||
user type!
|
||||
|
||||
This will add a wrapper object that is used to make calls to the given
|
||||
classname \c typeName. All slots that take a pointer to typeName as the first
|
||||
argument will be callable from Python on a variant object that contains such
|
||||
a type.
|
||||
*/
|
||||
void
|
||||
registerCPPClass(const char *typeName, const char *parentTypeName = nullptr,
|
||||
const char *package = nullptr,
|
||||
PythonQtQObjectCreatorFunctionCB *wrapperCreator = nullptr,
|
||||
PythonQtShellSetInstanceWrapperCB *shell = nullptr,
|
||||
PyObject *module = nullptr, int typeSlots = 0);
|
||||
|
||||
//! as an alternative to registerClass, you can tell PythonQt the names of
|
||||
//! QObject derived classes and it will register the classes when it first
|
||||
//! sees a pointer to such a derived class
|
||||
void registerQObjectClassNames(const QStringList &names);
|
||||
|
||||
//! add a decorator object
|
||||
void addDecorators(QObject *o, int decoTypes);
|
||||
|
||||
//! helper method that creates a PythonQtClassWrapper object (returns a new
|
||||
//! reference)
|
||||
PythonQtClassWrapper *
|
||||
createNewPythonQtClassWrapper(PythonQtClassInfo *info, PyObject *module,
|
||||
const QByteArray &pythonClassName);
|
||||
|
||||
//! create a new instance of the given enum type with given value (returns a
|
||||
//! new reference)
|
||||
static PyObject *createEnumValueInstance(PyObject *enumType,
|
||||
unsigned int enumValue);
|
||||
|
||||
//! helper that creates a new int derived class that represents the enum of
|
||||
//! the given name (returns a new reference)
|
||||
static PyObject *createNewPythonQtEnumWrapper(const char *enumName,
|
||||
PyObject *parentObject);
|
||||
|
||||
//! helper method that creates a PythonQtInstanceWrapper object and registers
|
||||
//! it in the object map
|
||||
PythonQtInstanceWrapper *
|
||||
createNewPythonQtInstanceWrapper(QObject *obj, PythonQtClassInfo *info,
|
||||
void *wrappedPtr = nullptr);
|
||||
|
||||
//! get the class info for a meta object (if available)
|
||||
PythonQtClassInfo *getClassInfo(const QMetaObject *meta);
|
||||
|
||||
//! get the class info for a meta object (if available)
|
||||
PythonQtClassInfo *getClassInfo(const QByteArray &className);
|
||||
|
||||
//! register a class name that causes lazy loading of the moduleToImport when
|
||||
//! PythonQt encounters the type
|
||||
void registerLazyClass(const QByteArray &name,
|
||||
const QByteArray &moduleToImport);
|
||||
|
||||
//! creates the new module from the given pycode
|
||||
PythonQtObjectPtr createModule(const QString &name, PyObject *pycode);
|
||||
|
||||
//! get the current class info (for the next PythonQtClassWrapper that is
|
||||
//! created) and reset it to NULL again
|
||||
PythonQtClassInfo *currentClassInfoForClassWrapperCreation();
|
||||
|
||||
//! the dummy tuple (which is empty and may be used to detected that a wrapper
|
||||
//! is called from internal wrapper creation
|
||||
static PyObject *dummyTuple();
|
||||
|
||||
//! called by virtual overloads when a python return value can not be
|
||||
//! converted to the required Qt type
|
||||
void handleVirtualOverloadReturnError(const char *signature,
|
||||
const PythonQtMethodInfo *methodInfo,
|
||||
PyObject *result);
|
||||
|
||||
//! get access to the PythonQt module
|
||||
PythonQtObjectPtr pythonQtModule() const { return _pythonQtModule; }
|
||||
|
||||
//! returns the profiling callback, which may be NULL
|
||||
PythonQt::ProfilingCB *profilingCB() const { return _profilingCB; }
|
||||
|
||||
//! determines the signature of the given callable object (similar as pydoc)
|
||||
QString getSignature(PyObject *object);
|
||||
|
||||
//! returns true if the object is a method descriptor (same as
|
||||
//! inspect.ismethoddescriptor() in inspect.py)
|
||||
bool isMethodDescriptor(PyObject *object) const;
|
||||
|
||||
//! get the dynamic meta object for the given wrapper. It will contain the
|
||||
//! signals/slots that have been added in Python
|
||||
const QMetaObject *
|
||||
getDynamicMetaObject(PythonQtInstanceWrapper *wrapper,
|
||||
const QMetaObject *prototypeMetaObject);
|
||||
|
||||
//! recursively creates the dynamic meta object chain down to the Qt class
|
||||
//! wrapper.
|
||||
const QMetaObject *
|
||||
setupDynamicMetaObjectChain(PythonQtClassWrapper *type,
|
||||
const QMetaObject *prototypeMetaObject);
|
||||
|
||||
//! builds and returns the dynamic meta object for the given type, derived
|
||||
//! from prototypeMetaObject.
|
||||
const QMetaObject *
|
||||
buildDynamicMetaObject(PythonQtClassWrapper *type,
|
||||
const QMetaObject *prototypeMetaObject);
|
||||
|
||||
//! redirected from shell classes, tries to call the given meta call on the
|
||||
//! Python wrapper.
|
||||
int handleMetaCall(QObject *object, PythonQtInstanceWrapper *wrapper,
|
||||
QMetaObject::Call call, int id, void **args);
|
||||
|
||||
//! calls the given method on Python function with same name.
|
||||
void callMethodInPython(QMetaMethod &method, PythonQtInstanceWrapper *wrapper,
|
||||
void **args);
|
||||
|
||||
private:
|
||||
//! Setup the shared library suffixes by getting them from the "imp" module.
|
||||
void setupSharedLibrarySuffixes();
|
||||
|
||||
//! create a new pythonqt class wrapper and place it in the pythonqt module
|
||||
void createPythonQtClassWrapper(PythonQtClassInfo *info, const char *package,
|
||||
PyObject *module = nullptr);
|
||||
|
||||
//! get/create new package module (the returned object is a borrowed
|
||||
//! reference)
|
||||
PyObject *packageByName(const char *name);
|
||||
|
||||
//! get the wrapper for a given pointer (and remove a wrapper of an already
|
||||
//! destroyed qobject)
|
||||
PythonQtInstanceWrapper *findWrapperAndRemoveUnused(void *obj);
|
||||
|
||||
//! stores pointer to PyObject mapping of wrapped QObjects AND C++ objects
|
||||
QHash<void *, PythonQtInstanceWrapper *> _wrappedObjects;
|
||||
|
||||
//! stores the meta info of known Qt classes
|
||||
QHash<QByteArray, PythonQtClassInfo *> _knownClassInfos;
|
||||
|
||||
//! names of qobject derived classes that can be casted to qobject savely
|
||||
QHash<QByteArray, bool> _knownQObjectClassNames;
|
||||
|
||||
//! lazy classes that cause PythonQt to trigger an import if they are
|
||||
//! encountered.
|
||||
QHash<QByteArray, QByteArray> _knownLazyClasses;
|
||||
|
||||
//! stores signal receivers for QObjects
|
||||
QHash<QObject *, PythonQtSignalReceiver *> _signalReceivers;
|
||||
|
||||
//! the PythonQt python module
|
||||
PythonQtObjectPtr _pythonQtModule;
|
||||
|
||||
//! the name of the PythonQt python module
|
||||
QByteArray _pythonQtModuleName;
|
||||
|
||||
//! the importer interface (if set)
|
||||
PythonQtImportFileInterface *_importInterface;
|
||||
|
||||
//! the default importer
|
||||
PythonQtQFileImporter *_defaultImporter;
|
||||
|
||||
PythonQtQObjectNoLongerWrappedCB *_noLongerWrappedCB;
|
||||
PythonQtQObjectWrappedCB *_wrappedCB;
|
||||
|
||||
QStringList _importIgnorePaths;
|
||||
QStringList _sharedLibrarySuffixes;
|
||||
|
||||
//! the cpp object wrapper factories
|
||||
QList<PythonQtCppWrapperFactory *> _cppWrapperFactories;
|
||||
|
||||
QList<PythonQtForeignWrapperFactory *> _foreignWrapperFactories;
|
||||
|
||||
QHash<QByteArray, PyObject *> _packages;
|
||||
|
||||
PythonQtClassInfo *_currentClassInfoForClassWrapperCreation;
|
||||
|
||||
PythonQt::ProfilingCB *_profilingCB;
|
||||
|
||||
PythonQtDebugAPI *_debugAPI;
|
||||
|
||||
int _initFlags;
|
||||
int _PythonQtObjectPtr_metaId;
|
||||
|
||||
bool _hadError;
|
||||
bool _systemExitExceptionHandlerEnabled;
|
||||
|
||||
friend class PythonQt;
|
||||
};
|
||||
|
||||
#endif
|
|
@ -0,0 +1,60 @@
|
|||
#ifndef _PYTHONQTBOOLRESULT_H
|
||||
#define _PYTHONQTBOOLRESULT_H
|
||||
|
||||
/*
|
||||
*
|
||||
* Copyright (C) 2010 MeVis Medical Solutions AG All Rights Reserved.
|
||||
*
|
||||
* This library is free software; you can redistribute it and/or
|
||||
* modify it under the terms of the GNU Lesser General Public
|
||||
* License as published by the Free Software Foundation; either
|
||||
* version 2.1 of the License, or (at your option) any later version.
|
||||
*
|
||||
* This library is distributed in the hope that it will be useful,
|
||||
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
|
||||
* Lesser General Public License for more details.
|
||||
*
|
||||
* Further, this software is distributed without any warranty that it is
|
||||
* free of the rightful claim of any third person regarding infringement
|
||||
* or the like. Any license provided herein, whether implied or
|
||||
* otherwise, applies only to this software file. Patent licenses, if
|
||||
* any, provided herein do not apply to combinations of this program with
|
||||
* other software, or any other product whatsoever.
|
||||
*
|
||||
* You should have received a copy of the GNU Lesser General Public
|
||||
* License along with this library; if not, write to the Free Software
|
||||
* Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
|
||||
*
|
||||
* Contact information: MeVis Medical Solutions AG, Universitaetsallee 29,
|
||||
* 28359 Bremen, Germany or:
|
||||
*
|
||||
* http://www.mevis.de
|
||||
*
|
||||
*/
|
||||
|
||||
//----------------------------------------------------------------------------------
|
||||
/*!
|
||||
// \file PythonQtBoolResultt.h
|
||||
// \author Florian Link
|
||||
// \date 2014-09
|
||||
*/
|
||||
//----------------------------------------------------------------------------------
|
||||
|
||||
#include "PythonQtPythonInclude.h"
|
||||
|
||||
#include "PythonQtSystem.h"
|
||||
#include "structmember.h"
|
||||
|
||||
extern PYTHONQT_EXPORT PyTypeObject PythonQtBoolResult_Type;
|
||||
|
||||
#define PythonQtBoolResult_Check(op) (Py_TYPE(op) == &PythonQtBoolResult_Type)
|
||||
|
||||
//! defines a python object that stores a single bool
|
||||
typedef struct {
|
||||
PyObject_HEAD
|
||||
bool _value;
|
||||
} PythonQtBoolResultObject;
|
||||
|
||||
|
||||
#endif
|
|
@ -0,0 +1,307 @@
|
|||
#ifndef _PYTHONQTCLASSINFO_H
|
||||
#define _PYTHONQTCLASSINFO_H
|
||||
|
||||
/*
|
||||
*
|
||||
* Copyright (C) 2010 MeVis Medical Solutions AG All Rights Reserved.
|
||||
*
|
||||
* This library is free software; you can redistribute it and/or
|
||||
* modify it under the terms of the GNU Lesser General Public
|
||||
* License as published by the Free Software Foundation; either
|
||||
* version 2.1 of the License, or (at your option) any later version.
|
||||
*
|
||||
* This library is distributed in the hope that it will be useful,
|
||||
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
|
||||
* Lesser General Public License for more details.
|
||||
*
|
||||
* Further, this software is distributed without any warranty that it is
|
||||
* free of the rightful claim of any third person regarding infringement
|
||||
* or the like. Any license provided herein, whether implied or
|
||||
* otherwise, applies only to this software file. Patent licenses, if
|
||||
* any, provided herein do not apply to combinations of this program with
|
||||
* other software, or any other product whatsoever.
|
||||
*
|
||||
* You should have received a copy of the GNU Lesser General Public
|
||||
* License along with this library; if not, write to the Free Software
|
||||
* Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
|
||||
*
|
||||
* Contact information: MeVis Medical Solutions AG, Universitaetsallee 29,
|
||||
* 28359 Bremen, Germany or:
|
||||
*
|
||||
* http://www.mevis.de
|
||||
*
|
||||
*/
|
||||
|
||||
#include <QMetaObject>
|
||||
#include <QMetaMethod>
|
||||
#include <QHash>
|
||||
#include <QByteArray>
|
||||
#include <QList>
|
||||
#include "PythonQt.h"
|
||||
|
||||
class PythonQtSlotInfo;
|
||||
class PythonQtClassInfo;
|
||||
|
||||
struct PythonQtDynamicClassInfo
|
||||
{
|
||||
PythonQtDynamicClassInfo() { _dynamicMetaObject = NULL; _classInfo = NULL; }
|
||||
~PythonQtDynamicClassInfo();
|
||||
|
||||
const QMetaObject* _dynamicMetaObject;
|
||||
PythonQtClassInfo* _classInfo;
|
||||
};
|
||||
|
||||
struct PythonQtMemberInfo {
|
||||
enum Type {
|
||||
Invalid, Slot, Signal, EnumValue, EnumWrapper, Property, NestedClass, NotFound
|
||||
};
|
||||
|
||||
PythonQtMemberInfo():_type(Invalid),_slot(NULL),_pythonType(NULL),_enumValue(0) { }
|
||||
|
||||
PythonQtMemberInfo(PythonQtSlotInfo* info);
|
||||
|
||||
PythonQtMemberInfo(const PythonQtObjectPtr& enumValue);
|
||||
|
||||
PythonQtMemberInfo(const QMetaProperty& prop);
|
||||
|
||||
Type _type;
|
||||
|
||||
// TODO: this could be a union...
|
||||
PythonQtSlotInfo* _slot;
|
||||
PyObject* _pythonType;
|
||||
PythonQtObjectPtr _enumValue;
|
||||
QMetaProperty _property;
|
||||
};
|
||||
|
||||
//! a class that stores all required information about a Qt object (and an optional associated C++ class name)
|
||||
/*! for fast lookup of slots when calling the object from Python
|
||||
*/
|
||||
class PYTHONQT_EXPORT PythonQtClassInfo {
|
||||
|
||||
public:
|
||||
PythonQtClassInfo();
|
||||
~PythonQtClassInfo();
|
||||
|
||||
//! store information about parent classes
|
||||
struct ParentClassInfo {
|
||||
ParentClassInfo(PythonQtClassInfo* parent, int upcastingOffset=0):_parent(parent),_upcastingOffset(upcastingOffset)
|
||||
{};
|
||||
|
||||
PythonQtClassInfo* _parent;
|
||||
int _upcastingOffset;
|
||||
};
|
||||
|
||||
|
||||
//! setup as a QObject, taking the meta object as meta information about the QObject
|
||||
void setupQObject(const QMetaObject* meta);
|
||||
|
||||
//! setup as a CPP (non-QObject), taking the classname
|
||||
void setupCPPObject(const QByteArray& classname);
|
||||
|
||||
//! set the type capabilities
|
||||
void setTypeSlots(int typeSlots) { _typeSlots = typeSlots; }
|
||||
//! get the type capabilities
|
||||
int typeSlots() const { return _typeSlots; }
|
||||
|
||||
//! get the Python method definition for a given slot name (without return type and signature)
|
||||
PythonQtMemberInfo member(const char* member);
|
||||
|
||||
//! get access to the constructor slot (which may be overloaded if there are multiple constructors)
|
||||
PythonQtSlotInfo* constructors();
|
||||
|
||||
//! get access to the destructor slot
|
||||
PythonQtSlotInfo* destructor();
|
||||
|
||||
//! add a constructor, ownership is passed to classinfo
|
||||
void addConstructor(PythonQtSlotInfo* info);
|
||||
|
||||
//! set a destructor, ownership is passed to classinfo
|
||||
void setDestructor(PythonQtSlotInfo* info);
|
||||
|
||||
//! add a decorator slot, ownership is passed to classinfo
|
||||
void addDecoratorSlot(PythonQtSlotInfo* info);
|
||||
|
||||
//! add a nested class, so that it can be shown as outer class member
|
||||
void addNestedClass(PythonQtClassInfo* info);
|
||||
|
||||
//! get the classname (either of the QObject or of the wrapped CPP object)
|
||||
const QByteArray& className() const;
|
||||
|
||||
//! get the unscoped classname (without ParentClass::) for nested classes
|
||||
QByteArray unscopedClassName() const;
|
||||
|
||||
//! returns if the QObject
|
||||
bool isQObject() { return _isQObject; }
|
||||
|
||||
//! returns if the class is a CPP wrapper
|
||||
bool isCPPWrapper() { return !_isQObject; }
|
||||
|
||||
//! get the meta object
|
||||
const QMetaObject* metaObject() { return _meta; }
|
||||
|
||||
//! set the meta object, this will reset the caching
|
||||
void setMetaObject(const QMetaObject* meta);
|
||||
|
||||
//! returns if this class inherits from the given classname
|
||||
bool inherits(const char* classname);
|
||||
|
||||
//! returns if this class inherits from the given classinfo
|
||||
bool inherits(PythonQtClassInfo* info);
|
||||
|
||||
//! casts the given \c ptr to an object of type \c classname, returns the new pointer
|
||||
//! which might be different to \c ptr due to C++ multiple inheritance
|
||||
//! (if the cast is not possible or if ptr is NULL, NULL is returned)
|
||||
void* castTo(void* ptr, const char* classname);
|
||||
|
||||
//! get help string for the metaobject
|
||||
QString help();
|
||||
|
||||
//! get list of all properties (on QObjects only, otherwise the list is empty)
|
||||
QStringList propertyList();
|
||||
|
||||
//! get list of all members (excluding properties, which can be listed with propertyList())
|
||||
QStringList memberList();
|
||||
|
||||
//! get the meta type id of this class (only valid for isCPPWrapper() == true)
|
||||
int metaTypeId() { return _metaTypeId; }
|
||||
|
||||
//! set an additional decorator provider that offers additional decorator slots for this class
|
||||
void setDecoratorProvider(PythonQtQObjectCreatorFunctionCB* cb);
|
||||
|
||||
//! get the decorator qobject instance
|
||||
QObject* decorator();
|
||||
|
||||
//! add the parent class info of a CPP object
|
||||
void addParentClass(const ParentClassInfo& info) { _parentClasses.append(info); }
|
||||
|
||||
//! set the associated PythonQtClassWrapper (which handles instance creation of this type)
|
||||
void setPythonQtClassWrapper(PyObject* obj) { _pythonQtClassWrapper = obj; }
|
||||
|
||||
//! get the associated PythonQtClassWrapper (which handles instance creation of this type)
|
||||
PyObject* pythonQtClassWrapper() { return _pythonQtClassWrapper; }
|
||||
|
||||
//! set the shell set instance wrapper cb
|
||||
void setShellSetInstanceWrapperCB(PythonQtShellSetInstanceWrapperCB* cb) {
|
||||
_shellSetInstanceWrapperCB = cb;
|
||||
}
|
||||
|
||||
//! get the shell set instance wrapper cb
|
||||
PythonQtShellSetInstanceWrapperCB* shellSetInstanceWrapperCB() {
|
||||
return _shellSetInstanceWrapperCB;
|
||||
}
|
||||
|
||||
//! add a handler for polymorphic downcasting
|
||||
void addPolymorphicHandler(PythonQtPolymorphicHandlerCB* cb) { _polymorphicHandlers.append(cb); }
|
||||
|
||||
//! cast the pointer down in the class hierarchy if a polymorphic handler allows to do that
|
||||
void* castDownIfPossible(void* ptr, PythonQtClassInfo** resultClassInfo);
|
||||
|
||||
//! returns if the localScope has an enum of that type name or if the enum contains a :: scope, if that class contails the enum
|
||||
static PyObject* findEnumWrapper(const QByteArray& name, PythonQtClassInfo* localScope, bool* isLocalEnum = NULL);
|
||||
|
||||
//! clear all members that where cached as "NotFound"
|
||||
void clearNotFoundCachedMembers();
|
||||
|
||||
//! get nested classes
|
||||
const QList<PythonQtClassInfo*>& nestedClasses() { return _nestedClasses; }
|
||||
|
||||
//! Create a copy of the given C++ object (which is known to be of a derived class), wrapped by Python and owned by PythonQt.
|
||||
//! This will downcast if possible and return a copy of the down casted object.
|
||||
//! This either requires a copy constructor on the class or it needs to be registered
|
||||
//! as a meta type.
|
||||
PyObject* copyObject(void* cppObject);
|
||||
|
||||
//! Get the copy constructor for this class
|
||||
PythonQtSlotInfo* getCopyConstructor();
|
||||
|
||||
//! Sets reference counting callbacks for this class and all its subclasses
|
||||
void setReferenceCounting(PythonQtVoidPtrCB* refCB, PythonQtVoidPtrCB* unrefCB);
|
||||
|
||||
//! Returns the ref counting CB, if there is any
|
||||
PythonQtVoidPtrCB* referenceCountingRefCB();
|
||||
//! Returns the unref counting CB, if there is any
|
||||
PythonQtVoidPtrCB* referenceCountingUnrefCB();
|
||||
|
||||
//! Returns the Python type object for a given property.
|
||||
//! (the returned object does not get an extra reference count)
|
||||
PyObject* getPythonTypeForProperty(const QString& name);
|
||||
|
||||
//! Returns the class info for given property, if available.
|
||||
PythonQtClassInfo* getClassInfoForProperty( const QString& name );
|
||||
|
||||
//! Returns if the class supports rich compare. This tests for
|
||||
//! __eq__, __ne__, __lt__, __le__, __gt__, __ge__ slots and if
|
||||
//! any of the slots is present it returns true and modifies the
|
||||
//! _typeSlots with Type_RichCompare. The result is cached internally.
|
||||
bool supportsRichCompare();
|
||||
|
||||
private:
|
||||
void updateRefCountingCBs();
|
||||
|
||||
void createEnumWrappers(const QObject* decoratorProvider);
|
||||
void createEnumWrappers(const QMetaObject* meta);
|
||||
PyObject* findEnumWrapper(const char* name);
|
||||
|
||||
//! clear all cached members
|
||||
void clearCachedMembers();
|
||||
|
||||
void* recursiveCastDownIfPossible(void* ptr, const char** resultClassName);
|
||||
|
||||
PythonQtSlotInfo* findDecoratorSlotsFromDecoratorProvider(const char* memberName, PythonQtSlotInfo* inputInfo, bool &found, QHash<QByteArray, PythonQtMemberInfo>& memberCache, int upcastingOffset);
|
||||
void listDecoratorSlotsFromDecoratorProvider(QStringList& list, bool metaOnly);
|
||||
PythonQtSlotInfo* recursiveFindDecoratorSlotsFromDecoratorProvider(const char* memberName, PythonQtSlotInfo* inputInfo, bool &found, QHash<QByteArray, PythonQtMemberInfo>& memberCache, int upcastingOffset);
|
||||
|
||||
void recursiveCollectClassInfos(QList<PythonQtClassInfo*>& classInfoObjects);
|
||||
void recursiveCollectDecoratorObjects(QList<QObject*>& decoratorObjects);
|
||||
|
||||
bool lookForPropertyAndCache(const char* memberName);
|
||||
bool lookForMethodAndCache(const char* memberName);
|
||||
bool lookForEnumAndCache(const QMetaObject* m, const char* memberName);
|
||||
|
||||
PythonQtSlotInfo* findDecoratorSlots(const char* memberName, PythonQtSlotInfo* tail, bool &found, QHash<QByteArray, PythonQtMemberInfo>& memberCache, int upcastingOffset);
|
||||
int findCharOffset(const char* sigStart, char someChar);
|
||||
|
||||
QHash<QByteArray, PythonQtMemberInfo> _cachedMembers;
|
||||
|
||||
PythonQtSlotInfo* _constructors;
|
||||
PythonQtSlotInfo* _destructor;
|
||||
|
||||
PythonQtVoidPtrCB* _refCallback;
|
||||
PythonQtVoidPtrCB* _unrefCallback;
|
||||
|
||||
QList<PythonQtSlotInfo*> _decoratorSlots;
|
||||
|
||||
QList<PythonQtObjectPtr> _enumWrappers;
|
||||
|
||||
const QMetaObject* _meta;
|
||||
|
||||
QByteArray _wrappedClassName;
|
||||
QList<ParentClassInfo> _parentClasses;
|
||||
|
||||
QList<PythonQtPolymorphicHandlerCB*> _polymorphicHandlers;
|
||||
|
||||
QList<PythonQtClassInfo*> _nestedClasses;
|
||||
|
||||
QObject* _decoratorProvider;
|
||||
PythonQtQObjectCreatorFunctionCB* _decoratorProviderCB;
|
||||
|
||||
PyObject* _pythonQtClassWrapper;
|
||||
|
||||
PythonQtShellSetInstanceWrapperCB* _shellSetInstanceWrapperCB;
|
||||
|
||||
int _metaTypeId;
|
||||
int _typeSlots;
|
||||
|
||||
bool _isQObject;
|
||||
bool _enumsCreated;
|
||||
bool _richCompareDetectionDone;
|
||||
bool _searchPolymorphicHandlerOnParent;
|
||||
bool _searchRefCountCB;
|
||||
|
||||
};
|
||||
|
||||
//---------------------------------------------------------------
|
||||
|
||||
|
||||
#endif
|
|
@ -0,0 +1,81 @@
|
|||
#ifndef PYTHONQTCLASSWRAPPER_H
|
||||
#define PYTHONQTCLASSWRAPPER_H
|
||||
|
||||
/*
|
||||
*
|
||||
* Copyright (C) 2010 MeVis Medical Solutions AG All Rights Reserved.
|
||||
*
|
||||
* This library is free software; you can redistribute it and/or
|
||||
* modify it under the terms of the GNU Lesser General Public
|
||||
* License as published by the Free Software Foundation; either
|
||||
* version 2.1 of the License, or (at your option) any later version.
|
||||
*
|
||||
* This library is distributed in the hope that it will be useful,
|
||||
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
|
||||
* Lesser General Public License for more details.
|
||||
*
|
||||
* Further, this software is distributed without any warranty that it is
|
||||
* free of the rightful claim of any third person regarding infringement
|
||||
* or the like. Any license provided herein, whether implied or
|
||||
* otherwise, applies only to this software file. Patent licenses, if
|
||||
* any, provided herein do not apply to combinations of this program with
|
||||
* other software, or any other product whatsoever.
|
||||
*
|
||||
* You should have received a copy of the GNU Lesser General Public
|
||||
* License along with this library; if not, write to the Free Software
|
||||
* Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
|
||||
*
|
||||
* Contact information: MeVis Medical Solutions AG, Universitaetsallee 29,
|
||||
* 28359 Bremen, Germany or:
|
||||
*
|
||||
* http://www.mevis.de
|
||||
*
|
||||
*/
|
||||
|
||||
//----------------------------------------------------------------------------------
|
||||
/*!
|
||||
// \file PythonQtClassWrapper.h
|
||||
// \author Florian Link
|
||||
// \author Last changed by $Author: florian $
|
||||
// \date 2006-05
|
||||
*/
|
||||
//----------------------------------------------------------------------------------
|
||||
|
||||
#include "PythonQtPythonInclude.h"
|
||||
|
||||
#include "PythonQtSystem.h"
|
||||
|
||||
#include "compile.h"
|
||||
#include "eval.h"
|
||||
#include "methodobject.h"
|
||||
#include "structmember.h"
|
||||
#include <QString>
|
||||
|
||||
class PythonQtClassInfo;
|
||||
|
||||
//! the type of the PythonQt class wrapper objects
|
||||
extern PYTHONQT_EXPORT PyTypeObject PythonQtClassWrapper_Type;
|
||||
|
||||
struct PythonQtDynamicClassInfo;
|
||||
|
||||
//---------------------------------------------------------------
|
||||
//! a Python wrapper object for PythonQt wrapped classes
|
||||
//! which inherits from the Python type object to allow
|
||||
//! deriving of wrapped CPP classes from Python.
|
||||
typedef struct {
|
||||
PyHeapTypeObject _base;
|
||||
|
||||
//! the additional class information that PythonQt stores for the CPP class
|
||||
PythonQtClassInfo *_classInfo;
|
||||
|
||||
//! get the class info
|
||||
PythonQtClassInfo *classInfo() { return _classInfo; }
|
||||
|
||||
PythonQtDynamicClassInfo *_dynamicClassInfo;
|
||||
|
||||
} PythonQtClassWrapper;
|
||||
|
||||
//---------------------------------------------------------------
|
||||
|
||||
#endif
|
|
@ -0,0 +1,644 @@
|
|||
#ifndef PYTHONQTCONVERSION_H
|
||||
#define PYTHONQTCONVERSION_H
|
||||
|
||||
/*
|
||||
*
|
||||
* Copyright (C) 2010 MeVis Medical Solutions AG All Rights Reserved.
|
||||
*
|
||||
* This library is free software; you can redistribute it and/or
|
||||
* modify it under the terms of the GNU Lesser General Public
|
||||
* License as published by the Free Software Foundation; either
|
||||
* version 2.1 of the License, or (at your option) any later version.
|
||||
*
|
||||
* This library is distributed in the hope that it will be useful,
|
||||
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
|
||||
* Lesser General Public License for more details.
|
||||
*
|
||||
* Further, this software is distributed without any warranty that it is
|
||||
* free of the rightful claim of any third person regarding infringement
|
||||
* or the like. Any license provided herein, whether implied or
|
||||
* otherwise, applies only to this software file. Patent licenses, if
|
||||
* any, provided herein do not apply to combinations of this program with
|
||||
* other software, or any other product whatsoever.
|
||||
*
|
||||
* You should have received a copy of the GNU Lesser General Public
|
||||
* License along with this library; if not, write to the Free Software
|
||||
* Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
|
||||
*
|
||||
* Contact information: MeVis Medical Solutions AG, Universitaetsallee 29,
|
||||
* 28359 Bremen, Germany or:
|
||||
*
|
||||
* http://www.mevis.de
|
||||
*
|
||||
*/
|
||||
|
||||
//----------------------------------------------------------------------------------
|
||||
/*!
|
||||
// \file PythonQtConversion.h
|
||||
// \author Florian Link
|
||||
// \author Last changed by $Author: florian $
|
||||
// \date 2006-05
|
||||
*/
|
||||
//----------------------------------------------------------------------------------
|
||||
|
||||
#include "PythonQt.h"
|
||||
#include "PythonQtClassInfo.h"
|
||||
#include "PythonQtMethodInfo.h"
|
||||
#include "PythonQtMisc.h"
|
||||
|
||||
#include <QList>
|
||||
#include <vector>
|
||||
|
||||
typedef PyObject *PythonQtConvertMetaTypeToPythonCB(const void *inObject,
|
||||
int metaTypeId);
|
||||
typedef bool PythonQtConvertPythonToMetaTypeCB(PyObject *inObject,
|
||||
void *outObject, int metaTypeId,
|
||||
bool strict);
|
||||
typedef QVariant
|
||||
PythonQtConvertPythonSequenceToQVariantListCB(PyObject *inObject);
|
||||
|
||||
#define PythonQtRegisterListTemplateConverter(type, innertype) \
|
||||
{ \
|
||||
int typeId = qRegisterMetaType<type<innertype>>(#type "<" #innertype ">"); \
|
||||
PythonQtConv::registerPythonToMetaTypeConverter( \
|
||||
typeId, PythonQtConvertPythonListToListOfValueType<type<innertype>, \
|
||||
innertype>); \
|
||||
PythonQtConv::registerMetaTypeToPythonConverter( \
|
||||
typeId, PythonQtConvertListOfValueTypeToPythonList<type<innertype>, \
|
||||
innertype>); \
|
||||
}
|
||||
|
||||
#define PythonQtRegisterListTemplateConverterForKnownClass(type, innertype) \
|
||||
{ \
|
||||
int typeId = qRegisterMetaType<type<innertype>>(#type "<" #innertype ">"); \
|
||||
PythonQtConv::registerPythonToMetaTypeConverter( \
|
||||
typeId, PythonQtConvertPythonListToListOfKnownClass<type<innertype>, \
|
||||
innertype>); \
|
||||
PythonQtConv::registerMetaTypeToPythonConverter( \
|
||||
typeId, PythonQtConvertListOfKnownClassToPythonList<type<innertype>, \
|
||||
innertype>); \
|
||||
}
|
||||
|
||||
#define PythonQtRegisterQPairConverter(type1, type2) \
|
||||
{ \
|
||||
int typeId = qRegisterMetaType<QPair<type1, type2>>("QPair<" #type1 \
|
||||
"," #type2 ">"); \
|
||||
PythonQtConv::registerPythonToMetaTypeConverter( \
|
||||
typeId, PythonQtConvertPythonToPair<type1, type2>); \
|
||||
PythonQtConv::registerMetaTypeToPythonConverter( \
|
||||
typeId, PythonQtConvertPairToPython<type1, type2>); \
|
||||
}
|
||||
|
||||
#define PythonQtRegisterIntegerMapConverter(type, innertype) \
|
||||
{ \
|
||||
int typeId = qRegisterMetaType<type<int, innertype>>( \
|
||||
#type "<int, " #innertype ">"); \
|
||||
PythonQtConv::registerPythonToMetaTypeConverter( \
|
||||
typeId, \
|
||||
PythonQtConvertPythonToIntegerMap<type<int, innertype>, innertype>); \
|
||||
PythonQtConv::registerMetaTypeToPythonConverter( \
|
||||
typeId, \
|
||||
PythonQtConvertIntegerMapToPython<type<int, innertype>, innertype>); \
|
||||
}
|
||||
|
||||
#define PythonQtRegisterListTemplateQPairConverter(listtype, type1, type2) \
|
||||
{ \
|
||||
qRegisterMetaType<QPair<type1, type2>>("QPair<" #type1 "," #type2 ">"); \
|
||||
int typeId = qRegisterMetaType<listtype<QPair<type1, type2>>>( \
|
||||
#listtype "<QPair<" #type1 "," #type2 ">>"); \
|
||||
PythonQtConv::registerPythonToMetaTypeConverter( \
|
||||
typeId, \
|
||||
PythonQtConvertPythonListToListOfPair<listtype<QPair<type1, type2>>, \
|
||||
type1, type2>); \
|
||||
PythonQtConv::registerMetaTypeToPythonConverter( \
|
||||
typeId, \
|
||||
PythonQtConvertListOfPairToPythonList<listtype<QPair<type1, type2>>, \
|
||||
type1, type2>); \
|
||||
}
|
||||
|
||||
#define PythonQtRegisterToolClassesTemplateConverter(innertype) \
|
||||
PythonQtRegisterListTemplateConverter(QList, innertype); \
|
||||
PythonQtRegisterListTemplateConverter(QVector, innertype); \
|
||||
PythonQtRegisterListTemplateConverter(std::vector, innertype);
|
||||
|
||||
#define PythonQtRegisterToolClassesTemplateConverterForKnownClass(innertype) \
|
||||
PythonQtRegisterListTemplateConverterForKnownClass(QList, innertype); \
|
||||
PythonQtRegisterListTemplateConverterForKnownClass(QVector, innertype); \
|
||||
PythonQtRegisterListTemplateConverterForKnownClass(std::vector, innertype);
|
||||
|
||||
//! a static class that offers methods for type conversion
|
||||
class PYTHONQT_EXPORT PythonQtConv {
|
||||
|
||||
public:
|
||||
//! get a ref counted True or False Python object
|
||||
static PyObject *GetPyBool(bool val);
|
||||
|
||||
//! converts the Qt parameter given in \c data, interpreting it as a \c info
|
||||
//! parameter, into a Python object,
|
||||
static PyObject *
|
||||
ConvertQtValueToPython(const PythonQtMethodInfo::ParameterInfo &info,
|
||||
const void *data);
|
||||
|
||||
//! convert python object to Qt (according to the given parameter) and if the
|
||||
//! conversion should be strict (classInfo is currently not used anymore)
|
||||
static void *ConvertPythonToQt(const PythonQtMethodInfo::ParameterInfo &info,
|
||||
PyObject *obj, bool strict,
|
||||
PythonQtClassInfo *classInfo,
|
||||
void *alreadyAllocatedCPPObject = NULL);
|
||||
|
||||
//! creates a data storage for the passed parameter type and returns a void
|
||||
//! pointer to be set as arg[0] of qt_metacall
|
||||
static void *
|
||||
CreateQtReturnValue(const PythonQtMethodInfo::ParameterInfo &info);
|
||||
|
||||
//! converts QString to Python string (unicode!)
|
||||
static PyObject *QStringToPyObject(const QString &str);
|
||||
|
||||
//! converts QStringList to Python tuple
|
||||
static PyObject *QStringListToPyObject(const QStringList &list);
|
||||
|
||||
//! converts QStringList to Python list
|
||||
static PyObject *QStringListToPyList(const QStringList &list);
|
||||
|
||||
//! get string representation of py object
|
||||
static QString PyObjGetRepresentation(PyObject *val);
|
||||
|
||||
//! get string value from py object
|
||||
static QString PyObjGetString(PyObject *val) {
|
||||
bool ok;
|
||||
QString s = PyObjGetString(val, false, ok);
|
||||
return s;
|
||||
}
|
||||
//! get string value from py object
|
||||
static QString PyObjGetString(PyObject *val, bool strict, bool &ok);
|
||||
//! get bytes from py object
|
||||
static QByteArray PyObjGetBytes(PyObject *val, bool strict, bool &ok);
|
||||
//! get int from py object
|
||||
static int PyObjGetInt(PyObject *val, bool strict, bool &ok);
|
||||
//! get int64 from py object
|
||||
static qint64 PyObjGetLongLong(PyObject *val, bool strict, bool &ok);
|
||||
//! get int64 from py object
|
||||
static quint64 PyObjGetULongLong(PyObject *val, bool strict, bool &ok);
|
||||
//! get double from py object
|
||||
static double PyObjGetDouble(PyObject *val, bool strict, bool &ok);
|
||||
//! get bool from py object
|
||||
static bool PyObjGetBool(PyObject *val, bool strict, bool &ok);
|
||||
|
||||
//! create a string list from python sequence
|
||||
static QStringList PyObjToStringList(PyObject *val, bool strict, bool &ok);
|
||||
|
||||
//! convert python object to qvariant, if type is given it will try to create
|
||||
//! a qvariant of that type, otherwise it will guess from the python type
|
||||
static QVariant PyObjToQVariant(PyObject *val, int type = -1);
|
||||
|
||||
//! convert QVariant from PyObject
|
||||
static PyObject *QVariantToPyObject(const QVariant &v);
|
||||
|
||||
static PyObject *QVariantHashToPyObject(const QVariantHash &m);
|
||||
static PyObject *QVariantMapToPyObject(const QVariantMap &m);
|
||||
static PyObject *QVariantListToPyObject(const QVariantList &l);
|
||||
|
||||
//! get human readable string from CPP object (when the metatype is known)
|
||||
static QString CPPObjectToString(int type, const void *data);
|
||||
|
||||
//! register a converter callback from python to cpp for given metatype
|
||||
static void
|
||||
registerPythonToMetaTypeConverter(int metaTypeId,
|
||||
PythonQtConvertPythonToMetaTypeCB *cb) {
|
||||
_pythonToMetaTypeConverters.insert(metaTypeId, cb);
|
||||
}
|
||||
|
||||
//! register a converter callback from cpp to python for given metatype
|
||||
static void
|
||||
registerMetaTypeToPythonConverter(int metaTypeId,
|
||||
PythonQtConvertMetaTypeToPythonCB *cb) {
|
||||
_metaTypeToPythonConverters.insert(metaTypeId, cb);
|
||||
}
|
||||
|
||||
//! set a callback that is called when a Python sequence should be converted
|
||||
//! to a QVariantList to allow special conversion.
|
||||
static void setPythonSequenceToQVariantListCallback(
|
||||
PythonQtConvertPythonSequenceToQVariantListCB *cb) {
|
||||
_pythonSequenceToQVariantListCB = cb;
|
||||
}
|
||||
|
||||
//! converts the Qt parameter given in \c data, interpreting it as a \c type
|
||||
//! registered qvariant/meta type, into a Python object,
|
||||
static PyObject *convertQtValueToPythonInternal(int type, const void *data);
|
||||
|
||||
//! creates a copy of given object, using the QMetaType
|
||||
static PyObject *createCopyFromMetaType(int type, const void *object);
|
||||
|
||||
//! cast wrapper to given className if possible
|
||||
static void *castWrapperTo(PythonQtInstanceWrapper *wrapper,
|
||||
const QByteArray &className, bool &ok);
|
||||
|
||||
static bool convertToPythonQtObjectPtr(PyObject *obj,
|
||||
void * /* PythonQtObjectPtr* */ outPtr,
|
||||
int /*metaTypeId*/, bool /*strict*/);
|
||||
static PyObject *
|
||||
convertFromPythonQtObjectPtr(const void * /* PythonQtObjectPtr* */ inObject,
|
||||
int /*metaTypeId*/);
|
||||
static bool convertToQListOfPythonQtObjectPtr(
|
||||
PyObject *obj, void * /* QList<PythonQtObjectPtr>* */ outList,
|
||||
int /*metaTypeId*/, bool /*strict*/);
|
||||
static PyObject *convertFromQListOfPythonQtObjectPtr(
|
||||
const void * /* QList<PythonQtObjectPtr>* */ inObject,
|
||||
int /*metaTypeId*/);
|
||||
static PyObject *convertFromStringRef(const void *inObject,
|
||||
int /*metaTypeId*/);
|
||||
|
||||
//! Returns the name of the equivalent CPP type (for signals and slots)
|
||||
static QByteArray getCPPTypeName(PyObject *type);
|
||||
|
||||
//! Returns if the given object is a string (or unicode string)
|
||||
static bool isStringType(PyTypeObject *type);
|
||||
|
||||
public:
|
||||
static PythonQtValueStorage<qint64, 128> global_valueStorage;
|
||||
static PythonQtValueStorage<void *, 128> global_ptrStorage;
|
||||
static PythonQtValueStorageWithCleanup<QVariant, 128> global_variantStorage;
|
||||
|
||||
protected:
|
||||
static QHash<int, PythonQtConvertMetaTypeToPythonCB *>
|
||||
_metaTypeToPythonConverters;
|
||||
static QHash<int, PythonQtConvertPythonToMetaTypeCB *>
|
||||
_pythonToMetaTypeConverters;
|
||||
static PythonQtConvertPythonSequenceToQVariantListCB
|
||||
*_pythonSequenceToQVariantListCB;
|
||||
|
||||
//! handle automatic conversion of some special types (QColor, QBrush, ...)
|
||||
static void *handlePythonToQtAutoConversion(int typeId, PyObject *obj,
|
||||
void *alreadyAllocatedCPPObject);
|
||||
|
||||
//! converts the list of pointers of given type to Python
|
||||
static PyObject *ConvertQListOfPointerTypeToPythonList(
|
||||
QList<void *> *list, const PythonQtMethodInfo::ParameterInfo &info);
|
||||
//! tries to convert the python object to a QList of pointers to \c type
|
||||
//! objects, returns true on success
|
||||
static bool ConvertPythonListToQListOfPointerType(
|
||||
PyObject *obj, QList<void *> *list,
|
||||
const PythonQtMethodInfo::ParameterInfo &info, bool strict);
|
||||
|
||||
//! helper template method for conversion from Python to QVariantMap/Hash
|
||||
template <typename Map>
|
||||
static void pythonToMapVariant(PyObject *val, QVariant &result);
|
||||
//! helper template function for QVariantMapToPyObject/QVariantHashToPyObject
|
||||
template <typename Map> static PyObject *mapToPython(const Map &m);
|
||||
};
|
||||
|
||||
template <class ListType, class T>
|
||||
PyObject *
|
||||
PythonQtConvertListOfValueTypeToPythonList(const void * /*QList<T>* */ inList,
|
||||
int metaTypeId) {
|
||||
ListType *list = (ListType *)inList;
|
||||
static const int innerType = PythonQtMethodInfo::getInnerTemplateMetaType(
|
||||
QByteArray(QMetaType::typeName(metaTypeId)));
|
||||
if (innerType == QVariant::Invalid) {
|
||||
std::cerr
|
||||
<< "PythonQtConvertListOfValueTypeToPythonList: unknown inner type "
|
||||
<< QMetaType::typeName(metaTypeId) << std::endl;
|
||||
}
|
||||
PyObject *result = PyTuple_New(list->size());
|
||||
int i = 0;
|
||||
Q_FOREACH (const T &value, *list) {
|
||||
PyTuple_SET_ITEM(
|
||||
result, i,
|
||||
PythonQtConv::convertQtValueToPythonInternal(innerType, &value));
|
||||
i++;
|
||||
}
|
||||
return result;
|
||||
}
|
||||
|
||||
template <class ListType, class T>
|
||||
bool PythonQtConvertPythonListToListOfValueType(PyObject *obj,
|
||||
void * /*QList<T>* */ outList,
|
||||
int metaTypeId,
|
||||
bool /*strict*/) {
|
||||
ListType *list = (ListType *)outList;
|
||||
static const int innerType = PythonQtMethodInfo::getInnerTemplateMetaType(
|
||||
QByteArray(QMetaType::typeName(metaTypeId)));
|
||||
if (innerType == QVariant::Invalid) {
|
||||
std::cerr
|
||||
<< "PythonQtConvertPythonListToListOfValueType: unknown inner type "
|
||||
<< QMetaType::typeName(metaTypeId) << std::endl;
|
||||
}
|
||||
bool result = false;
|
||||
if (PySequence_Check(obj)) {
|
||||
int count = PySequence_Size(obj);
|
||||
if (count >= 0) {
|
||||
result = true;
|
||||
PyObject *value;
|
||||
for (int i = 0; i < count; i++) {
|
||||
value = PySequence_GetItem(obj, i);
|
||||
// this is quite some overhead, but it avoids having another large
|
||||
// switch...
|
||||
QVariant v = PythonQtConv::PyObjToQVariant(value, innerType);
|
||||
Py_XDECREF(value);
|
||||
if (v.isValid()) {
|
||||
list->push_back(qvariant_cast<T>(v));
|
||||
} else {
|
||||
result = false;
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
return result;
|
||||
}
|
||||
|
||||
//--------------------------------------------------------------------------------------------------------------------
|
||||
|
||||
template <class ListType, class T>
|
||||
PyObject *
|
||||
PythonQtConvertListOfKnownClassToPythonList(const void * /*QList<T>* */ inList,
|
||||
int metaTypeId) {
|
||||
ListType *list = (ListType *)inList;
|
||||
static PythonQtClassInfo *innerType =
|
||||
PythonQt::priv()->getClassInfo(PythonQtMethodInfo::getInnerListTypeName(
|
||||
QByteArray(QMetaType::typeName(metaTypeId))));
|
||||
if (innerType == NULL) {
|
||||
std::cerr
|
||||
<< "PythonQtConvertListOfKnownClassToPythonList: unknown inner type "
|
||||
<< innerType->className().constData() << std::endl;
|
||||
}
|
||||
PyObject *result = PyTuple_New(list->size());
|
||||
int i = 0;
|
||||
Q_FOREACH (const T &value, *list) {
|
||||
T *newObject = new T(value);
|
||||
PythonQtInstanceWrapper *wrap =
|
||||
(PythonQtInstanceWrapper *)PythonQt::priv()->wrapPtr(
|
||||
newObject, innerType->className());
|
||||
wrap->_ownedByPythonQt = true;
|
||||
PyTuple_SET_ITEM(result, i, (PyObject *)wrap);
|
||||
i++;
|
||||
}
|
||||
return result;
|
||||
}
|
||||
|
||||
template <class ListType, class T>
|
||||
bool PythonQtConvertPythonListToListOfKnownClass(PyObject *obj,
|
||||
void * /*QList<T>* */ outList,
|
||||
int metaTypeId,
|
||||
bool /*strict*/) {
|
||||
ListType *list = (ListType *)outList;
|
||||
static PythonQtClassInfo *innerType =
|
||||
PythonQt::priv()->getClassInfo(PythonQtMethodInfo::getInnerListTypeName(
|
||||
QByteArray(QMetaType::typeName(metaTypeId))));
|
||||
if (innerType == NULL) {
|
||||
std::cerr
|
||||
<< "PythonQtConvertListOfKnownClassToPythonList: unknown inner type "
|
||||
<< innerType->className().constData() << std::endl;
|
||||
}
|
||||
bool result = false;
|
||||
if (PySequence_Check(obj)) {
|
||||
int count = PySequence_Size(obj);
|
||||
if (count >= 0) {
|
||||
result = true;
|
||||
PyObject *value;
|
||||
for (int i = 0; i < count; i++) {
|
||||
value = PySequence_GetItem(obj, i);
|
||||
if (PyObject_TypeCheck(value, &PythonQtInstanceWrapper_Type)) {
|
||||
PythonQtInstanceWrapper *wrap = (PythonQtInstanceWrapper *)value;
|
||||
bool ok;
|
||||
T *object = (T *)PythonQtConv::castWrapperTo(
|
||||
wrap, innerType->className(), ok);
|
||||
Py_XDECREF(value);
|
||||
if (ok) {
|
||||
list->push_back(*object);
|
||||
} else {
|
||||
result = false;
|
||||
break;
|
||||
}
|
||||
} else {
|
||||
Py_XDECREF(value);
|
||||
result = false;
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
return result;
|
||||
}
|
||||
|
||||
//--------------------------------------------------------------------------------------------------------------------
|
||||
|
||||
template <class T1, class T2>
|
||||
PyObject *PythonQtConvertPairToPython(const void * /*QPair<T1,T2>* */ inPair,
|
||||
int metaTypeId) {
|
||||
QPair<T1, T2> *pair = (QPair<T1, T2> *)inPair;
|
||||
static int innerType1 = -1;
|
||||
static int innerType2 = -1;
|
||||
if (innerType1 == -1) {
|
||||
QByteArray innerTypes = PythonQtMethodInfo::getInnerTemplateTypeName(
|
||||
QByteArray(QMetaType::typeName(metaTypeId)));
|
||||
QList<QByteArray> names = innerTypes.split(',');
|
||||
innerType1 = QMetaType::type(names.at(0).trimmed());
|
||||
innerType2 = QMetaType::type(names.at(1).trimmed());
|
||||
}
|
||||
if (innerType1 == QVariant::Invalid || innerType2 == QVariant::Invalid) {
|
||||
std::cerr << "PythonQtConvertPairToPython: unknown inner type "
|
||||
<< QMetaType::typeName(metaTypeId) << std::endl;
|
||||
}
|
||||
PyObject *result = PyTuple_New(2);
|
||||
PyTuple_SET_ITEM(
|
||||
result, 0,
|
||||
PythonQtConv::convertQtValueToPythonInternal(innerType1, &pair->first));
|
||||
PyTuple_SET_ITEM(
|
||||
result, 1,
|
||||
PythonQtConv::convertQtValueToPythonInternal(innerType2, &pair->second));
|
||||
return result;
|
||||
}
|
||||
|
||||
template <class T1, class T2>
|
||||
bool PythonQtConvertPythonToPair(PyObject *obj,
|
||||
void * /*QPair<T1,T2>* */ outPair,
|
||||
int metaTypeId, bool /*strict*/) {
|
||||
QPair<T1, T2> *pair = (QPair<T1, T2> *)outPair;
|
||||
static int innerType1 = -1;
|
||||
static int innerType2 = -1;
|
||||
if (innerType1 == -1) {
|
||||
QByteArray innerTypes = PythonQtMethodInfo::getInnerTemplateTypeName(
|
||||
QByteArray(QMetaType::typeName(metaTypeId)));
|
||||
QList<QByteArray> names = innerTypes.split(',');
|
||||
innerType1 = QMetaType::type(names.at(0).trimmed());
|
||||
innerType2 = QMetaType::type(names.at(1).trimmed());
|
||||
}
|
||||
if (innerType1 == QVariant::Invalid || innerType2 == QVariant::Invalid) {
|
||||
std::cerr << "PythonQtConvertPythonToPair: unknown inner type "
|
||||
<< QMetaType::typeName(metaTypeId) << std::endl;
|
||||
}
|
||||
bool result = false;
|
||||
if (PySequence_Check(obj)) {
|
||||
int count = PySequence_Size(obj);
|
||||
if (count == 2) {
|
||||
result = true;
|
||||
PyObject *value;
|
||||
|
||||
value = PySequence_GetItem(obj, 0);
|
||||
// this is quite some overhead, but it avoids having another large
|
||||
// switch...
|
||||
QVariant v = PythonQtConv::PyObjToQVariant(value, innerType1);
|
||||
Py_XDECREF(value);
|
||||
if (v.isValid()) {
|
||||
pair->first = qvariant_cast<T1>(v);
|
||||
} else {
|
||||
return false;
|
||||
}
|
||||
|
||||
value = PySequence_GetItem(obj, 1);
|
||||
// this is quite some overhead, but it avoids having another large
|
||||
// switch...
|
||||
v = PythonQtConv::PyObjToQVariant(value, innerType2);
|
||||
Py_XDECREF(value);
|
||||
if (v.isValid()) {
|
||||
pair->second = qvariant_cast<T2>(v);
|
||||
} else {
|
||||
return false;
|
||||
}
|
||||
}
|
||||
}
|
||||
return result;
|
||||
}
|
||||
|
||||
//--------------------------------------------------------------------------------------------------------------------
|
||||
|
||||
template <class ListType, class T1, class T2>
|
||||
PyObject *PythonQtConvertListOfPairToPythonList(
|
||||
const void * /*QList<QPair<T1,T2> >* */ inList, int metaTypeId) {
|
||||
ListType *list = (ListType *)inList;
|
||||
static int innerType = PythonQtMethodInfo::getInnerTemplateMetaType(
|
||||
QByteArray(QMetaType::typeName(metaTypeId)));
|
||||
if (innerType == QVariant::Invalid) {
|
||||
std::cerr << "PythonQtConvertListOfPairToPythonList: unknown inner type "
|
||||
<< QMetaType::typeName(metaTypeId) << std::endl;
|
||||
}
|
||||
PyObject *result = PyTuple_New(list->size());
|
||||
int i = 0;
|
||||
typedef const QPair<T1, T2> Pair;
|
||||
Q_FOREACH (Pair &value, *list) {
|
||||
PyObject *object = PythonQtConvertPairToPython<T1, T2>(&value, innerType);
|
||||
PyTuple_SET_ITEM(result, i, object);
|
||||
i++;
|
||||
}
|
||||
return result;
|
||||
}
|
||||
|
||||
template <class ListType, class T1, class T2>
|
||||
bool PythonQtConvertPythonListToListOfPair(
|
||||
PyObject *obj, void * /*QList<QPair<T1,T2> >* */ outList, int metaTypeId,
|
||||
bool /*strict*/) {
|
||||
ListType *list = (ListType *)outList;
|
||||
static int innerType = PythonQtMethodInfo::getInnerTemplateMetaType(
|
||||
QByteArray(QMetaType::typeName(metaTypeId)));
|
||||
if (innerType == QVariant::Invalid) {
|
||||
std::cerr << "PythonQtConvertPythonListToListOfPair: unknown inner type "
|
||||
<< QMetaType::typeName(metaTypeId) << std::endl;
|
||||
}
|
||||
bool result = false;
|
||||
if (PySequence_Check(obj)) {
|
||||
int count = PySequence_Size(obj);
|
||||
if (count >= 0) {
|
||||
result = true;
|
||||
PyObject *value;
|
||||
for (int i = 0; i < count; i++) {
|
||||
QPair<T1, T2> pair;
|
||||
value = PySequence_GetItem(obj, i);
|
||||
if (PythonQtConvertPythonToPair<T1, T2>(value, &pair, innerType,
|
||||
false)) {
|
||||
Py_XDECREF(value);
|
||||
list->push_back(pair);
|
||||
} else {
|
||||
Py_XDECREF(value);
|
||||
result = false;
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
return result;
|
||||
}
|
||||
|
||||
//--------------------------------------------------------------------------------------------------------------------
|
||||
|
||||
template <class MapType, class T>
|
||||
PyObject *
|
||||
PythonQtConvertIntegerMapToPython(const void * /*QMap<int, T>* */ inMap,
|
||||
int metaTypeId) {
|
||||
MapType *map = (MapType *)inMap;
|
||||
static int innerType = -1;
|
||||
if (innerType == -1) {
|
||||
QByteArray innerTypes = PythonQtMethodInfo::getInnerTemplateTypeName(
|
||||
QByteArray(QMetaType::typeName(metaTypeId)));
|
||||
QList<QByteArray> names = innerTypes.split(',');
|
||||
innerType = QMetaType::type(names.at(1).trimmed());
|
||||
}
|
||||
if (innerType == QVariant::Invalid) {
|
||||
std::cerr << "PythonQtConvertIntegerMapToPython: unknown inner type "
|
||||
<< QMetaType::typeName(metaTypeId) << std::endl;
|
||||
}
|
||||
|
||||
PyObject *result = PyDict_New();
|
||||
typename MapType::const_iterator t = map->constBegin();
|
||||
PyObject *key;
|
||||
PyObject *val;
|
||||
for (; t != map->constEnd(); t++) {
|
||||
key = PyInt_FromLong(t.key());
|
||||
val = PythonQtConv::convertQtValueToPythonInternal(innerType, &t.value());
|
||||
PyDict_SetItem(result, key, val);
|
||||
Py_DECREF(key);
|
||||
Py_DECREF(val);
|
||||
}
|
||||
return result;
|
||||
}
|
||||
|
||||
template <class MapType, class T>
|
||||
bool PythonQtConvertPythonToIntegerMap(PyObject *val,
|
||||
void * /*QMap<int, T>* */ outMap,
|
||||
int metaTypeId, bool /*strict*/) {
|
||||
MapType *map = (MapType *)outMap;
|
||||
static int innerType = -1;
|
||||
if (innerType == -1) {
|
||||
QByteArray innerTypes = PythonQtMethodInfo::getInnerTemplateTypeName(
|
||||
QByteArray(QMetaType::typeName(metaTypeId)));
|
||||
QList<QByteArray> names = innerTypes.split(',');
|
||||
innerType = QMetaType::type(names.at(1).trimmed());
|
||||
}
|
||||
if (innerType == QVariant::Invalid) {
|
||||
std::cerr << "PythonQtConvertPythonToIntegerMap: unknown inner type "
|
||||
<< QMetaType::typeName(metaTypeId) << std::endl;
|
||||
}
|
||||
bool result = false;
|
||||
if (PyMapping_Check(val)) {
|
||||
result = true;
|
||||
PyObject *items = PyMapping_Items(val);
|
||||
if (items) {
|
||||
int count = PyList_Size(items);
|
||||
PyObject *value;
|
||||
PyObject *key;
|
||||
PyObject *tuple;
|
||||
for (int i = 0; i < count; i++) {
|
||||
tuple = PyList_GetItem(items, i);
|
||||
key = PyTuple_GetItem(tuple, 0);
|
||||
value = PyTuple_GetItem(tuple, 1);
|
||||
|
||||
bool ok;
|
||||
int intKey = PythonQtConv::PyObjGetInt(key, false, ok);
|
||||
// this is quite some overhead, but it avoids having another large
|
||||
// switch...
|
||||
QVariant v = PythonQtConv::PyObjToQVariant(value, innerType);
|
||||
if (v.isValid() && ok) {
|
||||
map->insert(intKey, qvariant_cast<T>(v));
|
||||
} else {
|
||||
result = false;
|
||||
break;
|
||||
}
|
||||
}
|
||||
Py_DECREF(items);
|
||||
}
|
||||
}
|
||||
return result;
|
||||
}
|
||||
|
||||
#endif
|
|
@ -0,0 +1,86 @@
|
|||
#ifndef _PYTHONQTCPPWRAPPERFACTORY_H
|
||||
#define _PYTHONQTCPPWRAPPERFACTORY_H
|
||||
|
||||
/*
|
||||
*
|
||||
* Copyright (C) 2010 MeVis Medical Solutions AG All Rights Reserved.
|
||||
*
|
||||
* This library is free software; you can redistribute it and/or
|
||||
* modify it under the terms of the GNU Lesser General Public
|
||||
* License as published by the Free Software Foundation; either
|
||||
* version 2.1 of the License, or (at your option) any later version.
|
||||
*
|
||||
* This library is distributed in the hope that it will be useful,
|
||||
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
|
||||
* Lesser General Public License for more details.
|
||||
*
|
||||
* Further, this software is distributed without any warranty that it is
|
||||
* free of the rightful claim of any third person regarding infringement
|
||||
* or the like. Any license provided herein, whether implied or
|
||||
* otherwise, applies only to this software file. Patent licenses, if
|
||||
* any, provided herein do not apply to combinations of this program with
|
||||
* other software, or any other product whatsoever.
|
||||
*
|
||||
* You should have received a copy of the GNU Lesser General Public
|
||||
* License along with this library; if not, write to the Free Software
|
||||
* Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
|
||||
*
|
||||
* Contact information: MeVis Medical Solutions AG, Universitaetsallee 29,
|
||||
* 28359 Bremen, Germany or:
|
||||
*
|
||||
* http://www.mevis.de
|
||||
*
|
||||
*/
|
||||
|
||||
//----------------------------------------------------------------------------------
|
||||
/*!
|
||||
// \file PythonQtCppWrapperFactory.h
|
||||
// \author Florian Link
|
||||
// \author Last changed by $Author: florian $
|
||||
// \date 2006-06
|
||||
*/
|
||||
//----------------------------------------------------------------------------------
|
||||
|
||||
#include "PythonQtPythonInclude.h"
|
||||
|
||||
#include "PythonQtSystem.h"
|
||||
#include <QObject>
|
||||
#include <QByteArray>
|
||||
|
||||
//! Factory interface for C++ classes that can be wrapped by QObject objects
|
||||
/*! To create your own factory, derive PythonQtCppWrapperFactory and implement
|
||||
the create() method.
|
||||
A factory can be added to PythonQt by PythonQt::addCppWrapperFactory().
|
||||
*/
|
||||
class PYTHONQT_EXPORT PythonQtCppWrapperFactory
|
||||
{
|
||||
public:
|
||||
PythonQtCppWrapperFactory() {};
|
||||
virtual ~PythonQtCppWrapperFactory() {};
|
||||
|
||||
//! create a wrapper for the given object
|
||||
virtual QObject* create(const QByteArray& classname, void *ptr) = 0;
|
||||
|
||||
};
|
||||
|
||||
//! Factory interface for C++ classes that can be mapped directly from/to
|
||||
//! Python with other means than PythonQt/QObjects.
|
||||
class PYTHONQT_EXPORT PythonQtForeignWrapperFactory
|
||||
{
|
||||
public:
|
||||
PythonQtForeignWrapperFactory() {};
|
||||
virtual ~PythonQtForeignWrapperFactory() {};
|
||||
|
||||
//! create a Python object (with new reference count), wrapping the given \p ptr as class of type \p classname
|
||||
//! Return NULL (and not Py_None) if the object could not be wrapped.
|
||||
virtual PyObject* wrap(const QByteArray& classname, void *ptr) = 0;
|
||||
|
||||
//! unwrap the given object to a C++ object of type \p classname if possible
|
||||
//! Return NULL otherwise.
|
||||
virtual void* unwrap(const QByteArray& classname, PyObject* object) = 0;
|
||||
|
||||
};
|
||||
|
||||
#endif
|
||||
|
|
@ -0,0 +1,660 @@
|
|||
#ifndef PYTHONQTDOC_H
|
||||
#define PYTHONQTDOC_H
|
||||
|
||||
/*
|
||||
*
|
||||
* Copyright (C) 2010 MeVis Medical Solutions AG All Rights Reserved.
|
||||
*
|
||||
* This library is free software; you can redistribute it and/or
|
||||
* modify it under the terms of the GNU Lesser General Public
|
||||
* License as published by the Free Software Foundation; either
|
||||
* version 2.1 of the License, or (at your option) any later version.
|
||||
*
|
||||
* This library is distributed in the hope that it will be useful,
|
||||
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
|
||||
* Lesser General Public License for more details.
|
||||
*
|
||||
* Further, this software is distributed without any warranty that it is
|
||||
* free of the rightful claim of any third person regarding infringement
|
||||
* or the like. Any license provided herein, whether implied or
|
||||
* otherwise, applies only to this software file. Patent licenses, if
|
||||
* any, provided herein do not apply to combinations of this program with
|
||||
* other software, or any other product whatsoever.
|
||||
*
|
||||
* You should have received a copy of the GNU Lesser General Public
|
||||
* License along with this library; if not, write to the Free Software
|
||||
* Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
|
||||
*
|
||||
* Contact information: MeVis Medical Solutions AG, Universitaetsallee 29,
|
||||
* 28359 Bremen, Germany or:
|
||||
*
|
||||
* http://www.mevis.de
|
||||
*
|
||||
*/
|
||||
|
||||
//----------------------------------------------------------------------------------
|
||||
/*!
|
||||
// \file PythonQtDoc.h
|
||||
// \author Florian Link
|
||||
// \author Last changed by $Author: florian $
|
||||
// \date 2006-10
|
||||
*/
|
||||
//----------------------------------------------------------------------------------
|
||||
|
||||
/*!
|
||||
\if USE_GLOBAL_DOXYGEN_DOC
|
||||
\page PythonQtPage PythonQt Overview
|
||||
\else
|
||||
\mainpage notitle
|
||||
\endif
|
||||
|
||||
\image html PythonQt.jpg
|
||||
|
||||
\section Introduction
|
||||
|
||||
\b PythonQt is a dynamic <a href="http://www.python.org" target="_blank">
|
||||
Python</a> binding for the <a href="http://qt-project.org/" target="_blank">
|
||||
Qt framework</a>.
|
||||
It offers an easy way to embed the Python scripting language into
|
||||
your C++ Qt applications.
|
||||
|
||||
The focus of PythonQt is on embedding Python into an existing C++ application,
|
||||
not on writing the whole application completely in Python.
|
||||
|
||||
If you are looking for a simple way to embed Python objects into your C++/Qt
|
||||
Application and to script parts of your application via Python, PythonQt is the
|
||||
way to go!
|
||||
|
||||
PythonQt is a stable library that was developed to make the
|
||||
Image Processing and Visualization platform <a href="http://www.mevislab.de"
|
||||
target="_blank">MeVisLab</a> scriptable from Python.
|
||||
|
||||
- \ref Features
|
||||
- \ref Download
|
||||
- \ref License
|
||||
- \ref Developer
|
||||
- \ref Building
|
||||
- \ref Examples
|
||||
|
||||
\page Features Features
|
||||
|
||||
\section Builtin Built-in Features
|
||||
|
||||
The following are the built-in features of the PythonQt library:
|
||||
|
||||
- Access all \b slots, \b properties, children and registered enums of any
|
||||
QObject derived class from Python
|
||||
- Connecting Qt Signals to Python functions (both from within Python and from
|
||||
C++)
|
||||
- Easy wrapping of Python objects from C++ with smart, reference-counting
|
||||
PythonQtObjectPtr.
|
||||
- Convenient conversions to/from QVariant for PythonQtObjectPtr.
|
||||
- Wrapping of C++ objects (which are not derived from QObject) via
|
||||
PythonQtCppWrapperFactory
|
||||
- Extending C++ and QObject derived classes with additional slots, static
|
||||
methods and constructors (see Decorators)
|
||||
- StdOut/Err redirection to Qt signals instead of cout
|
||||
- Interface for creating your own \c import replacement, so that Python scripts
|
||||
can be e.g. signed/verified before they are executed
|
||||
(PythonQtImportFileInterface)
|
||||
- Mapping of plain-old-datatypes and ALL QVariant types to and from Python
|
||||
- Support for wrapping of user QVariant types which are registerd via QMetaType
|
||||
- Support for Qt namespace (with all enumerators)
|
||||
- All PythonQt wrapped objects support the dir() statement, so that you can see
|
||||
easily which attributes a QObject, CPP object or QVariant has
|
||||
- No preprocessing/wrapping tool needs to be started, PythonQt can script any
|
||||
QObject without prior knowledge about it (except for the MetaObject information
|
||||
from the \b moc)
|
||||
- Multiple inheritance for C++ objects (e.g. a QWidget is derived from QObject
|
||||
and QPaintDevice, PythonQt will automatically cast a QWidget to a QPaintDevice
|
||||
when needed)
|
||||
- Polymorphic downcasting (if e.g. PythonQt sees a QEvent, it can downcast it
|
||||
depending on the type(), so the Python e.g. sees a QPaintEvent instead of a
|
||||
plain QEvent)
|
||||
- Deriving C++ objects from Python and overwriting virtual method with a Python
|
||||
implementation (requires usage of wrapper generator or manual work!)
|
||||
- Extensible handler for Python/C++ conversion of complex types, e.g. mapping
|
||||
of QVector<SomeObject> to/from a Python array
|
||||
- Setting of dynamic QObject properties via setProperty(), dynamic properties
|
||||
can be accessed for reading and writing like normal Python attributes (but
|
||||
creating a new property needs to be done with setProperty(), to distinguish from
|
||||
normal Python attributes)
|
||||
- Support for QtCore.Signal, QtCore.Slot and QtCore.Property, including the
|
||||
creation of a dynamic QMetaObject.
|
||||
|
||||
\section FeaturesQtAll Features with wrapper generator
|
||||
|
||||
PythonQt offers the additional PythonQt_QtAll library which wraps the complete
|
||||
Qt API, including all C++ classes and all non-slots on QObject derived classes.
|
||||
This offers the following features:
|
||||
|
||||
- Complete Qt API wrapped and accessible
|
||||
- The following modules are available as submodules of the PythonQt module:
|
||||
- QtCore
|
||||
- QtGui
|
||||
- QtNetwork
|
||||
- QtOpenGL
|
||||
- QtSql
|
||||
- QtSvg
|
||||
- QtWebKit
|
||||
- QtXml
|
||||
- QtXmlPatterns
|
||||
- QtMultimedia
|
||||
- QtQml
|
||||
- QtQuick
|
||||
- Any Qt class that has virtual methods can be easily derived from Python and
|
||||
the virtual methods can be reimplemented in Python
|
||||
- Polymorphic downcasting on QEvent, QGraphicsItem, QStyleOption, ...
|
||||
- Multiple inheritance support (e.g., QGraphicsTextItem is a QObject and a
|
||||
QGraphicsItem, PythonQt will handle this well)
|
||||
- QtQuick support is experimental and currently it is not possible to register
|
||||
new qml components from Python
|
||||
|
||||
\section Supported Supported Versions
|
||||
|
||||
PythonQt supports:
|
||||
- Python 2 (>= Python 2.6)
|
||||
- Python 3 (>= Python 3.3)
|
||||
- Qt 4.x (Qt 4.7 and Qt 4.8 recommended)
|
||||
- Qt 5.x (Tested with Qt 5.0, 5.3, 5.4 and 5.6)
|
||||
|
||||
The last working Qt4 version is available at svn branches/Qt4LastWorkingVersion
|
||||
or you can download the PythonQt 3.0 release. The current svn trunk no longer
|
||||
supports Qt4, since we started to make use of some Qt5-only features.
|
||||
|
||||
\section Comparison Comparison with PySide
|
||||
|
||||
- PythonQt is not as pythonic as PySide in many details (e.g. buffer protocol,
|
||||
pickling, translation support, ...) and it is mainly thought for embedding and
|
||||
intercommunication between Qt/Cpp and Python
|
||||
- PythonQt offers properties as Python attributes, while PySide offers them as
|
||||
setter/getter methods (e.g. QWidget.width is a property in PythonQt and a method
|
||||
in PySide)
|
||||
- PythonQt currently does not support instanceof checks for Qt classes, except
|
||||
for the exact match and derived Python classes
|
||||
- QObject.emit to emit Qt signals from Python is not yet implemented but
|
||||
PythonQt allows to just emit a signal by calling it like a normal slot
|
||||
- Ownership handling of objects is not as complete as in PySide and PySide,
|
||||
especially in situations where the ownership is not clearly passed to C++ on the
|
||||
C++ API.
|
||||
- QStrings are always converted to unicode Python objects, QByteArray always
|
||||
stays a QByteArray and can be converted using QByteArray.data()
|
||||
- Qt methods that take an extra "bool* ok" parameter can be called passing
|
||||
PythonQt.BoolResult as parameter. In PySide, a tuple is returned instead.
|
||||
|
||||
\page Download Download
|
||||
|
||||
PythonQt is hosted on <a href="http://sourceforge.net/projects/pythonqt/"
|
||||
target="_blank">SourceForge</a>.
|
||||
|
||||
You can download the source code as a tarball at
|
||||
http://sourceforge.net/projects/pythonqt/files/. Alternatively you can get the
|
||||
latest version from the svn repository.
|
||||
|
||||
You can also browse the source code online via ViewVC:
|
||||
http://pythonqt.svn.sourceforge.net/viewvc/pythonqt/trunk/
|
||||
|
||||
\note We do not offer prebuilt binaries, since there are so many possible
|
||||
combinations of platforms (Windows/Linux/MacOs), architectures (32/64 bit) and
|
||||
Qt / Python versions.
|
||||
|
||||
\page License License
|
||||
|
||||
PythonQt is distributed under the LGPL 2.1 license. It can be used in
|
||||
commercial applications when following the LGPL 2.1 obligations.
|
||||
|
||||
The build system of PythonQt makes use of a modified version of the LGPL'ed
|
||||
QtScript generator, located in the "generator" directory.
|
||||
|
||||
See http://qt.gitorious.org/qt-labs/qtscriptgenerator for details on the
|
||||
original project. Thanks a lot to the QtJambi guys and the QtScript Generator
|
||||
project for the C++ parser and Qt typesystem files!
|
||||
|
||||
The PythonQt wrappers generated by the generator located in the "generated_cpp"
|
||||
directory are free to be used without any licensing restrictions.
|
||||
|
||||
The generated wrappers are pre-generated and checked-in for 5.0, 5.3, 5.4
|
||||
and 5.6, so you only need to build and run the generator when you want to build
|
||||
additional wrappers or you want to upgrade/downgrade to another Qt version. You
|
||||
may use the generator to generate C++ bindings for your own C++ classes (e.g.,
|
||||
to make them inheritable in Python), but this is currently not documented and
|
||||
involves creating your own typesystem files.
|
||||
|
||||
\page Developer Developer
|
||||
|
||||
\section Interface Interface
|
||||
|
||||
The main interface to PythonQt is the PythonQt singleton.
|
||||
PythonQt needs to be initialized via PythonQt::init() once.
|
||||
Afterwards you communicate with the singleton via PythonQt::self().
|
||||
PythonQt offers a complete Qt binding, which
|
||||
needs to be enabled via PythonQt_QtAll::init().
|
||||
|
||||
|
||||
\section Datatype Datatype Mapping
|
||||
|
||||
The following table shows the mapping between Python and Qt objects:
|
||||
<table>
|
||||
<tr><th>Qt/C++</th><th>Python</th></tr>
|
||||
<tr><td>bool</td><td>bool</td></tr>
|
||||
<tr><td>double</td><td>float</td></tr>
|
||||
<tr><td>float</td><td>float</td></tr>
|
||||
<tr><td>char/uchar,int/uint,short,ushort,QChar</td><td>integer</td></tr>
|
||||
<tr><td>long</td><td>integer</td></tr>
|
||||
<tr><td>ulong,longlong,ulonglong</td><td>long</td></tr>
|
||||
<tr><td>QString</td><td>unicode string</td></tr>
|
||||
<tr><td>QByteArray</td><td>QByteArray wrapper</td></tr>
|
||||
<tr><td>char*</td><td>str</td></tr>
|
||||
<tr><td>QStringList</td><td>tuple of unicode strings</td></tr>
|
||||
<tr><td>QVariantList</td><td>tuple of objects</td></tr>
|
||||
<tr><td>QVariantMap</td><td>dict of objects</td></tr>
|
||||
<tr><td>QVariant</td><td>depends on type, see below</td></tr>
|
||||
<tr><td>QSize, QRect and all other standard Qt QVariants</td><td>variant
|
||||
wrapper that supports complete API of the respective Qt classes</td></tr>
|
||||
<tr><td>OwnRegisteredMetaType</td><td>C++ wrapper, optionally with additional
|
||||
information/wrapping provided by registerCPPClass()</td></tr>
|
||||
<tr><td>QList<AnyObject*></td><td>converts to a list of CPP wrappers</td></tr>
|
||||
<tr><td>QVector<AnyObject*></td><td>converts to a list of CPP
|
||||
wrappers</td></tr> <tr><td>EnumType</td><td>Enum wrapper derived from python
|
||||
integer</td></tr> <tr><td>QObject (and derived classes)</td><td>QObject
|
||||
wrapper</td></tr> <tr><td>C++ object</td><td>CPP wrapper, either wrapped via
|
||||
PythonQtCppWrapperFactory or just decorated with decorators</td></tr>
|
||||
<tr><td>PyObject</td><td>PyObject</td></tr>
|
||||
</table>
|
||||
|
||||
PyObject is passed as direct pointer, which allows to pass/return any Python
|
||||
object directly to/from a Qt slot that uses PyObject* as its argument/return
|
||||
value. QVariants are mapped recursively as given above, e.g. a dictionary can
|
||||
contain lists of dictionaries of doubles.
|
||||
All Qt QVariant types are implemented, PythonQt supports the complete Qt API
|
||||
for these object.
|
||||
|
||||
\section QObject QObject Wrapping
|
||||
|
||||
All classes derived from QObject are automatically wrapped with a python
|
||||
wrapper class when they become visible to the Python interpreter. This can
|
||||
happen via
|
||||
- the PythonQt::addObject() method
|
||||
- when a Qt \b slot returns a QObject derived object to python
|
||||
- when a Qt \b signal contains a QObject and is connected to a python function
|
||||
|
||||
It is important that you call PythonQt::registerClass() for any QObject derived
|
||||
class that may become visible to Python, except when you add it via
|
||||
PythonQt::addObject(). This will register the complete parent hierachy of the
|
||||
registered class, so that when you register e.g. a QPushButton, QWidget will be
|
||||
registered as well (and all intermediate parents).
|
||||
|
||||
From Python, you can talk to the returned QObjects in a natural way by calling
|
||||
their slots and receiving the return values. You can also read/write all
|
||||
properties of the objects as if they where normal python properties.
|
||||
|
||||
In addition to this, the wrapped objects support
|
||||
- className() - returns a string that reprents the classname of the QObject
|
||||
- help() - shows all properties, slots, enums, decorator slots and constructors
|
||||
of the object, in a printable form
|
||||
- delete() - deletes the object (use with care, especially if you passed the
|
||||
ownership to C++)
|
||||
- connect(signal, function) - connect the signal of the given object to a
|
||||
python function
|
||||
- connect(signal, qobject, slot) - connect the signal of the given object to a
|
||||
slot of another QObject
|
||||
- disconnect(signal, function) - disconnect the signal of the given object from
|
||||
a python function
|
||||
- disconnect(signal, qobject, slot) - disconnect the signal of the given object
|
||||
from a slot of another QObject
|
||||
- children() - returns the children of the object
|
||||
- setParent(QObject) - set the parent
|
||||
- QObject* parent() - get the parent
|
||||
|
||||
The below example shows how to connect signals in Python:
|
||||
|
||||
\code
|
||||
# define a signal handler function
|
||||
def someFunction(flag):
|
||||
print flag
|
||||
|
||||
# button1 is a QPushButton that has been added to Python via addObject()
|
||||
# connect the clicked signal to a python function:
|
||||
button1.connect("clicked(bool)", someFunction)
|
||||
|
||||
\endcode
|
||||
|
||||
\section CPP CPP Wrapping
|
||||
|
||||
You can create dedicated wrapper QObjects for any C++ class. This is done by
|
||||
deriving from PythonQtCppWrapperFactory and adding your factory via
|
||||
addWrapperFactory(). Whenever PythonQt encounters a CPP pointer (e.g. on a slot
|
||||
or signal) and it does not known it as a QObject derived class, it will create a
|
||||
generic CPP wrapper. So even unknown C++ objects can be passed through Python.
|
||||
If the wrapper factory supports the CPP class, a QObject wrapper will be created
|
||||
for each instance that enters Python. An alternative to a complete wrapper via
|
||||
the wrapper factory are decorators, see \ref Decorators
|
||||
|
||||
\section MetaObject Meta Object/Class access
|
||||
|
||||
For each known C++ class, PythonQt provides a Python class. These classes are
|
||||
visible inside of the "PythonQt" python module or in subpackages if a package is
|
||||
given when the class is registered.
|
||||
|
||||
A Meta class supports:
|
||||
|
||||
- access to all declared enum values
|
||||
- constructors
|
||||
- static methods
|
||||
- unbound non-static methods
|
||||
- help() and className()
|
||||
|
||||
From within Python, you can import the module "PythonQt" to access these classes
|
||||
and the Qt namespace.
|
||||
|
||||
\code
|
||||
from PythonQt import QtCore
|
||||
|
||||
# namespace access:
|
||||
print QtCore.Qt.AlignLeft
|
||||
|
||||
# constructors
|
||||
a = QtCore.QSize(12,13)
|
||||
b = QtCore.QFont()
|
||||
|
||||
# static method
|
||||
QtCore.QDate.currentDate()
|
||||
|
||||
# enum value
|
||||
QtCore.QFont.UltraCondensed
|
||||
|
||||
\endcode
|
||||
|
||||
\section Decorators Decorator slots
|
||||
|
||||
PythonQt introduces a new generic approach to extend any wrapped QObject or CPP
|
||||
object with
|
||||
|
||||
- constructors
|
||||
- destructors (for CPP objects)
|
||||
- additional slots
|
||||
- static slots (callable on both the Meta object and the instances)
|
||||
|
||||
The idea behind decorators is that we wanted to make it as easy as possible to
|
||||
extend wrapped objects. Since we already have an implementation for invoking any
|
||||
Qt Slot from Python, it looked promising to use this approach for the extension
|
||||
of wrapped objects as well. This avoids that the PythonQt user needs to care
|
||||
about how Python arguments are mapped from/to Qt when he wants to create static
|
||||
methods, constructors and additional member functions.
|
||||
|
||||
The basic idea about decorators is to create a QObject derived class that
|
||||
implements slots which take one of the above roles (e.g. constructor, destructor
|
||||
etc.) via a naming convention. These slots are then assigned to other classes
|
||||
via the naming convention.
|
||||
|
||||
- SomeClassName* new_SomeClassName(...) - defines a constructor for
|
||||
"SomeClassName" that returns a new object of type SomeClassName (where
|
||||
SomeClassName can be any CPP class, not just QObject classes)
|
||||
- void delete_SomeClassName(SomeClassName* o) - defines a destructor, which
|
||||
should delete the passed in object o
|
||||
- anything static_SomeClassName_someMethodName(...) - defines a static method
|
||||
that is callable on instances and the meta class
|
||||
- anything someMethodName(SomeClassName* o, ...) - defines a slot that will be
|
||||
available on SomeClassName instances (and derived instances). When such a slot
|
||||
is called the first argument is the pointer to the instance and the rest of the
|
||||
arguments can be used to make a call on the instance.
|
||||
|
||||
The below example shows all kinds of decorators in action:
|
||||
|
||||
\code
|
||||
|
||||
// an example CPP object
|
||||
class YourCPPObject {
|
||||
public:
|
||||
YourCPPObject(int arg1, float arg2) { a = arg1; b = arg2; }
|
||||
|
||||
float doSomething(int arg1) { return arg1*a*b; };
|
||||
|
||||
private:
|
||||
|
||||
int a;
|
||||
float b;
|
||||
};
|
||||
|
||||
// an example decorator
|
||||
class ExampleDecorator : public QObject
|
||||
{
|
||||
Q_OBJECT
|
||||
|
||||
public slots:
|
||||
// add a constructor to QSize that takes a QPoint
|
||||
QSize* new_QSize(const QPoint& p) { return new QSize(p.x(), p.y()); }
|
||||
|
||||
// add a constructor for QPushButton that takes a text and a parent widget
|
||||
QPushButton* new_QPushButton(const QString& text, QWidget* parent=NULL) {
|
||||
return new QPushButton(text, parent); }
|
||||
|
||||
// add a constructor for a CPP object
|
||||
YourCPPObject* new_YourCPPObject(int arg1, float arg2) { return new
|
||||
YourCPPObject(arg1, arg2); }
|
||||
|
||||
// add a destructor for a CPP object
|
||||
void delete_YourCPPObject(YourCPPObject* obj) { delete obj; }
|
||||
|
||||
// add a static method to QWidget
|
||||
QWidget* static_QWidget_mouseGrabber() { return QWidget::mouseGrabber(); }
|
||||
|
||||
// add an additional slot to QWidget (make move() callable, which is not
|
||||
declared as a slot in QWidget) void move(QWidget* w, const QPoint& p) {
|
||||
w->move(p); }
|
||||
|
||||
// add an additional slot to QWidget, overloading the above move method
|
||||
void move(QWidget* w, int x, int y) { w->move(x,y); }
|
||||
|
||||
// add a method to your own CPP object
|
||||
int doSomething(YourCPPObject* obj, int arg1) { return obj->doSomething(arg1);
|
||||
}
|
||||
};
|
||||
|
||||
...
|
||||
|
||||
PythonQt::self()->addDecorators(new ExampleDecorator());
|
||||
PythonQt::self()->registerCPPClass("YourCPPObject");
|
||||
|
||||
\endcode
|
||||
|
||||
After you have registered an instance of the above ExampleDecorator, you can do
|
||||
the following from Python (all these calls are mapped to the above decorator
|
||||
slots):
|
||||
|
||||
\code
|
||||
from PythonQt import QtCore, QtGui, YourCPPObject
|
||||
|
||||
# call our new constructor of QSize
|
||||
size = QtCore.QSize(QPoint(1,2));
|
||||
|
||||
# call our new QPushButton constructor
|
||||
button = QtGui.QPushButton("sometext");
|
||||
|
||||
# call the move slot (overload1)
|
||||
button.move(QPoint(0,0))
|
||||
|
||||
# call the move slot (overload2)
|
||||
button.move(0,0)
|
||||
|
||||
# call the static method
|
||||
grabber = QtGui.QWidget.mouseWrapper();
|
||||
|
||||
# create a CPP object via constructor
|
||||
yourCpp = YourCPPObject(1,11.5)
|
||||
|
||||
# call the wrapped method on CPP object
|
||||
print yourCpp.doSomething(1);
|
||||
|
||||
# destructor will be called:
|
||||
yourCpp = None
|
||||
|
||||
\endcode
|
||||
|
||||
\section Ownership Ownership management
|
||||
|
||||
In PythonQt, each wrapped C++ object is either owned by Python or C++. When an
|
||||
object is created via a Python constructor, it is owned by Python by default.
|
||||
When an object is returned from a C++ API (e.g. a slot), it is owned by C++ by
|
||||
default. Since the Qt API contains various APIs that pass the ownership from/to
|
||||
other C++ objects, PythonQt needs to keep track of such API calls. This is
|
||||
archieved by annotating arguments and return values in wrapper slots with magic
|
||||
templates:
|
||||
|
||||
- PythonQtPassOwnershipToCPP
|
||||
- PythonQtPassOwnershipToPython
|
||||
- PythonQtNewOwnerOfThis
|
||||
|
||||
These annotation templates work for since C++ pointer types. In addition to
|
||||
that, they work for QList<AnyObject*>, to pass the ownership for each object in
|
||||
the list.
|
||||
|
||||
Examples:
|
||||
\code
|
||||
public slots:
|
||||
//! Pass ownership of return value to Python
|
||||
PythonQtPassOwnershipToPython<QGraphicsItem*> createNewItemOwnedByPython();
|
||||
|
||||
//! Pass ownership of item to C++
|
||||
void addItemToCPP(PythonQtPassOwnershipToPython<QGraphicsItem*> item);
|
||||
|
||||
//! Pass ownership of items to C++ (Note that the QList can't be a reference
|
||||
nor a pointer). void
|
||||
addItemToCPP(PythonQtPassOwnershipToPython<QList<QGraphicsItem*> > items);
|
||||
|
||||
//! Pass ownership of wrapped object to C++ if parent is != NULL
|
||||
void addItemParent(QGraphicsItem* wrappedObject,
|
||||
PythonQtNewOwnerOfThis<QGraphicsItem*> parent); \endcode
|
||||
|
||||
\page Building Building
|
||||
|
||||
PythonQt requires at least Qt 4.6.1 (for earlier Qt versions, you will need to
|
||||
run the pythonqt_generator, Qt 4.3 is the absolute minimum) and
|
||||
Python 2.6.x/2.7.x or Python 3.3 (or higher). To compile PythonQt, you will need
|
||||
a python developer installation which includes Python's header files and the
|
||||
python2x.[lib | dll | so | dynlib]. The recommended way to build PythonQt is to
|
||||
use the QMake-based *.pro file. The build scripts a currently set to use
|
||||
Python 2.6. You may need to tweak the \b build/python.prf file to set the
|
||||
correct Python includes and libs on your system.
|
||||
|
||||
\subsection Windows
|
||||
|
||||
On Windows, the (non-source) Python Windows installer can be used.
|
||||
Make sure that you use the same compiler as the one that your Python
|
||||
distribution is built with. If you want to use another compiler, you will need
|
||||
to build Python yourself, using your compiler.
|
||||
|
||||
To build PythonQt, you need to set the environment variable \b PYTHON_PATH to
|
||||
point to the root dir of the python installation and \b PYTHON_LIB to point to
|
||||
the directory where the python lib file is located.
|
||||
|
||||
When using the prebuild Python installer, this will be:
|
||||
|
||||
\code
|
||||
> set PYTHON_PATH = c:\Python26
|
||||
> set PYTHON_LIB = c:\Python26\libs
|
||||
\endcode
|
||||
|
||||
When using the python sources, this will be something like:
|
||||
|
||||
\code
|
||||
> set PYTHON_PATH = c:\yourDir\Python-2.6.1\
|
||||
> set PYTHON_LIB = c:\yourDir\Python-2.6.1\PCbuild8\Win32
|
||||
\endcode
|
||||
|
||||
To build all, do the following (after setting the above variables):
|
||||
|
||||
\code
|
||||
> cd PythonQtRoot
|
||||
> vcvars32
|
||||
> qmake
|
||||
> nmake
|
||||
\endcode
|
||||
|
||||
This should build everything. If Python can not be linked or include files can
|
||||
not be found, you probably need to tweak \b build/python.prf
|
||||
|
||||
The tests and examples are located in PythonQt/lib.
|
||||
|
||||
When using a Python distribution, the debug build typically does not work
|
||||
because the pythonxx_d.lib/.dll are not provided. You can tweak linking of the
|
||||
debug build to the release Python version, but this typically requires patching
|
||||
pyconfig.h and removing Py_DEBUG and linker pragmas (google for it!).
|
||||
|
||||
\subsection Linux
|
||||
|
||||
On Linux, you need to install a Python-dev package.
|
||||
If Python can not be linked or include files can not be found,
|
||||
you probably need to tweak \b build/python.prf
|
||||
|
||||
To build PythonQt, just do a:
|
||||
|
||||
\code
|
||||
> cd PythonQtRoot
|
||||
> qmake
|
||||
> make all
|
||||
\endcode
|
||||
|
||||
The tests and examples are located in PythonQt/lib.
|
||||
You should add PythonQt/lib to your LD_LIBRARY_PATH so that the runtime
|
||||
linker can find the *.so files.
|
||||
|
||||
\subsection MacOsX
|
||||
|
||||
On Mac, Python is installed as a Framework, so you should not need to install
|
||||
it. To build PythonQt, just do a:
|
||||
|
||||
\code
|
||||
> cd PythonQtRoot
|
||||
> qmake
|
||||
> make all
|
||||
\endcode
|
||||
|
||||
\section Tests
|
||||
|
||||
There is a unit test that tests most features of PythonQt, see the \b tests
|
||||
subdirectory for details.
|
||||
|
||||
\page Examples Examples
|
||||
|
||||
Examples are available in the \b examples directory. The PyScriptingConsole
|
||||
implements a simple interactive scripting console that shows how to script a
|
||||
simple application. The PyLauncher application can be used to run arbitrary
|
||||
PythonQt scripts given on the commandline.
|
||||
|
||||
The following shows a simple example on how to integrate PythonQt into your Qt
|
||||
application:
|
||||
|
||||
\code
|
||||
#include "PythonQt.h"
|
||||
#include <QApplication>
|
||||
...
|
||||
|
||||
int main( int argc, char **argv )
|
||||
{
|
||||
|
||||
QApplication qapp(argc, argv);
|
||||
|
||||
// init PythonQt and Python itself
|
||||
PythonQt::init();
|
||||
|
||||
// get a smart pointer to the __main__ module of the Python interpreter
|
||||
PythonQtObjectPtr context = PythonQt::self()->getMainModule();
|
||||
|
||||
// add a QObject as variable of name "example" to the namespace of the
|
||||
__main__ module PyExampleObject example; context.addObject("example", &example);
|
||||
|
||||
// do something
|
||||
context.evalScript("print example");
|
||||
context.evalScript("def multiply(a,b):\n return a*b;\n");
|
||||
QVariantList args;
|
||||
args << 42 << 47;
|
||||
QVariant result = context.call("multiply", args);
|
||||
...
|
||||
\endcode
|
||||
|
||||
|
||||
*/
|
||||
|
||||
#endif
|
|
@ -0,0 +1,81 @@
|
|||
#ifndef _PYTHONQTIMPORTFILEINTERFACE_H
|
||||
#define _PYTHONQTIMPORTFILEINTERFACE_H
|
||||
|
||||
/*
|
||||
*
|
||||
* Copyright (C) 2010 MeVis Medical Solutions AG All Rights Reserved.
|
||||
*
|
||||
* This library is free software; you can redistribute it and/or
|
||||
* modify it under the terms of the GNU Lesser General Public
|
||||
* License as published by the Free Software Foundation; either
|
||||
* version 2.1 of the License, or (at your option) any later version.
|
||||
*
|
||||
* This library is distributed in the hope that it will be useful,
|
||||
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
|
||||
* Lesser General Public License for more details.
|
||||
*
|
||||
* Further, this software is distributed without any warranty that it is
|
||||
* free of the rightful claim of any third person regarding infringement
|
||||
* or the like. Any license provided herein, whether implied or
|
||||
* otherwise, applies only to this software file. Patent licenses, if
|
||||
* any, provided herein do not apply to combinations of this program with
|
||||
* other software, or any other product whatsoever.
|
||||
*
|
||||
* You should have received a copy of the GNU Lesser General Public
|
||||
* License along with this library; if not, write to the Free Software
|
||||
* Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
|
||||
*
|
||||
* Contact information: MeVis Medical Solutions AG, Universitaetsallee 29,
|
||||
* 28359 Bremen, Germany or:
|
||||
*
|
||||
* http://www.mevis.de
|
||||
*
|
||||
*/
|
||||
|
||||
//----------------------------------------------------------------------------------
|
||||
/*!
|
||||
// \file PythonQtImportFileInterface.h
|
||||
// \author Florian Link
|
||||
// \author Last changed by $Author: florian $
|
||||
// \date 2006-05
|
||||
*/
|
||||
//----------------------------------------------------------------------------------
|
||||
|
||||
#include <QDateTime>
|
||||
#include <QString>
|
||||
#include <QByteArray>
|
||||
|
||||
//! Defines an abstract interface to file access for the Python import statement.
|
||||
//! see PythonQt::setImporter()
|
||||
class PythonQtImportFileInterface {
|
||||
|
||||
public:
|
||||
// get rid of warnings
|
||||
virtual ~PythonQtImportFileInterface() {}
|
||||
|
||||
//! read the given file as byte array, without doing any linefeed translations
|
||||
virtual QByteArray readFileAsBytes(const QString& filename) = 0;
|
||||
|
||||
//! read a source file, expects a readable Python text file with translated line feeds.
|
||||
//! If the file can not be load OR it can not be verified, ok is set to false
|
||||
virtual QByteArray readSourceFile(const QString& filename, bool& ok) = 0;
|
||||
|
||||
//! returns if the file exists
|
||||
virtual bool exists(const QString& filename) = 0;
|
||||
|
||||
//! get the last modified data of a file
|
||||
virtual QDateTime lastModifiedDate(const QString& filename) = 0;
|
||||
|
||||
//! indicates that *.py files which are newer than their corresponding *.pyc files
|
||||
//! are ignored
|
||||
virtual bool ignoreUpdatedPythonSourceFiles() { return false; }
|
||||
|
||||
//! called by PythonQt after successful import to allow
|
||||
//! recording of imports
|
||||
virtual void importedModule(const QString& /*module*/) {};
|
||||
|
||||
};
|
||||
|
||||
#endif
|
||||
|
|
@ -0,0 +1,146 @@
|
|||
#ifndef _PYTHONQTIMPORTER_
|
||||
#define _PYTHONQTIMPORTER_
|
||||
|
||||
/*
|
||||
*
|
||||
* Copyright (C) 2010 MeVis Medical Solutions AG All Rights Reserved.
|
||||
*
|
||||
* This library is free software; you can redistribute it and/or
|
||||
* modify it under the terms of the GNU Lesser General Public
|
||||
* License as published by the Free Software Foundation; either
|
||||
* version 2.1 of the License, or (at your option) any later version.
|
||||
*
|
||||
* This library is distributed in the hope that it will be useful,
|
||||
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
|
||||
* Lesser General Public License for more details.
|
||||
*
|
||||
* Further, this software is distributed without any warranty that it is
|
||||
* free of the rightful claim of any third person regarding infringement
|
||||
* or the like. Any license provided herein, whether implied or
|
||||
* otherwise, applies only to this software file. Patent licenses, if
|
||||
* any, provided herein do not apply to combinations of this program with
|
||||
* other software, or any other product whatsoever.
|
||||
*
|
||||
* You should have received a copy of the GNU Lesser General Public
|
||||
* License along with this library; if not, write to the Free Software
|
||||
* Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
|
||||
*
|
||||
* Contact information: MeVis Medical Solutions AG, Universitaetsallee 29,
|
||||
* 28359 Bremen, Germany or:
|
||||
*
|
||||
* http://www.mevis.de
|
||||
*
|
||||
*/
|
||||
|
||||
//----------------------------------------------------------------------------------
|
||||
/*!
|
||||
// \file PythonQtImporter.h
|
||||
// \author Florian Link
|
||||
// \author Last changed by $Author: stk $
|
||||
// \date 2004-06
|
||||
*/
|
||||
//----------------------------------------------------------------------------------
|
||||
|
||||
#include "PythonQtPythonInclude.h"
|
||||
|
||||
#include "structmember.h"
|
||||
#include "osdefs.h"
|
||||
#include "marshal.h"
|
||||
#include "compile.h"
|
||||
#include <time.h>
|
||||
|
||||
#include <qobject.h>
|
||||
#include <qstring.h>
|
||||
|
||||
|
||||
//! defines a python object that stores a Qt slot info
|
||||
typedef struct _PythonQtImporter {
|
||||
PyObject_HEAD
|
||||
QString* _path;
|
||||
} PythonQtImporter;
|
||||
|
||||
|
||||
//! implements importing of python files into PythonQt
|
||||
/*! also compiles/marshalls/unmarshalls py/pyc files and handles time stamps correctly
|
||||
*/
|
||||
class PythonQtImport
|
||||
{
|
||||
public:
|
||||
|
||||
enum ModuleType {
|
||||
MI_NOT_FOUND,
|
||||
MI_MODULE,
|
||||
MI_PACKAGE,
|
||||
MI_SHAREDLIBRARY
|
||||
};
|
||||
|
||||
struct ModuleInfo {
|
||||
ModuleInfo() {
|
||||
type = MI_NOT_FOUND;
|
||||
}
|
||||
QString fullPath; //!< the full path to the found file
|
||||
QString moduleName; //!< the module name without the package prefix
|
||||
ModuleType type;
|
||||
};
|
||||
|
||||
//! initialize
|
||||
static void init();
|
||||
|
||||
//! writes the python code to disk, marshalling and writing the time stamp
|
||||
static void writeCompiledModule(PyCodeObject *co, const QString& filename, long mtime, long sourceSize);
|
||||
|
||||
/*! Given the contents of a .py[co] file in a buffer, unmarshal the data
|
||||
and return the code object. Return None if it the magic word doesn't
|
||||
match (we do this instead of raising an exception as we fall back
|
||||
to .py if available and we don't want to mask other errors).
|
||||
Returns a new reference. */
|
||||
static PyObject *unmarshalCode(const QString& path, const QByteArray& data, time_t mtime);
|
||||
|
||||
//! Given a string buffer containing Python source code, compile it
|
||||
//! return and return a code object as a new reference.
|
||||
static PyObject *compileSource(const QString& path, const QByteArray& data);
|
||||
|
||||
//! Return the code object for the module named by 'fullname' from the
|
||||
//! Zip archive as a new reference.
|
||||
static PyObject *getCodeFromData(const QString& path, int isbytecode = 0, int ispackage = 0,
|
||||
time_t mtime = 0);
|
||||
|
||||
//! Get the code object associated with the module specified by
|
||||
//! 'fullname'. In Python3, modpath will always be the path to the *.py file and cachemodpath the path
|
||||
//! to the *.pyc file (if it exists).
|
||||
static PyObject * getModuleCode(PythonQtImporter *self,
|
||||
const char* fullname, QString& modpath, QString& cachemodpath);
|
||||
|
||||
|
||||
//! gets the compiled code for the given *.py file if there is a valid pyc file, otherwise compiles the file and writes the pyc
|
||||
static PyObject* getCodeFromPyc(const QString& file);
|
||||
|
||||
//! Return if module exists and is a package or a module
|
||||
static ModuleInfo getModuleInfo(PythonQtImporter* self, const QString& fullname);
|
||||
|
||||
//! get the last name of a dot chain (first.second.last)
|
||||
static QString getSubName(const QString& str);
|
||||
|
||||
//! Given a buffer, return the long that is represented by the first
|
||||
//! 4 bytes, encoded as little endian. This partially reimplements
|
||||
//! marshal.c:r_long()
|
||||
static long getLong(unsigned char *buf);
|
||||
|
||||
//! get time stamp of file
|
||||
static time_t getMTimeOfSource(const QString& path);
|
||||
|
||||
//! replace extension of file
|
||||
static QString replaceExtension(const QString& str, const QString& ext);
|
||||
|
||||
//! Returns the filename of the cache file for the given source file, e.g. test.pyc for test.py.
|
||||
//! Python 3 places cache files inside a __pycache__ directory, this also handled here.
|
||||
static QString getCacheFilename(const QString& sourceFile, bool isOptimizedFilename);
|
||||
|
||||
//! Returns the filename of the source file for the given cache file, e.g. test.py for test.pyc.
|
||||
//! Python 3 places cache files inside a __pycache__ directory, this also handled here.
|
||||
static QString getSourceFilename(const QString& cacheFile);
|
||||
};
|
||||
|
||||
#endif
|
||||
|
|
@ -0,0 +1,136 @@
|
|||
#ifndef _PYTHONQTINSTANCEWRAPPER_H
|
||||
#define _PYTHONQTINSTANCEWRAPPER_H
|
||||
|
||||
/*
|
||||
*
|
||||
* Copyright (C) 2010 MeVis Medical Solutions AG All Rights Reserved.
|
||||
*
|
||||
* This library is free software; you can redistribute it and/or
|
||||
* modify it under the terms of the GNU Lesser General Public
|
||||
* License as published by the Free Software Foundation; either
|
||||
* version 2.1 of the License, or (at your option) any later version.
|
||||
*
|
||||
* This library is distributed in the hope that it will be useful,
|
||||
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
|
||||
* Lesser General Public License for more details.
|
||||
*
|
||||
* Further, this software is distributed without any warranty that it is
|
||||
* free of the rightful claim of any third person regarding infringement
|
||||
* or the like. Any license provided herein, whether implied or
|
||||
* otherwise, applies only to this software file. Patent licenses, if
|
||||
* any, provided herein do not apply to combinations of this program with
|
||||
* other software, or any other product whatsoever.
|
||||
*
|
||||
* You should have received a copy of the GNU Lesser General Public
|
||||
* License along with this library; if not, write to the Free Software
|
||||
* Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
|
||||
*
|
||||
* Contact information: MeVis Medical Solutions AG, Universitaetsallee 29,
|
||||
* 28359 Bremen, Germany or:
|
||||
*
|
||||
* http://www.mevis.de
|
||||
*
|
||||
*/
|
||||
|
||||
//----------------------------------------------------------------------------------
|
||||
/*!
|
||||
// \file PythonQtInstanceWrapper.h
|
||||
// \author Florian Link
|
||||
// \author Last changed by $Author: florian $
|
||||
// \date 2006-05
|
||||
*/
|
||||
//----------------------------------------------------------------------------------
|
||||
|
||||
#include "PythonQtPythonInclude.h"
|
||||
|
||||
#include "PythonQtSystem.h"
|
||||
#include "PythonQtClassWrapper.h"
|
||||
#include <QPointer>
|
||||
|
||||
#include "structmember.h"
|
||||
#include "methodobject.h"
|
||||
#include "compile.h"
|
||||
#include "eval.h"
|
||||
|
||||
class PythonQtClassInfo;
|
||||
class QObject;
|
||||
|
||||
extern PYTHONQT_EXPORT PyTypeObject PythonQtInstanceWrapper_Type;
|
||||
|
||||
//---------------------------------------------------------------
|
||||
//! a Python wrapper object for Qt objects and C++ objects (that are themselves wrapped by wrapper QObjects)
|
||||
typedef struct PythonQtInstanceWrapperStruct {
|
||||
PyObject_HEAD
|
||||
|
||||
//! the class information, this is set even if the _obj or _wrappedPtr is NULL to support typed NULL pointers
|
||||
inline PythonQtClassInfo* classInfo()
|
||||
{ return ((PythonQtClassWrapper*)Py_TYPE(this))->_classInfo; }
|
||||
|
||||
inline PythonQtDynamicClassInfo* dynamicClassInfo()
|
||||
{ return ((PythonQtClassWrapper*)Py_TYPE(this))->_dynamicClassInfo; }
|
||||
|
||||
//! set the QObject pointer
|
||||
void setQObject(QObject* object) {
|
||||
_obj = object;
|
||||
_objPointerCopy = object;
|
||||
}
|
||||
|
||||
//! Passes the ownership of the wrapped object to C++
|
||||
void passOwnershipToCPP() {
|
||||
// we pass the ownership to C++
|
||||
_ownedByPythonQt = false;
|
||||
// handle shell instance
|
||||
if (_isShellInstance) {
|
||||
if (!_shellInstanceRefCountsWrapper) {
|
||||
// ref count the wrapper, so that the Python part of the shell instance can not go
|
||||
// away until the C++ object gets deleted...
|
||||
Py_INCREF((PyObject*)this);
|
||||
_shellInstanceRefCountsWrapper = true;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
//! Passes the ownership to Python
|
||||
void passOwnershipToPython() {
|
||||
_ownedByPythonQt = true;
|
||||
// if the shell instance was owned by C++ and the ownership goes to Python,
|
||||
// we need to remove the extra ref count that kept the Python part alive from the C++ side.
|
||||
if (_shellInstanceRefCountsWrapper) {
|
||||
Py_DECREF((PyObject*)this);
|
||||
_shellInstanceRefCountsWrapper = false;
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
//! pointer to the wrapped Qt object or if _wrappedPtr is set, the Qt object that wraps the C++ Ptr
|
||||
QPointer<QObject> _obj;
|
||||
//! a copy of the _obj pointer, which is required because the wrapper needs to
|
||||
//! deregister itself via the _obj pointer, even when the QPointer<QObject> object was destroyed
|
||||
void* _objPointerCopy;
|
||||
|
||||
//! optional C++ object Ptr that is wrapped by the above _obj
|
||||
void* _wrappedPtr;
|
||||
|
||||
// TODO xxx: put booleans into int that holds flags
|
||||
|
||||
//! flag that stores if the object is owned by pythonQt
|
||||
bool _ownedByPythonQt;
|
||||
|
||||
//! stores that the owned object should be destroyed using QMetaType::destroy()
|
||||
bool _useQMetaTypeDestroy;
|
||||
|
||||
//! stores if the object is a shell instance
|
||||
bool _isShellInstance;
|
||||
|
||||
//! stores if the shell instance (C++) owns the wrapper with its ref count
|
||||
bool _shellInstanceRefCountsWrapper;
|
||||
|
||||
} PythonQtInstanceWrapper;
|
||||
|
||||
int PythonQtInstanceWrapper_init(PythonQtInstanceWrapper * self, PyObject * args, PyObject * kwds);
|
||||
|
||||
PyObject *PythonQtInstanceWrapper_delete(PythonQtInstanceWrapper * self);
|
||||
|
||||
#endif
|
||||
|
|
@ -0,0 +1,227 @@
|
|||
#ifndef _PYTHONQTMETHODINFO_H
|
||||
#define _PYTHONQTMETHODINFO_H
|
||||
|
||||
/*
|
||||
*
|
||||
* Copyright (C) 2010 MeVis Medical Solutions AG All Rights Reserved.
|
||||
*
|
||||
* This library is free software; you can redistribute it and/or
|
||||
* modify it under the terms of the GNU Lesser General Public
|
||||
* License as published by the Free Software Foundation; either
|
||||
* version 2.1 of the License, or (at your option) any later version.
|
||||
*
|
||||
* This library is distributed in the hope that it will be useful,
|
||||
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
|
||||
* Lesser General Public License for more details.
|
||||
*
|
||||
* Further, this software is distributed without any warranty that it is
|
||||
* free of the rightful claim of any third person regarding infringement
|
||||
* or the like. Any license provided herein, whether implied or
|
||||
* otherwise, applies only to this software file. Patent licenses, if
|
||||
* any, provided herein do not apply to combinations of this program with
|
||||
* other software, or any other product whatsoever.
|
||||
*
|
||||
* You should have received a copy of the GNU Lesser General Public
|
||||
* License along with this library; if not, write to the Free Software
|
||||
* Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
|
||||
*
|
||||
* Contact information: MeVis Medical Solutions AG, Universitaetsallee 29,
|
||||
* 28359 Bremen, Germany or:
|
||||
*
|
||||
* http://www.mevis.de
|
||||
*
|
||||
*/
|
||||
|
||||
//----------------------------------------------------------------------------------
|
||||
/*!
|
||||
// \file PythonQtMethodInfo.h
|
||||
// \author Florian Link
|
||||
// \author Last changed by $Author: florian $
|
||||
// \date 2006-05
|
||||
*/
|
||||
//----------------------------------------------------------------------------------
|
||||
|
||||
#include "PythonQtSystem.h"
|
||||
|
||||
#include <QByteArray>
|
||||
#include <QHash>
|
||||
#include <QList>
|
||||
#include <QMetaMethod>
|
||||
|
||||
class PythonQtClassInfo;
|
||||
struct _object;
|
||||
typedef struct _object PyObject;
|
||||
|
||||
//! stores information about a specific signal/slot/method
|
||||
class PYTHONQT_EXPORT PythonQtMethodInfo
|
||||
{
|
||||
public:
|
||||
enum ParameterType {
|
||||
Unknown = -1,
|
||||
Variant = -2
|
||||
};
|
||||
|
||||
//! stores various informations about a parameter/type name
|
||||
struct ParameterInfo {
|
||||
QByteArray name;
|
||||
QByteArray innerName; // if the type is a template, this stores the inner name
|
||||
PyObject* enumWrapper; // if it is an enum, a pointer to the enum wrapper
|
||||
int typeId; // a mixture from QMetaType and ParameterType
|
||||
char pointerCount; // the number of pointer indirections
|
||||
char innerNamePointerCount; // the number of pointer indirections in the inner name
|
||||
bool isConst;
|
||||
bool isReference;
|
||||
bool isQList;
|
||||
bool passOwnershipToCPP;
|
||||
bool passOwnershipToPython;
|
||||
bool newOwnerOfThis;
|
||||
};
|
||||
|
||||
PythonQtMethodInfo() {};
|
||||
~PythonQtMethodInfo() {};
|
||||
PythonQtMethodInfo(const QMetaMethod& meta, PythonQtClassInfo* classInfo);
|
||||
PythonQtMethodInfo(const QByteArray& typeName, const QList<QByteArray>& args);
|
||||
PythonQtMethodInfo(const PythonQtMethodInfo& other) {
|
||||
_parameters = other._parameters;
|
||||
}
|
||||
|
||||
//! returns the method info of the signature, uses a cache internally to speed up
|
||||
//! multiple requests for the same method, classInfo is passed to allow local enum resolution (if NULL is passed, no local enums are recognized)
|
||||
static const PythonQtMethodInfo* getCachedMethodInfo(const QMetaMethod& method, PythonQtClassInfo* classInfo);
|
||||
|
||||
//! get the cached method info using the passed in list of return value and arguments, return value needs to be passed as first arg
|
||||
static const PythonQtMethodInfo* getCachedMethodInfoFromArgumentList(int numArgs, const char** args);
|
||||
|
||||
//! cleanup the cache
|
||||
static void cleanupCachedMethodInfos();
|
||||
|
||||
//! returns the number of parameters including the return value
|
||||
int parameterCount() const { return _parameters.size(); };
|
||||
|
||||
//! returns the id for the given type (using an internal dictionary)
|
||||
static int nameToType(const char* name);
|
||||
|
||||
//! get the parameter infos
|
||||
const QList<ParameterInfo>& parameters() const { return _parameters; }
|
||||
|
||||
//! add an alias for a typename, e.g. QObjectList and QList<QObject*>.
|
||||
static void addParameterTypeAlias(const QByteArray& alias, const QByteArray& name);
|
||||
|
||||
//! fill the parameter info for the given type name
|
||||
static void fillParameterInfo(ParameterInfo& type, const QByteArray& name, PythonQtClassInfo* classInfo = NULL);
|
||||
|
||||
//! returns a parameter info for the given metatype (and creates and caches one if it is not yet present)
|
||||
static const ParameterInfo& getParameterInfoForMetaType(int type);
|
||||
|
||||
//! returns the inner type id of a simple template of the form SomeObject<InnerType>
|
||||
static int getInnerTemplateMetaType(const QByteArray& typeName);
|
||||
|
||||
//! returns the inner type name of a simple template of the form SomeObject<InnerType>
|
||||
static QByteArray getInnerTemplateTypeName(const QByteArray& typeName);
|
||||
|
||||
//! returns the inner type name of a simple template or the typename without appended "List".
|
||||
static QByteArray getInnerListTypeName(const QByteArray& typeName);
|
||||
|
||||
protected:
|
||||
|
||||
static QHash<QByteArray, int> _parameterTypeDict;
|
||||
static QHash<QByteArray, QByteArray> _parameterNameAliases;
|
||||
|
||||
//! stores the cached signatures of methods to speedup mapping from Qt to Python types
|
||||
static QHash<QByteArray, PythonQtMethodInfo*> _cachedSignatures;
|
||||
|
||||
static QHash<int, ParameterInfo> _cachedParameterInfos;
|
||||
|
||||
QList<ParameterInfo> _parameters;
|
||||
};
|
||||
|
||||
//! stores information about a slot, including a next pointer to overloaded slots
|
||||
class PYTHONQT_EXPORT PythonQtSlotInfo : public PythonQtMethodInfo
|
||||
{
|
||||
public:
|
||||
enum Type {
|
||||
MemberSlot, InstanceDecorator, ClassDecorator
|
||||
};
|
||||
|
||||
PythonQtSlotInfo(const PythonQtSlotInfo& info):PythonQtMethodInfo() {
|
||||
_meta = info._meta;
|
||||
_parameters = info._parameters;
|
||||
_slotIndex = info._slotIndex;
|
||||
_next = NULL;
|
||||
_decorator = info._decorator;
|
||||
_type = info._type;
|
||||
_upcastingOffset = 0;
|
||||
}
|
||||
|
||||
PythonQtSlotInfo(PythonQtClassInfo* classInfo, const QMetaMethod& meta, int slotIndex, QObject* decorator = NULL, Type type = MemberSlot ):PythonQtMethodInfo()
|
||||
{
|
||||
const PythonQtMethodInfo* info = getCachedMethodInfo(meta, classInfo);
|
||||
_meta = meta;
|
||||
_parameters = info->parameters();
|
||||
_slotIndex = slotIndex;
|
||||
_next = NULL;
|
||||
_decorator = decorator;
|
||||
_type = type;
|
||||
_upcastingOffset = 0;
|
||||
}
|
||||
|
||||
|
||||
public:
|
||||
//! get the parameter infos for the arguments, without return type and instance decorator.
|
||||
QList<ParameterInfo> arguments() const;
|
||||
|
||||
void deleteOverloadsAndThis();
|
||||
|
||||
const QMetaMethod* metaMethod() const { return &_meta; }
|
||||
|
||||
void setUpcastingOffset(int upcastingOffset) { _upcastingOffset = upcastingOffset; }
|
||||
|
||||
int upcastingOffset() const { return _upcastingOffset; }
|
||||
|
||||
//! get the index of the slot (needed for qt_metacall)
|
||||
int slotIndex() const { return _slotIndex; }
|
||||
|
||||
//! get next overloaded slot (which has the same name)
|
||||
PythonQtSlotInfo* nextInfo() const { return _next; }
|
||||
|
||||
//! set the next overloaded slot
|
||||
void setNextInfo(PythonQtSlotInfo* next) { _next = next; }
|
||||
|
||||
//! returns if the slot is a decorator slot
|
||||
bool isInstanceDecorator() const { return _decorator!=NULL && _type == InstanceDecorator; }
|
||||
|
||||
//! returns if the slot is a constructor slot
|
||||
bool isClassDecorator() const { return _decorator!=NULL && _type == ClassDecorator; }
|
||||
|
||||
QObject* decorator() const { return _decorator; }
|
||||
|
||||
//! get the full signature including return type
|
||||
QString fullSignature(bool skipReturnValue = false, int optionalArgsIndex = -1) const;
|
||||
|
||||
//! get the Qt signature of the slot
|
||||
QByteArray signature() const;
|
||||
|
||||
//! get the short slot name
|
||||
QByteArray slotName(bool removeDecorators = false) const;
|
||||
|
||||
//! gets a list of all overload signatures. Signatures
|
||||
//! which only differ because of default values are joined using "[]" to
|
||||
//! indicate the optional arguments.
|
||||
QStringList overloads(bool skipReturnValue = false) const;
|
||||
|
||||
//! Returns the class name that originally implements this method,
|
||||
//! regardless where the wrapper is located/implemented.
|
||||
QByteArray getImplementingClassName() const;
|
||||
|
||||
private:
|
||||
int _slotIndex;
|
||||
PythonQtSlotInfo* _next;
|
||||
QObject* _decorator;
|
||||
Type _type;
|
||||
QMetaMethod _meta;
|
||||
int _upcastingOffset;
|
||||
};
|
||||
|
||||
|
||||
#endif
|
|
@ -0,0 +1,178 @@
|
|||
#ifndef PYTHONQTMISC_H
|
||||
#define PYTHONQTMISC_H
|
||||
|
||||
/*
|
||||
*
|
||||
* Copyright (C) 2010 MeVis Medical Solutions AG All Rights Reserved.
|
||||
*
|
||||
* This library is free software; you can redistribute it and/or
|
||||
* modify it under the terms of the GNU Lesser General Public
|
||||
* License as published by the Free Software Foundation; either
|
||||
* version 2.1 of the License, or (at your option) any later version.
|
||||
*
|
||||
* This library is distributed in the hope that it will be useful,
|
||||
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
|
||||
* Lesser General Public License for more details.
|
||||
*
|
||||
* Further, this software is distributed without any warranty that it is
|
||||
* free of the rightful claim of any third person regarding infringement
|
||||
* or the like. Any license provided herein, whether implied or
|
||||
* otherwise, applies only to this software file. Patent licenses, if
|
||||
* any, provided herein do not apply to combinations of this program with
|
||||
* other software, or any other product whatsoever.
|
||||
*
|
||||
* You should have received a copy of the GNU Lesser General Public
|
||||
* License along with this library; if not, write to the Free Software
|
||||
* Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
|
||||
*
|
||||
* Contact information: MeVis Medical Solutions AG, Universitaetsallee 29,
|
||||
* 28359 Bremen, Germany or:
|
||||
*
|
||||
* http://www.mevis.de
|
||||
*
|
||||
*/
|
||||
|
||||
//----------------------------------------------------------------------------------
|
||||
/*!
|
||||
// \file PythonQtMisc.h
|
||||
// \author Florian Link
|
||||
// \author Last changed by $Author: florian $
|
||||
// \date 2006-05
|
||||
*/
|
||||
//----------------------------------------------------------------------------------
|
||||
|
||||
#include <QList>
|
||||
|
||||
#define PythonQtValueStorage_ADD_VALUE(store, type, value, ptr) \
|
||||
{ \
|
||||
type *item = (type *)store.nextValuePtr(); \
|
||||
*item = value; \
|
||||
ptr = (void *)item; \
|
||||
}
|
||||
|
||||
#define PythonQtValueStorage_ADD_VALUE_IF_NEEDED(alreadyAllocatedPtr, store, \
|
||||
type, value, ptr) \
|
||||
{ \
|
||||
type *item = (type *)(alreadyAllocatedPtr ? alreadyAllocatedPtr \
|
||||
: store.nextValuePtr()); \
|
||||
*item = value; \
|
||||
ptr = (void *)item; \
|
||||
}
|
||||
|
||||
//! stores a position in the PythonQtValueStorage
|
||||
class PythonQtValueStoragePosition {
|
||||
|
||||
public:
|
||||
PythonQtValueStoragePosition() {
|
||||
chunkIdx = 0;
|
||||
chunkOffset = 0;
|
||||
}
|
||||
|
||||
int chunkIdx;
|
||||
int chunkOffset;
|
||||
};
|
||||
|
||||
//! a helper class that stores basic C++ value types in chunks
|
||||
template <typename T, int chunkEntries> class PythonQtValueStorage {
|
||||
public:
|
||||
PythonQtValueStorage() {
|
||||
_chunkIdx = 0;
|
||||
_chunkOffset = 0;
|
||||
_currentChunk = new T[chunkEntries];
|
||||
_chunks.append(_currentChunk);
|
||||
}
|
||||
|
||||
//! clear all memory
|
||||
void clear() {
|
||||
T *chunk;
|
||||
Q_FOREACH (chunk, _chunks) { delete[] chunk; }
|
||||
_chunks.clear();
|
||||
}
|
||||
|
||||
//! get the current position to be restored with setPos
|
||||
void getPos(PythonQtValueStoragePosition &pos) {
|
||||
pos.chunkIdx = _chunkIdx;
|
||||
pos.chunkOffset = _chunkOffset;
|
||||
}
|
||||
|
||||
//! set the current position (without freeing memory, thus caching old entries
|
||||
//! for reuse)
|
||||
void setPos(const PythonQtValueStoragePosition &pos) {
|
||||
_chunkOffset = pos.chunkOffset;
|
||||
if (_chunkIdx != pos.chunkIdx) {
|
||||
_chunkIdx = pos.chunkIdx;
|
||||
_currentChunk = _chunks.at(_chunkIdx);
|
||||
}
|
||||
}
|
||||
|
||||
//! add one default constructed value and return the pointer to it
|
||||
T *nextValuePtr() {
|
||||
if (_chunkOffset >= chunkEntries) {
|
||||
_chunkIdx++;
|
||||
if (_chunkIdx >= _chunks.size()) {
|
||||
T *newChunk = new T[chunkEntries];
|
||||
_chunks.append(newChunk);
|
||||
_currentChunk = newChunk;
|
||||
} else {
|
||||
_currentChunk = _chunks.at(_chunkIdx);
|
||||
}
|
||||
_chunkOffset = 0;
|
||||
}
|
||||
T *newEntry = _currentChunk + _chunkOffset;
|
||||
_chunkOffset++;
|
||||
return newEntry;
|
||||
}
|
||||
|
||||
protected:
|
||||
QList<T *> _chunks;
|
||||
|
||||
int _chunkIdx;
|
||||
int _chunkOffset;
|
||||
T *_currentChunk;
|
||||
};
|
||||
|
||||
//! a helper class that stores basic C++ value types in chunks and clears the
|
||||
//! unused values on setPos() usage.
|
||||
template <typename T, int chunkEntries>
|
||||
class PythonQtValueStorageWithCleanup
|
||||
: public PythonQtValueStorage<T, chunkEntries> {
|
||||
public:
|
||||
void setPos(const PythonQtValueStoragePosition &pos) {
|
||||
if (_chunkIdx > pos.chunkIdx) {
|
||||
T *firstChunk = _chunks.at(pos.chunkIdx);
|
||||
// clear region in first chunk
|
||||
for (int i = pos.chunkOffset; i < chunkEntries; i++) {
|
||||
firstChunk[i] = T();
|
||||
}
|
||||
for (int chunk = pos.chunkIdx + 1; chunk < _chunkIdx; chunk++) {
|
||||
// clear the full chunks between the first and last chunk
|
||||
T *fullChunk = _chunks.at(chunk);
|
||||
for (int i = 0; i < chunkEntries; i++) {
|
||||
fullChunk[i] = T();
|
||||
}
|
||||
}
|
||||
// clear region in last chunk
|
||||
T *lastChunk = _chunks.at(_chunkIdx);
|
||||
for (int i = 0; i < _chunkOffset; i++) {
|
||||
lastChunk[i] = T();
|
||||
}
|
||||
} else if (_chunkIdx == pos.chunkIdx) {
|
||||
// clear the region in the last chunk only
|
||||
T *lastChunk = _chunks.at(_chunkIdx);
|
||||
for (int i = pos.chunkOffset; i < _chunkOffset; i++) {
|
||||
lastChunk[i] = T();
|
||||
}
|
||||
}
|
||||
|
||||
PythonQtValueStorage<T, chunkEntries>::setPos(pos);
|
||||
}
|
||||
|
||||
private:
|
||||
using PythonQtValueStorage<T, chunkEntries>::_chunks;
|
||||
using PythonQtValueStorage<T, chunkEntries>::_chunkIdx;
|
||||
using PythonQtValueStorage<T, chunkEntries>::_chunkOffset;
|
||||
using PythonQtValueStorage<T, chunkEntries>::_currentChunk;
|
||||
};
|
||||
|
||||
#endif
|
|
@ -0,0 +1,164 @@
|
|||
#ifndef PYTHONQTOBJECTPTR_H
|
||||
#define PYTHONQTOBJECTPTR_H
|
||||
|
||||
/*
|
||||
*
|
||||
* Copyright (C) 2010 MeVis Medical Solutions AG All Rights Reserved.
|
||||
*
|
||||
* This library is free software; you can redistribute it and/or
|
||||
* modify it under the terms of the GNU Lesser General Public
|
||||
* License as published by the Free Software Foundation; either
|
||||
* version 2.1 of the License, or (at your option) any later version.
|
||||
*
|
||||
* This library is distributed in the hope that it will be useful,
|
||||
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
|
||||
* Lesser General Public License for more details.
|
||||
*
|
||||
* Further, this software is distributed without any warranty that it is
|
||||
* free of the rightful claim of any third person regarding infringement
|
||||
* or the like. Any license provided herein, whether implied or
|
||||
* otherwise, applies only to this software file. Patent licenses, if
|
||||
* any, provided herein do not apply to combinations of this program with
|
||||
* other software, or any other product whatsoever.
|
||||
*
|
||||
* You should have received a copy of the GNU Lesser General Public
|
||||
* License along with this library; if not, write to the Free Software
|
||||
* Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
|
||||
*
|
||||
* Contact information: MeVis Medical Solutions AG, Universitaetsallee 29,
|
||||
* 28359 Bremen, Germany or:
|
||||
*
|
||||
* http://www.mevis.de
|
||||
*
|
||||
*/
|
||||
|
||||
//----------------------------------------------------------------------------------
|
||||
/*!
|
||||
// \file PythonQtObjectPtr.h
|
||||
// \author Florian Link
|
||||
// \author Last changed by $Author: florian $
|
||||
// \date 2006-05
|
||||
*/
|
||||
//----------------------------------------------------------------------------------
|
||||
|
||||
#include "PythonQtPythonInclude.h"
|
||||
|
||||
#include "PythonQtSystem.h"
|
||||
#include <QVariant>
|
||||
#include <QVariantList>
|
||||
#include <QVariantMap>
|
||||
|
||||
//! a smart pointer that stores a PyObject pointer and that handles reference
|
||||
//! counting automatically
|
||||
class PYTHONQT_EXPORT PythonQtObjectPtr {
|
||||
public:
|
||||
PythonQtObjectPtr() : _object(nullptr) {}
|
||||
|
||||
PythonQtObjectPtr(const PythonQtObjectPtr &p) : _object(nullptr) {
|
||||
setObject(p.object());
|
||||
}
|
||||
|
||||
//! If the given variant holds a PythonQtObjectPtr, extract the value from it
|
||||
//! and hold onto the reference. This results in an increment of the reference
|
||||
//! count.
|
||||
PythonQtObjectPtr(const QVariant &variant) : _object(nullptr) {
|
||||
fromVariant(variant);
|
||||
}
|
||||
|
||||
PythonQtObjectPtr(PyObject *o);
|
||||
|
||||
~PythonQtObjectPtr();
|
||||
|
||||
//! If the given variant holds a PythonQtObjectPtr, extract the value from it
|
||||
//! and hold onto the reference. This results in an increment of the reference
|
||||
//! count.
|
||||
bool fromVariant(const QVariant &variant);
|
||||
|
||||
PythonQtObjectPtr &operator=(const PythonQtObjectPtr &p) {
|
||||
setObject(p.object());
|
||||
return *this;
|
||||
}
|
||||
|
||||
PythonQtObjectPtr &operator=(PyObject *o) {
|
||||
setObject(o);
|
||||
return *this;
|
||||
}
|
||||
|
||||
PythonQtObjectPtr &operator=(const QVariant &variant) {
|
||||
fromVariant(variant);
|
||||
return *this;
|
||||
}
|
||||
|
||||
bool operator==(const PythonQtObjectPtr &p) const {
|
||||
return object() == p.object();
|
||||
}
|
||||
|
||||
bool operator!=(const PythonQtObjectPtr &p) const { return !(*this == p); }
|
||||
|
||||
bool operator==(PyObject *p) const { return object() == p; }
|
||||
|
||||
bool operator!=(PyObject *p) const { return object() != p; }
|
||||
|
||||
bool isNull() const { return !object(); }
|
||||
|
||||
PyObject *operator->() const { return object(); }
|
||||
|
||||
PyObject &operator*() const { return *(object()); }
|
||||
|
||||
operator PyObject *() const { return object(); }
|
||||
|
||||
//! sets the object and passes the ownership (stealing the reference, in
|
||||
//! Python slang)
|
||||
void setNewRef(PyObject *o);
|
||||
|
||||
PyObject *object() const { return _object; }
|
||||
|
||||
//! evaluates the given script code in the context of this object and returns
|
||||
//! the result value
|
||||
QVariant evalScript(const QString &script, int start = Py_file_input);
|
||||
|
||||
//! evaluates the given code and returns the result value (use Py_Compile etc.
|
||||
//! to create pycode from string) If pycode is NULL, a python error is
|
||||
//! printed.
|
||||
QVariant evalCode(PyObject *pycode);
|
||||
|
||||
//! evaluates the given code in the context
|
||||
void evalFile(const QString &filename);
|
||||
|
||||
//! add the given \c object to the \c module as a variable with \c name (it
|
||||
//! can be removed via clearVariable)
|
||||
void addObject(const QString &name, QObject *object);
|
||||
|
||||
//! add the given variable to the module
|
||||
void addVariable(const QString &name, const QVariant &v);
|
||||
|
||||
//! remove the given variable
|
||||
void removeVariable(const QString &name);
|
||||
|
||||
//! get the variable with the \c name of the \c module, returns an invalid
|
||||
//! QVariant on error
|
||||
QVariant getVariable(const QString &name);
|
||||
|
||||
//! call the given python object (in the scope of the current object), returns
|
||||
//! the result converted to a QVariant
|
||||
QVariant call(const QString &callable,
|
||||
const QVariantList &args = QVariantList(),
|
||||
const QVariantMap &kwargs = QVariantMap());
|
||||
|
||||
//! call the contained python object directly, returns the result converted to
|
||||
//! a QVariant
|
||||
QVariant call(const QVariantList &args = QVariantList(),
|
||||
const QVariantMap &kwargs = QVariantMap());
|
||||
|
||||
protected:
|
||||
void setObject(PyObject *o);
|
||||
|
||||
private:
|
||||
PyObject *_object;
|
||||
};
|
||||
|
||||
// register it to the meta type system
|
||||
Q_DECLARE_METATYPE(PythonQtObjectPtr)
|
||||
|
||||
#endif
|
|
@ -0,0 +1,94 @@
|
|||
#pragma once
|
||||
|
||||
/*
|
||||
*
|
||||
* Copyright (C) 2010 MeVis Medical Solutions AG All Rights Reserved.
|
||||
*
|
||||
* This library is free software; you can redistribute it and/or
|
||||
* modify it under the terms of the GNU Lesser General Public
|
||||
* License as published by the Free Software Foundation; either
|
||||
* version 2.1 of the License, or (at your option) any later version.
|
||||
*
|
||||
* This library is distributed in the hope that it will be useful,
|
||||
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
|
||||
* Lesser General Public License for more details.
|
||||
*
|
||||
* Further, this software is distributed without any warranty that it is
|
||||
* free of the rightful claim of any third person regarding infringement
|
||||
* or the like. Any license provided herein, whether implied or
|
||||
* otherwise, applies only to this software file. Patent licenses, if
|
||||
* any, provided herein do not apply to combinations of this program with
|
||||
* other software, or any other product whatsoever.
|
||||
*
|
||||
* You should have received a copy of the GNU Lesser General Public
|
||||
* License along with this library; if not, write to the Free Software
|
||||
* Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
|
||||
*
|
||||
* Contact information: MeVis Medical Solutions AG, Universitaetsallee 29,
|
||||
* 28359 Bremen, Germany or:
|
||||
*
|
||||
* http://www.mevis.de
|
||||
*
|
||||
*/
|
||||
|
||||
#include "PythonQtSystem.h"
|
||||
#include "PythonQtPythonInclude.h"
|
||||
#include <QByteArray>
|
||||
#include <QList>
|
||||
|
||||
#include <structmember.h>
|
||||
|
||||
extern PYTHONQT_EXPORT PyTypeObject PythonQtProperty_Type;
|
||||
|
||||
#define PythonQtProperty_Check(op) (Py_TYPE(op) == &PythonQtProperty_Type)
|
||||
|
||||
struct PythonQtPropertyData
|
||||
{
|
||||
PythonQtPropertyData() {
|
||||
fget = NULL;
|
||||
fset = NULL;
|
||||
fdel = NULL;
|
||||
freset = NULL;
|
||||
notify = NULL;
|
||||
doc = NULL;
|
||||
designable = true;
|
||||
scriptable = true;
|
||||
stored = true;
|
||||
user = false;
|
||||
constant = false;
|
||||
final = false;
|
||||
}
|
||||
|
||||
//! Call the fset method in Python, bound to the wrapper object.
|
||||
//! Returns true if successful
|
||||
bool callSetter(PyObject* wrapper, PyObject* newValue);
|
||||
|
||||
//! Call the fget method in Python, bound to the wrapper object.
|
||||
//! Returns the return value of the call (with a new ref).
|
||||
PyObject* callGetter(PyObject* wrapper);
|
||||
|
||||
//! Call the freset method in Python, bound to the wrapper object.
|
||||
bool callReset(PyObject* wrapper);
|
||||
|
||||
QByteArray cppType;
|
||||
|
||||
PyObject* fget;
|
||||
PyObject* fset;
|
||||
PyObject* fdel;
|
||||
PyObject* freset;
|
||||
PyObject* notify;
|
||||
PyObject* doc;
|
||||
|
||||
bool designable;
|
||||
bool scriptable;
|
||||
bool stored;
|
||||
bool user;
|
||||
bool constant;
|
||||
bool final;
|
||||
};
|
||||
|
||||
typedef struct {
|
||||
PyObject_HEAD
|
||||
PythonQtPropertyData* data;
|
||||
} PythonQtProperty;
|
|
@ -0,0 +1,93 @@
|
|||
/*
|
||||
*
|
||||
* Copyright (C) 2011 MeVis Medical Solutions AG All Rights Reserved.
|
||||
*
|
||||
* This library is free software; you can redistribute it and/or
|
||||
* modify it under the terms of the GNU Lesser General Public
|
||||
* License as published by the Free Software Foundation; either
|
||||
* version 2.1 of the License, or (at your option) any later version.
|
||||
*
|
||||
* This library is distributed in the hope that it will be useful,
|
||||
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
|
||||
* Lesser General Public License for more details.
|
||||
*
|
||||
* Further, this software is distributed without any warranty that it is
|
||||
* free of the rightful claim of any third person regarding infringement
|
||||
* or the like. Any license provided herein, whether implied or
|
||||
* otherwise, applies only to this software file. Patent licenses, if
|
||||
* any, provided herein do not apply to combinations of this program with
|
||||
* other software, or any other product whatsoever.
|
||||
*
|
||||
* You should have received a copy of the GNU Lesser General Public
|
||||
* License along with this library; if not, write to the Free Software
|
||||
* Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
|
||||
*
|
||||
* Contact information: MeVis Medical Solutions AG, Universitaetsallee 29,
|
||||
* 28359 Bremen, Germany or:
|
||||
*
|
||||
* http://www.mevis.de
|
||||
*
|
||||
*/
|
||||
|
||||
#ifndef __PythonQtPythonInclude_h
|
||||
#define __PythonQtPythonInclude_h
|
||||
|
||||
// Undefine macros that Python.h defines to avoid redefinition warning.
|
||||
#undef _POSIX_C_SOURCE
|
||||
#undef _POSIX_THREADS
|
||||
#undef _XOPEN_SOURCE
|
||||
|
||||
// Undefine Qt keywords that conflict with Python headers
|
||||
#ifdef slots
|
||||
#undef slots
|
||||
#define PYTHONQT_RESTORE_KEYWORDS
|
||||
#endif
|
||||
|
||||
// If PYTHONQT_USE_RELEASE_PYTHON_FALLBACK is enabled, try to link
|
||||
// release Python DLL if it is available by undefining _DEBUG while
|
||||
// including Python.h
|
||||
#if defined(PYTHONQT_USE_RELEASE_PYTHON_FALLBACK) && defined(_DEBUG)
|
||||
#undef _DEBUG
|
||||
#if defined(_MSC_VER) && _MSC_VER >= 1400
|
||||
#define _CRT_NOFORCE_MANIFEST 1
|
||||
#define _STL_NOFORCE_MANIFEST 1
|
||||
#endif
|
||||
#include <Python.h>
|
||||
#define _DEBUG
|
||||
#else
|
||||
#include <Python.h>
|
||||
#endif
|
||||
|
||||
// get Qt keywords back
|
||||
#ifdef PYTHONQT_RESTORE_KEYWORDS
|
||||
#define slots Q_SLOTS
|
||||
#undef PYTHONQT_RESTORE_KEYWORDS
|
||||
#endif
|
||||
|
||||
#if PY_MAJOR_VERSION >= 3
|
||||
#define PY3K
|
||||
// Helper defines to facilitate porting
|
||||
#define PyString_FromString PyUnicode_FromString
|
||||
#define PyString_AS_STRING PyUnicode_AsUTF8
|
||||
#define PyString_AsString PyUnicode_AsUTF8
|
||||
#define PyString_FromFormat PyUnicode_FromFormat
|
||||
#define PyString_Check PyUnicode_Check
|
||||
|
||||
#define PyInt_Type PyLong_Type
|
||||
#define PyInt_FromLong PyLong_FromLong
|
||||
#define PyInt_AS_LONG PyLong_AS_LONG
|
||||
#define PyInt_Check PyLong_Check
|
||||
#define PyInt_AsLong PyLong_AsLong
|
||||
|
||||
#else
|
||||
// Defines to use Python 3 names in Python 2 code
|
||||
#define PyBytes_Type PyString_Type
|
||||
#define PyBytes_Check PyString_Check
|
||||
#define PyBytes_AS_STRING PyString_AS_STRING
|
||||
#define PyBytes_AsString PyString_AsString
|
||||
#define PyBytes_GET_SIZE PyString_GET_SIZE
|
||||
#define PyBytes_FromStringAndSize PyString_FromStringAndSize
|
||||
#endif
|
||||
|
||||
#endif
|
|
@ -0,0 +1,63 @@
|
|||
#ifndef _PYTHONQTQFILEIMPORTER_H
|
||||
#define _PYTHONQTQFILEIMPORTER_H
|
||||
|
||||
/*
|
||||
*
|
||||
* Copyright (C) 2010 MeVis Medical Solutions AG All Rights Reserved.
|
||||
*
|
||||
* This library is free software; you can redistribute it and/or
|
||||
* modify it under the terms of the GNU Lesser General Public
|
||||
* License as published by the Free Software Foundation; either
|
||||
* version 2.1 of the License, or (at your option) any later version.
|
||||
*
|
||||
* This library is distributed in the hope that it will be useful,
|
||||
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
|
||||
* Lesser General Public License for more details.
|
||||
*
|
||||
* Further, this software is distributed without any warranty that it is
|
||||
* free of the rightful claim of any third person regarding infringement
|
||||
* or the like. Any license provided herein, whether implied or
|
||||
* otherwise, applies only to this software file. Patent licenses, if
|
||||
* any, provided herein do not apply to combinations of this program with
|
||||
* other software, or any other product whatsoever.
|
||||
*
|
||||
* You should have received a copy of the GNU Lesser General Public
|
||||
* License along with this library; if not, write to the Free Software
|
||||
* Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
|
||||
*
|
||||
* Contact information: MeVis Medical Solutions AG, Universitaetsallee 29,
|
||||
* 28359 Bremen, Germany or:
|
||||
*
|
||||
* http://www.mevis.de
|
||||
*
|
||||
*/
|
||||
|
||||
//----------------------------------------------------------------------------------
|
||||
/*!
|
||||
// \file PythonQtQFileImporter.h
|
||||
// \author Florian Link
|
||||
// \author Last changed by $Author: florian $
|
||||
// \date 2009-03
|
||||
*/
|
||||
//----------------------------------------------------------------------------------
|
||||
|
||||
#include <PythonQtImportFileInterface.h>
|
||||
|
||||
//! default importer implementation using QFile to load python code
|
||||
class PythonQtQFileImporter : public PythonQtImportFileInterface {
|
||||
public:
|
||||
PythonQtQFileImporter();
|
||||
~PythonQtQFileImporter();
|
||||
|
||||
QByteArray readFileAsBytes (const QString &filename);
|
||||
|
||||
QByteArray readSourceFile (const QString &filename, bool &ok);
|
||||
|
||||
bool exists (const QString &filename);
|
||||
|
||||
QDateTime lastModifiedDate (const QString &filename);
|
||||
|
||||
};
|
||||
|
||||
#endif
|
|
@ -0,0 +1,75 @@
|
|||
#ifndef _PythonQtSignal_H
|
||||
#define _PythonQtSignal_H
|
||||
|
||||
/*
|
||||
*
|
||||
* Copyright (C) 2010 MeVis Medical Solutions AG All Rights Reserved.
|
||||
*
|
||||
* This library is free software; you can redistribute it and/or
|
||||
* modify it under the terms of the GNU Lesser General Public
|
||||
* License as published by the Free Software Foundation; either
|
||||
* version 2.1 of the License, or (at your option) any later version.
|
||||
*
|
||||
* This library is distributed in the hope that it will be useful,
|
||||
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
|
||||
* Lesser General Public License for more details.
|
||||
*
|
||||
* Further, this software is distributed without any warranty that it is
|
||||
* free of the rightful claim of any third person regarding infringement
|
||||
* or the like. Any license provided herein, whether implied or
|
||||
* otherwise, applies only to this software file. Patent licenses, if
|
||||
* any, provided herein do not apply to combinations of this program with
|
||||
* other software, or any other product whatsoever.
|
||||
*
|
||||
* You should have received a copy of the GNU Lesser General Public
|
||||
* License along with this library; if not, write to the Free Software
|
||||
* Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
|
||||
*
|
||||
* Contact information: MeVis Medical Solutions AG, Universitaetsallee 29,
|
||||
* 28359 Bremen, Germany or:
|
||||
*
|
||||
* http://www.mevis.de
|
||||
*
|
||||
*/
|
||||
|
||||
//----------------------------------------------------------------------------------
|
||||
/*!
|
||||
// \file PythonQtSignal.h
|
||||
// \author Florian Link
|
||||
// \author Last changed by $Author: florian $
|
||||
// \date 2006-05
|
||||
*/
|
||||
//----------------------------------------------------------------------------------
|
||||
|
||||
#include "PythonQtPythonInclude.h"
|
||||
|
||||
#include "PythonQtSystem.h"
|
||||
#include "structmember.h"
|
||||
|
||||
class PythonQtSlotInfo;
|
||||
|
||||
extern PYTHONQT_EXPORT PyTypeObject PythonQtSignalFunction_Type;
|
||||
|
||||
#define PythonQtSignalFunction_Check(op) (Py_TYPE(op) == &PythonQtSignalFunction_Type)
|
||||
|
||||
PyObject* PythonQtSignalFunction_New(PythonQtSlotInfo *, PyObject *,
|
||||
PyObject *);
|
||||
|
||||
struct PythonQtDynamicSignalInfo
|
||||
{
|
||||
QByteArray name;
|
||||
QList<QByteArray> signatures;
|
||||
};
|
||||
|
||||
//! defines a python object that stores a Qt signal info
|
||||
typedef struct {
|
||||
PyObject_HEAD
|
||||
PythonQtSlotInfo *m_ml; /* Description of the C function to call */
|
||||
PyObject *m_self; /* Passed as 'self' arg to the C func, can be NULL */
|
||||
PyObject *m_module; /* The __module__ attribute, can be anything */
|
||||
PythonQtDynamicSignalInfo* _dynamicInfo;
|
||||
} PythonQtSignalFunctionObject;
|
||||
|
||||
|
||||
#endif
|
|
@ -0,0 +1,144 @@
|
|||
#ifndef _PYTHONQTSIGNALRECEIVER_H
|
||||
#define _PYTHONQTSIGNALRECEIVER_H
|
||||
|
||||
/*
|
||||
*
|
||||
* Copyright (C) 2010 MeVis Medical Solutions AG All Rights Reserved.
|
||||
*
|
||||
* This library is free software; you can redistribute it and/or
|
||||
* modify it under the terms of the GNU Lesser General Public
|
||||
* License as published by the Free Software Foundation; either
|
||||
* version 2.1 of the License, or (at your option) any later version.
|
||||
*
|
||||
* This library is distributed in the hope that it will be useful,
|
||||
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
|
||||
* Lesser General Public License for more details.
|
||||
*
|
||||
* Further, this software is distributed without any warranty that it is
|
||||
* free of the rightful claim of any third person regarding infringement
|
||||
* or the like. Any license provided herein, whether implied or
|
||||
* otherwise, applies only to this software file. Patent licenses, if
|
||||
* any, provided herein do not apply to combinations of this program with
|
||||
* other software, or any other product whatsoever.
|
||||
*
|
||||
* You should have received a copy of the GNU Lesser General Public
|
||||
* License along with this library; if not, write to the Free Software
|
||||
* Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
|
||||
*
|
||||
* Contact information: MeVis Medical Solutions AG, Universitaetsallee 29,
|
||||
* 28359 Bremen, Germany or:
|
||||
*
|
||||
* http://www.mevis.de
|
||||
*
|
||||
*/
|
||||
|
||||
//----------------------------------------------------------------------------------
|
||||
/*!
|
||||
// \file PythonQtSignalReceiver.h
|
||||
// \author Florian Link
|
||||
// \author Last changed by $Author: florian $
|
||||
// \date 2006-05
|
||||
*/
|
||||
//----------------------------------------------------------------------------------
|
||||
|
||||
#include "PythonQtPythonInclude.h"
|
||||
|
||||
#include "PythonQtSystem.h"
|
||||
#include "PythonQtObjectPtr.h"
|
||||
|
||||
class PythonQtMethodInfo;
|
||||
class PythonQtClassInfo;
|
||||
|
||||
//! stores information about a signal target
|
||||
/*! copy construction and assignment works fine with the C++ standard behavior and are thus not implemented
|
||||
*/
|
||||
class PYTHONQT_EXPORT PythonQtSignalTarget {
|
||||
public:
|
||||
PythonQtSignalTarget() {
|
||||
_signalId = -1;
|
||||
_methodInfo = NULL;
|
||||
_slotId = -1;
|
||||
}
|
||||
|
||||
PythonQtSignalTarget(int signalId,const PythonQtMethodInfo* methodInfo, int slotId, PyObject* callable)
|
||||
{
|
||||
_signalId = signalId;
|
||||
_slotId = slotId;
|
||||
_methodInfo = methodInfo;
|
||||
_callable = callable;
|
||||
};
|
||||
|
||||
~PythonQtSignalTarget() {
|
||||
};
|
||||
|
||||
//! get the id of the original signal
|
||||
int signalId() const { return _signalId; }
|
||||
|
||||
//! get the id that was assigned to this simulated slot
|
||||
int slotId() const { return _slotId; }
|
||||
|
||||
//! get the signals parameter info
|
||||
const PythonQtMethodInfo* methodInfo() const { return _methodInfo; }
|
||||
|
||||
//! call the python callable with the given arguments (as defined in methodInfo)
|
||||
void call(void **arguments) const;
|
||||
|
||||
//! check if it is the same signal target
|
||||
bool isSame(int signalId, PyObject* callable) const;
|
||||
|
||||
//! call the given callable with arguments described by PythonQtMethodInfo, returns a new reference as result value (or NULL)
|
||||
static PyObject* call(PyObject* callable, const PythonQtMethodInfo* methodInfo, void **arguments, bool skipFirstArgumentOfMethodInfo = false);
|
||||
|
||||
private:
|
||||
int _signalId;
|
||||
int _slotId;
|
||||
const PythonQtMethodInfo* _methodInfo;
|
||||
PythonQtObjectPtr _callable;
|
||||
};
|
||||
|
||||
//! base class for signal receivers
|
||||
/*!
|
||||
*/
|
||||
class PythonQtSignalReceiverBase : public QObject {
|
||||
Q_OBJECT
|
||||
public:
|
||||
PythonQtSignalReceiverBase(QObject* obj):QObject(obj) {};
|
||||
};
|
||||
|
||||
//! receives all signals for one QObject
|
||||
/*! we derive from our base but do not declare the QObject macro because we want to reimplement qt_metacall only.
|
||||
*/
|
||||
class PythonQtSignalReceiver : public PythonQtSignalReceiverBase {
|
||||
|
||||
public:
|
||||
PythonQtSignalReceiver(QObject* obj);
|
||||
~PythonQtSignalReceiver();
|
||||
|
||||
//! add a signal handler
|
||||
bool addSignalHandler(const char* signal, PyObject* callable);
|
||||
|
||||
//! remove a signal handler for given callable (or all callables on that signal if callable is NULL)
|
||||
bool removeSignalHandler(const char* signal, PyObject* callable = NULL);
|
||||
|
||||
//! we implement this method to simulate a number of slots that match the ids in _targets
|
||||
virtual int qt_metacall(QMetaObject::Call c, int id, void **arguments);
|
||||
|
||||
private:
|
||||
//! get the index of the signal
|
||||
int getSignalIndex(const char* signal);
|
||||
|
||||
QObject* _obj;
|
||||
PythonQtClassInfo* _objClassInfo;
|
||||
int _slotCount;
|
||||
int _destroyedSignalCount;
|
||||
// linear list may get slow on multiple targets, but I think typically we have many objects and just a few signals
|
||||
QList<PythonQtSignalTarget> _targets;
|
||||
|
||||
static int _destroyedSignal1Id;
|
||||
static int _destroyedSignal2Id;
|
||||
};
|
||||
|
||||
|
||||
#endif
|
||||
|
|
@ -0,0 +1,92 @@
|
|||
#ifndef _PYTHONQTSLOT_H
|
||||
#define _PYTHONQTSLOT_H
|
||||
|
||||
/*
|
||||
*
|
||||
* Copyright (C) 2010 MeVis Medical Solutions AG All Rights Reserved.
|
||||
*
|
||||
* This library is free software; you can redistribute it and/or
|
||||
* modify it under the terms of the GNU Lesser General Public
|
||||
* License as published by the Free Software Foundation; either
|
||||
* version 2.1 of the License, or (at your option) any later version.
|
||||
*
|
||||
* This library is distributed in the hope that it will be useful,
|
||||
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
|
||||
* Lesser General Public License for more details.
|
||||
*
|
||||
* Further, this software is distributed without any warranty that it is
|
||||
* free of the rightful claim of any third person regarding infringement
|
||||
* or the like. Any license provided herein, whether implied or
|
||||
* otherwise, applies only to this software file. Patent licenses, if
|
||||
* any, provided herein do not apply to combinations of this program with
|
||||
* other software, or any other product whatsoever.
|
||||
*
|
||||
* You should have received a copy of the GNU Lesser General Public
|
||||
* License along with this library; if not, write to the Free Software
|
||||
* Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
|
||||
*
|
||||
* Contact information: MeVis Medical Solutions AG, Universitaetsallee 29,
|
||||
* 28359 Bremen, Germany or:
|
||||
*
|
||||
* http://www.mevis.de
|
||||
*
|
||||
*/
|
||||
|
||||
//----------------------------------------------------------------------------------
|
||||
/*!
|
||||
// \file PythonQtSlot.h
|
||||
// \author Florian Link
|
||||
// \author Last changed by $Author: florian $
|
||||
// \date 2006-05
|
||||
*/
|
||||
//----------------------------------------------------------------------------------
|
||||
|
||||
#include "PythonQtPythonInclude.h"
|
||||
|
||||
#include "PythonQtSystem.h"
|
||||
#include "structmember.h"
|
||||
|
||||
class PythonQtSlotInfo;
|
||||
|
||||
enum PythonQtPassThisOwnershipType
|
||||
{
|
||||
IgnoreOwnership,
|
||||
PassOwnershipToCPP,
|
||||
PassOwnershipToPython
|
||||
};
|
||||
|
||||
extern PYTHONQT_EXPORT PyTypeObject PythonQtSlotFunction_Type;
|
||||
|
||||
#define PythonQtSlotFunction_Check(op) (Py_TYPE(op) == &PythonQtSlotFunction_Type)
|
||||
|
||||
PythonQtSlotInfo* PythonQtSlotFunction_GetSlotInfo(PyObject *);
|
||||
PyObject* PythonQtSlotFunction_GetSelf(PyObject *);
|
||||
|
||||
/* Macros for direct access to these values. Type checks are *not*
|
||||
done, so use with care. */
|
||||
#define PythonQtSlotFunction_GET_SELF(func) \
|
||||
(((PythonQtSlotFunctionObject *)func) -> m_self)
|
||||
|
||||
PyObject* PythonQtSlotFunction_Call(PyObject *, PyObject *, PyObject *);
|
||||
|
||||
PyObject *PythonQtSlotFunction_CallImpl(PythonQtClassInfo* classInfo, QObject* objectToCall, PythonQtSlotInfo* info, PyObject *args, PyObject *kw, void* firstArg=NULL, void** directReturnValuePointer=NULL, PythonQtPassThisOwnershipType* passThisOwnershipToCPP = NULL);
|
||||
|
||||
PyObject* PythonQtSlotFunction_New(PythonQtSlotInfo *, PyObject *,
|
||||
PyObject *);
|
||||
|
||||
PyObject *PythonQtMemberFunction_Call(PythonQtSlotInfo* info, PyObject* m_self, PyObject *args, PyObject *kw);
|
||||
PyObject *PythonQtMemberFunction_parameterTypes(PythonQtSlotInfo* theInfo);
|
||||
PyObject *PythonQtMemberFunction_parameterNames(PythonQtSlotInfo* theInfo);
|
||||
PyObject *PythonQtMemberFunction_typeName(PythonQtSlotInfo* theInfo);
|
||||
|
||||
//! defines a python object that stores a Qt slot info
|
||||
typedef struct {
|
||||
PyObject_HEAD
|
||||
PythonQtSlotInfo *m_ml; /* Description of the C function to call */
|
||||
PyObject *m_self; /* Passed as 'self' arg to the C func, can be NULL */
|
||||
PyObject *m_module; /* The __module__ attribute, can be anything */
|
||||
} PythonQtSlotFunctionObject;
|
||||
|
||||
|
||||
#endif
|
|
@ -0,0 +1,50 @@
|
|||
#pragma once
|
||||
|
||||
/*
|
||||
*
|
||||
* Copyright (C) 2010 MeVis Medical Solutions AG All Rights Reserved.
|
||||
*
|
||||
* This library is free software; you can redistribute it and/or
|
||||
* modify it under the terms of the GNU Lesser General Public
|
||||
* License as published by the Free Software Foundation; either
|
||||
* version 2.1 of the License, or (at your option) any later version.
|
||||
*
|
||||
* This library is distributed in the hope that it will be useful,
|
||||
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
|
||||
* Lesser General Public License for more details.
|
||||
*
|
||||
* Further, this software is distributed without any warranty that it is
|
||||
* free of the rightful claim of any third person regarding infringement
|
||||
* or the like. Any license provided herein, whether implied or
|
||||
* otherwise, applies only to this software file. Patent licenses, if
|
||||
* any, provided herein do not apply to combinations of this program with
|
||||
* other software, or any other product whatsoever.
|
||||
*
|
||||
* You should have received a copy of the GNU Lesser General Public
|
||||
* License along with this library; if not, write to the Free Software
|
||||
* Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
|
||||
*
|
||||
* Contact information: MeVis Medical Solutions AG, Universitaetsallee 29,
|
||||
* 28359 Bremen, Germany or:
|
||||
*
|
||||
* http://www.mevis.de
|
||||
*
|
||||
*/
|
||||
|
||||
#include "PythonQtSystem.h"
|
||||
#include "PythonQtPythonInclude.h"
|
||||
#include <QByteArray>
|
||||
#include <QList>
|
||||
|
||||
#include <structmember.h>
|
||||
|
||||
extern PYTHONQT_EXPORT PyTypeObject PythonQtSlotDecorator_Type;
|
||||
|
||||
#define PythonQtSlotDecorator_Check(op) (Py_TYPE(op) == &PythonQtSlotDecorator_Type)
|
||||
|
||||
typedef struct {
|
||||
PyObject_HEAD
|
||||
QByteArray* args;
|
||||
QByteArray* returnType;
|
||||
} PythonQtSlotDecorator;
|
|
@ -0,0 +1,282 @@
|
|||
#ifndef _PYTHONQTSTDDECORATORS_H
|
||||
#define _PYTHONQTSTDDECORATORS_H
|
||||
|
||||
/*
|
||||
*
|
||||
* Copyright (C) 2010 MeVis Medical Solutions AG All Rights Reserved.
|
||||
*
|
||||
* This library is free software; you can redistribute it and/or
|
||||
* modify it under the terms of the GNU Lesser General Public
|
||||
* License as published by the Free Software Foundation; either
|
||||
* version 2.1 of the License, or (at your option) any later version.
|
||||
*
|
||||
* This library is distributed in the hope that it will be useful,
|
||||
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
|
||||
* Lesser General Public License for more details.
|
||||
*
|
||||
* Further, this software is distributed without any warranty that it is
|
||||
* free of the rightful claim of any third person regarding infringement
|
||||
* or the like. Any license provided herein, whether implied or
|
||||
* otherwise, applies only to this software file. Patent licenses, if
|
||||
* any, provided herein do not apply to combinations of this program with
|
||||
* other software, or any other product whatsoever.
|
||||
*
|
||||
* You should have received a copy of the GNU Lesser General Public
|
||||
* License along with this library; if not, write to the Free Software
|
||||
* Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
|
||||
*
|
||||
* Contact information: MeVis Medical Solutions AG, Universitaetsallee 29,
|
||||
* 28359 Bremen, Germany or:
|
||||
*
|
||||
* http://www.mevis.de
|
||||
*
|
||||
*/
|
||||
|
||||
//----------------------------------------------------------------------------------
|
||||
/*!
|
||||
// \file PythonQtStdDecorators.h
|
||||
// \author Florian Link
|
||||
// \author Last changed by $Author: florian $
|
||||
// \date 2007-04
|
||||
*/
|
||||
//----------------------------------------------------------------------------------
|
||||
|
||||
#include "PythonQtPythonInclude.h"
|
||||
|
||||
#include "PythonQt.h"
|
||||
|
||||
#include <QColor>
|
||||
#include <QDate>
|
||||
#include <QDateTime>
|
||||
#include <QImage>
|
||||
#include <QMetaEnum>
|
||||
#include <QMetaMethod>
|
||||
#include <QMetaProperty>
|
||||
#include <QObject>
|
||||
#include <QTextDocument>
|
||||
#include <QTime>
|
||||
#include <QTimer>
|
||||
#include <QVariantList>
|
||||
|
||||
class PYTHONQT_EXPORT PythonQtStdDecorators : public QObject {
|
||||
Q_OBJECT
|
||||
|
||||
public Q_SLOTS:
|
||||
bool connect(QObject *sender, const QString &signal, PyObject *callable);
|
||||
bool connect(QObject *sender, const QString &signal, QObject *receiver,
|
||||
const QString &slot,
|
||||
Qt::ConnectionType type = Qt::AutoConnection);
|
||||
bool connect(QObject *receiver, QObject *sender, const QString &signal,
|
||||
const QString &slot,
|
||||
Qt::ConnectionType type = Qt::AutoConnection) {
|
||||
return connect(sender, signal, receiver, slot, type);
|
||||
}
|
||||
bool static_QObject_connect(QObject *sender, const QString &signal,
|
||||
PyObject *callable) {
|
||||
return connect(sender, signal, callable);
|
||||
}
|
||||
bool static_QObject_connect(QObject *sender, const QString &signal,
|
||||
QObject *receiver, const QString &slot,
|
||||
Qt::ConnectionType type = Qt::AutoConnection) {
|
||||
return connect(sender, signal, receiver, slot, type);
|
||||
}
|
||||
bool disconnect(QObject *sender, const QString &signal,
|
||||
PyObject *callable = nullptr);
|
||||
bool disconnect(QObject *sender, const QString &signal, QObject *receiver,
|
||||
const QString &slot);
|
||||
bool static_QObject_disconnect(QObject *sender, const QString &signal,
|
||||
PyObject *callable = nullptr) {
|
||||
return disconnect(sender, signal, callable);
|
||||
}
|
||||
bool static_QObject_disconnect(QObject *sender, const QString &signal,
|
||||
QObject *receiver, const QString &slot) {
|
||||
return connect(sender, signal, receiver, slot);
|
||||
}
|
||||
|
||||
const QMetaObject *metaObject(QObject *obj);
|
||||
|
||||
QObject *parent(QObject *o);
|
||||
void setParent(QObject *o, PythonQtNewOwnerOfThis<QObject *> parent);
|
||||
|
||||
const QObjectList *children(QObject *o);
|
||||
QObject *findChild(QObject *parent, PyObject *type,
|
||||
const QString &name = QString());
|
||||
QList<QObject *> findChildren(QObject *parent, PyObject *type,
|
||||
const QString &name = QString());
|
||||
QList<QObject *> findChildren(QObject *parent, PyObject *type,
|
||||
const QRegExp ®Exp);
|
||||
|
||||
bool setProperty(QObject *o, const char *name, const QVariant &value);
|
||||
QVariant property(QObject *o, const char *name);
|
||||
|
||||
double static_Qt_qAbs(double a) { return qAbs(a); }
|
||||
double static_Qt_qBound(double a, double b, double c) {
|
||||
return qBound(a, b, c);
|
||||
}
|
||||
void static_Qt_qDebug(const QByteArray &msg) {
|
||||
qDebug("%s", msg.constData());
|
||||
}
|
||||
// TODO: multi arg qDebug...
|
||||
void static_Qt_qWarning(const QByteArray &msg) {
|
||||
qWarning("%s", msg.constData());
|
||||
}
|
||||
// TODO: multi arg qWarning...
|
||||
void static_Qt_qCritical(const QByteArray &msg) {
|
||||
qCritical("%s", msg.constData());
|
||||
}
|
||||
// TODO: multi arg qCritical...
|
||||
void static_Qt_qFatal(const QByteArray &msg) {
|
||||
qFatal("%s", msg.constData());
|
||||
}
|
||||
// TODO: multi arg qFatal...
|
||||
bool static_Qt_qFuzzyCompare(double a, double b) {
|
||||
return qFuzzyCompare(a, b);
|
||||
}
|
||||
double static_Qt_qMax(double a, double b) { return qMax(a, b); }
|
||||
double static_Qt_qMin(double a, double b) { return qMin(a, b); }
|
||||
int static_Qt_qRound(double a) { return qRound(a); }
|
||||
qint64 static_Qt_qRound64(double a) { return qRound64(a); }
|
||||
const char *static_Qt_qVersion() { return qVersion(); }
|
||||
int static_Qt_qrand() { return qrand(); }
|
||||
void static_Qt_qsrand(uint a) { qsrand(a); }
|
||||
|
||||
QString tr(QObject *obj, const QString &text,
|
||||
const QString &ambig = QString(), int n = -1);
|
||||
|
||||
QString static_Qt_SIGNAL(const QString &s) { return QString("2") + s; }
|
||||
QString static_Qt_SLOT(const QString &s) { return QString("1") + s; }
|
||||
|
||||
void static_QTimer_singleShot(int msec, PyObject *callable);
|
||||
|
||||
private:
|
||||
QObject *findChild(QObject *parent, const char *typeName,
|
||||
const QMetaObject *meta, const QString &name);
|
||||
int findChildren(QObject *parent, const char *typeName,
|
||||
const QMetaObject *meta, const QString &name,
|
||||
QList<QObject *> &list);
|
||||
int findChildren(QObject *parent, const char *typeName,
|
||||
const QMetaObject *meta, const QRegExp ®Exp,
|
||||
QList<QObject *> &list);
|
||||
};
|
||||
|
||||
class PythonQtSingleShotTimer : public QTimer {
|
||||
Q_OBJECT
|
||||
public:
|
||||
PythonQtSingleShotTimer(int msec, const PythonQtObjectPtr &callable);
|
||||
|
||||
public Q_SLOTS:
|
||||
void slotTimeout();
|
||||
|
||||
private:
|
||||
PythonQtObjectPtr _callable;
|
||||
};
|
||||
|
||||
class PythonQtWrapper_QMetaObject : public QObject {
|
||||
Q_OBJECT
|
||||
|
||||
public Q_SLOTS:
|
||||
const char *className(QMetaObject *obj) const { return obj->className(); }
|
||||
const QMetaObject *superClass(QMetaObject *obj) const {
|
||||
return obj->superClass();
|
||||
}
|
||||
|
||||
int methodOffset(QMetaObject *obj) const { return obj->methodOffset(); }
|
||||
int enumeratorOffset(QMetaObject *obj) const {
|
||||
return obj->enumeratorOffset();
|
||||
}
|
||||
int propertyOffset(QMetaObject *obj) const { return obj->propertyOffset(); }
|
||||
int classInfoOffset(QMetaObject *obj) const { return obj->classInfoOffset(); }
|
||||
|
||||
int constructorCount(QMetaObject *obj) const {
|
||||
return obj->constructorCount();
|
||||
}
|
||||
int methodCount(QMetaObject *obj) const { return obj->methodCount(); }
|
||||
int enumeratorCount(QMetaObject *obj) const { return obj->enumeratorCount(); }
|
||||
int propertyCount(QMetaObject *obj) const { return obj->propertyCount(); }
|
||||
int classInfoCount(QMetaObject *obj) const { return obj->classInfoCount(); }
|
||||
|
||||
int indexOfConstructor(QMetaObject *obj, const char *constructor) const {
|
||||
return obj->indexOfConstructor(constructor);
|
||||
}
|
||||
int indexOfMethod(QMetaObject *obj, const char *method) const {
|
||||
return obj->indexOfMethod(method);
|
||||
}
|
||||
int indexOfSignal(QMetaObject *obj, const char *signal) const {
|
||||
return obj->indexOfSignal(signal);
|
||||
}
|
||||
int indexOfSlot(QMetaObject *obj, const char *slot) const {
|
||||
return obj->indexOfSlot(slot);
|
||||
}
|
||||
int indexOfEnumerator(QMetaObject *obj, const char *name) const {
|
||||
return obj->indexOfEnumerator(name);
|
||||
}
|
||||
int indexOfProperty(QMetaObject *obj, const char *name) const {
|
||||
return obj->indexOfProperty(name);
|
||||
}
|
||||
int indexOfClassInfo(QMetaObject *obj, const char *name) const {
|
||||
return obj->indexOfClassInfo(name);
|
||||
}
|
||||
|
||||
QMetaMethod constructor(QMetaObject *obj, int index) const {
|
||||
return obj->constructor(index);
|
||||
}
|
||||
QMetaMethod method(QMetaObject *obj, int index) const {
|
||||
return obj->method(index);
|
||||
}
|
||||
QMetaEnum enumerator(QMetaObject *obj, int index) const {
|
||||
return obj->enumerator(index);
|
||||
}
|
||||
QMetaProperty property(QMetaObject *obj, int index) const {
|
||||
return obj->property(index);
|
||||
}
|
||||
QMetaClassInfo classInfo(QMetaObject *obj, int index) const {
|
||||
return obj->classInfo(index);
|
||||
}
|
||||
QMetaProperty userProperty(QMetaObject *obj) const {
|
||||
return obj->userProperty();
|
||||
}
|
||||
|
||||
bool static_QMetaObject_checkConnectArgs(const char *signal,
|
||||
const char *method) {
|
||||
return QMetaObject::checkConnectArgs(signal, method);
|
||||
}
|
||||
QByteArray static_QMetaObject_normalizedSignature(const char *method) {
|
||||
return QMetaObject::normalizedSignature(method);
|
||||
}
|
||||
QByteArray static_QMetaObject_normalizedType(const char *type) {
|
||||
return QMetaObject::normalizedType(type);
|
||||
}
|
||||
};
|
||||
|
||||
//! Some helper methods that allow testing of the ownership
|
||||
class PYTHONQT_EXPORT PythonQtDebugAPI : public QObject {
|
||||
Q_OBJECT
|
||||
public:
|
||||
PythonQtDebugAPI(QObject *parent) : QObject(parent) {}
|
||||
|
||||
public slots:
|
||||
//! Returns if the C++ object is owned by PythonQt and will be deleted when
|
||||
//! the reference goes away.
|
||||
bool isOwnedByPython(PyObject *object);
|
||||
//! Returns if the C++ object is an instance of a Python class that derives a
|
||||
//! C++ class.
|
||||
bool isDerivedShellInstance(PyObject *object);
|
||||
//! Returns if the shell instance has an extra ref count from the C++ side.
|
||||
bool hasExtraShellRefCount(PyObject *object);
|
||||
|
||||
//! Pass the ownership of the given object to CPP (so that it will not be
|
||||
//! deleted by Python if the reference goes away)
|
||||
bool passOwnershipToCPP(PyObject *object);
|
||||
//! Pass the ownership of the given object to Python (so that the C++ object
|
||||
//! will be deleted when the Python reference goes away)
|
||||
bool passOwnershipToPython(PyObject *object);
|
||||
|
||||
//! Returns if the given object is a PythonQt instance wrapper (or derived
|
||||
//! class)
|
||||
bool isPythonQtInstanceWrapper(PyObject *object);
|
||||
//! Returns if the given object is a PythonQt class wrapper (or derived class)
|
||||
bool isPythonQtClassWrapper(PyObject *object);
|
||||
};
|
||||
|
||||
#endif
|
|
@ -0,0 +1,63 @@
|
|||
#ifndef _PYTHONQTSTDIN_H
|
||||
#define _PYTHONQTSTDIN_H
|
||||
|
||||
/*
|
||||
*
|
||||
* Copyright (C) 2011 MeVis Medical Solutions AG All Rights Reserved.
|
||||
*
|
||||
* This library is free software; you can redistribute it and/or
|
||||
* modify it under the terms of the GNU Lesser General Public
|
||||
* License as published by the Free Software Foundation; either
|
||||
* version 2.1 of the License, or (at your option) any later version.
|
||||
*
|
||||
* This library is distributed in the hope that it will be useful,
|
||||
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
|
||||
* Lesser General Public License for more details.
|
||||
*
|
||||
* Further, this software is distributed without any warranty that it is
|
||||
* free of the rightful claim of any third person regarding infringement
|
||||
* or the like. Any license provided herein, whether implied or
|
||||
* otherwise, applies only to this software file. Patent licenses, if
|
||||
* any, provided herein do not apply to combinations of this program with
|
||||
* other software, or any other product whatsoever.
|
||||
*
|
||||
* You should have received a copy of the GNU Lesser General Public
|
||||
* License along with this library; if not, write to the Free Software
|
||||
* Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
|
||||
*
|
||||
* Contact information: MeVis Medical Solutions AG, Universitaetsallee 29,
|
||||
* 28359 Bremen, Germany or:
|
||||
*
|
||||
* http://www.mevis.de
|
||||
*
|
||||
*/
|
||||
|
||||
//----------------------------------------------------------------------------------
|
||||
/*!
|
||||
// \file PythonQtStdIn.h
|
||||
// \author Jean-Christophe Fillion-Robin
|
||||
// \author Last changed by $Author: jcfr $
|
||||
// \date 2011
|
||||
*/
|
||||
//----------------------------------------------------------------------------------
|
||||
|
||||
|
||||
#include "PythonQtPythonInclude.h"
|
||||
#include "structmember.h"
|
||||
#include <QString>
|
||||
|
||||
//! declares the type of the stdout redirection class
|
||||
extern PyTypeObject PythonQtStdInRedirectType;
|
||||
|
||||
//! declares the callback that is called from the write() function
|
||||
typedef QString PythonQtInputChangedCB(void* callData);
|
||||
|
||||
//! declares the stdin redirection class
|
||||
typedef struct {
|
||||
PyObject_HEAD
|
||||
PythonQtInputChangedCB* _cb;
|
||||
void * _callData;
|
||||
} PythonQtStdInRedirect;
|
||||
|
||||
#endif
|
|
@ -0,0 +1,65 @@
|
|||
#ifndef _PYTHONQTSTDOUT_H
|
||||
#define _PYTHONQTSTDOUT_H
|
||||
|
||||
/*
|
||||
*
|
||||
* Copyright (C) 2010 MeVis Medical Solutions AG All Rights Reserved.
|
||||
*
|
||||
* This library is free software; you can redistribute it and/or
|
||||
* modify it under the terms of the GNU Lesser General Public
|
||||
* License as published by the Free Software Foundation; either
|
||||
* version 2.1 of the License, or (at your option) any later version.
|
||||
*
|
||||
* This library is distributed in the hope that it will be useful,
|
||||
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
|
||||
* Lesser General Public License for more details.
|
||||
*
|
||||
* Further, this software is distributed without any warranty that it is
|
||||
* free of the rightful claim of any third person regarding infringement
|
||||
* or the like. Any license provided herein, whether implied or
|
||||
* otherwise, applies only to this software file. Patent licenses, if
|
||||
* any, provided herein do not apply to combinations of this program with
|
||||
* other software, or any other product whatsoever.
|
||||
*
|
||||
* You should have received a copy of the GNU Lesser General Public
|
||||
* License along with this library; if not, write to the Free Software
|
||||
* Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
|
||||
*
|
||||
* Contact information: MeVis Medical Solutions AG, Universitaetsallee 29,
|
||||
* 28359 Bremen, Germany or:
|
||||
*
|
||||
* http://www.mevis.de
|
||||
*
|
||||
*/
|
||||
|
||||
//----------------------------------------------------------------------------------
|
||||
/*!
|
||||
// \file PythonQtStdOut.h
|
||||
// \author Florian Link
|
||||
// \author Last changed by $Author: florian $
|
||||
// \date 2006-05
|
||||
*/
|
||||
//----------------------------------------------------------------------------------
|
||||
|
||||
|
||||
#include "PythonQtPythonInclude.h"
|
||||
|
||||
#include "structmember.h"
|
||||
#include <QString>
|
||||
|
||||
//! declares the type of the stdout redirection class
|
||||
extern PyTypeObject PythonQtStdOutRedirectType;
|
||||
|
||||
//! declares the callback that is called from the write() function
|
||||
typedef void PythonQtOutputChangedCB(const QString& str);
|
||||
|
||||
//! declares the stdout redirection class
|
||||
typedef struct {
|
||||
PyObject_HEAD
|
||||
PythonQtOutputChangedCB* _cb;
|
||||
int softspace;
|
||||
bool closed;
|
||||
} PythonQtStdOutRedirect;
|
||||
|
||||
#endif
|
|
@ -0,0 +1,56 @@
|
|||
#ifndef _PYTHONQTSYSTEM_
|
||||
#define _PYTHONQTSYSTEM_
|
||||
|
||||
/*
|
||||
*
|
||||
* Copyright (C) 2010 MeVis Medical Solutions AG All Rights Reserved.
|
||||
*
|
||||
* This library is free software; you can redistribute it and/or
|
||||
* modify it under the terms of the GNU Lesser General Public
|
||||
* License as published by the Free Software Foundation; either
|
||||
* version 2.1 of the License, or (at your option) any later version.
|
||||
*
|
||||
* This library is distributed in the hope that it will be useful,
|
||||
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
|
||||
* Lesser General Public License for more details.
|
||||
*
|
||||
* Further, this software is distributed without any warranty that it is
|
||||
* free of the rightful claim of any third person regarding infringement
|
||||
* or the like. Any license provided herein, whether implied or
|
||||
* otherwise, applies only to this software file. Patent licenses, if
|
||||
* any, provided herein do not apply to combinations of this program with
|
||||
* other software, or any other product whatsoever.
|
||||
*
|
||||
* You should have received a copy of the GNU Lesser General Public
|
||||
* License along with this library; if not, write to the Free Software
|
||||
* Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
|
||||
*
|
||||
* Contact information: MeVis Medical Solutions AG, Universitaetsallee 29,
|
||||
* 28359 Bremen, Germany or:
|
||||
*
|
||||
* http://www.mevis.de
|
||||
*
|
||||
*/
|
||||
|
||||
//----------------------------------------------------------------------------------
|
||||
/*!
|
||||
// \file PythonQtSystem.h
|
||||
// \author Florian Link
|
||||
// \author Last changed by $Author: florian $
|
||||
// \date 2006-05
|
||||
*/
|
||||
//----------------------------------------------------------------------------------
|
||||
|
||||
#ifdef WIN32
|
||||
#ifdef PYTHONQT_EXPORTS
|
||||
#define PYTHONQT_EXPORT __declspec(dllexport)
|
||||
#else
|
||||
#define PYTHONQT_EXPORT __declspec(dllimport)
|
||||
#endif
|
||||
#else
|
||||
#define PYTHONQT_EXPORT
|
||||
#endif
|
||||
|
||||
#endif
|
||||
|
|
@ -0,0 +1,97 @@
|
|||
#ifndef _PYTHONQTUTILS_H
|
||||
#define _PYTHONQTUTILS_H
|
||||
|
||||
/*
|
||||
*
|
||||
* Copyright (C) 2010 MeVis Medical Solutions AG All Rights Reserved.
|
||||
*
|
||||
* This library is free software; you can redistribute it and/or
|
||||
* modify it under the terms of the GNU Lesser General Public
|
||||
* License as published by the Free Software Foundation; either
|
||||
* version 2.1 of the License, or (at your option) any later version.
|
||||
*
|
||||
* This library is distributed in the hope that it will be useful,
|
||||
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
|
||||
* Lesser General Public License for more details.
|
||||
*
|
||||
* Further, this software is distributed without any warranty that it is
|
||||
* free of the rightful claim of any third person regarding infringement
|
||||
* or the like. Any license provided herein, whether implied or
|
||||
* otherwise, applies only to this software file. Patent licenses, if
|
||||
* any, provided herein do not apply to combinations of this program with
|
||||
* other software, or any other product whatsoever.
|
||||
*
|
||||
* You should have received a copy of the GNU Lesser General Public
|
||||
* License along with this library; if not, write to the Free Software
|
||||
* Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
|
||||
*
|
||||
* Contact information: MeVis Medical Solutions AG, Universitaetsallee 29,
|
||||
* 28359 Bremen, Germany or:
|
||||
*
|
||||
* http://www.mevis.de
|
||||
*
|
||||
*/
|
||||
|
||||
//----------------------------------------------------------------------------------
|
||||
/*!
|
||||
// \file PythonQtUtils.h
|
||||
// \author Florian Link
|
||||
// \author Last changed by $Author: florian $
|
||||
// \date 2014-09
|
||||
*/
|
||||
//----------------------------------------------------------------------------------
|
||||
|
||||
#include "PythonQtPythonInclude.h"
|
||||
#include "PythonQtSystem.h"
|
||||
|
||||
#include <QByteArray>
|
||||
#include <QMetaMethod>
|
||||
|
||||
namespace PythonQtUtils
|
||||
{
|
||||
inline QByteArray signature(const QMetaMethod& method) {
|
||||
#if( QT_VERSION >= QT_VERSION_CHECK(5,0,0) )
|
||||
return method.methodSignature();
|
||||
#else
|
||||
return QByteArray(method.signature());
|
||||
#endif
|
||||
}
|
||||
|
||||
inline QByteArray methodName(const QMetaMethod& method) {
|
||||
#if( QT_VERSION >= QT_VERSION_CHECK(5,0,0) )
|
||||
return method.name();
|
||||
#else
|
||||
QByteArray sig(method.signature());
|
||||
int idx = sig.indexOf('(');
|
||||
sig = sig.left(idx);
|
||||
return sig;
|
||||
#endif
|
||||
}
|
||||
|
||||
inline QByteArray typeName(const QMetaMethod& method) {
|
||||
#if( QT_VERSION >= QT_VERSION_CHECK(5,0,0) )
|
||||
QByteArray result = method.typeName();
|
||||
if (result == "void") {
|
||||
return QByteArray();
|
||||
} else {
|
||||
return result;
|
||||
}
|
||||
#else
|
||||
return method.typeName();
|
||||
#endif
|
||||
}
|
||||
|
||||
//! Returns of the python object is a class type
|
||||
inline bool isPythonClassType(PyObject* obj) {
|
||||
#ifdef PY3K
|
||||
return PyType_Check(obj);
|
||||
#else
|
||||
// support old-style classes and new style classes
|
||||
return (obj->ob_type == &PyClass_Type || obj->ob_type == &PyType_Type);
|
||||
#endif
|
||||
}
|
||||
}
|
||||
|
||||
#endif
|
||||
|
|
@ -0,0 +1,78 @@
|
|||
#ifndef _PYTHONQTVARIANTS_
|
||||
#define _PYTHONQTVARIANTS_
|
||||
|
||||
/*
|
||||
*
|
||||
* Copyright (C) 2010 MeVis Medical Solutions AG All Rights Reserved.
|
||||
*
|
||||
* This library is free software; you can redistribute it and/or
|
||||
* modify it under the terms of the GNU Lesser General Public
|
||||
* License as published by the Free Software Foundation; either
|
||||
* version 2.1 of the License, or (at your option) any later version.
|
||||
*
|
||||
* This library is distributed in the hope that it will be useful,
|
||||
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
|
||||
* Lesser General Public License for more details.
|
||||
*
|
||||
* Further, this software is distributed without any warranty that it is
|
||||
* free of the rightful claim of any third person regarding infringement
|
||||
* or the like. Any license provided herein, whether implied or
|
||||
* otherwise, applies only to this software file. Patent licenses, if
|
||||
* any, provided herein do not apply to combinations of this program with
|
||||
* other software, or any other product whatsoever.
|
||||
*
|
||||
* You should have received a copy of the GNU Lesser General Public
|
||||
* License along with this library; if not, write to the Free Software
|
||||
* Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
|
||||
*
|
||||
* Contact information: MeVis Medical Solutions AG, Universitaetsallee 29,
|
||||
* 28359 Bremen, Germany or:
|
||||
*
|
||||
* http://www.mevis.de
|
||||
*
|
||||
*/
|
||||
|
||||
//----------------------------------------------------------------------------------
|
||||
/*!
|
||||
// \file PythonQtVariants.h
|
||||
// \author Florian Link
|
||||
// \author Last changed by $Author: stk $
|
||||
// \date 2006-08
|
||||
*/
|
||||
//----------------------------------------------------------------------------------
|
||||
|
||||
#include <QBitArray>
|
||||
#include <QDate>
|
||||
#include <QTime>
|
||||
#include <QDateTime>
|
||||
#include <QUrl>
|
||||
#include <QLocale>
|
||||
#include <QRect>
|
||||
#include <QRectF>
|
||||
#include <QLine>
|
||||
#include <QLineF>
|
||||
#include <QPoint>
|
||||
#include <QPointF>
|
||||
#include <QRegExp>
|
||||
|
||||
#include <QFont>
|
||||
#include <QBitmap>
|
||||
#include <QBrush>
|
||||
#include <QColor>
|
||||
#include <QPalette>
|
||||
#include <QIcon>
|
||||
#include <QImage>
|
||||
#include <QPolygon>
|
||||
#include <QRegion>
|
||||
#include <QBitmap>
|
||||
#include <QCursor>
|
||||
#include <QSizePolicy>
|
||||
#include <QKeySequence>
|
||||
#include <QPen>
|
||||
#include <QTextLength>
|
||||
#include <QTextFormat>
|
||||
#include <QMatrix>
|
||||
|
||||
#endif
|
||||
|
|
@ -0,0 +1,51 @@
|
|||
#ifndef PYTHONQT_QTALL_H
|
||||
#define PYTHONQT_QTALL_H
|
||||
|
||||
/*
|
||||
*
|
||||
* Copyright (C) 2010 MeVis Medical Solutions AG All Rights Reserved.
|
||||
*
|
||||
* This library is free software; you can redistribute it and/or
|
||||
* modify it under the terms of the GNU Lesser General Public
|
||||
* License as published by the Free Software Foundation; either
|
||||
* version 2.1 of the License, or (at your option) any later version.
|
||||
*
|
||||
* This library is distributed in the hope that it will be useful,
|
||||
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
|
||||
* Lesser General Public License for more details.
|
||||
*
|
||||
* Further, this software is distributed without any warranty that it is
|
||||
* free of the rightful claim of any third person regarding infringement
|
||||
* or the like. Any license provided herein, whether implied or
|
||||
* otherwise, applies only to this software file. Patent licenses, if
|
||||
* any, provided herein do not apply to combinations of this program with
|
||||
* other software, or any other product whatsoever.
|
||||
*
|
||||
* You should have received a copy of the GNU Lesser General Public
|
||||
* License along with this library; if not, write to the Free Software
|
||||
* Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
|
||||
*
|
||||
* Contact information: MeVis Medical Solutions AG, Universitaetsallee 29,
|
||||
* 28359 Bremen, Germany or:
|
||||
*
|
||||
* http://www.mevis.de
|
||||
*
|
||||
*/
|
||||
|
||||
#ifdef WIN32
|
||||
#ifdef PYTHONQT_QTALL_EXPORTS
|
||||
#define PYTHONQT_QTALL_EXPORT __declspec(dllexport)
|
||||
#else
|
||||
#define PYTHONQT_QTALL_EXPORT __declspec(dllimport)
|
||||
#endif
|
||||
#else
|
||||
#define PYTHONQT_QTALL_EXPORT
|
||||
#endif
|
||||
|
||||
namespace PythonQt_QtAll {
|
||||
//! initialize the Qt binding
|
||||
PYTHONQT_QTALL_EXPORT void init();
|
||||
}; // namespace PythonQt_QtAll
|
||||
|
||||
#endif
|
|
@ -0,0 +1,557 @@
|
|||
/*
|
||||
*
|
||||
* Copyright (C) 2010 MeVis Medical Solutions AG All Rights Reserved.
|
||||
*
|
||||
* This library is free software; you can redistribute it and/or
|
||||
* modify it under the terms of the GNU Lesser General Public
|
||||
* License as published by the Free Software Foundation; either
|
||||
* version 2.1 of the License, or (at your option) any later version.
|
||||
*
|
||||
* This library is distributed in the hope that it will be useful,
|
||||
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
|
||||
* Lesser General Public License for more details.
|
||||
*
|
||||
* Further, this software is distributed without any warranty that it is
|
||||
* free of the rightful claim of any third person regarding infringement
|
||||
* or the like. Any license provided herein, whether implied or
|
||||
* otherwise, applies only to this software file. Patent licenses, if
|
||||
* any, provided herein do not apply to combinations of this program with
|
||||
* other software, or any other product whatsoever.
|
||||
*
|
||||
* You should have received a copy of the GNU Lesser General Public
|
||||
* License along with this library; if not, write to the Free Software
|
||||
* Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
|
||||
*
|
||||
* Contact information: MeVis Medical Solutions AG, Universitaetsallee 29,
|
||||
* 28359 Bremen, Germany or:
|
||||
*
|
||||
* http://www.mevis.de
|
||||
*
|
||||
*/
|
||||
|
||||
//----------------------------------------------------------------------------------
|
||||
/*!
|
||||
// \file PythonQtScriptingConsole.cpp
|
||||
// \author Florian Link
|
||||
// \author Last changed by $Author: florian $
|
||||
// \date 2006-10
|
||||
*/
|
||||
//----------------------------------------------------------------------------------
|
||||
|
||||
#include "PythonQtScriptingConsole.h"
|
||||
|
||||
#include <QAbstractItemView>
|
||||
#include <QApplication>
|
||||
#include <QCompleter>
|
||||
#include <QDebug>
|
||||
#include <QKeyEvent>
|
||||
#include <QMenu>
|
||||
#include <QMouseEvent>
|
||||
#include <QScrollBar>
|
||||
#include <QStringListModel>
|
||||
#include <QTextBlock>
|
||||
#include <QTextCursor>
|
||||
#include <QTextDocumentFragment>
|
||||
|
||||
//-----------------------------------------------------------------------------
|
||||
|
||||
PythonQtScriptingConsole::PythonQtScriptingConsole(
|
||||
QWidget *parent, const PythonQtObjectPtr &context,
|
||||
Qt::WindowFlags windowFlags)
|
||||
: QTextEdit(parent) {
|
||||
|
||||
setWindowFlags(windowFlags);
|
||||
|
||||
_defaultTextCharacterFormat = currentCharFormat();
|
||||
_context = context;
|
||||
_historyPosition = 0;
|
||||
_hadError = false;
|
||||
|
||||
_completer = new QCompleter(this);
|
||||
_completer->setWidget(this);
|
||||
QObject::connect(_completer, SIGNAL(activated(const QString &)), this,
|
||||
SLOT(insertCompletion(const QString &)));
|
||||
|
||||
clear();
|
||||
setUndoRedoEnabled(false);
|
||||
setAcceptRichText(false);
|
||||
|
||||
connect(PythonQt::self(), SIGNAL(pythonStdOut(const QString &)), this,
|
||||
SLOT(stdOut(const QString &)));
|
||||
connect(PythonQt::self(), SIGNAL(pythonStdErr(const QString &)), this,
|
||||
SLOT(stdErr(const QString &)));
|
||||
}
|
||||
|
||||
//-----------------------------------------------------------------------------
|
||||
|
||||
void PythonQtScriptingConsole::stdOut(const QString &s) {
|
||||
_stdOut += s;
|
||||
int idx;
|
||||
while ((idx = _stdOut.indexOf('\n')) != -1) {
|
||||
auto msg = _stdOut.left(idx);
|
||||
consoleMessage(QString("<font color=\"green\">%1</font>")
|
||||
.arg(msg)); // modified by wingsummer
|
||||
std::cout << msg.toLatin1().data() << std::endl;
|
||||
_stdOut = _stdOut.mid(idx + 1);
|
||||
}
|
||||
}
|
||||
|
||||
void PythonQtScriptingConsole::stdErr(const QString &s) {
|
||||
_hadError = true;
|
||||
_stdErr += s;
|
||||
int idx;
|
||||
while ((idx = _stdErr.indexOf('\n')) != -1) {
|
||||
auto msg = _stdErr.left(idx);
|
||||
consoleMessage(QString("<font color=\"red\">%1</font>")
|
||||
.arg(msg)); // modified by wingsummer
|
||||
std::cerr << msg.toLatin1().data() << std::endl;
|
||||
_stdErr = _stdErr.mid(idx + 1);
|
||||
}
|
||||
}
|
||||
|
||||
void PythonQtScriptingConsole::flushStdOut() {
|
||||
if (!_stdOut.isEmpty()) {
|
||||
stdOut("\n");
|
||||
}
|
||||
if (!_stdErr.isEmpty()) {
|
||||
stdErr("\n");
|
||||
}
|
||||
}
|
||||
|
||||
//-----------------------------------------------------------------------------
|
||||
|
||||
PythonQtScriptingConsole::~PythonQtScriptingConsole() {}
|
||||
|
||||
//-----------------------------------------------------------------------------
|
||||
|
||||
void PythonQtScriptingConsole::clear() {
|
||||
QTextEdit::clear();
|
||||
appendCommandPrompt();
|
||||
}
|
||||
|
||||
//-----------------------------------------------------------------------------
|
||||
|
||||
void PythonQtScriptingConsole::executeLine(bool storeOnly) {
|
||||
QTextCursor textCursor = this->textCursor();
|
||||
textCursor.movePosition(QTextCursor::End);
|
||||
|
||||
// Select the text from the command prompt until the end of the block
|
||||
// and get the selected text.
|
||||
textCursor.setPosition(commandPromptPosition());
|
||||
textCursor.movePosition(QTextCursor::End, QTextCursor::KeepAnchor);
|
||||
QString code = textCursor.selectedText();
|
||||
|
||||
// i don't know where this trailing space is coming from, blast it!
|
||||
if (code.endsWith(" ")) {
|
||||
code.truncate(code.length() - 1);
|
||||
}
|
||||
|
||||
if (!code.isEmpty()) {
|
||||
// Update the history
|
||||
_history << code;
|
||||
_historyPosition = _history.count();
|
||||
_currentMultiLineCode += code + "\n";
|
||||
|
||||
if (!storeOnly) {
|
||||
executeCode(_currentMultiLineCode);
|
||||
_currentMultiLineCode = "";
|
||||
}
|
||||
}
|
||||
// Insert a new command prompt
|
||||
appendCommandPrompt(storeOnly);
|
||||
}
|
||||
|
||||
void PythonQtScriptingConsole::executeCode(const QString &code) {
|
||||
// put visible cursor to the end of the line
|
||||
QTextCursor cursor = QTextEdit::textCursor();
|
||||
cursor.movePosition(QTextCursor::End);
|
||||
setTextCursor(cursor);
|
||||
|
||||
// int cursorPosition = this->textCursor().position();
|
||||
|
||||
// evaluate the code
|
||||
_stdOut = "";
|
||||
_stdErr = "";
|
||||
PythonQtObjectPtr p;
|
||||
PyObject *dict = nullptr;
|
||||
if (PyModule_Check(_context)) {
|
||||
dict = PyModule_GetDict(_context);
|
||||
} else if (PyDict_Check(_context)) {
|
||||
dict = _context;
|
||||
}
|
||||
if (dict) {
|
||||
p.setNewRef(
|
||||
PyRun_String(code.toUtf8().data(), Py_single_input, dict, dict));
|
||||
}
|
||||
|
||||
if (!p) {
|
||||
PythonQt::self()->handleError();
|
||||
}
|
||||
|
||||
flushStdOut();
|
||||
|
||||
// bool messageInserted = (this->textCursor().position() != cursorPosition);
|
||||
// If a message was inserted, then put another empty line before the command
|
||||
// prompt to improve readability.
|
||||
// if (messageInserted) {
|
||||
// append(QString());
|
||||
//}
|
||||
}
|
||||
|
||||
//-----------------------------------------------------------------------------
|
||||
|
||||
void PythonQtScriptingConsole::appendCommandPrompt(bool storeOnly) {
|
||||
if (storeOnly) {
|
||||
_commandPrompt = "... > ";
|
||||
} else {
|
||||
_commandPrompt = "py > ";
|
||||
}
|
||||
append(_commandPrompt);
|
||||
|
||||
QTextCursor cursor = textCursor();
|
||||
cursor.movePosition(QTextCursor::End);
|
||||
setTextCursor(cursor);
|
||||
}
|
||||
|
||||
//-----------------------------------------------------------------------------
|
||||
|
||||
void PythonQtScriptingConsole::setCurrentFont(const QColor &color, bool bold) {
|
||||
|
||||
QTextCharFormat charFormat(_defaultTextCharacterFormat);
|
||||
|
||||
QFont font(charFormat.font());
|
||||
font.setBold(bold);
|
||||
charFormat.setFont(font);
|
||||
|
||||
QBrush brush(charFormat.foreground());
|
||||
brush.setColor(color);
|
||||
charFormat.setForeground(brush);
|
||||
|
||||
setCurrentCharFormat(charFormat);
|
||||
}
|
||||
|
||||
//-----------------------------------------------------------------------------
|
||||
|
||||
int PythonQtScriptingConsole::commandPromptPosition() {
|
||||
|
||||
QTextCursor textCursor(this->textCursor());
|
||||
textCursor.movePosition(QTextCursor::End);
|
||||
|
||||
return textCursor.block().position() + _commandPrompt.length();
|
||||
}
|
||||
|
||||
//-----------------------------------------------------------------------------
|
||||
|
||||
void PythonQtScriptingConsole::insertCompletion(const QString &completion) {
|
||||
QTextCursor tc = textCursor();
|
||||
tc.movePosition(QTextCursor::Left, QTextCursor::KeepAnchor);
|
||||
if (tc.selectedText() == ".") {
|
||||
tc.insertText(QString(".") + completion);
|
||||
} else {
|
||||
tc = textCursor();
|
||||
tc.movePosition(QTextCursor::StartOfWord, QTextCursor::MoveAnchor);
|
||||
tc.movePosition(QTextCursor::EndOfWord, QTextCursor::KeepAnchor);
|
||||
tc.insertText(completion);
|
||||
setTextCursor(tc);
|
||||
}
|
||||
}
|
||||
|
||||
//-----------------------------------------------------------------------------
|
||||
void PythonQtScriptingConsole::handleTabCompletion() {
|
||||
QTextCursor textCursor = this->textCursor();
|
||||
int pos = textCursor.position();
|
||||
textCursor.setPosition(commandPromptPosition());
|
||||
textCursor.movePosition(QTextCursor::End, QTextCursor::KeepAnchor);
|
||||
int startPos = textCursor.selectionStart();
|
||||
|
||||
int offset = pos - startPos;
|
||||
QString text = textCursor.selectedText();
|
||||
|
||||
QString textToComplete;
|
||||
int cur = offset;
|
||||
while (cur--) {
|
||||
QChar c = text.at(cur);
|
||||
if (c.isLetterOrNumber() || c == '.' || c == '_') {
|
||||
textToComplete.prepend(c);
|
||||
} else {
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
QString lookup;
|
||||
QString compareText = textToComplete;
|
||||
int dot = compareText.lastIndexOf('.');
|
||||
if (dot != -1) {
|
||||
lookup = compareText.mid(0, dot);
|
||||
compareText = compareText.mid(dot + 1, offset);
|
||||
}
|
||||
if (!lookup.isEmpty() || !compareText.isEmpty()) {
|
||||
compareText = compareText.toLower();
|
||||
QStringList found;
|
||||
QStringList l =
|
||||
PythonQt::self()->introspection(_context, lookup, PythonQt::Anything);
|
||||
Q_FOREACH (QString n, l) {
|
||||
if (n.toLower().startsWith(compareText)) {
|
||||
found << n;
|
||||
}
|
||||
}
|
||||
|
||||
if (!found.isEmpty()) {
|
||||
_completer->setCompletionPrefix(compareText);
|
||||
_completer->setCompletionMode(QCompleter::PopupCompletion);
|
||||
_completer->setModel(new QStringListModel(found, _completer));
|
||||
_completer->setCaseSensitivity(Qt::CaseInsensitive);
|
||||
QTextCursor c = this->textCursor();
|
||||
c.movePosition(QTextCursor::StartOfWord);
|
||||
QRect cr = cursorRect(c);
|
||||
cr.setWidth(_completer->popup()->sizeHintForColumn(0) +
|
||||
_completer->popup()->verticalScrollBar()->sizeHint().width());
|
||||
cr.translate(0, 8);
|
||||
_completer->complete(cr);
|
||||
} else {
|
||||
_completer->popup()->hide();
|
||||
}
|
||||
} else {
|
||||
_completer->popup()->hide();
|
||||
}
|
||||
}
|
||||
|
||||
void PythonQtScriptingConsole::keyPressEvent(QKeyEvent *event) {
|
||||
|
||||
if (_completer && _completer->popup()->isVisible()) {
|
||||
// The following keys are forwarded by the completer to the widget
|
||||
switch (event->key()) {
|
||||
case Qt::Key_Return:
|
||||
if (!_completer->popup()->currentIndex().isValid()) {
|
||||
insertCompletion(_completer->currentCompletion());
|
||||
_completer->popup()->hide();
|
||||
event->accept();
|
||||
}
|
||||
event->ignore();
|
||||
return;
|
||||
break;
|
||||
case Qt::Key_Enter:
|
||||
case Qt::Key_Escape:
|
||||
case Qt::Key_Tab:
|
||||
case Qt::Key_Backtab:
|
||||
|
||||
event->ignore();
|
||||
return; // let the completer do default behavior
|
||||
default:
|
||||
break;
|
||||
}
|
||||
}
|
||||
bool eventHandled = false;
|
||||
QTextCursor textCursor = this->textCursor();
|
||||
|
||||
int key = event->key();
|
||||
switch (key) {
|
||||
|
||||
case Qt::Key_Left:
|
||||
|
||||
// Moving the cursor left is limited to the position
|
||||
// of the command prompt.
|
||||
|
||||
if (textCursor.position() <= commandPromptPosition()) {
|
||||
|
||||
QApplication::beep();
|
||||
eventHandled = true;
|
||||
}
|
||||
break;
|
||||
|
||||
case Qt::Key_Up:
|
||||
|
||||
// Display the previous command in the history
|
||||
if (_historyPosition > 0) {
|
||||
_historyPosition--;
|
||||
changeHistory();
|
||||
}
|
||||
|
||||
eventHandled = true;
|
||||
break;
|
||||
|
||||
case Qt::Key_Down:
|
||||
|
||||
// Display the next command in the history
|
||||
if (_historyPosition + 1 < _history.count()) {
|
||||
_historyPosition++;
|
||||
changeHistory();
|
||||
}
|
||||
|
||||
eventHandled = true;
|
||||
break;
|
||||
|
||||
case Qt::Key_Return:
|
||||
|
||||
executeLine(event->modifiers() & Qt::ShiftModifier);
|
||||
eventHandled = true;
|
||||
break;
|
||||
|
||||
case Qt::Key_Backspace:
|
||||
|
||||
if (textCursor.hasSelection()) {
|
||||
|
||||
cut();
|
||||
eventHandled = true;
|
||||
|
||||
} else {
|
||||
|
||||
// Intercept backspace key event to check if
|
||||
// deleting a character is allowed. It is not
|
||||
// allowed, if the user wants to delete the
|
||||
// command prompt.
|
||||
|
||||
if (textCursor.position() <= commandPromptPosition()) {
|
||||
|
||||
QApplication::beep();
|
||||
eventHandled = true;
|
||||
}
|
||||
}
|
||||
break;
|
||||
|
||||
case Qt::Key_Delete:
|
||||
|
||||
cut();
|
||||
eventHandled = true;
|
||||
break;
|
||||
|
||||
default:
|
||||
|
||||
if (key >= Qt::Key_Space && key <= Qt::Key_division) {
|
||||
|
||||
if (textCursor.hasSelection() && !verifySelectionBeforeDeletion()) {
|
||||
|
||||
// The selection must not be deleted.
|
||||
eventHandled = true;
|
||||
|
||||
} else {
|
||||
|
||||
// The key is an input character, check if the cursor is
|
||||
// behind the last command prompt, else inserting the
|
||||
// character is not allowed.
|
||||
|
||||
int commandPromptPosition = this->commandPromptPosition();
|
||||
if (textCursor.position() < commandPromptPosition) {
|
||||
|
||||
textCursor.setPosition(commandPromptPosition);
|
||||
setTextCursor(textCursor);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
if (eventHandled) {
|
||||
|
||||
_completer->popup()->hide();
|
||||
event->accept();
|
||||
|
||||
} else {
|
||||
|
||||
QTextEdit::keyPressEvent(event);
|
||||
QString text = event->text();
|
||||
if (!text.isEmpty()) {
|
||||
handleTabCompletion();
|
||||
} else {
|
||||
_completer->popup()->hide();
|
||||
}
|
||||
eventHandled = true;
|
||||
}
|
||||
}
|
||||
|
||||
//-----------------------------------------------------------------------------
|
||||
|
||||
void PythonQtScriptingConsole::cut() {
|
||||
|
||||
bool deletionAllowed = verifySelectionBeforeDeletion();
|
||||
if (deletionAllowed) {
|
||||
QTextEdit::cut();
|
||||
}
|
||||
}
|
||||
|
||||
//-----------------------------------------------------------------------------
|
||||
|
||||
bool PythonQtScriptingConsole::verifySelectionBeforeDeletion() {
|
||||
|
||||
bool deletionAllowed = true;
|
||||
|
||||
QTextCursor textCursor = this->textCursor();
|
||||
|
||||
int commandPromptPosition = this->commandPromptPosition();
|
||||
int selectionStart = textCursor.selectionStart();
|
||||
int selectionEnd = textCursor.selectionEnd();
|
||||
|
||||
if (textCursor.hasSelection()) {
|
||||
|
||||
// Selected text may only be deleted after the last command prompt.
|
||||
// If the selection is partly after the command prompt set the selection
|
||||
// to the part and deletion is allowed. If the selection occurs before the
|
||||
// last command prompt, then deletion is not allowed.
|
||||
|
||||
if (selectionStart < commandPromptPosition ||
|
||||
selectionEnd < commandPromptPosition) {
|
||||
|
||||
// Assure selectionEnd is bigger than selection start
|
||||
if (selectionStart > selectionEnd) {
|
||||
int tmp = selectionEnd;
|
||||
selectionEnd = selectionStart;
|
||||
selectionStart = tmp;
|
||||
}
|
||||
|
||||
if (selectionEnd < commandPromptPosition) {
|
||||
|
||||
// Selection is completely before command prompt,
|
||||
// so deletion is not allowed.
|
||||
QApplication::beep();
|
||||
deletionAllowed = false;
|
||||
|
||||
} else {
|
||||
|
||||
// The selectionEnd is after the command prompt, so set
|
||||
// the selection start to the commandPromptPosition.
|
||||
selectionStart = commandPromptPosition;
|
||||
textCursor.setPosition(selectionStart);
|
||||
textCursor.setPosition(selectionStart, QTextCursor::KeepAnchor);
|
||||
setTextCursor(textCursor);
|
||||
}
|
||||
}
|
||||
|
||||
} else { // if (hasSelectedText())
|
||||
|
||||
// When there is no selected text, deletion is not allowed before the
|
||||
// command prompt.
|
||||
if (textCursor.position() < commandPromptPosition) {
|
||||
|
||||
QApplication::beep();
|
||||
deletionAllowed = false;
|
||||
}
|
||||
}
|
||||
|
||||
return deletionAllowed;
|
||||
}
|
||||
|
||||
//-----------------------------------------------------------------------------
|
||||
|
||||
void PythonQtScriptingConsole::changeHistory() {
|
||||
|
||||
// Select the text after the last command prompt ...
|
||||
QTextCursor textCursor = this->textCursor();
|
||||
textCursor.movePosition(QTextCursor::End);
|
||||
textCursor.setPosition(commandPromptPosition(), QTextCursor::KeepAnchor);
|
||||
|
||||
// ... and replace it with the history text.
|
||||
textCursor.insertText(_history.value(_historyPosition));
|
||||
|
||||
textCursor.movePosition(QTextCursor::End);
|
||||
setTextCursor(textCursor);
|
||||
}
|
||||
|
||||
//-----------------------------------------------------------------------------
|
||||
|
||||
void PythonQtScriptingConsole::consoleMessage(const QString &message) {
|
||||
append(QString());
|
||||
insertHtml(message); // modified by wingsummer
|
||||
|
||||
// Reset all font modifications done by the html string
|
||||
setCurrentCharFormat(_defaultTextCharacterFormat);
|
||||
}
|
|
@ -0,0 +1,147 @@
|
|||
#ifndef PythonQtScriptingConsole_H
|
||||
#define PythonQtScriptingConsole_H
|
||||
|
||||
/*
|
||||
*
|
||||
* Copyright (C) 2010 MeVis Medical Solutions AG All Rights Reserved.
|
||||
*
|
||||
* This library is free software; you can redistribute it and/or
|
||||
* modify it under the terms of the GNU Lesser General Public
|
||||
* License as published by the Free Software Foundation; either
|
||||
* version 2.1 of the License, or (at your option) any later version.
|
||||
*
|
||||
* This library is distributed in the hope that it will be useful,
|
||||
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
|
||||
* Lesser General Public License for more details.
|
||||
*
|
||||
* Further, this software is distributed without any warranty that it is
|
||||
* free of the rightful claim of any third person regarding infringement
|
||||
* or the like. Any license provided herein, whether implied or
|
||||
* otherwise, applies only to this software file. Patent licenses, if
|
||||
* any, provided herein do not apply to combinations of this program with
|
||||
* other software, or any other product whatsoever.
|
||||
*
|
||||
* You should have received a copy of the GNU Lesser General Public
|
||||
* License along with this library; if not, write to the Free Software
|
||||
* Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
|
||||
*
|
||||
* Contact information: MeVis Medical Solutions AG, Universitaetsallee 29,
|
||||
* 28359 Bremen, Germany or:
|
||||
*
|
||||
* http://www.mevis.de
|
||||
*
|
||||
*/
|
||||
|
||||
//----------------------------------------------------------------------------------
|
||||
/*!
|
||||
// \file PythonQtScriptingConsole.h
|
||||
// \author Florian Link
|
||||
// \author Last changed by $Author: florian $
|
||||
// \date 2006-10
|
||||
*/
|
||||
//----------------------------------------------------------------------------------
|
||||
|
||||
#include "../PythonQt.h"
|
||||
#include <QTextEdit>
|
||||
#include <QVariant>
|
||||
|
||||
class QCompleter;
|
||||
|
||||
//-------------------------------------------------------------------------------
|
||||
//! A simple console for python scripting
|
||||
class PYTHONQT_EXPORT PythonQtScriptingConsole : public QTextEdit {
|
||||
Q_OBJECT
|
||||
|
||||
public:
|
||||
PythonQtScriptingConsole(QWidget *parent, const PythonQtObjectPtr &context,
|
||||
Qt::WindowFlags i = Qt::Widget);
|
||||
|
||||
~PythonQtScriptingConsole();
|
||||
|
||||
public Q_SLOTS:
|
||||
//! execute current line
|
||||
void executeLine(bool storeOnly);
|
||||
|
||||
//! derived key press event
|
||||
void keyPressEvent(QKeyEvent *e);
|
||||
|
||||
//! output from console
|
||||
void consoleMessage(const QString &message);
|
||||
|
||||
//! get history
|
||||
QStringList history() { return _history; }
|
||||
|
||||
//! set history
|
||||
void setHistory(const QStringList &h) {
|
||||
_history = h;
|
||||
_historyPosition = 0;
|
||||
}
|
||||
|
||||
//! clear the console
|
||||
void clear();
|
||||
|
||||
//! overridden to control which characters a user may delete
|
||||
virtual void cut();
|
||||
|
||||
//! output redirection
|
||||
void stdOut(const QString &s);
|
||||
//! output redirection
|
||||
void stdErr(const QString &s);
|
||||
|
||||
void insertCompletion(const QString &);
|
||||
|
||||
//! Appends a newline and command prompt at the end of the document.
|
||||
void appendCommandPrompt(bool storeOnly = false);
|
||||
|
||||
public:
|
||||
//! returns true if python cerr had an error
|
||||
bool hadError() { return _hadError; }
|
||||
|
||||
//! returns true if python cerr had an error
|
||||
void clearError() { _hadError = false; }
|
||||
|
||||
protected:
|
||||
//! handle the pressing of tab
|
||||
void handleTabCompletion();
|
||||
|
||||
//! Returns the position of the command prompt
|
||||
int commandPromptPosition();
|
||||
|
||||
//! Returns if deletion is allowed at the current cursor
|
||||
//! (with and without selected text)
|
||||
bool verifySelectionBeforeDeletion();
|
||||
|
||||
//! Sets the current font
|
||||
void setCurrentFont(const QColor &color = QColor(0, 0, 0), bool bold = false);
|
||||
|
||||
//! change the history according to _historyPos
|
||||
void changeHistory();
|
||||
|
||||
//! flush output that was not yet printed
|
||||
void flushStdOut();
|
||||
|
||||
private:
|
||||
void executeCode(const QString &code);
|
||||
|
||||
PythonQtObjectPtr _context;
|
||||
|
||||
QStringList _history;
|
||||
int _historyPosition;
|
||||
|
||||
QString _clickedAnchor;
|
||||
QString _storageKey;
|
||||
QString _commandPrompt;
|
||||
|
||||
QString _currentMultiLineCode;
|
||||
|
||||
QString _stdOut;
|
||||
QString _stdErr;
|
||||
|
||||
QTextCharFormat _defaultTextCharacterFormat;
|
||||
QCompleter *_completer;
|
||||
|
||||
bool _hadError;
|
||||
};
|
||||
|
||||
#endif
|
|
@ -0,0 +1,642 @@
|
|||
// QCodeEditor
|
||||
#include "QCodeEditor.hpp"
|
||||
#include "QFramedTextAttribute.hpp"
|
||||
#include "QLineNumberArea.hpp"
|
||||
#include "QPythonHighlighter.hpp"
|
||||
#include "QStyleSyntaxHighlighter.hpp"
|
||||
#include "QSyntaxStyle.hpp"
|
||||
|
||||
// Qt
|
||||
#include <QAbstractItemView>
|
||||
#include <QAbstractTextDocumentLayout>
|
||||
#include <QCompleter>
|
||||
#include <QCursor>
|
||||
#include <QFontDatabase>
|
||||
#include <QMimeData>
|
||||
#include <QPaintEvent>
|
||||
#include <QScrollBar>
|
||||
#include <QShortcut>
|
||||
#include <QTextBlock>
|
||||
#include <QTextCharFormat>
|
||||
|
||||
// PythonQt
|
||||
#include <QStringListModel>
|
||||
|
||||
static QVector<QPair<QString, QString>> parentheses = {
|
||||
{"(", ")"}, {"{", "}"}, {"[", "]"}, {"\"", "\""}, {"'", "'"}};
|
||||
|
||||
QCodeEditor::QCodeEditor(QWidget *widget)
|
||||
: QTextEdit(widget), m_highlighter(nullptr), m_syntaxStyle(nullptr),
|
||||
m_lineNumberArea(new QLineNumberArea(this)),
|
||||
m_completer(new QCompleter(this)),
|
||||
m_framedAttribute(new QFramedTextAttribute(this)),
|
||||
m_autoIndentation(true), m_autoParentheses(true), m_replaceTab(true),
|
||||
m_tabReplace(QString(4, ' ')) {
|
||||
initDocumentLayoutHandlers();
|
||||
initFont();
|
||||
performConnections();
|
||||
setSyntaxStyle(QSyntaxStyle::defaultStyle());
|
||||
py = PythonQt::self();
|
||||
_context = py->getMainModule();
|
||||
connect(m_completer, QOverload<const QString &>::of(&QCompleter::activated),
|
||||
this, &QCodeEditor::insertCompletion);
|
||||
}
|
||||
|
||||
void QCodeEditor::initDocumentLayoutHandlers() {
|
||||
document()->documentLayout()->registerHandler(QFramedTextAttribute::type(),
|
||||
m_framedAttribute);
|
||||
}
|
||||
|
||||
void QCodeEditor::initFont() {
|
||||
auto fnt = QFontDatabase::systemFont(QFontDatabase::FixedFont);
|
||||
fnt.setFixedPitch(true);
|
||||
fnt.setPointSize(10);
|
||||
|
||||
setFont(fnt);
|
||||
}
|
||||
|
||||
void QCodeEditor::performConnections() {
|
||||
connect(document(), &QTextDocument::blockCountChanged, this,
|
||||
&QCodeEditor::updateLineNumberAreaWidth);
|
||||
|
||||
connect(verticalScrollBar(), &QScrollBar::valueChanged,
|
||||
[this](int) { m_lineNumberArea->update(); });
|
||||
|
||||
connect(this, &QTextEdit::cursorPositionChanged, this,
|
||||
&QCodeEditor::updateExtraSelection);
|
||||
|
||||
connect(this, &QTextEdit::selectionChanged, this,
|
||||
&QCodeEditor::onSelectionChanged);
|
||||
}
|
||||
|
||||
void QCodeEditor::setHighlighter(QStyleSyntaxHighlighter *highlighter) {
|
||||
if (m_highlighter) {
|
||||
m_highlighter->setDocument(nullptr);
|
||||
}
|
||||
|
||||
m_highlighter = highlighter;
|
||||
|
||||
if (m_highlighter) {
|
||||
m_highlighter->setSyntaxStyle(m_syntaxStyle);
|
||||
m_highlighter->setDocument(document());
|
||||
}
|
||||
}
|
||||
|
||||
void QCodeEditor::setSyntaxStyle(QSyntaxStyle *style) {
|
||||
m_syntaxStyle = style;
|
||||
|
||||
m_framedAttribute->setSyntaxStyle(m_syntaxStyle);
|
||||
m_lineNumberArea->setSyntaxStyle(m_syntaxStyle);
|
||||
|
||||
if (m_highlighter) {
|
||||
m_highlighter->setSyntaxStyle(m_syntaxStyle);
|
||||
}
|
||||
|
||||
updateStyle();
|
||||
}
|
||||
|
||||
void QCodeEditor::updateStyle() {
|
||||
if (m_highlighter) {
|
||||
m_highlighter->rehighlight();
|
||||
}
|
||||
|
||||
if (m_syntaxStyle) {
|
||||
auto currentPalette = palette();
|
||||
|
||||
// Setting text format/color
|
||||
currentPalette.setColor(
|
||||
QPalette::ColorRole::Text,
|
||||
m_syntaxStyle->getFormat("Text").foreground().color());
|
||||
|
||||
// Setting common background
|
||||
currentPalette.setColor(
|
||||
QPalette::Base, m_syntaxStyle->getFormat("Text").background().color());
|
||||
|
||||
// Setting selection color
|
||||
currentPalette.setColor(
|
||||
QPalette::Highlight,
|
||||
m_syntaxStyle->getFormat("Selection").background().color());
|
||||
|
||||
setPalette(currentPalette);
|
||||
}
|
||||
|
||||
updateExtraSelection();
|
||||
}
|
||||
|
||||
void QCodeEditor::onSelectionChanged() {
|
||||
auto selected = textCursor().selectedText();
|
||||
|
||||
auto cursor = textCursor();
|
||||
|
||||
// Cursor is null if setPlainText was called.
|
||||
if (cursor.isNull()) {
|
||||
return;
|
||||
}
|
||||
|
||||
cursor.movePosition(QTextCursor::MoveOperation::Left);
|
||||
cursor.select(QTextCursor::SelectionType::WordUnderCursor);
|
||||
|
||||
QSignalBlocker blocker(this);
|
||||
m_framedAttribute->clear(cursor);
|
||||
|
||||
if (selected.size() > 1 && cursor.selectedText() == selected) {
|
||||
auto backup = textCursor();
|
||||
|
||||
// Perform search selecting
|
||||
handleSelectionQuery(cursor);
|
||||
|
||||
setTextCursor(backup);
|
||||
}
|
||||
}
|
||||
|
||||
void QCodeEditor::resizeEvent(QResizeEvent *e) {
|
||||
QTextEdit::resizeEvent(e);
|
||||
|
||||
updateLineGeometry();
|
||||
}
|
||||
|
||||
void QCodeEditor::updateLineGeometry() {
|
||||
QRect cr = contentsRect();
|
||||
m_lineNumberArea->setGeometry(QRect(
|
||||
cr.left(), cr.top(), m_lineNumberArea->sizeHint().width(), cr.height()));
|
||||
}
|
||||
|
||||
void QCodeEditor::updateLineNumberAreaWidth(int) {
|
||||
setViewportMargins(m_lineNumberArea->sizeHint().width(), 0, 0, 0);
|
||||
}
|
||||
|
||||
void QCodeEditor::updateLineNumberArea(const QRect &rect) {
|
||||
m_lineNumberArea->update(0, rect.y(), m_lineNumberArea->sizeHint().width(),
|
||||
rect.height());
|
||||
updateLineGeometry();
|
||||
|
||||
if (rect.contains(viewport()->rect())) {
|
||||
updateLineNumberAreaWidth(0);
|
||||
}
|
||||
}
|
||||
|
||||
void QCodeEditor::handleSelectionQuery(QTextCursor cursor) {
|
||||
|
||||
auto searchIterator = cursor;
|
||||
searchIterator.movePosition(QTextCursor::Start);
|
||||
searchIterator = document()->find(cursor.selectedText(), searchIterator);
|
||||
while (searchIterator.hasSelection()) {
|
||||
m_framedAttribute->frame(searchIterator);
|
||||
|
||||
searchIterator = document()->find(cursor.selectedText(), searchIterator);
|
||||
}
|
||||
}
|
||||
|
||||
void QCodeEditor::updateExtraSelection() {
|
||||
QList<QTextEdit::ExtraSelection> extra;
|
||||
|
||||
highlightCurrentLine(extra);
|
||||
highlightParenthesis(extra);
|
||||
|
||||
setExtraSelections(extra);
|
||||
}
|
||||
|
||||
void QCodeEditor::highlightParenthesis(
|
||||
QList<QTextEdit::ExtraSelection> &extraSelection) {
|
||||
auto currentSymbol = charUnderCursor();
|
||||
auto prevSymbol = charUnderCursor(-1);
|
||||
|
||||
for (auto &pair : parentheses) {
|
||||
int direction;
|
||||
|
||||
QChar counterSymbol;
|
||||
QChar activeSymbol;
|
||||
auto position = textCursor().position();
|
||||
|
||||
if (pair.first == currentSymbol) {
|
||||
direction = 1;
|
||||
counterSymbol = pair.second[0];
|
||||
activeSymbol = currentSymbol;
|
||||
} else if (pair.second == prevSymbol) {
|
||||
direction = -1;
|
||||
counterSymbol = pair.first[0];
|
||||
activeSymbol = prevSymbol;
|
||||
position--;
|
||||
} else {
|
||||
continue;
|
||||
}
|
||||
|
||||
auto counter = 1;
|
||||
|
||||
while (counter != 0 && position > 0 &&
|
||||
position < (document()->characterCount() - 1)) {
|
||||
// Moving position
|
||||
position += direction;
|
||||
|
||||
auto character = document()->characterAt(position);
|
||||
// Checking symbol under position
|
||||
if (character == activeSymbol) {
|
||||
++counter;
|
||||
} else if (character == counterSymbol) {
|
||||
--counter;
|
||||
}
|
||||
}
|
||||
|
||||
auto format = m_syntaxStyle->getFormat("Parentheses");
|
||||
|
||||
// Found
|
||||
if (counter == 0) {
|
||||
ExtraSelection selection{};
|
||||
|
||||
auto directionEnum = direction < 0 ? QTextCursor::MoveOperation::Left
|
||||
: QTextCursor::MoveOperation::Right;
|
||||
|
||||
selection.format = format;
|
||||
selection.cursor = textCursor();
|
||||
selection.cursor.clearSelection();
|
||||
selection.cursor.movePosition(
|
||||
directionEnum, QTextCursor::MoveMode::MoveAnchor,
|
||||
std::abs(textCursor().position() - position));
|
||||
|
||||
selection.cursor.movePosition(QTextCursor::MoveOperation::Right,
|
||||
QTextCursor::MoveMode::KeepAnchor, 1);
|
||||
|
||||
extraSelection.append(selection);
|
||||
|
||||
selection.cursor = textCursor();
|
||||
selection.cursor.clearSelection();
|
||||
selection.cursor.movePosition(directionEnum,
|
||||
QTextCursor::MoveMode::KeepAnchor, 1);
|
||||
|
||||
extraSelection.append(selection);
|
||||
}
|
||||
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
void QCodeEditor::highlightCurrentLine(
|
||||
QList<QTextEdit::ExtraSelection> &extraSelection) {
|
||||
if (!isReadOnly()) {
|
||||
QTextEdit::ExtraSelection selection{};
|
||||
|
||||
selection.format = m_syntaxStyle->getFormat("CurrentLine");
|
||||
selection.format.setForeground(QBrush());
|
||||
selection.format.setProperty(QTextFormat::FullWidthSelection, true);
|
||||
selection.cursor = textCursor();
|
||||
selection.cursor.clearSelection();
|
||||
|
||||
extraSelection.append(selection);
|
||||
}
|
||||
}
|
||||
|
||||
void QCodeEditor::paintEvent(QPaintEvent *e) {
|
||||
updateLineNumberArea(e->rect());
|
||||
QTextEdit::paintEvent(e);
|
||||
}
|
||||
|
||||
int QCodeEditor::getFirstVisibleBlock() {
|
||||
// Detect the first block for which bounding rect - once translated
|
||||
// in absolute coordinated - is contained by the editor's text area
|
||||
|
||||
// Costly way of doing but since "blockBoundingGeometry(...)" doesn't
|
||||
// exists for "QTextEdit"...
|
||||
|
||||
QTextCursor curs = QTextCursor(document());
|
||||
curs.movePosition(QTextCursor::Start);
|
||||
for (int i = 0; i < document()->blockCount(); ++i) {
|
||||
QTextBlock block = curs.block();
|
||||
|
||||
QRect r1 = viewport()->geometry();
|
||||
QRect r2 = document()
|
||||
->documentLayout()
|
||||
->blockBoundingRect(block)
|
||||
.translated(viewport()->geometry().x(),
|
||||
viewport()->geometry().y() -
|
||||
verticalScrollBar()->sliderPosition())
|
||||
.toRect();
|
||||
|
||||
if (r1.intersects(r2)) {
|
||||
return i;
|
||||
}
|
||||
|
||||
curs.movePosition(QTextCursor::NextBlock);
|
||||
}
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
bool QCodeEditor::proceedCompleterBegin(QKeyEvent *e) {
|
||||
if (m_completer && m_completer->popup()->isVisible()) {
|
||||
switch (e->key()) {
|
||||
case Qt::Key_Enter:
|
||||
case Qt::Key_Return: { // added by wingsummer
|
||||
if (!m_completer->popup()->currentIndex().isValid()) {
|
||||
insertCompletion(m_completer->currentCompletion());
|
||||
m_completer->popup()->hide();
|
||||
e->accept();
|
||||
}
|
||||
e->ignore();
|
||||
return true;
|
||||
break;
|
||||
}
|
||||
case Qt::Key_Escape:
|
||||
case Qt::Key_Tab:
|
||||
case Qt::Key_Backtab:
|
||||
e->ignore();
|
||||
return true; // let the completer do default behavior
|
||||
default:
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
// todo: Replace with modifiable QShortcut
|
||||
auto isShortcut =
|
||||
((e->modifiers() & Qt::ControlModifier) && e->key() == Qt::Key_Space);
|
||||
|
||||
return !(!m_completer || !isShortcut);
|
||||
}
|
||||
|
||||
void QCodeEditor::proceedCompleterEnd(QKeyEvent *e) {
|
||||
auto ctrlOrShift = e->modifiers() & (Qt::ControlModifier | Qt::ShiftModifier);
|
||||
|
||||
if (!m_completer || (ctrlOrShift && e->text().isEmpty()) ||
|
||||
e->key() == Qt::Key_Delete) {
|
||||
return;
|
||||
}
|
||||
|
||||
static QString eow(R"(~!@#$%^&*()_+{}|:"<>?,./;'[]\-=)");
|
||||
|
||||
auto isShortcut =
|
||||
((e->modifiers() & Qt::ControlModifier) && e->key() == Qt::Key_Space);
|
||||
auto completionPrefix = wordUnderCursor();
|
||||
|
||||
if (!isShortcut && (e->text().isEmpty() || completionPrefix.length() < 2 ||
|
||||
eow.contains(e->text().right(1)))) {
|
||||
m_completer->popup()->hide();
|
||||
return;
|
||||
}
|
||||
|
||||
// if (completionPrefix != m_completer->completionPrefix()) {
|
||||
// m_completer->setCompletionPrefix(completionPrefix);
|
||||
// m_completer->popup()->setCurrentIndex(
|
||||
// m_completer->completionModel()->index(0, 0));
|
||||
// }
|
||||
|
||||
// auto cursRect = cursorRect();
|
||||
// cursRect.setWidth(
|
||||
// m_completer->popup()->sizeHintForColumn(0) +
|
||||
// m_completer->popup()->verticalScrollBar()->sizeHint().width());
|
||||
|
||||
handleTabCompletion();
|
||||
}
|
||||
|
||||
void QCodeEditor::keyPressEvent(QKeyEvent *e) {
|
||||
#if QT_VERSION >= 0x050A00
|
||||
const int defaultIndent =
|
||||
int(tabStopDistance() / fontMetrics().averageCharWidth());
|
||||
#else
|
||||
const int defaultIndent = tabStopWidth() / fontMetrics().averageCharWidth();
|
||||
#endif
|
||||
|
||||
auto completerSkip = proceedCompleterBegin(e);
|
||||
|
||||
if (!completerSkip) {
|
||||
if (m_replaceTab && e->key() == Qt::Key_Tab &&
|
||||
e->modifiers() == Qt::NoModifier) {
|
||||
insertPlainText(m_tabReplace);
|
||||
return;
|
||||
}
|
||||
|
||||
// Auto indentation
|
||||
int indentationLevel = getIndentationSpaces();
|
||||
|
||||
#if QT_VERSION >= 0x050A00
|
||||
int tabCounts = int(indentationLevel * fontMetrics().averageCharWidth() /
|
||||
tabStopDistance());
|
||||
#else
|
||||
int tabCounts =
|
||||
indentationLevel * fontMetrics().averageCharWidth() / tabStopWidth();
|
||||
#endif
|
||||
|
||||
// Have Qt Edior like behaviour, if {|} and enter is pressed indent the two
|
||||
// parenthesis
|
||||
if (m_autoIndentation &&
|
||||
(e->key() == Qt::Key_Return || e->key() == Qt::Key_Enter) &&
|
||||
charUnderCursor() == '}' && charUnderCursor(-1) == '{') {
|
||||
int charsBack = 0;
|
||||
insertPlainText("\n");
|
||||
|
||||
if (m_replaceTab)
|
||||
insertPlainText(QString(indentationLevel + defaultIndent, ' '));
|
||||
else
|
||||
insertPlainText(QString(tabCounts + 1, '\t'));
|
||||
|
||||
insertPlainText("\n");
|
||||
charsBack++;
|
||||
|
||||
if (m_replaceTab) {
|
||||
insertPlainText(QString(indentationLevel, ' '));
|
||||
charsBack += indentationLevel;
|
||||
} else {
|
||||
insertPlainText(QString(tabCounts, '\t'));
|
||||
charsBack += tabCounts;
|
||||
}
|
||||
|
||||
while (charsBack--)
|
||||
moveCursor(QTextCursor::MoveOperation::Left);
|
||||
return;
|
||||
}
|
||||
|
||||
// Shortcut for moving line to left
|
||||
if (m_replaceTab && e->key() == Qt::Key_Backtab) {
|
||||
indentationLevel = std::min(indentationLevel, m_tabReplace.size());
|
||||
|
||||
auto cursor = textCursor();
|
||||
|
||||
cursor.movePosition(QTextCursor::MoveOperation::StartOfLine);
|
||||
cursor.movePosition(QTextCursor::MoveOperation::Right,
|
||||
QTextCursor::MoveMode::KeepAnchor, indentationLevel);
|
||||
|
||||
cursor.removeSelectedText();
|
||||
return;
|
||||
}
|
||||
|
||||
QTextEdit::keyPressEvent(e);
|
||||
|
||||
if (m_autoIndentation &&
|
||||
(e->key() == Qt::Key_Return || e->key() == Qt::Key_Enter)) {
|
||||
if (m_replaceTab)
|
||||
insertPlainText(QString(indentationLevel, ' '));
|
||||
else
|
||||
insertPlainText(QString(tabCounts, '\t'));
|
||||
}
|
||||
|
||||
if (m_autoParentheses) {
|
||||
for (auto &&el : parentheses) {
|
||||
// Inserting closed brace
|
||||
if (el.first == e->text()) {
|
||||
insertPlainText(el.second);
|
||||
moveCursor(QTextCursor::MoveOperation::Left);
|
||||
break;
|
||||
}
|
||||
|
||||
// If it's close brace - check parentheses
|
||||
if (el.second == e->text()) {
|
||||
auto symbol = charUnderCursor();
|
||||
|
||||
if (symbol == el.second) {
|
||||
textCursor().deletePreviousChar();
|
||||
moveCursor(QTextCursor::MoveOperation::Right);
|
||||
}
|
||||
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
proceedCompleterEnd(e);
|
||||
}
|
||||
|
||||
void QCodeEditor::handleTabCompletion() {
|
||||
QTextCursor textCursor = this->textCursor();
|
||||
int pos = textCursor.position();
|
||||
textCursor.movePosition(QTextCursor::StartOfLine);
|
||||
textCursor.movePosition(QTextCursor::EndOfLine, QTextCursor::KeepAnchor);
|
||||
int startPos = textCursor.selectionStart();
|
||||
|
||||
int offset = pos - startPos;
|
||||
QString text = textCursor.selectedText();
|
||||
|
||||
QString textToComplete;
|
||||
int cur = offset;
|
||||
while (cur--) {
|
||||
QChar c = text.at(cur);
|
||||
if (c.isLetterOrNumber() || c == '.' || c == '_') {
|
||||
textToComplete.prepend(c);
|
||||
} else {
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
QString lookup;
|
||||
QString compareText = textToComplete;
|
||||
int dot = compareText.lastIndexOf('.');
|
||||
if (dot != -1) {
|
||||
lookup = compareText.mid(0, dot);
|
||||
compareText = compareText.mid(dot + 1, offset);
|
||||
}
|
||||
if (!lookup.isEmpty() || !compareText.isEmpty()) {
|
||||
compareText = compareText.toLower();
|
||||
QStringList found;
|
||||
QStringList l = py->introspection(_context, lookup, PythonQt::Anything);
|
||||
Q_FOREACH (QString n, l) {
|
||||
if (n.toLower().startsWith(compareText)) {
|
||||
found << n;
|
||||
}
|
||||
}
|
||||
|
||||
if (!found.isEmpty()) {
|
||||
m_completer->setCompletionPrefix(compareText);
|
||||
m_completer->setCompletionMode(QCompleter::PopupCompletion);
|
||||
m_completer->setModel(new QStringListModel(found, m_completer));
|
||||
m_completer->setCaseSensitivity(Qt::CaseInsensitive);
|
||||
QTextCursor c = this->textCursor();
|
||||
c.movePosition(QTextCursor::StartOfWord);
|
||||
QRect cr = cursorRect(c);
|
||||
cr.setWidth(
|
||||
m_completer->popup()->sizeHintForColumn(0) +
|
||||
m_completer->popup()->verticalScrollBar()->sizeHint().width());
|
||||
cr.translate(0, 8);
|
||||
m_completer->complete(cr);
|
||||
} else {
|
||||
m_completer->popup()->hide();
|
||||
}
|
||||
} else {
|
||||
m_completer->popup()->hide();
|
||||
}
|
||||
}
|
||||
|
||||
void QCodeEditor::setAutoIndentation(bool enabled) {
|
||||
m_autoIndentation = enabled;
|
||||
}
|
||||
|
||||
bool QCodeEditor::autoIndentation() const { return m_autoIndentation; }
|
||||
|
||||
void QCodeEditor::setAutoParentheses(bool enabled) {
|
||||
m_autoParentheses = enabled;
|
||||
}
|
||||
|
||||
bool QCodeEditor::autoParentheses() const { return m_autoParentheses; }
|
||||
|
||||
void QCodeEditor::setTabReplace(bool enabled) { m_replaceTab = enabled; }
|
||||
|
||||
bool QCodeEditor::tabReplace() const { return m_replaceTab; }
|
||||
|
||||
void QCodeEditor::setTabReplaceSize(int val) {
|
||||
m_tabReplace.clear();
|
||||
|
||||
m_tabReplace.fill(' ', val);
|
||||
}
|
||||
|
||||
int QCodeEditor::tabReplaceSize() const { return m_tabReplace.size(); }
|
||||
|
||||
void QCodeEditor::focusInEvent(QFocusEvent *e) {
|
||||
if (m_completer) {
|
||||
m_completer->setWidget(this);
|
||||
}
|
||||
|
||||
QTextEdit::focusInEvent(e);
|
||||
}
|
||||
|
||||
void QCodeEditor::insertCompletion(QString s) {
|
||||
if (m_completer->widget() != this) {
|
||||
return;
|
||||
}
|
||||
|
||||
auto tc = textCursor();
|
||||
tc.select(QTextCursor::SelectionType::WordUnderCursor);
|
||||
tc.insertText(s);
|
||||
setTextCursor(tc);
|
||||
}
|
||||
|
||||
QChar QCodeEditor::charUnderCursor(int offset) const {
|
||||
auto block = textCursor().blockNumber();
|
||||
auto index = textCursor().positionInBlock();
|
||||
auto text = document()->findBlockByNumber(block).text();
|
||||
|
||||
index += offset;
|
||||
|
||||
if (index < 0 || index >= text.size()) {
|
||||
return {};
|
||||
}
|
||||
|
||||
return text[index];
|
||||
}
|
||||
|
||||
QString QCodeEditor::wordUnderCursor() const {
|
||||
auto tc = textCursor();
|
||||
tc.select(QTextCursor::WordUnderCursor);
|
||||
return tc.selectedText();
|
||||
}
|
||||
|
||||
void QCodeEditor::insertFromMimeData(const QMimeData *source) {
|
||||
insertPlainText(source->text());
|
||||
}
|
||||
|
||||
int QCodeEditor::getIndentationSpaces() {
|
||||
auto blockText = textCursor().block().text();
|
||||
|
||||
int indentationLevel = 0;
|
||||
|
||||
for (auto i = 0;
|
||||
i < blockText.size() && QString("\t ").contains(blockText[i]); ++i) {
|
||||
if (blockText[i] == ' ') {
|
||||
indentationLevel++;
|
||||
} else {
|
||||
#if QT_VERSION >= 0x050A00
|
||||
indentationLevel += tabStopDistance() / fontMetrics().averageCharWidth();
|
||||
#else
|
||||
indentationLevel += tabStopWidth() / fontMetrics().averageCharWidth();
|
||||
#endif
|
||||
}
|
||||
}
|
||||
|
||||
return indentationLevel;
|
||||
}
|
|
@ -0,0 +1,268 @@
|
|||
#ifndef QCODEEDITOR_H
|
||||
#define QCODEEDITOR_H
|
||||
|
||||
// Qt
|
||||
#include <QTextEdit> // Required for inheritance
|
||||
|
||||
#include "PythonQt/PythonQt.h"
|
||||
|
||||
class QCompleter;
|
||||
class QLineNumberArea;
|
||||
class QSyntaxStyle;
|
||||
class QStyleSyntaxHighlighter;
|
||||
class QFramedTextAttribute;
|
||||
|
||||
/**
|
||||
* @brief Class, that describes code editor.
|
||||
*/
|
||||
class QCodeEditor : public QTextEdit {
|
||||
Q_OBJECT
|
||||
|
||||
public:
|
||||
/**
|
||||
* @brief Constructor.
|
||||
* @param widget Pointer to parent widget.
|
||||
*/
|
||||
explicit QCodeEditor(QWidget *widget = nullptr);
|
||||
|
||||
// Disable copying
|
||||
QCodeEditor(const QCodeEditor &) = delete;
|
||||
QCodeEditor &operator=(const QCodeEditor &) = delete;
|
||||
|
||||
/**
|
||||
* @brief Method for getting first visible block
|
||||
* index.
|
||||
* @return Index.
|
||||
*/
|
||||
int getFirstVisibleBlock();
|
||||
|
||||
/**
|
||||
* @brief Method for setting highlighter.
|
||||
* @param highlighter Pointer to syntax highlighter.
|
||||
*/
|
||||
void setHighlighter(QStyleSyntaxHighlighter *highlighter);
|
||||
|
||||
/**
|
||||
* @brief Method for setting syntax sty.e.
|
||||
* @param style Pointer to syntax style.
|
||||
*/
|
||||
void setSyntaxStyle(QSyntaxStyle *style);
|
||||
|
||||
/**
|
||||
* @brief Method setting auto parentheses enabled.
|
||||
*/
|
||||
void setAutoParentheses(bool enabled);
|
||||
|
||||
/**
|
||||
* @brief Method for getting is auto parentheses enabled.
|
||||
* Default value: true
|
||||
*/
|
||||
bool autoParentheses() const;
|
||||
|
||||
/**
|
||||
* @brief Method for setting tab replacing
|
||||
* enabled.
|
||||
*/
|
||||
void setTabReplace(bool enabled);
|
||||
|
||||
/**
|
||||
* @brief Method for getting is tab replacing enabled.
|
||||
* Default value: true
|
||||
*/
|
||||
bool tabReplace() const;
|
||||
|
||||
/**
|
||||
* @brief Method for setting amount of spaces, that will
|
||||
* replace tab.
|
||||
* @param val Number of spaces.
|
||||
*/
|
||||
void setTabReplaceSize(int val);
|
||||
|
||||
/**
|
||||
* @brief Method for getting number of spaces, that will
|
||||
* replace tab if `tabReplace` is true.
|
||||
* Default: 4
|
||||
*/
|
||||
int tabReplaceSize() const;
|
||||
|
||||
/**
|
||||
* @brief Method for setting auto indentation enabled.
|
||||
*/
|
||||
void setAutoIndentation(bool enabled);
|
||||
|
||||
/**
|
||||
* @brief Method for getting is auto indentation enabled.
|
||||
* Default: true
|
||||
*/
|
||||
bool autoIndentation() const;
|
||||
|
||||
public Q_SLOTS:
|
||||
|
||||
/**
|
||||
* @brief Slot, that performs insertion of
|
||||
* completion info into code.
|
||||
* @param s Data.
|
||||
*/
|
||||
void insertCompletion(QString s);
|
||||
|
||||
/**
|
||||
* @brief Slot, that performs update of
|
||||
* internal editor viewport based on line
|
||||
* number area width.
|
||||
*/
|
||||
void updateLineNumberAreaWidth(int);
|
||||
|
||||
/**
|
||||
* @brief Slot, that performs update of some
|
||||
* part of line number area.
|
||||
* @param rect Area that has to be updated.
|
||||
*/
|
||||
void updateLineNumberArea(const QRect &rect);
|
||||
|
||||
/**
|
||||
* @brief Slot, that will proceed extra selection
|
||||
* for current cursor position.
|
||||
*/
|
||||
void updateExtraSelection();
|
||||
|
||||
/**
|
||||
* @brief Slot, that will update editor style.
|
||||
*/
|
||||
void updateStyle();
|
||||
|
||||
/**
|
||||
* @brief Slot, that will be called on selection
|
||||
* change.
|
||||
*/
|
||||
void onSelectionChanged();
|
||||
|
||||
protected:
|
||||
/**
|
||||
* @brief Method, that's called on any text insertion of
|
||||
* mimedata into editor. If it's text - it inserts text
|
||||
* as plain text.
|
||||
*/
|
||||
void insertFromMimeData(const QMimeData *source) override;
|
||||
|
||||
/**
|
||||
* @brief Method, that's called on editor painting. This
|
||||
* method if overloaded for line number area redraw.
|
||||
*/
|
||||
void paintEvent(QPaintEvent *e) override;
|
||||
|
||||
/**
|
||||
* @brief Method, that's called on any widget resize.
|
||||
* This method if overloaded for line number area
|
||||
* resizing.
|
||||
*/
|
||||
void resizeEvent(QResizeEvent *e) override;
|
||||
|
||||
/**
|
||||
* @brief Method, that's called on any key press, posted
|
||||
* into code editor widget. This method is overloaded for:
|
||||
*
|
||||
* 1. Completion
|
||||
* 2. Tab to spaces
|
||||
* 3. Low indentation
|
||||
* 4. Auto parenthesis
|
||||
*/
|
||||
void keyPressEvent(QKeyEvent *e) override;
|
||||
|
||||
/**
|
||||
* @brief Method, that's called on focus into widget.
|
||||
* It's required for setting this widget to set
|
||||
* completer.
|
||||
*/
|
||||
void focusInEvent(QFocusEvent *e) override;
|
||||
|
||||
private:
|
||||
/**
|
||||
* @brief Method for initializing document
|
||||
* layout handlers.
|
||||
*/
|
||||
void initDocumentLayoutHandlers();
|
||||
|
||||
/**
|
||||
* @brief Method for initializing default
|
||||
* monospace font.
|
||||
*/
|
||||
void initFont();
|
||||
|
||||
/**
|
||||
* @brief Method for performing connection
|
||||
* of objects.
|
||||
*/
|
||||
void performConnections();
|
||||
|
||||
/**
|
||||
* @brief Method, that performs selection
|
||||
* frame selection.
|
||||
*/
|
||||
void handleSelectionQuery(QTextCursor cursor);
|
||||
|
||||
/**
|
||||
* @brief Method for updating geometry of line number area.
|
||||
*/
|
||||
void updateLineGeometry();
|
||||
|
||||
/**
|
||||
* @brief Method, that performs completer processing.
|
||||
* Returns true if event has to be dropped.
|
||||
* @param e Pointer to key event.
|
||||
* @return Shall event be dropped.
|
||||
*/
|
||||
bool proceedCompleterBegin(QKeyEvent *e);
|
||||
void proceedCompleterEnd(QKeyEvent *e);
|
||||
|
||||
void handleTabCompletion(); // added by wingsummer from PythonQt
|
||||
|
||||
/**
|
||||
* @brief Method for getting character under
|
||||
* cursor.
|
||||
* @param offset Offset to cursor.
|
||||
*/
|
||||
QChar charUnderCursor(int offset = 0) const;
|
||||
|
||||
/**
|
||||
* @brief Method for getting word under
|
||||
* cursor.
|
||||
* @return Word under cursor.
|
||||
*/
|
||||
QString wordUnderCursor() const;
|
||||
|
||||
/**
|
||||
* @brief Method, that adds highlighting of
|
||||
* currently selected line to extra selection list.
|
||||
*/
|
||||
void highlightCurrentLine(QList<QTextEdit::ExtraSelection> &extraSelection);
|
||||
|
||||
/**
|
||||
* @brief Method, that adds highlighting of
|
||||
* parenthesis if available.
|
||||
*/
|
||||
void highlightParenthesis(QList<QTextEdit::ExtraSelection> &extraSelection);
|
||||
|
||||
/**
|
||||
* @brief Method for getting number of indentation
|
||||
* spaces in current line. Tabs will be treated
|
||||
* as `tabWidth / spaceWidth`
|
||||
*/
|
||||
int getIndentationSpaces();
|
||||
|
||||
QStyleSyntaxHighlighter *m_highlighter;
|
||||
QSyntaxStyle *m_syntaxStyle;
|
||||
QLineNumberArea *m_lineNumberArea;
|
||||
QCompleter *m_completer;
|
||||
|
||||
QFramedTextAttribute *m_framedAttribute;
|
||||
|
||||
bool m_autoIndentation;
|
||||
bool m_autoParentheses;
|
||||
bool m_replaceTab;
|
||||
QString m_tabReplace;
|
||||
|
||||
PythonQt *py;
|
||||
PythonQtObjectPtr _context;
|
||||
};
|
||||
|
||||
#endif
|
|
@ -0,0 +1,85 @@
|
|||
// QCodeEditor
|
||||
#include "QFramedTextAttribute.hpp"
|
||||
#include "QSyntaxStyle.hpp"
|
||||
|
||||
// Qt
|
||||
#include <QDebug>
|
||||
#include <QFontMetrics>
|
||||
#include <QPainter>
|
||||
#include <QTextBlock>
|
||||
|
||||
int QFramedTextAttribute::type() { return QTextFormat::UserFormat + 1; }
|
||||
|
||||
QFramedTextAttribute::QFramedTextAttribute(QObject *parent)
|
||||
: QObject(parent), m_style(nullptr) {}
|
||||
|
||||
void QFramedTextAttribute::setSyntaxStyle(QSyntaxStyle *style) {
|
||||
m_style = style;
|
||||
}
|
||||
|
||||
QSyntaxStyle *QFramedTextAttribute::syntaxStyle() const { return m_style; }
|
||||
|
||||
QSizeF QFramedTextAttribute::intrinsicSize(QTextDocument *, int,
|
||||
const QTextFormat &) {
|
||||
return {0, 0};
|
||||
}
|
||||
|
||||
void QFramedTextAttribute::drawObject(QPainter *painter, const QRectF &rect,
|
||||
QTextDocument *, int,
|
||||
const QTextFormat &format) {
|
||||
// Casting
|
||||
auto textCharFormat = reinterpret_cast<const QTextCharFormat &>(format);
|
||||
|
||||
// Getting font data
|
||||
auto font = textCharFormat.font();
|
||||
QFontMetrics metrics(font);
|
||||
|
||||
// Getting required size
|
||||
auto string = format.property(FramedString).toString();
|
||||
auto stringSize = metrics.boundingRect(string).size();
|
||||
|
||||
// Creating frame rect
|
||||
QRectF drawRect(rect.topLeft(), stringSize);
|
||||
drawRect.moveTop(rect.top() - stringSize.height());
|
||||
drawRect.adjust(0, 4, 0, 4);
|
||||
|
||||
// Drawing
|
||||
painter->setPen(m_style->getFormat("Occurrences").background().color());
|
||||
painter->setRenderHint(QPainter::Antialiasing);
|
||||
painter->drawRoundedRect(drawRect, 4, 4);
|
||||
}
|
||||
|
||||
void QFramedTextAttribute::frame(QTextCursor cursor) {
|
||||
auto text = cursor.document()->findBlockByNumber(cursor.blockNumber()).text();
|
||||
|
||||
QTextCharFormat format;
|
||||
format.setObjectType(type());
|
||||
format.setProperty(FramedString, cursor.selectedText());
|
||||
|
||||
if (cursor.selectionEnd() > cursor.selectionStart()) {
|
||||
cursor.setPosition(cursor.selectionStart());
|
||||
} else {
|
||||
cursor.setPosition(cursor.selectionEnd());
|
||||
}
|
||||
|
||||
cursor.insertText(QString(QChar::ObjectReplacementCharacter), format);
|
||||
}
|
||||
|
||||
void QFramedTextAttribute::clear(QTextCursor cursor) {
|
||||
auto doc = cursor.document();
|
||||
|
||||
for (auto blockIndex = 0; blockIndex < doc->blockCount(); ++blockIndex) {
|
||||
auto block = doc->findBlockByNumber(blockIndex);
|
||||
|
||||
auto formats = block.textFormats();
|
||||
int offset = 0;
|
||||
|
||||
for (auto &format : formats) {
|
||||
if (format.format.objectType() == type()) {
|
||||
cursor.setPosition(block.position() + format.start - offset);
|
||||
cursor.deleteChar();
|
||||
++offset;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
|
@ -0,0 +1,79 @@
|
|||
#ifndef QFRAMEDTEXTATTRIBUTE_H
|
||||
#define QFRAMEDTEXTATTRIBUTE_H
|
||||
|
||||
// Qt
|
||||
#include <QObject> // Required for inheritance
|
||||
#include <QTextObjectInterface> // Required for inheritance
|
||||
|
||||
class QSyntaxStyle;
|
||||
|
||||
/**
|
||||
* @brief Class, that describes
|
||||
* attribute for making text frame.
|
||||
*/
|
||||
class QFramedTextAttribute : public QObject, public QTextObjectInterface {
|
||||
Q_OBJECT
|
||||
Q_INTERFACES(QTextObjectInterface)
|
||||
|
||||
public:
|
||||
enum Property { FramedString = 1 };
|
||||
|
||||
/**
|
||||
* @brief Static method for getting framed text
|
||||
* attribute type.
|
||||
*/
|
||||
static int type();
|
||||
|
||||
/**
|
||||
* @brief Constructor.
|
||||
* @param parent Pointer to parent QObject.
|
||||
*/
|
||||
explicit QFramedTextAttribute(QObject *parent = nullptr);
|
||||
|
||||
// Disable copying
|
||||
QFramedTextAttribute(const QFramedTextAttribute &) = delete;
|
||||
QFramedTextAttribute &operator=(const QFramedTextAttribute &) = delete;
|
||||
|
||||
/**
|
||||
* @brief Method for getting custom element (frame)
|
||||
* size. Though frame symbol has no size, this
|
||||
* method returns {0, 0}
|
||||
*/
|
||||
QSizeF intrinsicSize(QTextDocument *doc, int posInDocument,
|
||||
const QTextFormat &format) override;
|
||||
|
||||
/**
|
||||
* @brief Method for drawing frame.
|
||||
*/
|
||||
void drawObject(QPainter *painter, const QRectF &rect, QTextDocument *doc,
|
||||
int posInDocument, const QTextFormat &format) override;
|
||||
|
||||
/**
|
||||
* @brief Method for creating frame in cursor
|
||||
* selection.
|
||||
* @param cursor Cursor.
|
||||
*/
|
||||
void frame(QTextCursor cursor);
|
||||
|
||||
/**
|
||||
* @brief Method for clearing all frames
|
||||
* with desired cursor.
|
||||
*/
|
||||
void clear(QTextCursor cursor);
|
||||
|
||||
/**
|
||||
* @brief Method for setting syntax style
|
||||
* for rendering.
|
||||
*/
|
||||
void setSyntaxStyle(QSyntaxStyle *style);
|
||||
|
||||
/**
|
||||
* @brief Method for getting syntax style.
|
||||
*/
|
||||
QSyntaxStyle *syntaxStyle() const;
|
||||
|
||||
private:
|
||||
QSyntaxStyle *m_style;
|
||||
};
|
||||
|
||||
#endif
|
|
@ -0,0 +1,24 @@
|
|||
#pragma once
|
||||
|
||||
// Qt
|
||||
#include <QRegularExpression>
|
||||
#include <QString>
|
||||
|
||||
struct QHighlightBlockRule
|
||||
{
|
||||
QHighlightBlockRule() :
|
||||
startPattern(),
|
||||
endPattern(),
|
||||
formatName()
|
||||
{}
|
||||
|
||||
QHighlightBlockRule(QRegularExpression start, QRegularExpression end, QString format) :
|
||||
startPattern(std::move(start)),
|
||||
endPattern(std::move(end)),
|
||||
formatName(std::move(format))
|
||||
{}
|
||||
|
||||
QRegularExpression startPattern;
|
||||
QRegularExpression endPattern;
|
||||
QString formatName;
|
||||
};
|
|
@ -0,0 +1,21 @@
|
|||
#pragma once
|
||||
|
||||
// Qt
|
||||
#include <QRegularExpression>
|
||||
#include <QString>
|
||||
|
||||
struct QHighlightRule
|
||||
{
|
||||
QHighlightRule() :
|
||||
pattern(),
|
||||
formatName()
|
||||
{}
|
||||
|
||||
QHighlightRule(QRegularExpression p, QString f) :
|
||||
pattern(std::move(p)),
|
||||
formatName(std::move(f))
|
||||
{}
|
||||
|
||||
QRegularExpression pattern;
|
||||
QString formatName;
|
||||
};
|
|
@ -0,0 +1,57 @@
|
|||
// QCodeEditor
|
||||
#include "QLanguage.hpp"
|
||||
|
||||
// Qt
|
||||
#include <QIODevice>
|
||||
#include <QXmlStreamReader>
|
||||
|
||||
QLanguage::QLanguage(QIODevice *device, QObject *parent)
|
||||
: QObject(parent), m_loaded(false), m_list() {
|
||||
load(device);
|
||||
}
|
||||
|
||||
bool QLanguage::load(QIODevice *device) {
|
||||
if (device == nullptr) {
|
||||
return false;
|
||||
}
|
||||
|
||||
QXmlStreamReader reader(device);
|
||||
|
||||
QString name;
|
||||
QStringList list;
|
||||
bool readText = false;
|
||||
|
||||
while (!reader.atEnd() && !reader.hasError()) {
|
||||
auto type = reader.readNext();
|
||||
|
||||
if (type == QXmlStreamReader::TokenType::StartElement) {
|
||||
if (reader.name() == "section") {
|
||||
if (!list.empty()) {
|
||||
m_list[name] = list;
|
||||
list.clear();
|
||||
}
|
||||
|
||||
name = reader.attributes().value("name").toString();
|
||||
} else if (reader.name() == "name") {
|
||||
readText = true;
|
||||
}
|
||||
} else if (type == QXmlStreamReader::TokenType::Characters && readText) {
|
||||
list << reader.text().toString();
|
||||
readText = false;
|
||||
}
|
||||
}
|
||||
|
||||
if (!list.empty()) {
|
||||
m_list[name] = list;
|
||||
}
|
||||
|
||||
m_loaded = !reader.hasError();
|
||||
|
||||
return m_loaded;
|
||||
}
|
||||
|
||||
QStringList QLanguage::keys() { return m_list.keys(); }
|
||||
|
||||
QStringList QLanguage::names(const QString &key) { return m_list[key]; }
|
||||
|
||||
bool QLanguage::isLoaded() const { return m_loaded; }
|
|
@ -0,0 +1,61 @@
|
|||
#pragma once
|
||||
|
||||
// Qt
|
||||
#include <QObject> // Required for inheritance
|
||||
#include <QString>
|
||||
#include <QMap>
|
||||
|
||||
class QIODevice;
|
||||
|
||||
/**
|
||||
* Class, that describes object for parsing
|
||||
* language file.
|
||||
*/
|
||||
class QLanguage : public QObject
|
||||
{
|
||||
Q_OBJECT
|
||||
|
||||
public:
|
||||
|
||||
/**
|
||||
* @brief Constructor.
|
||||
* @param parent Pointer to parent QObject.
|
||||
*/
|
||||
explicit QLanguage(QIODevice* device=nullptr, QObject* parent=nullptr);
|
||||
|
||||
/**
|
||||
* @brief Method for parsing.
|
||||
* @param device Pointer to device.
|
||||
* @return Success.
|
||||
*/
|
||||
bool load(QIODevice* device);
|
||||
|
||||
/**
|
||||
* @brief Method for getting available keys.
|
||||
*/
|
||||
QStringList keys();
|
||||
|
||||
/**
|
||||
* @brief Method for getting names
|
||||
* from key.
|
||||
* @param name
|
||||
* @return
|
||||
*/
|
||||
QStringList names(const QString& key);
|
||||
|
||||
/**
|
||||
* @brief Method for getting is object loaded.
|
||||
*/
|
||||
bool isLoaded() const;
|
||||
|
||||
private:
|
||||
|
||||
bool m_loaded;
|
||||
|
||||
QMap<
|
||||
QString,
|
||||
QStringList
|
||||
> m_list;
|
||||
|
||||
};
|
||||
|
|
@ -0,0 +1,94 @@
|
|||
// QCodeEditor
|
||||
#include "QLineNumberArea.hpp"
|
||||
#include "QCodeEditor.hpp"
|
||||
#include "QSyntaxStyle.hpp"
|
||||
|
||||
// Qt
|
||||
#include <QAbstractTextDocumentLayout>
|
||||
#include <QPaintEvent>
|
||||
#include <QPainter>
|
||||
#include <QScrollBar>
|
||||
#include <QTextBlock>
|
||||
#include <QTextEdit>
|
||||
|
||||
QLineNumberArea::QLineNumberArea(QCodeEditor *parent)
|
||||
: QWidget(parent), m_syntaxStyle(nullptr), m_codeEditParent(parent) {}
|
||||
|
||||
QSize QLineNumberArea::sizeHint() const {
|
||||
if (m_codeEditParent == nullptr) {
|
||||
return QWidget::sizeHint();
|
||||
}
|
||||
|
||||
// Calculating width
|
||||
int digits = 1;
|
||||
int max = qMax(1, m_codeEditParent->document()->blockCount());
|
||||
while (max >= 10) {
|
||||
max /= 10;
|
||||
++digits;
|
||||
}
|
||||
|
||||
#if QT_VERSION >= 0x050B00
|
||||
int space =
|
||||
13 + m_codeEditParent->fontMetrics().horizontalAdvance(QLatin1Char('9')) *
|
||||
digits;
|
||||
#else
|
||||
int space =
|
||||
13 + m_codeEditParent->fontMetrics().width(QLatin1Char('9')) * digits;
|
||||
#endif
|
||||
|
||||
return {space, 0};
|
||||
}
|
||||
|
||||
void QLineNumberArea::setSyntaxStyle(QSyntaxStyle *style) {
|
||||
m_syntaxStyle = style;
|
||||
}
|
||||
|
||||
QSyntaxStyle *QLineNumberArea::syntaxStyle() const { return m_syntaxStyle; }
|
||||
|
||||
void QLineNumberArea::paintEvent(QPaintEvent *event) {
|
||||
QPainter painter(this);
|
||||
|
||||
// Clearing rect to update
|
||||
painter.fillRect(event->rect(),
|
||||
m_syntaxStyle->getFormat("Text").background().color());
|
||||
|
||||
auto blockNumber = m_codeEditParent->getFirstVisibleBlock();
|
||||
auto block = m_codeEditParent->document()->findBlockByNumber(blockNumber);
|
||||
auto top = (int)m_codeEditParent->document()
|
||||
->documentLayout()
|
||||
->blockBoundingRect(block)
|
||||
.translated(0, -m_codeEditParent->verticalScrollBar()->value())
|
||||
.top();
|
||||
auto bottom = top + (int)m_codeEditParent->document()
|
||||
->documentLayout()
|
||||
->blockBoundingRect(block)
|
||||
.height();
|
||||
|
||||
auto currentLine =
|
||||
m_syntaxStyle->getFormat("CurrentLineNumber").foreground().color();
|
||||
auto otherLines = m_syntaxStyle->getFormat("LineNumber").foreground().color();
|
||||
|
||||
painter.setFont(m_codeEditParent->font());
|
||||
|
||||
while (block.isValid() && top <= event->rect().bottom()) {
|
||||
if (block.isVisible() && bottom >= event->rect().top()) {
|
||||
QString number = QString::number(blockNumber + 1);
|
||||
|
||||
auto isCurrentLine =
|
||||
m_codeEditParent->textCursor().blockNumber() == blockNumber;
|
||||
painter.setPen(isCurrentLine ? currentLine : otherLines);
|
||||
|
||||
painter.drawText(-5, top, sizeHint().width(),
|
||||
m_codeEditParent->fontMetrics().height(), Qt::AlignRight,
|
||||
number);
|
||||
}
|
||||
|
||||
block = block.next();
|
||||
top = bottom;
|
||||
bottom = top + (int)m_codeEditParent->document()
|
||||
->documentLayout()
|
||||
->blockBoundingRect(block)
|
||||
.height();
|
||||
++blockNumber;
|
||||
}
|
||||
}
|
|
@ -0,0 +1,54 @@
|
|||
#ifndef QLINENUMBERAREA_H
|
||||
#define QLINENUMBERAREA_H
|
||||
|
||||
// Qt
|
||||
#include <QWidget> // Required for inheritance
|
||||
|
||||
class QCodeEditor;
|
||||
class QSyntaxStyle;
|
||||
|
||||
/**
|
||||
* @brief Class, that describes line number area widget.
|
||||
*/
|
||||
class QLineNumberArea : public QWidget {
|
||||
Q_OBJECT
|
||||
|
||||
public:
|
||||
/**
|
||||
* @brief Constructor.
|
||||
* @param parent Pointer to parent QTextEdit widget.
|
||||
*/
|
||||
explicit QLineNumberArea(QCodeEditor *parent = nullptr);
|
||||
|
||||
// Disable copying
|
||||
QLineNumberArea(const QLineNumberArea &) = delete;
|
||||
QLineNumberArea &operator=(const QLineNumberArea &) = delete;
|
||||
|
||||
/**
|
||||
* @brief Overridden method for getting line number area
|
||||
* size.
|
||||
*/
|
||||
QSize sizeHint() const override;
|
||||
|
||||
/**
|
||||
* @brief Method for setting syntax style object.
|
||||
* @param style Pointer to syntax style.
|
||||
*/
|
||||
void setSyntaxStyle(QSyntaxStyle *style);
|
||||
|
||||
/**
|
||||
* @brief Method for getting syntax style.
|
||||
* @return Pointer to syntax style.
|
||||
*/
|
||||
QSyntaxStyle *syntaxStyle() const;
|
||||
|
||||
protected:
|
||||
void paintEvent(QPaintEvent *event) override;
|
||||
|
||||
private:
|
||||
QSyntaxStyle *m_syntaxStyle;
|
||||
|
||||
QCodeEditor *m_codeEditParent;
|
||||
};
|
||||
|
||||
#endif
|
|
@ -0,0 +1,121 @@
|
|||
// QCodeEditor
|
||||
#include "QPythonHighlighter.hpp"
|
||||
#include "QLanguage.hpp"
|
||||
#include "QSyntaxStyle.hpp"
|
||||
|
||||
// Qt
|
||||
#include <QDebug>
|
||||
#include <QFile>
|
||||
|
||||
QPythonHighlighter::QPythonHighlighter(QTextDocument *document)
|
||||
: QStyleSyntaxHighlighter(document), m_highlightRules(),
|
||||
m_highlightBlockRules(),
|
||||
m_includePattern(QRegularExpression(R"(import \w+)")),
|
||||
m_functionPattern(QRegularExpression(
|
||||
R"(\b([A-Za-z0-9_]+(?:\.))*([A-Za-z0-9_]+)(?=\())")),
|
||||
m_defTypePattern(QRegularExpression(
|
||||
R"(\b([A-Za-z0-9_]+)\s+[A-Za-z]{1}[A-Za-z0-9_]+\s*[;=])")) {
|
||||
QFile fl(":/WingToolPy/python.xml");
|
||||
|
||||
if (!fl.open(QIODevice::ReadOnly)) {
|
||||
return;
|
||||
}
|
||||
|
||||
QLanguage language(&fl);
|
||||
|
||||
if (!language.isLoaded()) {
|
||||
return;
|
||||
}
|
||||
|
||||
auto keys = language.keys();
|
||||
for (auto &&key : keys) {
|
||||
auto names = language.names(key);
|
||||
for (auto &&name : names) {
|
||||
m_highlightRules.append(
|
||||
{QRegularExpression(QString(R"(\b%1\b)").arg(name)), key});
|
||||
}
|
||||
}
|
||||
|
||||
// Following rules has higher priority to display
|
||||
// than language specific keys
|
||||
// So they must be applied at last.
|
||||
// Numbers
|
||||
m_highlightRules.append(
|
||||
{QRegularExpression(R"(\b(0b|0x){0,1}[\d.']+\b)"), "Number"});
|
||||
|
||||
// Strings
|
||||
m_highlightRules.append({QRegularExpression(R"("[^\n"]*")"), "String"});
|
||||
m_highlightRules.append({QRegularExpression(R"('[^\n"]*')"), "String"});
|
||||
|
||||
// Single line comment
|
||||
m_highlightRules.append({QRegularExpression("#[^\n]*"), "Comment"});
|
||||
|
||||
// Multiline string
|
||||
m_highlightBlockRules.append(
|
||||
{QRegularExpression("(''')"), QRegularExpression("(''')"), "String"});
|
||||
m_highlightBlockRules.append({QRegularExpression("(\"\"\")"),
|
||||
QRegularExpression("(\"\"\")"), "String"});
|
||||
}
|
||||
|
||||
void QPythonHighlighter::highlightBlock(const QString &text) {
|
||||
// Checking for function
|
||||
{
|
||||
auto matchIterator = m_functionPattern.globalMatch(text);
|
||||
|
||||
while (matchIterator.hasNext()) {
|
||||
auto match = matchIterator.next();
|
||||
|
||||
setFormat(match.capturedStart(), match.capturedLength(),
|
||||
syntaxStyle()->getFormat("Type"));
|
||||
|
||||
setFormat(match.capturedStart(2), match.capturedLength(2),
|
||||
syntaxStyle()->getFormat("Function"));
|
||||
}
|
||||
}
|
||||
|
||||
for (auto &rule : m_highlightRules) {
|
||||
auto matchIterator = rule.pattern.globalMatch(text);
|
||||
|
||||
while (matchIterator.hasNext()) {
|
||||
auto match = matchIterator.next();
|
||||
|
||||
setFormat(match.capturedStart(), match.capturedLength(),
|
||||
syntaxStyle()->getFormat(rule.formatName));
|
||||
}
|
||||
}
|
||||
|
||||
setCurrentBlockState(0);
|
||||
int startIndex = 0;
|
||||
int highlightRuleId = previousBlockState();
|
||||
if (highlightRuleId < 1 || highlightRuleId > m_highlightBlockRules.size()) {
|
||||
for (int i = 0; i < m_highlightBlockRules.size(); ++i) {
|
||||
startIndex = text.indexOf(m_highlightBlockRules.at(i).startPattern);
|
||||
|
||||
if (startIndex >= 0) {
|
||||
highlightRuleId = i + 1;
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
while (startIndex >= 0) {
|
||||
const auto &blockRules = m_highlightBlockRules.at(highlightRuleId - 1);
|
||||
auto match = blockRules.endPattern.match(
|
||||
text, startIndex + 1); // Should be + length of start pattern
|
||||
|
||||
int endIndex = match.capturedStart();
|
||||
int matchLength = 0;
|
||||
|
||||
if (endIndex == -1) {
|
||||
setCurrentBlockState(highlightRuleId);
|
||||
matchLength = text.length() - startIndex;
|
||||
} else {
|
||||
matchLength = endIndex - startIndex + match.capturedLength();
|
||||
}
|
||||
|
||||
setFormat(startIndex, matchLength,
|
||||
syntaxStyle()->getFormat(blockRules.formatName));
|
||||
startIndex =
|
||||
text.indexOf(blockRules.startPattern, startIndex + matchLength);
|
||||
}
|
||||
}
|
|
@ -0,0 +1,40 @@
|
|||
#ifndef QPYTHONHIGHLIGHTER_H
|
||||
#define QPYTHONHIGHLIGHTER_H
|
||||
|
||||
// QCodeEditor
|
||||
#include "QHighlightBlockRule.hpp"
|
||||
#include "QHighlightRule.hpp"
|
||||
#include "QStyleSyntaxHighlighter.hpp" // Required for inheritance
|
||||
|
||||
// Qt
|
||||
#include <QRegularExpression>
|
||||
#include <QVector>
|
||||
|
||||
class QSyntaxStyle;
|
||||
|
||||
/**
|
||||
* @brief Class, that describes Glsl code
|
||||
* highlighter.
|
||||
*/
|
||||
class QPythonHighlighter : public QStyleSyntaxHighlighter {
|
||||
Q_OBJECT
|
||||
public:
|
||||
/**
|
||||
* @brief Constructor.
|
||||
* @param document Pointer to document.
|
||||
*/
|
||||
explicit QPythonHighlighter(QTextDocument *document = nullptr);
|
||||
|
||||
protected:
|
||||
void highlightBlock(const QString &text) override;
|
||||
|
||||
private:
|
||||
QVector<QHighlightRule> m_highlightRules;
|
||||
QVector<QHighlightBlockRule> m_highlightBlockRules;
|
||||
|
||||
QRegularExpression m_includePattern;
|
||||
QRegularExpression m_functionPattern;
|
||||
QRegularExpression m_defTypePattern;
|
||||
};
|
||||
|
||||
#endif
|
|
@ -0,0 +1,13 @@
|
|||
// QCodeEditor
|
||||
#include "QStyleSyntaxHighlighter.hpp"
|
||||
|
||||
QStyleSyntaxHighlighter::QStyleSyntaxHighlighter(QTextDocument *document)
|
||||
: QSyntaxHighlighter(document), m_syntaxStyle(nullptr) {}
|
||||
|
||||
void QStyleSyntaxHighlighter::setSyntaxStyle(QSyntaxStyle *style) {
|
||||
m_syntaxStyle = style;
|
||||
}
|
||||
|
||||
QSyntaxStyle *QStyleSyntaxHighlighter::syntaxStyle() const {
|
||||
return m_syntaxStyle;
|
||||
}
|
|
@ -0,0 +1,41 @@
|
|||
#pragma once
|
||||
|
||||
// Qt
|
||||
#include <QSyntaxHighlighter> // Required for inheritance
|
||||
|
||||
class QSyntaxStyle;
|
||||
|
||||
/**
|
||||
* @brief Class, that descrubes highlighter with
|
||||
* syntax style.
|
||||
*/
|
||||
class QStyleSyntaxHighlighter : public QSyntaxHighlighter
|
||||
{
|
||||
public:
|
||||
|
||||
/**
|
||||
* @brief Constructor.
|
||||
* @param document Pointer to text document.
|
||||
*/
|
||||
explicit QStyleSyntaxHighlighter(QTextDocument* document=nullptr);
|
||||
|
||||
// Disable copying
|
||||
QStyleSyntaxHighlighter(const QStyleSyntaxHighlighter&) = delete;
|
||||
QStyleSyntaxHighlighter& operator=(const QStyleSyntaxHighlighter&) = delete;
|
||||
|
||||
/**
|
||||
* @brief Method for setting syntax style.
|
||||
* @param style Pointer to syntax style.
|
||||
*/
|
||||
void setSyntaxStyle(QSyntaxStyle* style);
|
||||
|
||||
/**
|
||||
* @brief Method for getting syntax style.
|
||||
* @return Pointer to syntax style. May be nullptr.
|
||||
*/
|
||||
QSyntaxStyle* syntaxStyle() const;
|
||||
|
||||
private:
|
||||
QSyntaxStyle* m_syntaxStyle;
|
||||
};
|
||||
|
|
@ -0,0 +1,116 @@
|
|||
// QCodeEditor
|
||||
#include "QSyntaxStyle.hpp"
|
||||
|
||||
// Qt
|
||||
#include <QDebug>
|
||||
#include <QFile>
|
||||
#include <QXmlStreamReader>
|
||||
|
||||
QSyntaxStyle::QSyntaxStyle(QObject *parent)
|
||||
: QObject(parent), m_name(), m_data(), m_loaded(false) {}
|
||||
|
||||
bool QSyntaxStyle::load(QString fl) {
|
||||
QXmlStreamReader reader(fl);
|
||||
|
||||
while (!reader.atEnd() && !reader.hasError()) {
|
||||
auto token = reader.readNext();
|
||||
|
||||
if (token == QXmlStreamReader::StartElement) {
|
||||
if (reader.name() == "style-scheme") {
|
||||
if (reader.attributes().hasAttribute("name")) {
|
||||
m_name = reader.attributes().value("name").toString();
|
||||
}
|
||||
} else if (reader.name() == "style") {
|
||||
auto attributes = reader.attributes();
|
||||
|
||||
auto name = attributes.value("name");
|
||||
|
||||
QTextCharFormat format;
|
||||
|
||||
if (attributes.hasAttribute("background")) {
|
||||
format.setBackground(
|
||||
QColor(attributes.value("background").toString()));
|
||||
}
|
||||
|
||||
if (attributes.hasAttribute("foreground")) {
|
||||
format.setForeground(
|
||||
QColor(attributes.value("foreground").toString()));
|
||||
}
|
||||
|
||||
if (attributes.hasAttribute("bold") &&
|
||||
attributes.value("bold") == "true") {
|
||||
format.setFontWeight(QFont::Weight::Bold);
|
||||
}
|
||||
|
||||
if (attributes.hasAttribute("italic") &&
|
||||
attributes.value("italic") == "true") {
|
||||
format.setFontItalic(true);
|
||||
}
|
||||
|
||||
if (attributes.hasAttribute("underlineStyle")) {
|
||||
auto underline = attributes.value("underlineStyle");
|
||||
|
||||
auto s = QTextCharFormat::UnderlineStyle::NoUnderline;
|
||||
|
||||
if (underline == "SingleUnderline") {
|
||||
s = QTextCharFormat::UnderlineStyle::SingleUnderline;
|
||||
} else if (underline == "DashUnderline") {
|
||||
s = QTextCharFormat::UnderlineStyle::DashUnderline;
|
||||
} else if (underline == "DotLine") {
|
||||
s = QTextCharFormat::UnderlineStyle::DotLine;
|
||||
} else if (underline == "DashDotLine") {
|
||||
s = QTextCharFormat::DashDotLine;
|
||||
} else if (underline == "DashDotDotLine") {
|
||||
s = QTextCharFormat::DashDotDotLine;
|
||||
} else if (underline == "WaveUnderline") {
|
||||
s = QTextCharFormat::WaveUnderline;
|
||||
} else if (underline == "SpellCheckUnderline") {
|
||||
s = QTextCharFormat::SpellCheckUnderline;
|
||||
} else {
|
||||
qDebug() << "Unknown underline value " << underline;
|
||||
}
|
||||
|
||||
format.setUnderlineStyle(s);
|
||||
}
|
||||
|
||||
m_data[name.toString()] = format;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
m_loaded = !reader.hasError();
|
||||
|
||||
return m_loaded;
|
||||
}
|
||||
|
||||
QString QSyntaxStyle::name() const { return m_name; }
|
||||
|
||||
QTextCharFormat QSyntaxStyle::getFormat(QString name) const {
|
||||
auto result = m_data.find(name);
|
||||
|
||||
if (result == m_data.end()) {
|
||||
return QTextCharFormat();
|
||||
}
|
||||
|
||||
return result.value();
|
||||
}
|
||||
|
||||
bool QSyntaxStyle::isLoaded() const { return m_loaded; }
|
||||
|
||||
QSyntaxStyle *QSyntaxStyle::defaultStyle() {
|
||||
static QSyntaxStyle style;
|
||||
|
||||
if (!style.isLoaded()) {
|
||||
QFile fl(":/WingToolPy/default_style.xml");
|
||||
|
||||
if (!fl.open(QIODevice::ReadOnly)) {
|
||||
return &style;
|
||||
}
|
||||
|
||||
if (!style.load(fl.readAll())) {
|
||||
qDebug() << "Can't load default style.";
|
||||
}
|
||||
}
|
||||
|
||||
return &style;
|
||||
}
|
|
@ -0,0 +1,70 @@
|
|||
#pragma once
|
||||
|
||||
// Qt
|
||||
#include <QObject> // Required for inheritance
|
||||
#include <QMap>
|
||||
#include <QString>
|
||||
#include <QTextCharFormat>
|
||||
|
||||
/**
|
||||
* @brief Class, that describes Qt style
|
||||
* parser for QCodeEditor.
|
||||
*/
|
||||
class QSyntaxStyle : public QObject
|
||||
{
|
||||
Q_OBJECT
|
||||
|
||||
public:
|
||||
|
||||
/**
|
||||
* @brief Constructor.
|
||||
* @param parent Pointer to parent QObject
|
||||
*/
|
||||
explicit QSyntaxStyle(QObject* parent=nullptr);
|
||||
|
||||
/**
|
||||
* @brief Method for loading and parsing
|
||||
* style.
|
||||
* @param fl Style.
|
||||
* @return Success.
|
||||
*/
|
||||
bool load(QString fl);
|
||||
|
||||
/**
|
||||
* @brief Method for getting style name.
|
||||
* @return Name.
|
||||
*/
|
||||
QString name() const;
|
||||
|
||||
/**
|
||||
* @brief Method for checking is syntax style loaded.
|
||||
* @return Is loaded.
|
||||
*/
|
||||
bool isLoaded() const;
|
||||
|
||||
/**
|
||||
* @brief Method for getting format for property
|
||||
* name.
|
||||
* @param name Property name.
|
||||
* @return Text char format.
|
||||
*/
|
||||
QTextCharFormat getFormat(QString name) const;
|
||||
|
||||
/**
|
||||
* @brief Static method for getting default style.
|
||||
* @return Pointer to default style.
|
||||
*/
|
||||
static QSyntaxStyle* defaultStyle();
|
||||
|
||||
private:
|
||||
|
||||
QString m_name;
|
||||
|
||||
QMap<
|
||||
QString,
|
||||
QTextCharFormat
|
||||
> m_data;
|
||||
|
||||
bool m_loaded;
|
||||
};
|
||||
|
|
@ -0,0 +1,66 @@
|
|||
<?xml version="1.0" encoding="UTF-8"?>
|
||||
<style-scheme version="1.0" name="Default">
|
||||
<style name="Text" foreground="#000000" background="#ffffff"/>
|
||||
<style name="Link" foreground="#0000ff"/>
|
||||
<style name="Selection" foreground="#eff0f1" background="#3daee9"/>
|
||||
<style name="LineNumber" foreground="#6272a4"/>
|
||||
<style name="SearchResult" background="#ffef0b"/>
|
||||
<style name="SearchScope" background="#2d5c76"/>
|
||||
<style name="Parentheses" foreground="#ff0000" background="#b4eeb4"/>
|
||||
<style name="ParenthesesMismatch" background="#ff00ff"/>
|
||||
<style name="AutoComplete" foreground="#000080" background="#c0c0ff"/>
|
||||
<style name="CurrentLine" background="#eeeeee"/>
|
||||
<style name="CurrentLineNumber" foreground="#808080" bold="true"/>
|
||||
<style name="Occurrences" background="#b4b4b4"/>
|
||||
<style name="Occurrences.Unused" underlineColor="#808000" underlineStyle="SingleUnderline"/>
|
||||
<style name="Occurrences.Rename" background="#ff6464"/>
|
||||
<style name="Number" foreground="#000080"/>
|
||||
<style name="String" foreground="#008000"/>
|
||||
<style name="Type" foreground="#800080"/>
|
||||
<style name="Local" foreground="#092e64"/>
|
||||
<style name="Global" foreground="#ce5c00"/>
|
||||
<style name="Field" foreground="#800000"/>
|
||||
<style name="Static" foreground="#800080"/>
|
||||
<style name="VirtualMethod" foreground="#00677c" background="#ffffff" italic="true"/>
|
||||
<style name="Function" foreground="#00677c" background="#ffffff"/>
|
||||
<style name="Keyword" foreground="#808000"/>
|
||||
<style name="PrimitiveType" foreground="#808000"/>
|
||||
<style name="Operator"/>
|
||||
<style name="Overloaded Operator"/>
|
||||
<style name="Preprocessor" foreground="#000080"/>
|
||||
<style name="Label" foreground="#800000"/>
|
||||
<style name="Comment" foreground="#008000"/>
|
||||
<style name="Doxygen.Comment" foreground="#000080"/>
|
||||
<style name="Doxygen.Tag" foreground="#0000ff"/>
|
||||
<style name="VisualWhitespace" foreground="#c0c0c0"/>
|
||||
<style name="QmlLocalId" foreground="#000000" background="#ffffff" italic="true"/>
|
||||
<style name="QmlExternalId" foreground="#000080" background="#ffffff" italic="true"/>
|
||||
<style name="QmlTypeId" foreground="#800080"/>
|
||||
<style name="QmlRootObjectProperty" foreground="#000000" background="#ffffff" italic="true"/>
|
||||
<style name="QmlScopeObjectProperty" foreground="#000000" background="#ffffff" italic="true"/>
|
||||
<style name="QmlExternalObjectProperty" foreground="#000080" background="#ffffff" italic="true"/>
|
||||
<style name="JsScopeVar" foreground="#2985c7" background="#ffffff" italic="true"/>
|
||||
<style name="JsImportVar" foreground="#0055af" background="#ffffff" italic="true"/>
|
||||
<style name="JsGlobalVar" foreground="#0055af" background="#ffffff" italic="true"/>
|
||||
<style name="QmlStateName" foreground="#000000" background="#ffffff" italic="true"/>
|
||||
<style name="Binding" foreground="#800000"/>
|
||||
<style name="DisabledCode" background="#efefef"/>
|
||||
<style name="AddedLine" foreground="#00aa00"/>
|
||||
<style name="RemovedLine" foreground="#ff0000"/>
|
||||
<style name="DiffFile" foreground="#000080"/>
|
||||
<style name="DiffLocation" foreground="#0000ff"/>
|
||||
<style name="DiffFileLine" background="#ffff00"/>
|
||||
<style name="DiffContextLine" background="#afd7e7"/>
|
||||
<style name="DiffSourceLine" background="#ffdfdf"/>
|
||||
<style name="DiffSourceChar" background="#ffafaf"/>
|
||||
<style name="DiffDestLine" background="#dfffdf"/>
|
||||
<style name="DiffDestChar" background="#afffaf"/>
|
||||
<style name="LogChangeLine" foreground="#c00000"/>
|
||||
<style name="Warning" underlineColor="#ffbe00" underlineStyle="SingleUnderline"/>
|
||||
<style name="WarningContext" underlineColor="#ffbe00" underlineStyle="DotLine"/>
|
||||
<style name="Error" underlineColor="#ff0000" underlineStyle="SingleUnderline"/>
|
||||
<style name="ErrorContext" underlineColor="#ff0000" underlineStyle="DotLine"/>
|
||||
<style name="Declaration" bold="true"/>
|
||||
<style name="FunctionDefinition"/>
|
||||
<style name="OutputArgument" italic="true"/>
|
||||
</style-scheme>
|
|
@ -0,0 +1,66 @@
|
|||
<?xml version="1.0" encoding="UTF-8"?>
|
||||
<style-scheme version="1.0" name="Dracula">
|
||||
<style name="Text" foreground="#f8f8f2" background="#282a36"/>
|
||||
<style name="Link" foreground="#8be9fd" underlineStyle="SingleUnderline"/>
|
||||
<style name="Selection" background="#44475a"/>
|
||||
<style name="LineNumber" foreground="#6272a4"/>
|
||||
<style name="SearchResult" foreground="#d57544" bold="true"/>
|
||||
<style name="SearchScope" foreground="#000000" background="#f8f8f2"/>
|
||||
<style name="Parentheses" foreground="#f8f8f2" bold="true"/>
|
||||
<style name="ParenthesesMismatch" foreground="#f8f8f2"/>
|
||||
<style name="AutoComplete" foreground="#f8f8f2"/>
|
||||
<style name="CurrentLine" foreground="#000000" background="#383b4c"/>
|
||||
<style name="CurrentLineNumber" foreground="#f8f8f2"/>
|
||||
<style name="Occurrences" foreground="#000000" background="#f8f8f2"/>
|
||||
<style name="Occurrences.Unused" foreground="#f8f8f2"/>
|
||||
<style name="Occurrences.Rename" foreground="#000000" background="#f8f8f2"/>
|
||||
<style name="Number" foreground="#bd93f9"/>
|
||||
<style name="String" foreground="#f1fa8c"/>
|
||||
<style name="Type" foreground="#7ce4fb"/>
|
||||
<style name="Local" foreground="#ffffff"/>
|
||||
<style name="Global" foreground="#ffb86c"/>
|
||||
<style name="Field" foreground="#ffffff"/>
|
||||
<style name="Static" foreground="#ffb86c"/>
|
||||
<style name="VirtualMethod" foreground="#50fa7b" italic="true"/>
|
||||
<style name="Function" foreground="#50fa7b"/>
|
||||
<style name="Keyword" foreground="#ff79c6" bold="true"/>
|
||||
<style name="PrimitiveType" foreground="#7ce4fb" italic="true"/>
|
||||
<style name="Operator" foreground="#ffffff"/>
|
||||
<style name="Overloaded Operator"/>
|
||||
<style name="Preprocessor" foreground="#ff79c6"/>
|
||||
<style name="Label" foreground="#ffb86c"/>
|
||||
<style name="Comment" foreground="#6272a4" bold="true"/>
|
||||
<style name="Doxygen.Comment" foreground="#6272a4"/>
|
||||
<style name="Doxygen.Tag" foreground="#6272a4" bold="true"/>
|
||||
<style name="VisualWhitespace" foreground="#6272a4"/>
|
||||
<style name="QmlLocalId" foreground="#50fa7b" italic="true"/>
|
||||
<style name="QmlExternalId" foreground="#ffb86c" italic="true"/>
|
||||
<style name="QmlTypeId" foreground="#8be9fd"/>
|
||||
<style name="QmlRootObjectProperty" foreground="#50fa7b" italic="true"/>
|
||||
<style name="QmlScopeObjectProperty" foreground="#50fa7b" italic="true"/>
|
||||
<style name="QmlExternalObjectProperty" foreground="#ffb86c" italic="true"/>
|
||||
<style name="JsScopeVar" foreground="#bd93f9" italic="true"/>
|
||||
<style name="JsImportVar" foreground="#8be9fd" italic="true"/>
|
||||
<style name="JsGlobalVar" foreground="#8be9fd" italic="true"/>
|
||||
<style name="QmlStateName" foreground="#50fa7b" italic="true"/>
|
||||
<style name="Binding" foreground="#ff79c6"/>
|
||||
<style name="DisabledCode" foreground="#6272a4"/>
|
||||
<style name="AddedLine" foreground="#50fa7b"/>
|
||||
<style name="RemovedLine" foreground="#ff5555"/>
|
||||
<style name="DiffFile" foreground="#8be9fd"/>
|
||||
<style name="DiffLocation" foreground="#ffb86c"/>
|
||||
<style name="DiffFileLine" foreground="#282a36" background="#f1fa8c"/>
|
||||
<style name="DiffContextLine" foreground="#282a36" background="#8be9fd"/>
|
||||
<style name="DiffSourceLine" background="#ff5555"/>
|
||||
<style name="DiffSourceChar" background="#cc2222"/>
|
||||
<style name="DiffDestLine" foreground="#282a36" background="#50fa7b"/>
|
||||
<style name="DiffDestChar" foreground="#282a36" background="#1dc748"/>
|
||||
<style name="LogChangeLine" foreground="#ff5555"/>
|
||||
<style name="Warning" underlineColor="#ffb86c" underlineStyle="SingleUnderline"/>
|
||||
<style name="WarningContext" underlineColor="#ffb86c" underlineStyle="DotLine"/>
|
||||
<style name="Error" underlineColor="#ff5555" underlineStyle="SingleUnderline"/>
|
||||
<style name="ErrorContext" underlineColor="#ff5555" underlineStyle="DotLine"/>
|
||||
<style name="Declaration" bold="true"/>
|
||||
<style name="FunctionDefinition"/>
|
||||
<style name="OutputArgument" italic="true"/>
|
||||
</style-scheme>
|
|
@ -0,0 +1,49 @@
|
|||
<?xml version="1.0" encoding="UTF-8" ?>
|
||||
<root>
|
||||
<section name="Keyword">
|
||||
<name>break</name>
|
||||
<name>continue</name>
|
||||
<name>do</name>
|
||||
<name>for</name>
|
||||
<name>while</name>
|
||||
<name>if</name>
|
||||
<name>else</name>
|
||||
<name>def</name>
|
||||
<name>from</name>
|
||||
<name>import</name>
|
||||
<name>return</name>
|
||||
<name>class</name>
|
||||
<name>in</name>
|
||||
<name>is</name>
|
||||
<name>not</name>
|
||||
<name>or</name>
|
||||
<name>and</name>
|
||||
<name>enumerate</name>
|
||||
<name>with</name>
|
||||
<name>as</name>
|
||||
</section>
|
||||
<section name="Namespace">
|
||||
<name>WingPlgReader</name>
|
||||
<name>WingPlgCtl</name>
|
||||
<name>WingPlgService</name>
|
||||
</section>
|
||||
<section name="Function">
|
||||
<name>min</name>
|
||||
<name>max</name>
|
||||
<name>len</name>
|
||||
<name>main</name>
|
||||
</section>
|
||||
<section name="PrimitiveType">
|
||||
<name>float</name>
|
||||
<name>int</name>
|
||||
<name>bool</name>
|
||||
<name>True</name>
|
||||
<name>False</name>
|
||||
<name>str</name>
|
||||
<name>unicode</name>
|
||||
<name>byte</name>
|
||||
<name>bytearray</name>
|
||||
<name>set</name>
|
||||
<name>dict</name>
|
||||
</section>
|
||||
</root>
|
|
@ -0,0 +1,156 @@
|
|||
<h1 align="center"> WingSummer.WingToolPy</h1>
|
||||
|
||||
<p align="center">
|
||||
<img alt="WingToolPy" src="img/icon.png">
|
||||
<p align="center">WingToolPy</p>
|
||||
</p>
|
||||
|
||||
<p align="center">
|
||||
<img alt="作者" src="https://img.shields.io/badge/Author-Wingsummer-green">
|
||||
<img alt="开源协议" src="https://img.shields.io/badge/License-AGPL--3.0-red">
|
||||
</p>
|
||||
|
||||
- 开源不易,给个 Star 或者 [捐助](#捐助) 吧
|
||||
|
||||
## WingHexPy
|
||||
|
||||
  `WingToolPy`是一个强大的羽云工具箱插件,它具有对 Python3 脚本的支持,拥有即时交互控制台。本插件几乎支持所有的原生`IWingToolPlg`的所有接口,于此同时也拥有自己独特的接口以供与插件进行交互。
|
||||
|
||||
  本插件基于 QCodeEditor 和 PythonQt 以及深度文本编辑器的部分代码(纯粹自己懒)进行开发。为了和深度主题适配所以有 DTK 依赖。
|
||||
|
||||
### 使用声明
|
||||
|
||||
1. 开发本软件目的是让羽云十六进制编辑器具有强大的脚本分析功能,使用 C++ 的 Python 拓展来弥补羽云十六进制编辑器相对于 010 Editor 的不足之处。
|
||||
2. 本人学生,由于本软件是用我的业余时间编写,不能及时修复 Bug 或者提供技术支持,请见谅。
|
||||
3. 本人非计算机专业,编写程序难免有 Bug ,欢迎提交 PR 。
|
||||
|
||||
### 参与贡献
|
||||
|
||||
1. 如果您有想参与本软件代码开发递交,请在 pull request 联系我。
|
||||
2. 本项目支持捐助,如有意愿请到本仓库通过微信或者支付宝的方式进行,一瓶水的价钱足以提高我的维护该项目的热情,感谢大家的支持。
|
||||
3. 如果您想提交修复或者增进程序的代码,请在 pull request 递交。
|
||||
4. 任何成功参与代码 Bug 修复以及增进程序功能的同志和 Sponsor ,都会在本仓库 ReadMe 和附属说明文件中体现,您如果是其中之一,本人可以按照您合理的意愿来进行说明。
|
||||
|
||||
**加入我们并不意味着就是代码的维护,你可以选择下列一项或多项进行参与:**
|
||||
|
||||
1. 代码维护:实现新功能或修复 BUG ,对代码进行维护和升级。
|
||||
2. 文档编辑:主要是接口文档和教程需要撰写编辑,这很重要。
|
||||
3. 参与讨论:主要是讨论本项目未来发展和方向等。
|
||||
4. 编写插件:一起增强该软件的功能。
|
||||
|
||||
### 协议
|
||||
|
||||
  本插件仓库将采用`AGPL-3.0`协议,不得将该插件代码用于改协议之外的用途。
|
||||
|
||||
### issue 前必读
|
||||
|
||||
  如果你有任何形式的建议,在提交 issue 之前,请一定要阅读下面的声明,以免浪费我们双方宝贵的时间:
|
||||
|
||||
1. 本人不考虑多语言支持,主要是没时间和资金。由于本人是中国人,本人不考虑其他语言使用者。但如果使用其他语言,如果你有语言包,只需要简单的替换文件即可。
|
||||
2. 本人不会将此插件单独打包为 deb ,会捆绑在“羽云十六进制编辑器”的安装包内供大家使用。
|
||||
3. 本人不考虑主题 UI 层面的问题,开发本插件与窗体相关一切采用 DTK 原生样式,觉得丑找官方,或者自己写个样式编译加载。
|
||||
|
||||
  上面一切的一切,如果你是志同道合的开源贡献者,欢迎 fork 我的仓库进行相应的维护!
|
||||
|
||||
### 有关 QCodeEditor
|
||||
|
||||
  本软件自带的编写脚本编辑器基于`QCodeEditor`,我对该软件进行的删减和修改增强以适配该插件的功能。如下是原仓库的部分说明,详情请点击 [此链接](https://github.com/Megaxela/QCodeEditor) :
|
||||
|
||||
---
|
||||
|
||||
# Qt Code Editor Widget
|
||||
It's a widget for editing/viewing code.
|
||||
|
||||
This project uses a resource named `qcodeeditor_resources.qrc`. The main application
|
||||
must not use a resource file with the same name.
|
||||
|
||||
(It's not a project from a Qt example.)
|
||||
|
||||
## Requirements
|
||||
0. C++11 featured compiler.
|
||||
0. Qt 5.
|
||||
|
||||
## Abilities
|
||||
1. Auto parentheses.
|
||||
1. Different highlight rules.
|
||||
1. Auto indentation.
|
||||
1. Replace tabs with spaces.
|
||||
1. GLSL completion rules.
|
||||
1. GLSL highlight rules.
|
||||
1. C++ highlight rules.
|
||||
1. XML highlight rules.
|
||||
1. JSON highligh rules.
|
||||
1. Frame selection.
|
||||
1. Qt Creator styles.
|
||||
|
||||
## LICENSE
|
||||
|
||||
<img align="right" src="http://opensource.org/trademarks/opensource/OSI-Approved-License-100x137.png">
|
||||
|
||||
Library is licensed under the [MIT License](https://opensource.org/licenses/MIT)
|
||||
|
||||
Permission is hereby granted, free of charge, to any person obtaining a copy
|
||||
of this software and associated documentation files (the "Software"), to deal
|
||||
in the Software without restriction, including without limitation the rights
|
||||
to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
|
||||
copies of the Software, and to permit persons to whom the Software is
|
||||
furnished to do so, subject to the following conditions:
|
||||
|
||||
The above copyright notice and this permission notice shall be included in all
|
||||
copies or substantial portions of the Software.
|
||||
|
||||
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
||||
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
||||
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
||||
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
||||
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
|
||||
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
|
||||
SOFTWARE.
|
||||
|
||||
---
|
||||
|
||||
### 有关 PythonQt
|
||||
|
||||
  所有的 QT C++ 代码与 Python 脚本进行交互基础支持库,如果没有该框架,就不会有该插件的出现。该库遵守`LGPL`协议,如下是原仓库的部分说明,详情请点击 [此链接](https://github.com/MeVisLab/pythonqt) :
|
||||
|
||||
---
|
||||
|
||||
PythonQt is a dynamic Python binding for Qt. It offers an easy way to embed the Python scripting language into your Qt applications.
|
||||
|
||||
Documentation
|
||||
API documentation is available at: https://mevislab.github.io/pythonqt
|
||||
|
||||
Licensing
|
||||
PythonQt is distributed under the LGPL 2.1 license.
|
||||
|
||||
---
|
||||
|
||||
  鉴于 Linux 的动态库调用没有 Windows 方便之处,所以我使用了静态链接,按照协议必须开源修改后的代码。我把该库的`PythonQtScriptingConsole`单独出来进行编译,所有修改的代码都在头文件(减少警告)和代码文件`PythonQtScriptingConsole.hpp`和`PythonQtScriptingConsole.cpp`中。也就是说,所有的修改部分均在我的仓库文件当中。
|
||||
|
||||
## 捐助
|
||||
|
||||
**<p align="center">您的每一份支持都将是本项目推进的强大动力,十分感谢您的支持</p>**
|
||||
|
||||
<p align="center">
|
||||
|
||||
<img alt="支付宝" src="img/支付宝捐助.jpg" height=50% width=50%>
|
||||
<p align="center">感谢支持</p>
|
||||
|
||||
</p>
|
||||
|
||||
<p align="center">
|
||||
<img alt="微信" src="img/微信捐助.png" height=50% width=50%>
|
||||
<p align="center">感谢支持</p>
|
||||
|
||||
</p>
|
||||
|
||||
## 有关仓库
|
||||
|
||||
* GitLink : https://www.gitlink.org.cn/wingsummer/WingToolPy
|
||||
* Gitea : https://code.gitlink.org.cn/wingsummer/WingToolPy
|
||||
* Gitee : https://gitee.com/wing-cloud/wing-tool-py
|
||||
* Github : https://github.com/Wing-summer/WingToolPy
|
||||
|
||||
## WIKI
|
||||
|
||||
  WIKI 建设完毕,想学习脚本编写的话请看 [教程](https://code.gitlink.org.cn/wingsummer/WingToolPy/wiki/%E6%95%99%E7%A8%8B) 。
|
|
@ -0,0 +1,110 @@
|
|||
#-------------------------------------------------
|
||||
#
|
||||
# Project created by QtCreator 2022-10-12T12:07:07
|
||||
#
|
||||
#-------------------------------------------------
|
||||
|
||||
QT += core gui dtkwidget
|
||||
|
||||
TARGET = WingToolPy
|
||||
TEMPLATE = lib
|
||||
CONFIG += plugin
|
||||
|
||||
greaterThan(QT_MAJOR_VERSION, 4): QT += widgets
|
||||
|
||||
# The following define makes your compiler emit warnings if you use
|
||||
# any feature of Qt which has been marked as deprecated (the exact warnings
|
||||
# depend on your compiler). Please consult the documentation of the
|
||||
# deprecated API in order to know how to port your code away from it.
|
||||
DEFINES += QT_DEPRECATED_WARNINGS
|
||||
|
||||
# You can also make your code fail to compile if you use deprecated APIs.
|
||||
# In order to do so, uncomment the following line.
|
||||
# You can also select to disable deprecated APIs only up to a certain version of Qt.
|
||||
#DEFINES += QT_DISABLE_DEPRECATED_BEFORE=0x060000 # disables all the APIs deprecated before Qt 6.0.0
|
||||
|
||||
SOURCES += \
|
||||
wingtoolpy.cpp \
|
||||
QCodeEditor/QCodeEditor.cpp \
|
||||
QCodeEditor/QFramedTextAttribute.cpp \
|
||||
QCodeEditor/QLineNumberArea.cpp \
|
||||
QCodeEditor/QPythonHighlighter.cpp \
|
||||
QCodeEditor/QStyleSyntaxHighlighter.cpp \
|
||||
QCodeEditor/QSyntaxStyle.cpp \
|
||||
QCodeEditor/QLanguage.cpp \
|
||||
scriptwindow.cpp \
|
||||
recentfilemanager.cpp \
|
||||
PythonQt/gui/PythonQtScriptingConsole.cpp \
|
||||
findbar.cpp \
|
||||
linebar.cpp \
|
||||
replacebar.cpp \
|
||||
scriptmanager.cpp \
|
||||
scriptcenterwindow.cpp \
|
||||
wingtoolpyservice.cpp \
|
||||
aboutdialog.cpp
|
||||
|
||||
HEADERS += \
|
||||
wingtoolpy.h \
|
||||
QCodeEditor/QCodeEditor.hpp \
|
||||
QCodeEditor/QFramedTextAttribute.hpp \
|
||||
QCodeEditor/QLineNumberArea.hpp \
|
||||
QCodeEditor/QPythonHighlighter.hpp \
|
||||
QCodeEditor/QStyleSyntaxHighlighter.hpp \
|
||||
QCodeEditor/QSyntaxStyle.hpp \
|
||||
QCodeEditor/QHighlightBlockRule.hpp \
|
||||
QCodeEditor/QHighlightRule.hpp \
|
||||
QCodeEditor/QLanguage.hpp \
|
||||
scriptwindow.h \
|
||||
recentfilemanager.h \
|
||||
PythonQt/PythonQt.h \
|
||||
PythonQt/PythonQtBoolResult.h \
|
||||
PythonQt/PythonQtClassInfo.h \
|
||||
PythonQt/PythonQtClassWrapper.h \
|
||||
PythonQt/PythonQtConversion.h \
|
||||
PythonQt/PythonQtCppWrapperFactory.h \
|
||||
PythonQt/PythonQtDoc.h \
|
||||
PythonQt/PythonQtImporter.h \
|
||||
PythonQt/PythonQtImportFileInterface.h \
|
||||
PythonQt/PythonQtInstanceWrapper.h \
|
||||
PythonQt/PythonQtMethodInfo.h \
|
||||
PythonQt/PythonQtMisc.h \
|
||||
PythonQt/PythonQtObjectPtr.h \
|
||||
PythonQt/PythonQtProperty.h \
|
||||
PythonQt/PythonQtPythonInclude.h \
|
||||
PythonQt/PythonQtQFileImporter.h \
|
||||
PythonQt/PythonQtSignal.h \
|
||||
PythonQt/PythonQtSignalReceiver.h \
|
||||
PythonQt/PythonQtSlot.h \
|
||||
PythonQt/PythonQtSlotDecorator.h \
|
||||
PythonQt/PythonQtStdDecorators.h \
|
||||
PythonQt/PythonQtStdIn.h \
|
||||
PythonQt/PythonQtStdOut.h \
|
||||
PythonQt/PythonQtSystem.h \
|
||||
PythonQt/PythonQtUtils.h \
|
||||
PythonQt/PythonQtVariants.h \
|
||||
PythonQt/gui/PythonQtScriptingConsole.h \
|
||||
findbar.h \
|
||||
linebar.h \
|
||||
replacebar.h \
|
||||
scriptmanager.h \
|
||||
scriptcenterwindow.h \
|
||||
PythonQt/PythonQt_QtAll.h \
|
||||
../WingTool/plugin/iwingtoolplg.h \
|
||||
wingtoolpyservice.h \
|
||||
aboutdialog.h
|
||||
|
||||
DISTFILES += WingToolPy.json
|
||||
|
||||
TRANSLATIONS += \
|
||||
$$PWD/lang/WingToolPy.ts
|
||||
|
||||
LIBS += $$PWD/PythonQt/libPythonQt-Qt5-Python3.7.a \
|
||||
$$PWD/PythonQt/libPythonQt_QtAll-Qt5-Python3.7.a
|
||||
|
||||
DEFINES += PYTHONQT_CATCH_ALL_EXCEPTIONS
|
||||
|
||||
LIBS += /usr/lib/x86_64-linux-gnu/libpython3.7m.so.1
|
||||
INCLUDEPATH += -I /usr/include/python3.7
|
||||
|
||||
RESOURCES += \
|
||||
resources.qrc
|
|
@ -0,0 +1,24 @@
|
|||
#include "aboutdialog.h"
|
||||
#include <DLabel>
|
||||
#include <DTextBrowser>
|
||||
#include <QPixmap>
|
||||
|
||||
AboutDialog::AboutDialog(DMainWindow *parent) : DDialog(parent) {
|
||||
setWindowTitle(tr("About"));
|
||||
|
||||
auto l = new DLabel(this);
|
||||
l->setFixedSize(100, 100);
|
||||
l->setScaledContents(true);
|
||||
l->setPixmap(QPixmap(":/images/author.jpg"));
|
||||
addContent(l, Qt::AlignHCenter);
|
||||
addSpacing(10);
|
||||
auto b = new DTextBrowser(this);
|
||||
|
||||
b->setSearchPaths(QStringList({":/WingToolPy/img"}));
|
||||
|
||||
b->setSource(QUrl("README.md"), QTextDocument::MarkdownResource);
|
||||
|
||||
b->setFixedSize(800, 500);
|
||||
b->setOpenExternalLinks(true);
|
||||
addContent(b);
|
||||
}
|
|
@ -0,0 +1,20 @@
|
|||
#ifndef ABOUTSOFTWAREDIALOG_H
|
||||
#define ABOUTSOFTWAREDIALOG_H
|
||||
|
||||
#include <DDialog>
|
||||
#include <DMainWindow>
|
||||
#include <QObject>
|
||||
|
||||
DWIDGET_USE_NAMESPACE
|
||||
class AboutDialog : public DDialog {
|
||||
|
||||
Q_OBJECT
|
||||
public:
|
||||
explicit AboutDialog(DMainWindow *parent = nullptr);
|
||||
|
||||
signals:
|
||||
|
||||
public slots:
|
||||
};
|
||||
|
||||
#endif // ABOUTSOFTWAREDIALOG_H
|
|
@ -0,0 +1,190 @@
|
|||
/* -*- Mode: C++; indent-tabs-mode: nil; tab-width: 4 -*-
|
||||
* -*- coding: utf-8 -*-
|
||||
*
|
||||
* Copyright (C) 2011 ~ 2018 Deepin, Inc.
|
||||
*
|
||||
* Author: Wang Yong <wangyong@deepin.com>
|
||||
* Maintainer: Rekols <rekols@foxmail.com>
|
||||
*
|
||||
* This program is free software: you can redistribute it and/or modify
|
||||
* it under the terms of the GNU General Public License as published by
|
||||
* the Free Software Foundation, either version 3 of the License, or
|
||||
* any later version.
|
||||
*
|
||||
* This program is distributed in the hope that it will be useful,
|
||||
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
* GNU General Public License for more details.
|
||||
*
|
||||
* You should have received a copy of the GNU General Public License
|
||||
* along with this program. If not, see <http://www.gnu.org/licenses/>.
|
||||
*/
|
||||
|
||||
#include "findbar.h"
|
||||
|
||||
#include <QDebug>
|
||||
|
||||
FindBar::FindBar(QWidget *parent) : DFloatingWidget(parent) {
|
||||
// Init.
|
||||
// setWindowFlags(Qt::FramelessWindowHint | Qt::X11BypassWindowManagerHint);
|
||||
hide();
|
||||
setFixedHeight(60);
|
||||
|
||||
// Init layout and widgets.
|
||||
|
||||
m_layout = new QHBoxLayout();
|
||||
m_layout->setSpacing(10);
|
||||
m_findLabel = new QLabel(tr("Find"));
|
||||
m_findLabel->setMinimumHeight(36);
|
||||
m_editLine = new LineBar();
|
||||
m_editLine->lineEdit()->setMinimumHeight(36);
|
||||
m_findPrevButton = new QPushButton(tr("Previous"));
|
||||
// m_findPrevButton->setFixedSize(80, 36);
|
||||
m_findNextButton = new QPushButton(tr("Next"));
|
||||
// m_findNextButton->setFixedSize(80, 36);
|
||||
m_closeButton = new DIconButton(DStyle::SP_CloseButton);
|
||||
m_closeButton->setIconSize(QSize(30, 30));
|
||||
m_closeButton->setFixedSize(30, 30);
|
||||
m_closeButton->setEnabledCircle(true);
|
||||
m_closeButton->setFlat(true);
|
||||
m_layout->setContentsMargins(16, 6, 10, 6);
|
||||
|
||||
m_layout->addWidget(m_findLabel);
|
||||
m_layout->addWidget(m_editLine);
|
||||
m_layout->addWidget(m_findPrevButton);
|
||||
m_layout->addWidget(m_findNextButton);
|
||||
m_layout->addWidget(m_closeButton);
|
||||
this->setLayout(m_layout);
|
||||
|
||||
// Make button don't grab keyboard focus after click it.
|
||||
// m_findNextButton->setFocusPolicy(Qt::NoFocus);
|
||||
// m_findPrevButton->setFocusPolicy(Qt::NoFocus);
|
||||
// m_closeButton->setFocusPolicy(Qt::NoFocus);
|
||||
|
||||
connect(this, &FindBar::pressEsc, this, &FindBar::findCancel,
|
||||
Qt::QueuedConnection);
|
||||
// connect(m_editLine, &LineBar::pressEnter, this, &FindBar::findNext,
|
||||
// Qt::QueuedConnection); //Shielded by Hengbo ,for new demand.
|
||||
// 20200220
|
||||
// connect(m_editLine, &LineBar::pressCtrlEnter, this, &FindBar::findPrev,
|
||||
// Qt::QueuedConnection);
|
||||
connect(m_editLine, &LineBar::returnPressed, this,
|
||||
&FindBar::handleContentChanged, Qt::QueuedConnection);
|
||||
connect(m_editLine, &LineBar::signal_sentText, this, &FindBar::receiveText,
|
||||
Qt::QueuedConnection);
|
||||
// connect(m_editLine, &LineBar::contentChanged, this,
|
||||
// &FindBar::slot_ifClearSearchWord, Qt::QueuedConnection);
|
||||
|
||||
connect(m_findNextButton, &QPushButton::clicked, this,
|
||||
&FindBar::handleFindNext, Qt::QueuedConnection);
|
||||
connect(m_findPrevButton, &QPushButton::clicked, this,
|
||||
&FindBar::handleFindPrev, Qt::QueuedConnection);
|
||||
// connect(m_findPrevButton, &QPushButton::clicked, this, &FindBar::findPrev,
|
||||
// Qt::QueuedConnection);
|
||||
|
||||
connect(m_closeButton, &DIconButton::clicked, this, &FindBar::findCancel,
|
||||
Qt::QueuedConnection);
|
||||
}
|
||||
|
||||
bool FindBar::isFocus() { return m_editLine->lineEdit()->hasFocus(); }
|
||||
|
||||
void FindBar::focus() {
|
||||
m_editLine->lineEdit()->setFocus();
|
||||
m_editLine->lineEdit()->selectAll();
|
||||
}
|
||||
|
||||
void FindBar::activeInput(QString text, int row, int column, int scrollOffset) {
|
||||
// Try fill keyword with select text.
|
||||
m_editLine->lineEdit()->clear();
|
||||
m_editLine->lineEdit()->insert(text);
|
||||
m_editLine->lineEdit()->selectAll();
|
||||
|
||||
// Show.
|
||||
QWidget::show();
|
||||
|
||||
// Save file info for back to position.
|
||||
m_findFileRow = row;
|
||||
m_findFileColumn = column;
|
||||
m_findFileSrollOffset = scrollOffset;
|
||||
|
||||
// Focus.
|
||||
focus();
|
||||
}
|
||||
|
||||
void FindBar::findCancel() {
|
||||
QWidget::hide();
|
||||
emit sigFindbarClose();
|
||||
}
|
||||
|
||||
void FindBar::handleContentChanged() {
|
||||
updateSearchKeyword(m_editLine->lineEdit()->text().trimmed());
|
||||
}
|
||||
|
||||
void FindBar::handleFindPrev() {
|
||||
findPrev(m_editLine->lineEdit()->text().trimmed());
|
||||
}
|
||||
|
||||
void FindBar::handleFindNext() {
|
||||
findNext(m_editLine->lineEdit()->text().trimmed());
|
||||
}
|
||||
|
||||
void FindBar::hideEvent(QHideEvent *) {
|
||||
//保留查询标记
|
||||
// removeSearchKeyword();
|
||||
}
|
||||
|
||||
bool FindBar::focusNextPrevChild(bool next) {
|
||||
Q_UNUSED(next);
|
||||
return false;
|
||||
}
|
||||
|
||||
// modiefied by wingsummer
|
||||
void FindBar::keyPressEvent(QKeyEvent *e) {
|
||||
bool unhandled = false;
|
||||
if (e->modifiers() == Qt::KeyboardModifier::NoModifier) {
|
||||
switch (e->key()) {
|
||||
case Qt::Key_Escape: {
|
||||
QWidget::hide();
|
||||
emit sigFindbarClose();
|
||||
} break;
|
||||
case Qt::Key_Tab: {
|
||||
if (m_closeButton->hasFocus())
|
||||
m_editLine->lineEdit()->setFocus();
|
||||
} break;
|
||||
case Qt::Key_Enter: {
|
||||
if (m_findPrevButton->hasFocus()) {
|
||||
m_editLine->lineEdit()->setFocus();
|
||||
}
|
||||
if (m_findNextButton->hasFocus()) {
|
||||
m_findNextButton->click();
|
||||
}
|
||||
} break;
|
||||
default:
|
||||
unhandled = true;
|
||||
break;
|
||||
}
|
||||
}
|
||||
if (unhandled)
|
||||
DFloatingWidget::keyPressEvent(e);
|
||||
}
|
||||
|
||||
void FindBar::setMismatchAlert(bool isAlert) { m_editLine->setAlert(isAlert); }
|
||||
|
||||
void FindBar::receiveText(QString t) {
|
||||
searched = false;
|
||||
if (t != "") {
|
||||
m_receivedText = t;
|
||||
}
|
||||
}
|
||||
|
||||
void FindBar::setSearched(bool _) { searched = _; }
|
||||
|
||||
void FindBar::findPreClicked() {
|
||||
if (!searched) {
|
||||
updateSearchKeyword(m_editLine->lineEdit()->text());
|
||||
emit findPrev(m_editLine->lineEdit()->text());
|
||||
searched = true;
|
||||
} else {
|
||||
emit findPrev(m_editLine->lineEdit()->text());
|
||||
}
|
||||
}
|
|
@ -0,0 +1,101 @@
|
|||
/* -*- Mode: C++; indent-tabs-mode: nil; tab-width: 4 -*-
|
||||
* -*- coding: utf-8 -*-
|
||||
*
|
||||
* Copyright (C) 2011 ~ 2018 Deepin, Inc.
|
||||
*
|
||||
* Author: Wang Yong <wangyong@deepin.com>
|
||||
* Maintainer: Rekols <rekols@foxmail.com>
|
||||
*
|
||||
* This program is free software: you can redistribute it and/or modify
|
||||
* it under the terms of the GNU General Public License as published by
|
||||
* the Free Software Foundation, either version 3 of the License, or
|
||||
* any later version.
|
||||
*
|
||||
* This program is distributed in the hope that it will be useful,
|
||||
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
* GNU General Public License for more details.
|
||||
*
|
||||
* You should have received a copy of the GNU General Public License
|
||||
* along with this program. If not, see <http://www.gnu.org/licenses/>.
|
||||
*/
|
||||
|
||||
#ifndef FINDBAR_H
|
||||
#define FINDBAR_H
|
||||
|
||||
#include "linebar.h"
|
||||
|
||||
#include "dimagebutton.h"
|
||||
#include <DApplicationHelper>
|
||||
#include <DFloatingWidget>
|
||||
#include <DIconButton>
|
||||
#include <QColor>
|
||||
#include <QHBoxLayout>
|
||||
#include <QLabel>
|
||||
#include <QMouseEvent>
|
||||
#include <QMouseEventTransition>
|
||||
#include <QPainter>
|
||||
#include <QPushButton>
|
||||
#include <QWidget>
|
||||
#include <qmouseeventtransition.h>
|
||||
|
||||
#include <DAbstractDialog>
|
||||
#include <DPalette>
|
||||
|
||||
DWIDGET_USE_NAMESPACE
|
||||
|
||||
class FindBar : public DFloatingWidget {
|
||||
Q_OBJECT
|
||||
|
||||
public:
|
||||
explicit FindBar(QWidget *parent = nullptr);
|
||||
|
||||
bool isFocus();
|
||||
void focus();
|
||||
|
||||
void activeInput(QString text, int row, int column, int scrollOffset);
|
||||
void setMismatchAlert(bool isAlert);
|
||||
void receiveText(QString t);
|
||||
void setSearched(bool _);
|
||||
void findPreClicked();
|
||||
|
||||
signals:
|
||||
void pressEsc();
|
||||
void findNext(const QString &keyword);
|
||||
void findPrev(const QString &keyword);
|
||||
|
||||
void removeSearchKeyword();
|
||||
void updateSearchKeyword(QString keyword);
|
||||
|
||||
// add guoshao
|
||||
void sigFindbarClose();
|
||||
|
||||
public slots:
|
||||
void findCancel();
|
||||
void handleContentChanged();
|
||||
void handleFindNext();
|
||||
void handleFindPrev();
|
||||
|
||||
protected:
|
||||
void hideEvent(QHideEvent *event) override;
|
||||
bool focusNextPrevChild(bool next) override;
|
||||
void keyPressEvent(QKeyEvent *e) override;
|
||||
|
||||
private:
|
||||
QPushButton *m_findNextButton;
|
||||
QPushButton *m_findPrevButton;
|
||||
DIconButton *m_closeButton;
|
||||
LineBar *m_editLine;
|
||||
QHBoxLayout *m_layout;
|
||||
QLabel *m_findLabel;
|
||||
int m_findFileColumn;
|
||||
int m_findFileRow;
|
||||
int m_findFileSrollOffset;
|
||||
QColor m_backgroundColor;
|
||||
QString m_receivedText = " ";
|
||||
bool searched = false;
|
||||
|
||||
QPoint last;
|
||||
};
|
||||
|
||||
#endif
|
|
@ -0,0 +1,50 @@
|
|||
## WingHexPy
|
||||
|
||||
  `WingToolPy`是一个强大的羽云工具箱插件,它具有对 Python3 脚本的支持,拥有即时交互控制台。本插件几乎支持所有的原生`IWingToolPlg`的所有接口,于此同时也拥有自己独特的接口以供与插件进行交互。
|
||||
|
||||
  本插件基于 QCodeEditor 和 PythonQt 以及深度文本编辑器的部分代码(纯粹自己懒)进行开发。为了和深度主题适配所以有 DTK 依赖。
|
||||
|
||||
### 使用声明
|
||||
|
||||
1. 开发本软件目的是让羽云十六进制编辑器具有强大的脚本分析功能,使用 C++ 的 Python 拓展来弥补羽云十六进制编辑器相对于 010 Editor 的不足之处。
|
||||
2. 本人学生,由于本软件是用我的业余时间编写,不能及时修复 Bug 或者提供技术支持,请见谅。
|
||||
3. 本人非计算机专业,编写程序难免有 Bug ,欢迎提交 PR 。
|
||||
|
||||
### 参与贡献
|
||||
|
||||
1. 如果您有想参与本软件代码开发递交,请在 pull request 联系我。
|
||||
2. 本项目支持捐助,如有意愿请到本仓库通过微信或者支付宝的方式进行,一瓶水的价钱足以提高我的维护该项目的热情,感谢大家的支持。
|
||||
3. 如果您想提交修复或者增进程序的代码,请在 pull request 递交。
|
||||
4. 任何成功参与代码 Bug 修复以及增进程序功能的同志和 Sponsor ,都会在本仓库 ReadMe 和附属说明文件中体现,您如果是其中之一,本人可以按照您合理的意愿来进行说明。
|
||||
|
||||
**加入我们并不意味着就是代码的维护,你可以选择下列一项或多项进行参与:**
|
||||
|
||||
1. 代码维护:实现新功能或修复 BUG ,对代码进行维护和升级。
|
||||
2. 文档编辑:主要是接口文档和教程需要撰写编辑,这很重要。
|
||||
3. 参与讨论:主要是讨论本项目未来发展和方向等。
|
||||
4. 编写插件:一起增强该软件的功能。
|
||||
|
||||
### 协议
|
||||
|
||||
  本插件仓库将采用`AGPL-3.0`协议,不得将该插件代码用于改协议之外的用途。
|
||||
|
||||
### issue 前必读
|
||||
|
||||
  如果你有任何形式的建议,在提交 issue 之前,请一定要阅读下面的声明,以免浪费我们双方宝贵的时间:
|
||||
|
||||
1. 本人不考虑多语言支持,主要是没时间和资金。由于本人是中国人,本人不考虑其他语言使用者。但如果使用其他语言,如果你有语言包,只需要简单的替换文件即可。
|
||||
2. 本人不会将此插件单独打包为 deb ,会捆绑在“羽云十六进制编辑器”的安装包内供大家使用。
|
||||
3. 本人不考虑主题 UI 层面的问题,开发本插件与窗体相关一切采用 DTK 原生样式,觉得丑找官方,或者自己写个样式编译加载。
|
||||
|
||||
  上面一切的一切,如果你是志同道合的开源贡献者,欢迎 fork 我的仓库进行相应的维护!
|
||||
|
||||
## 有关仓库
|
||||
|
||||
* GitLink : https://www.gitlink.org.cn/wingsummer/WingToolPy
|
||||
* Gitea : https://code.gitlink.org.cn/wingsummer/WingToolPy
|
||||
* Gitee : https://gitee.com/wing-cloud/wing-tool-py
|
||||
* Github : https://github.com/Wing-summer/WingToolPy
|
||||
|
||||
## WIKI
|
||||
|
||||
  WIKI 建设完毕,想学习脚本编写的话请看 [教程](https://code.gitlink.org.cn/wingsummer/WingToolPy/wiki/%E6%95%99%E7%A8%8B) 。
|
After Width: | Height: | Size: 49 KiB |
After Width: | Height: | Size: 11 KiB |
After Width: | Height: | Size: 7.4 KiB |
After Width: | Height: | Size: 6.2 KiB |
After Width: | Height: | Size: 3.4 KiB |
After Width: | Height: | Size: 9.0 KiB |
After Width: | Height: | Size: 10 KiB |
After Width: | Height: | Size: 5.6 KiB |
After Width: | Height: | Size: 2.8 KiB |
After Width: | Height: | Size: 22 KiB |
After Width: | Height: | Size: 5.7 KiB |
After Width: | Height: | Size: 8.0 KiB |
After Width: | Height: | Size: 7.2 KiB |
After Width: | Height: | Size: 6.5 KiB |
After Width: | Height: | Size: 3.7 KiB |
After Width: | Height: | Size: 6.5 KiB |
After Width: | Height: | Size: 19 KiB |
After Width: | Height: | Size: 4.7 KiB |
After Width: | Height: | Size: 5.0 KiB |
After Width: | Height: | Size: 4.7 KiB |
After Width: | Height: | Size: 5.0 KiB |
After Width: | Height: | Size: 8.4 KiB |
After Width: | Height: | Size: 2.2 KiB |
After Width: | Height: | Size: 11 KiB |
After Width: | Height: | Size: 2.1 KiB |
After Width: | Height: | Size: 13 KiB |
After Width: | Height: | Size: 2.3 KiB |
After Width: | Height: | Size: 7.8 KiB |
After Width: | Height: | Size: 4.3 KiB |
After Width: | Height: | Size: 4.6 KiB |
After Width: | Height: | Size: 2.3 KiB |
After Width: | Height: | Size: 5.1 KiB |
|
@ -0,0 +1,400 @@
|
|||
<?xml version="1.0" encoding="utf-8"?>
|
||||
<!DOCTYPE TS>
|
||||
<TS version="2.1" language="zh_CN">
|
||||
<context>
|
||||
<name>AboutDialog</name>
|
||||
<message>
|
||||
<location filename="../aboutdialog.cpp" line="7"/>
|
||||
<source>About</source>
|
||||
<translation>关于</translation>
|
||||
</message>
|
||||
</context>
|
||||
<context>
|
||||
<name>FindBar</name>
|
||||
<message>
|
||||
<location filename="../findbar.cpp" line="37"/>
|
||||
<source>Find</source>
|
||||
<translation>查找</translation>
|
||||
</message>
|
||||
<message>
|
||||
<location filename="../findbar.cpp" line="41"/>
|
||||
<source>Previous</source>
|
||||
<translation>上一个</translation>
|
||||
</message>
|
||||
<message>
|
||||
<location filename="../findbar.cpp" line="43"/>
|
||||
<source>Next</source>
|
||||
<translation>下一个</translation>
|
||||
</message>
|
||||
</context>
|
||||
<context>
|
||||
<name>RecentFileManager</name>
|
||||
<message>
|
||||
<location filename="../recentfilemanager.cpp" line="17"/>
|
||||
<source>ClearHistory</source>
|
||||
<translation>清空历史</translation>
|
||||
</message>
|
||||
<message>
|
||||
<location filename="../recentfilemanager.cpp" line="23"/>
|
||||
<source>RemoveItem</source>
|
||||
<translation>删除项目</translation>
|
||||
</message>
|
||||
<message>
|
||||
<location filename="../recentfilemanager.cpp" line="28"/>
|
||||
<location filename="../recentfilemanager.cpp" line="112"/>
|
||||
<source>NoHistoryDel</source>
|
||||
<translation>清空历史</translation>
|
||||
</message>
|
||||
<message>
|
||||
<location filename="../recentfilemanager.cpp" line="32"/>
|
||||
<source>Input</source>
|
||||
<translation>输入</translation>
|
||||
</message>
|
||||
<message>
|
||||
<location filename="../recentfilemanager.cpp" line="32"/>
|
||||
<source>InputIndex</source>
|
||||
<translation>请输入要删除的索引号:</translation>
|
||||
</message>
|
||||
<message>
|
||||
<location filename="../recentfilemanager.cpp" line="123"/>
|
||||
<source>HistoryClearFinished</source>
|
||||
<translation>清理历史记录完毕!</translation>
|
||||
</message>
|
||||
</context>
|
||||
<context>
|
||||
<name>ReplaceBar</name>
|
||||
<message>
|
||||
<location filename="../replacebar.cpp" line="36"/>
|
||||
<location filename="../replacebar.cpp" line="44"/>
|
||||
<source>Replace</source>
|
||||
<translation>替换</translation>
|
||||
</message>
|
||||
<message>
|
||||
<location filename="../replacebar.cpp" line="40"/>
|
||||
<source>Replace With</source>
|
||||
<translation>替换文本</translation>
|
||||
</message>
|
||||
<message>
|
||||
<location filename="../replacebar.cpp" line="47"/>
|
||||
<source>Skip</source>
|
||||
<translation>跳过</translation>
|
||||
</message>
|
||||
<message>
|
||||
<location filename="../replacebar.cpp" line="50"/>
|
||||
<source>Replace All</source>
|
||||
<translation>替换全部</translation>
|
||||
</message>
|
||||
</context>
|
||||
<context>
|
||||
<name>ScriptCenterWindow</name>
|
||||
<message>
|
||||
<location filename="../scriptcenterwindow.cpp" line="10"/>
|
||||
<source>ScriptCenter</source>
|
||||
<translation>脚本中心</translation>
|
||||
</message>
|
||||
<message>
|
||||
<location filename="../scriptcenterwindow.cpp" line="25"/>
|
||||
<source>Run</source>
|
||||
<translation>执行</translation>
|
||||
</message>
|
||||
<message>
|
||||
<location filename="../scriptcenterwindow.cpp" line="36"/>
|
||||
<source>Name</source>
|
||||
<translation>名称</translation>
|
||||
</message>
|
||||
<message>
|
||||
<location filename="../scriptcenterwindow.cpp" line="38"/>
|
||||
<source>Author</source>
|
||||
<translation>作者</translation>
|
||||
</message>
|
||||
<message>
|
||||
<location filename="../scriptcenterwindow.cpp" line="40"/>
|
||||
<source>License</source>
|
||||
<translation>协议</translation>
|
||||
</message>
|
||||
<message>
|
||||
<location filename="../scriptcenterwindow.cpp" line="49"/>
|
||||
<source>Catagory</source>
|
||||
<translation>分类</translation>
|
||||
</message>
|
||||
</context>
|
||||
<context>
|
||||
<name>ScriptManager</name>
|
||||
<message>
|
||||
<location filename="../scriptmanager.cpp" line="46"/>
|
||||
<source>NoScript</source>
|
||||
<translation>暂无脚本</translation>
|
||||
</message>
|
||||
</context>
|
||||
<context>
|
||||
<name>ScriptWindow</name>
|
||||
<message>
|
||||
<location filename="../scriptwindow.cpp" line="36"/>
|
||||
<source>PyScriptWindow</source>
|
||||
<translation>羽云工具箱脚本编辑器</translation>
|
||||
</message>
|
||||
<message>
|
||||
<location filename="../scriptwindow.cpp" line="77"/>
|
||||
<source>File</source>
|
||||
<translation>文件</translation>
|
||||
</message>
|
||||
<message>
|
||||
<location filename="../scriptwindow.cpp" line="80"/>
|
||||
<location filename="../scriptwindow.cpp" line="185"/>
|
||||
<source>New</source>
|
||||
<translation>新建</translation>
|
||||
</message>
|
||||
<message>
|
||||
<location filename="../scriptwindow.cpp" line="84"/>
|
||||
<location filename="../scriptwindow.cpp" line="187"/>
|
||||
<source>Open</source>
|
||||
<translation>打开</translation>
|
||||
</message>
|
||||
<message>
|
||||
<location filename="../scriptwindow.cpp" line="88"/>
|
||||
<location filename="../scriptwindow.cpp" line="189"/>
|
||||
<source>Save</source>
|
||||
<translation>保存</translation>
|
||||
</message>
|
||||
<message>
|
||||
<location filename="../scriptwindow.cpp" line="92"/>
|
||||
<location filename="../scriptwindow.cpp" line="191"/>
|
||||
<source>SaveAs</source>
|
||||
<translation>另存为</translation>
|
||||
</message>
|
||||
<message>
|
||||
<location filename="../scriptwindow.cpp" line="97"/>
|
||||
<source>RecentFile</source>
|
||||
<translation>最近文件</translation>
|
||||
</message>
|
||||
<message>
|
||||
<location filename="../scriptwindow.cpp" line="101"/>
|
||||
<source>Close</source>
|
||||
<translation>关闭</translation>
|
||||
</message>
|
||||
<message>
|
||||
<location filename="../scriptwindow.cpp" line="106"/>
|
||||
<source>Edit</source>
|
||||
<translation>编辑</translation>
|
||||
</message>
|
||||
<message>
|
||||
<location filename="../scriptwindow.cpp" line="108"/>
|
||||
<location filename="../scriptwindow.cpp" line="194"/>
|
||||
<source>Undo</source>
|
||||
<translation>撤销</translation>
|
||||
</message>
|
||||
<message>
|
||||
<location filename="../scriptwindow.cpp" line="114"/>
|
||||
<location filename="../scriptwindow.cpp" line="198"/>
|
||||
<source>Redo</source>
|
||||
<translation>恢复</translation>
|
||||
</message>
|
||||
<message>
|
||||
<location filename="../scriptwindow.cpp" line="121"/>
|
||||
<location filename="../scriptwindow.cpp" line="202"/>
|
||||
<source>Cut</source>
|
||||
<translation>剪切</translation>
|
||||
</message>
|
||||
<message>
|
||||
<location filename="../scriptwindow.cpp" line="125"/>
|
||||
<location filename="../scriptwindow.cpp" line="204"/>
|
||||
<source>Copy</source>
|
||||
<translation>复制</translation>
|
||||
</message>
|
||||
<message>
|
||||
<location filename="../scriptwindow.cpp" line="129"/>
|
||||
<location filename="../scriptwindow.cpp" line="206"/>
|
||||
<source>Paste</source>
|
||||
<translation>粘贴</translation>
|
||||
</message>
|
||||
<message>
|
||||
<location filename="../scriptwindow.cpp" line="134"/>
|
||||
<location filename="../scriptwindow.cpp" line="209"/>
|
||||
<source>Find</source>
|
||||
<translation>查找查找</translation>
|
||||
</message>
|
||||
<message>
|
||||
<location filename="../scriptwindow.cpp" line="138"/>
|
||||
<location filename="../scriptwindow.cpp" line="211"/>
|
||||
<source>Replace</source>
|
||||
<translation>替换替换</translation>
|
||||
</message>
|
||||
<message>
|
||||
<location filename="../scriptwindow.cpp" line="142"/>
|
||||
<location filename="../scriptwindow.cpp" line="213"/>
|
||||
<location filename="../scriptwindow.cpp" line="564"/>
|
||||
<source>Goto</source>
|
||||
<translation>跳转</translation>
|
||||
</message>
|
||||
<message>
|
||||
<location filename="../scriptwindow.cpp" line="148"/>
|
||||
<source>Script</source>
|
||||
<translation>脚本</translation>
|
||||
</message>
|
||||
<message>
|
||||
<location filename="../scriptwindow.cpp" line="151"/>
|
||||
<location filename="../scriptwindow.cpp" line="216"/>
|
||||
<source>Run</source>
|
||||
<translation>执行</translation>
|
||||
</message>
|
||||
<message>
|
||||
<location filename="../scriptwindow.cpp" line="155"/>
|
||||
<location filename="../scriptwindow.cpp" line="218"/>
|
||||
<source>RunFile</source>
|
||||
<translation>从文件执行</translation>
|
||||
</message>
|
||||
<message>
|
||||
<location filename="../scriptwindow.cpp" line="162"/>
|
||||
<source>About</source>
|
||||
<translation>关于</translation>
|
||||
</message>
|
||||
<message>
|
||||
<location filename="../scriptwindow.cpp" line="165"/>
|
||||
<location filename="../scriptwindow.cpp" line="221"/>
|
||||
<source>AboutPlugin</source>
|
||||
<translation>关于插件</translation>
|
||||
</message>
|
||||
<message>
|
||||
<location filename="../scriptwindow.cpp" line="249"/>
|
||||
<source>row:</source>
|
||||
<translation>行:</translation>
|
||||
</message>
|
||||
<message>
|
||||
<location filename="../scriptwindow.cpp" line="254"/>
|
||||
<source>col:</source>
|
||||
<translation>列:</translation>
|
||||
</message>
|
||||
<message>
|
||||
<location filename="../scriptwindow.cpp" line="259"/>
|
||||
<source>len:</source>
|
||||
<translation>长度:</translation>
|
||||
</message>
|
||||
<message>
|
||||
<location filename="../scriptwindow.cpp" line="265"/>
|
||||
<source>InfoSave</source>
|
||||
<translation>是否已保存</translation>
|
||||
</message>
|
||||
<message>
|
||||
<location filename="../scriptwindow.cpp" line="268"/>
|
||||
<source>InfoReadWrite</source>
|
||||
<translation>是否可写</translation>
|
||||
</message>
|
||||
<message>
|
||||
<location filename="../scriptwindow.cpp" line="297"/>
|
||||
<source>FindReachTheEnd</source>
|
||||
<translation>查找已到文件末尾!</translation>
|
||||
</message>
|
||||
<message>
|
||||
<location filename="../scriptwindow.cpp" line="308"/>
|
||||
<source>FindReachTheStart</source>
|
||||
<translation>查找已到文件头部!</translation>
|
||||
</message>
|
||||
<message>
|
||||
<location filename="../scriptwindow.cpp" line="366"/>
|
||||
<source>ReplaceReachTheStart</source>
|
||||
<translation>替换已到文件头部!</translation>
|
||||
</message>
|
||||
<message>
|
||||
<location filename="../scriptwindow.cpp" line="447"/>
|
||||
<source>CloseConfirm</source>
|
||||
<translation>新建将会关闭原来的文件,你确定要继续操作吗?</translation>
|
||||
</message>
|
||||
<message>
|
||||
<location filename="../scriptwindow.cpp" line="448"/>
|
||||
<source>NotSaved</source>
|
||||
<translation>未保存提示</translation>
|
||||
</message>
|
||||
<message>
|
||||
<location filename="../scriptwindow.cpp" line="457"/>
|
||||
<source>ChooseFile</source>
|
||||
<translation>选择文件</translation>
|
||||
</message>
|
||||
<message>
|
||||
<location filename="../scriptwindow.cpp" line="473"/>
|
||||
<source>OpenFail</source>
|
||||
<translation>打开失败</translation>
|
||||
</message>
|
||||
<message>
|
||||
<location filename="../scriptwindow.cpp" line="490"/>
|
||||
<source>SaveFail</source>
|
||||
<translation>保存失败</translation>
|
||||
</message>
|
||||
<message>
|
||||
<location filename="../scriptwindow.cpp" line="495"/>
|
||||
<source>ChooseSaveFile</source>
|
||||
<translation>请输入保存的文件路径</translation>
|
||||
</message>
|
||||
<message>
|
||||
<location filename="../scriptwindow.cpp" line="508"/>
|
||||
<source>SaveAsFail</source>
|
||||
<translation>另存为失败</translation>
|
||||
</message>
|
||||
<message>
|
||||
<location filename="../scriptwindow.cpp" line="529"/>
|
||||
<location filename="../scriptwindow.cpp" line="541"/>
|
||||
<source>OtherScriptRunning</source>
|
||||
<translation>有其他的脚本正在运行</translation>
|
||||
</message>
|
||||
<message>
|
||||
<location filename="../scriptwindow.cpp" line="534"/>
|
||||
<source>ChoosePyScript</source>
|
||||
<translation>请选择运行的脚本文件</translation>
|
||||
</message>
|
||||
<message>
|
||||
<location filename="../scriptwindow.cpp" line="564"/>
|
||||
<source>Line</source>
|
||||
<translation>行</translation>
|
||||
</message>
|
||||
</context>
|
||||
<context>
|
||||
<name>WingToolPy</name>
|
||||
<message>
|
||||
<location filename="../wingtoolpy.cpp" line="21"/>
|
||||
<source>ScriptCenter</source>
|
||||
<translation>脚本中心</translation>
|
||||
</message>
|
||||
<message>
|
||||
<location filename="../wingtoolpy.cpp" line="29"/>
|
||||
<source>WingToolPy</source>
|
||||
<translation>WingToolPy</translation>
|
||||
</message>
|
||||
<message>
|
||||
<location filename="../wingtoolpy.cpp" line="40"/>
|
||||
<source>A powerful plugin to support PyScript automation!</source>
|
||||
<translation>一个强大的使用 Python 脚本利用现有插件实现自动化的插件</translation>
|
||||
</message>
|
||||
</context>
|
||||
<context>
|
||||
<name>WingToolPyService</name>
|
||||
<message>
|
||||
<location filename="../wingtoolpyservice.cpp" line="66"/>
|
||||
<source>[ExcuteFromScriptWindow]</source>
|
||||
<translation>【从脚本编辑器执行】</translation>
|
||||
</message>
|
||||
<message>
|
||||
<location filename="../wingtoolpyservice.h" line="24"/>
|
||||
<source>showEditor</source>
|
||||
<translation>打开编辑器</translation>
|
||||
</message>
|
||||
<message>
|
||||
<location filename="../wingtoolpyservice.h" line="25"/>
|
||||
<source>showConsole</source>
|
||||
<translation>打开控制台</translation>
|
||||
</message>
|
||||
<message>
|
||||
<location filename="../wingtoolpyservice.h" line="26"/>
|
||||
<source>showScriptCenter</source>
|
||||
<translation>显示脚本中心</translation>
|
||||
</message>
|
||||
<message>
|
||||
<location filename="../wingtoolpyservice.h" line="27"/>
|
||||
<source>runScript</source>
|
||||
<translation>执行脚本</translation>
|
||||
</message>
|
||||
<message>
|
||||
<location filename="../wingtoolpyservice.h" line="28"/>
|
||||
<source>runScriptFile</source>
|
||||
<translation>运行脚本文件</translation>
|
||||
</message>
|
||||
</context>
|
||||
</TS>
|
|
@ -0,0 +1,83 @@
|
|||
/* -*- Mode: C++; indent-tabs-mode: nil; tab-width: 4 -*-
|
||||
* -*- coding: utf-8 -*-
|
||||
*
|
||||
* Copyright (C) 2011 ~ 2018 Deepin, Inc.
|
||||
*
|
||||
* Author: Wang Yong <wangyong@deepin.com>
|
||||
* Maintainer: Rekols <rekols@foxmail.com>
|
||||
*
|
||||
* This program is free software: you can redistribute it and/or modify
|
||||
* it under the terms of the GNU General Public License as published by
|
||||
* the Free Software Foundation, either version 3 of the License, or
|
||||
* any later version.
|
||||
*
|
||||
* This program is distributed in the hope that it will be useful,
|
||||
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
* GNU General Public License for more details.
|
||||
*
|
||||
* You should have received a copy of the GNU General Public License
|
||||
* along with this program. If not, see <http://www.gnu.org/licenses/>.
|
||||
*/
|
||||
|
||||
#include "linebar.h"
|
||||
#include <QDebug>
|
||||
#include <QKeyEvent>
|
||||
|
||||
LineBar::LineBar(DLineEdit *parent) : DLineEdit(parent) {
|
||||
// Init.
|
||||
setClearButtonEnabled(true);
|
||||
|
||||
m_autoSaveInternal = 50;
|
||||
m_autoSaveTimer = new QTimer(this);
|
||||
m_autoSaveTimer->setSingleShot(true);
|
||||
|
||||
connect(m_autoSaveTimer, &QTimer::timeout, this,
|
||||
&LineBar::handleTextChangeTimer);
|
||||
connect(this, &DLineEdit::textEdited, this, &LineBar::sendText,
|
||||
Qt::QueuedConnection);
|
||||
connect(this, &DLineEdit::textChanged, this, &LineBar::handleTextChanged,
|
||||
Qt::QueuedConnection);
|
||||
}
|
||||
|
||||
void LineBar::handleTextChangeTimer() {
|
||||
// Emit contentChanged signal.
|
||||
contentChanged();
|
||||
}
|
||||
|
||||
void LineBar::handleTextChanged() {
|
||||
// Stop timer if new character is typed, avoid unused timer run.
|
||||
if (m_autoSaveTimer->isActive()) {
|
||||
m_autoSaveTimer->stop();
|
||||
}
|
||||
|
||||
// Start new timer.
|
||||
m_autoSaveTimer->start(m_autoSaveInternal);
|
||||
}
|
||||
|
||||
void LineBar::sendText(QString t) { emit signal_sentText(t); }
|
||||
|
||||
void LineBar::focusOutEvent(QFocusEvent *e) {
|
||||
// Emit focus out signal.
|
||||
focusOut();
|
||||
|
||||
// Throw event out avoid DLineEdit can't hide cursor after lost focus.
|
||||
DLineEdit::focusOutEvent(e);
|
||||
}
|
||||
|
||||
void LineBar::keyPressEvent(QKeyEvent *e) {
|
||||
auto modifiers = e->modifiers();
|
||||
if (modifiers == Qt::ControlModifier && e->text() == "\r") {
|
||||
pressCtrlEnter();
|
||||
} else if (modifiers == Qt::AltModifier && e->text() == "\r") {
|
||||
pressAltEnter();
|
||||
} else if (modifiers == Qt::MetaModifier && e->text() == "\r") {
|
||||
pressMetaEnter();
|
||||
} else if (modifiers == Qt::NoModifier && e->text() == "\r") {
|
||||
pressEnter();
|
||||
} else {
|
||||
// Pass event to DLineEdit continue, otherwise you can't type anything after
|
||||
// here. ;)
|
||||
DLineEdit::keyPressEvent(e);
|
||||
}
|
||||
}
|
|
@ -0,0 +1,61 @@
|
|||
/* -*- Mode: C++; indent-tabs-mode: nil; tab-width: 4 -*-
|
||||
* -*- coding: utf-8 -*-
|
||||
*
|
||||
* Copyright (C) 2011 ~ 2018 Deepin, Inc.
|
||||
*
|
||||
* Author: Wang Yong <wangyong@deepin.com>
|
||||
* Maintainer: Rekols <rekols@foxmail.com>
|
||||
*
|
||||
* This program is free software: you can redistribute it and/or modify
|
||||
* it under the terms of the GNU General Public License as published by
|
||||
* the Free Software Foundation, either version 3 of the License, or
|
||||
* any later version.
|
||||
*
|
||||
* This program is distributed in the hope that it will be useful,
|
||||
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
* GNU General Public License for more details.
|
||||
*
|
||||
* You should have received a copy of the GNU General Public License
|
||||
* along with this program. If not, see <http://www.gnu.org/licenses/>.
|
||||
*/
|
||||
|
||||
#ifndef LINEBAR_H
|
||||
#define LINEBAR_H
|
||||
|
||||
#include "dlineedit.h"
|
||||
|
||||
#include <QTimer>
|
||||
|
||||
DWIDGET_USE_NAMESPACE
|
||||
|
||||
class LineBar : public DLineEdit {
|
||||
Q_OBJECT
|
||||
|
||||
public:
|
||||
explicit LineBar(DLineEdit *parent = nullptr);
|
||||
|
||||
public slots:
|
||||
void handleTextChangeTimer();
|
||||
void handleTextChanged();
|
||||
void sendText(QString t);
|
||||
|
||||
signals:
|
||||
void contentChanged();
|
||||
void focusOut();
|
||||
void pressAltEnter();
|
||||
void pressCtrlEnter();
|
||||
void pressEnter();
|
||||
void pressMetaEnter();
|
||||
void signal_sentText(QString t);
|
||||
|
||||
protected:
|
||||
virtual void focusOutEvent(QFocusEvent *e);
|
||||
virtual void keyPressEvent(QKeyEvent *e);
|
||||
|
||||
private:
|
||||
QTimer *m_autoSaveTimer;
|
||||
int m_autoSaveInternal;
|
||||
};
|
||||
|
||||
#endif
|
|
@ -0,0 +1,124 @@
|
|||
#include "recentfilemanager.h"
|
||||
#include <DInputDialog>
|
||||
#include <DMenu>
|
||||
#include <DMessageManager>
|
||||
#include <QApplication>
|
||||
#include <QFile>
|
||||
#include <QSettings>
|
||||
|
||||
#define ICONRES(name) QIcon(":/WingToolPy/img/" name ".png")
|
||||
|
||||
RecentFileManager::RecentFileManager(DMenu *menu, DMainWindow *parent)
|
||||
: QObject(parent), m_menu(menu), m_parent(parent) {}
|
||||
|
||||
void RecentFileManager::apply() {
|
||||
QAction *a;
|
||||
a = new QAction(m_menu);
|
||||
a->setText(tr("ClearHistory"));
|
||||
a->setIcon(ICONRES("clearhis"));
|
||||
connect(a, &QAction::triggered, this, &RecentFileManager::clearFile);
|
||||
m_menu->addAction(a);
|
||||
|
||||
a = new QAction(m_menu);
|
||||
a->setText(tr("RemoveItem"));
|
||||
a->setIcon(ICONRES("del"));
|
||||
connect(a, &QAction::triggered, [=] {
|
||||
if (hitems.count() == 0) {
|
||||
DMessageManager::instance()->sendMessage(m_parent, ICONRES("clearhis"),
|
||||
tr("NoHistoryDel"));
|
||||
return;
|
||||
}
|
||||
bool ok;
|
||||
auto d = DInputDialog::getInt(nullptr, tr("Input"), tr("InputIndex"), 0, 0,
|
||||
m_recents.count(), 1, &ok);
|
||||
if (ok) {
|
||||
m_menu->removeAction(hitems.at(d));
|
||||
m_recents.removeAt(d);
|
||||
for (auto it = hitems.begin() + d; it != hitems.end(); it++) {
|
||||
(*it)->setIconText(QString::number(d++));
|
||||
}
|
||||
}
|
||||
});
|
||||
m_menu->addAction(a);
|
||||
|
||||
m_menu->addSeparator();
|
||||
|
||||
QSettings settings(QApplication::organizationName(), "WingHexPy");
|
||||
auto s = settings.value("recent").toStringList();
|
||||
|
||||
int i = 0;
|
||||
for (auto item : s) {
|
||||
if (QFile::exists(item)) {
|
||||
if (m_recents.count() > 10)
|
||||
break;
|
||||
m_recents << item;
|
||||
a = new QAction(m_menu);
|
||||
a->setText(QString("%1 : %2").arg(i++).arg(item));
|
||||
a->setData(item);
|
||||
connect(a, &QAction::triggered, this, &RecentFileManager::trigger);
|
||||
hitems.push_back(a);
|
||||
m_menu->addAction(a);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
RecentFileManager::~RecentFileManager() {
|
||||
QSettings settings(QApplication::organizationName(), "WingHexPy");
|
||||
settings.setValue("recent", m_recents);
|
||||
}
|
||||
|
||||
void RecentFileManager::addRecentFile(QString filename) {
|
||||
while (m_recents.count() >= 10) {
|
||||
m_recents.pop_back();
|
||||
}
|
||||
if (QFile::exists(filename) && m_recents.indexOf(filename) < 0) {
|
||||
auto a = new QAction(m_menu);
|
||||
a = new QAction(m_menu);
|
||||
a->setData(filename);
|
||||
connect(a, &QAction::triggered, this, &RecentFileManager::trigger);
|
||||
m_recents.push_front(filename);
|
||||
if (hitems.count())
|
||||
m_menu->insertAction(hitems.first(), a);
|
||||
else
|
||||
m_menu->addAction(a);
|
||||
hitems.push_front(a);
|
||||
auto i = 0;
|
||||
for (auto item : hitems) {
|
||||
item->setText(QString("%1 : %2").arg(i++).arg(item->data().toString()));
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
void RecentFileManager::trigger() {
|
||||
auto send = qobject_cast<QAction *>(sender());
|
||||
if (send) {
|
||||
auto f = send->data().toString();
|
||||
if (QFile::exists(f)) {
|
||||
emit openFile(f);
|
||||
return;
|
||||
}
|
||||
}
|
||||
auto index = hitems.indexOf(send);
|
||||
if (index >= 0) {
|
||||
m_menu->removeAction(send);
|
||||
hitems.removeAt(index);
|
||||
m_recents.removeAt(index);
|
||||
}
|
||||
}
|
||||
|
||||
void RecentFileManager::clearFile() {
|
||||
if (hitems.count() == 0) {
|
||||
DMessageManager::instance()->sendMessage(m_parent, ICONRES("clearhis"),
|
||||
tr("NoHistoryDel"));
|
||||
return;
|
||||
}
|
||||
for (auto item : hitems) {
|
||||
m_menu->removeAction(item);
|
||||
}
|
||||
m_recents.clear();
|
||||
hitems.clear();
|
||||
QSettings settings(QApplication::organizationName(), "WingHexPy");
|
||||
settings.setValue("recent", m_recents);
|
||||
DMessageManager::instance()->sendMessage(m_parent, ICONRES("clearhis"),
|
||||
tr("HistoryClearFinished"));
|
||||
}
|
|
@ -0,0 +1,32 @@
|
|||
#ifndef RECENTFILEMANAGER_H
|
||||
#define RECENTFILEMANAGER_H
|
||||
|
||||
#include <DMainWindow>
|
||||
#include <DMenu>
|
||||
#include <QAction>
|
||||
#include <QList>
|
||||
#include <QObject>
|
||||
|
||||
DWIDGET_USE_NAMESPACE
|
||||
|
||||
class RecentFileManager : public QObject {
|
||||
Q_OBJECT
|
||||
public:
|
||||
explicit RecentFileManager(DMenu *menu, DMainWindow *parent = nullptr);
|
||||
~RecentFileManager();
|
||||
void addRecentFile(QString filename);
|
||||
void clearFile();
|
||||
void apply();
|
||||
|
||||
signals:
|
||||
bool openFile(QString filename);
|
||||
|
||||
private:
|
||||
DMenu *m_menu;
|
||||
QStringList m_recents;
|
||||
QList<QAction *> hitems;
|
||||
DMainWindow *m_parent;
|
||||
void trigger();
|
||||
};
|
||||
|
||||
#endif // RECENTFILEMANAGER_H
|
|
@ -0,0 +1,222 @@
|
|||
/* -*- Mode: C++; indent-tabs-mode: nil; tab-width: 4 -*-
|
||||
* -*- coding: utf-8 -*-
|
||||
*
|
||||
* Copyright (C) 2011 ~ 2018 Deepin, Inc.
|
||||
*
|
||||
* Author: Wang Yong <wangyong@deepin.com>
|
||||
* Maintainer: Rekols <rekols@foxmail.com>
|
||||
*
|
||||
* This program is free software: you can redistribute it and/or modify
|
||||
* it under the terms of the GNU General Public License as published by
|
||||
* the Free Software Foundation, either version 3 of the License, or
|
||||
* any later version.
|
||||
*
|
||||
* This program is distributed in the hope that it will be useful,
|
||||
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
* GNU General Public License for more details.
|
||||
*
|
||||
* You should have received a copy of the GNU General Public License
|
||||
* along with this program. If not, see <http://www.gnu.org/licenses/>.
|
||||
*/
|
||||
|
||||
#include "replacebar.h"
|
||||
#include <QDebug>
|
||||
#include <QKeyEvent>
|
||||
|
||||
ReplaceBar::ReplaceBar(QWidget *parent) : DFloatingWidget(parent) {
|
||||
// Init.
|
||||
hide();
|
||||
setFixedHeight(60);
|
||||
|
||||
// Init layout and widgets.
|
||||
m_layout = new QHBoxLayout();
|
||||
m_layout->setSpacing(10);
|
||||
m_layout->setContentsMargins(16, 6, 10, 6);
|
||||
m_replaceLabel = new QLabel(tr("Replace"));
|
||||
// m_replaceLabel->setMinimumHeight(36);
|
||||
m_replaceLine = new LineBar();
|
||||
// m_replaceLine->lineEdit()->setMinimumHeight(36);
|
||||
m_withLabel = new QLabel(tr("Replace With"));
|
||||
// m_withLabel->setMinimumHeight(36);
|
||||
m_withLine = new LineBar();
|
||||
// m_withLine->lineEdit()->setMinimumHeight(36);
|
||||
m_replaceButton = new QPushButton(tr("Replace"));
|
||||
// m_replaceButton->setMinimumWidth(66);
|
||||
// m_replaceButton->setMinimumHeight(36);
|
||||
m_replaceSkipButton = new QPushButton(tr("Skip"));
|
||||
// m_replaceRestButton->setMinimumWidth(80);
|
||||
// m_replaceRestButton->setMinimumHeight(36);
|
||||
m_replaceAllButton = new QPushButton(tr("Replace All"));
|
||||
// m_replaceAllButton->setMinimumWidth(80);
|
||||
// m_replaceAllButton->setMinimumHeight(36);
|
||||
m_closeButton = new DIconButton(DStyle::SP_CloseButton);
|
||||
m_closeButton->setFlat(true);
|
||||
m_closeButton->setFixedSize(30, 30);
|
||||
m_closeButton->setEnabledCircle(true);
|
||||
m_closeButton->setIconSize(QSize(30, 30));
|
||||
|
||||
m_layout->addWidget(m_replaceLabel);
|
||||
m_layout->addWidget(m_replaceLine);
|
||||
m_layout->addWidget(m_withLabel);
|
||||
m_layout->addWidget(m_withLine);
|
||||
m_layout->addWidget(m_replaceButton);
|
||||
m_layout->addWidget(m_replaceSkipButton);
|
||||
m_layout->addWidget(m_replaceAllButton);
|
||||
m_layout->addWidget(m_closeButton);
|
||||
this->setLayout(m_layout);
|
||||
|
||||
// Make button don't grab keyboard focus after click it.
|
||||
#if 0
|
||||
m_replaceButton->setFocusPolicy(Qt::NoFocus);
|
||||
m_replaceSkipButton->setFocusPolicy(Qt::NoFocus);
|
||||
m_replaceRestButton->setFocusPolicy(Qt::NoFocus);
|
||||
m_replaceAllButton->setFocusPolicy(Qt::NoFocus);
|
||||
m_closeButton->setFocusPolicy(Qt::NoFocus);
|
||||
#endif
|
||||
connect(m_replaceLine, &LineBar::signal_sentText, this, &ReplaceBar::change,
|
||||
Qt::QueuedConnection);
|
||||
|
||||
connect(this, &ReplaceBar::pressEsc, this, &ReplaceBar::replaceClose,
|
||||
Qt::QueuedConnection);
|
||||
|
||||
// connect(m_replaceLine, &LineBar::pressEnter, this,
|
||||
// &ReplaceBar::handleReplaceNext, Qt::QueuedConnection); //Shielded
|
||||
// by Hengbo for new demand.
|
||||
connect(m_withLine, &LineBar::returnPressed, this,
|
||||
&ReplaceBar::handleReplaceNext, Qt::QueuedConnection);
|
||||
|
||||
connect(m_replaceLine, &LineBar::pressCtrlEnter, this,
|
||||
[=]() { emit replaceSkip(m_replaceLine->lineEdit()->text()); });
|
||||
connect(m_withLine, &LineBar::pressCtrlEnter, this,
|
||||
[=]() { emit replaceSkip(m_replaceLine->lineEdit()->text()); });
|
||||
|
||||
connect(m_replaceLine, &LineBar::pressMetaEnter, this,
|
||||
&ReplaceBar::handleReplaceAll, Qt::QueuedConnection);
|
||||
connect(m_withLine, &LineBar::pressMetaEnter, this,
|
||||
&ReplaceBar::handleReplaceAll, Qt::QueuedConnection);
|
||||
|
||||
connect(m_replaceLine, &LineBar::returnPressed, this,
|
||||
&ReplaceBar::handleContentChanged, Qt::QueuedConnection);
|
||||
|
||||
connect(m_replaceButton, &QPushButton::clicked, this,
|
||||
&ReplaceBar::handleReplaceNext, Qt::QueuedConnection);
|
||||
connect(m_replaceSkipButton, &QPushButton::clicked, this,
|
||||
[=]() { emit replaceSkip(m_replaceLine->lineEdit()->text()); });
|
||||
connect(m_replaceAllButton, &QPushButton::clicked, this,
|
||||
&ReplaceBar::handleReplaceAll, Qt::QueuedConnection);
|
||||
|
||||
connect(m_closeButton, &DIconButton::clicked, this, &ReplaceBar::replaceClose,
|
||||
Qt::QueuedConnection);
|
||||
}
|
||||
|
||||
bool ReplaceBar::isFocus() { return m_replaceLine->hasFocus(); }
|
||||
|
||||
void ReplaceBar::focus() { m_replaceLine->lineEdit()->setFocus(); }
|
||||
|
||||
void ReplaceBar::activeInput(QString text, int row, int column,
|
||||
int scrollOffset) {
|
||||
// Try fill keyword with select text.
|
||||
m_withLine->lineEdit()->clear();
|
||||
m_replaceLine->lineEdit()->clear();
|
||||
m_replaceLine->lineEdit()->insert(text);
|
||||
m_replaceLine->lineEdit()->selectAll();
|
||||
|
||||
// Show.
|
||||
show();
|
||||
|
||||
// Save file info for back to position.
|
||||
m_replaceFileRow = row;
|
||||
m_replaceFileColumn = column;
|
||||
m_replaceFileSrollOffset = scrollOffset;
|
||||
|
||||
// Focus.
|
||||
focus();
|
||||
}
|
||||
|
||||
void ReplaceBar::replaceClose() {
|
||||
searched = false;
|
||||
hide();
|
||||
emit sigReplacebarClose();
|
||||
}
|
||||
|
||||
void ReplaceBar::handleContentChanged() {
|
||||
updateSearchKeyword(m_replaceLine->lineEdit()->text());
|
||||
}
|
||||
|
||||
void ReplaceBar::handleReplaceNext() {
|
||||
if (!searched) {
|
||||
emit removeSearchKeyword();
|
||||
}
|
||||
replaceNext(m_replaceLine->lineEdit()->text(),
|
||||
m_withLine->lineEdit()->text());
|
||||
searched = true;
|
||||
}
|
||||
|
||||
void ReplaceBar::handleReplaceAll() {
|
||||
replaceAll(m_replaceLine->lineEdit()->text(), m_withLine->lineEdit()->text());
|
||||
}
|
||||
|
||||
void ReplaceBar::hideEvent(QHideEvent *) {
|
||||
searched = false;
|
||||
removeSearchKeyword();
|
||||
}
|
||||
|
||||
bool ReplaceBar::focusNextPrevChild(bool) {
|
||||
// Make keyword jump between two EditLine widgets.
|
||||
auto *editWidget = qobject_cast<LineBar *>(focusWidget());
|
||||
if (editWidget != nullptr) {
|
||||
if (editWidget == m_replaceLine) {
|
||||
m_withLine->lineEdit()->setFocus();
|
||||
|
||||
return true;
|
||||
} else if (editWidget == m_withLine) {
|
||||
m_replaceLine->lineEdit()->setFocus();
|
||||
|
||||
return true;
|
||||
}
|
||||
}
|
||||
|
||||
return false;
|
||||
}
|
||||
|
||||
void ReplaceBar::keyPressEvent(QKeyEvent *e) {
|
||||
|
||||
bool unhandled = false;
|
||||
if (e->modifiers() == Qt::KeyboardModifier::NoModifier) {
|
||||
switch (e->key()) {
|
||||
case Qt::Key_Escape: {
|
||||
QWidget::hide();
|
||||
emit sigReplacebarClose();
|
||||
} break;
|
||||
case Qt::Key_Tab: {
|
||||
if (m_closeButton->hasFocus())
|
||||
m_replaceLine->lineEdit()->setFocus();
|
||||
} break;
|
||||
case Qt::Key_Enter: {
|
||||
if (m_replaceAllButton->hasFocus()) {
|
||||
m_replaceAllButton->click();
|
||||
}
|
||||
if (m_replaceButton->hasFocus()) {
|
||||
m_replaceButton->click();
|
||||
}
|
||||
if (m_replaceSkipButton->hasFocus()) {
|
||||
m_replaceSkipButton->click();
|
||||
}
|
||||
} break;
|
||||
default:
|
||||
unhandled = true;
|
||||
break;
|
||||
}
|
||||
}
|
||||
if (unhandled)
|
||||
DFloatingWidget::keyPressEvent(e);
|
||||
}
|
||||
|
||||
void ReplaceBar::setMismatchAlert(bool isAlert) {
|
||||
m_replaceLine->setAlert(isAlert);
|
||||
}
|
||||
|
||||
void ReplaceBar::setsearched(bool _) { searched = _; }
|
||||
|
||||
void ReplaceBar::change() { searched = false; }
|
|
@ -0,0 +1,96 @@
|
|||
/* -*- Mode: C++; indent-tabs-mode: nil; tab-width: 4 -*-
|
||||
* -*- coding: utf-8 -*-
|
||||
*
|
||||
* Copyright (C) 2011 ~ 2018 Deepin, Inc.
|
||||
*
|
||||
* Author: Wang Yong <wangyong@deepin.com>
|
||||
* Maintainer: Rekols <rekols@foxmail.com>
|
||||
*
|
||||
* This program is free software: you can redistribute it and/or modify
|
||||
* it under the terms of the GNU General Public License as published by
|
||||
* the Free Software Foundation, either version 3 of the License, or
|
||||
* any later version.
|
||||
*
|
||||
* This program is distributed in the hope that it will be useful,
|
||||
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
* GNU General Public License for more details.
|
||||
*
|
||||
* You should have received a copy of the GNU General Public License
|
||||
* along with this program. If not, see <http://www.gnu.org/licenses/>.
|
||||
*/
|
||||
|
||||
#ifndef REPLACEBAR_H
|
||||
#define REPLACEBAR_H
|
||||
|
||||
#include "dimagebutton.h"
|
||||
#include "linebar.h"
|
||||
#include <DAbstractDialog>
|
||||
#include <DApplicationHelper>
|
||||
#include <DFloatingWidget>
|
||||
#include <DIconButton>
|
||||
#include <QHBoxLayout>
|
||||
#include <QLabel>
|
||||
#include <QPainter>
|
||||
#include <QPushButton>
|
||||
#include <QWidget>
|
||||
|
||||
DWIDGET_USE_NAMESPACE
|
||||
|
||||
class ReplaceBar : public DFloatingWidget {
|
||||
Q_OBJECT
|
||||
|
||||
public:
|
||||
explicit ReplaceBar(QWidget *parent = nullptr);
|
||||
|
||||
bool isFocus();
|
||||
void focus();
|
||||
|
||||
void activeInput(QString text, int row, int column, int scrollOffset);
|
||||
void setMismatchAlert(bool isAlert);
|
||||
void setsearched(bool _);
|
||||
|
||||
signals:
|
||||
void pressEsc();
|
||||
void replaceNext(QString replaceText, QString withText);
|
||||
void replaceSkip(QString keyword);
|
||||
void replaceAll(QString replaceText, QString withText);
|
||||
void backToPosition(int row, int column, int scrollOffset);
|
||||
|
||||
void removeSearchKeyword();
|
||||
void updateSearchKeyword(QString keyword);
|
||||
|
||||
void sigReplacebarClose();
|
||||
|
||||
public slots:
|
||||
void change();
|
||||
void replaceClose();
|
||||
void handleContentChanged();
|
||||
void handleReplaceAll();
|
||||
void handleReplaceNext();
|
||||
|
||||
protected:
|
||||
void hideEvent(QHideEvent *event);
|
||||
bool focusNextPrevChild(bool next);
|
||||
void keyPressEvent(QKeyEvent *e);
|
||||
|
||||
private:
|
||||
QPushButton *m_replaceAllButton;
|
||||
QPushButton *m_replaceButton;
|
||||
QPushButton *m_replaceSkipButton;
|
||||
DIconButton *m_closeButton;
|
||||
LineBar *m_replaceLine;
|
||||
LineBar *m_withLine;
|
||||
QHBoxLayout *m_layout;
|
||||
QLabel *m_replaceLabel;
|
||||
QLabel *m_withLabel;
|
||||
int m_replaceFileColumn;
|
||||
int m_replaceFileRow;
|
||||
int m_replaceFileSrollOffset;
|
||||
QColor m_backgroundColor;
|
||||
bool searched = false;
|
||||
|
||||
QPoint last;
|
||||
};
|
||||
|
||||
#endif
|
|
@ -0,0 +1,39 @@
|
|||
<RCC>
|
||||
<qresource prefix="/WingToolPy">
|
||||
<file>img/icon.png</file>
|
||||
<file>img/copy.png</file>
|
||||
<file>img/cut.png</file>
|
||||
<file>img/find.png</file>
|
||||
<file>img/jmp.png</file>
|
||||
<file>img/new.png</file>
|
||||
<file>img/open.png</file>
|
||||
<file>img/paste.png</file>
|
||||
<file>img/readonly.png</file>
|
||||
<file>img/redo.png</file>
|
||||
<file>img/replace.png</file>
|
||||
<file>img/run.png</file>
|
||||
<file>img/runf.png</file>
|
||||
<file>img/rwg.png</file>
|
||||
<file>img/save.png</file>
|
||||
<file>img/saveas.png</file>
|
||||
<file>img/saved.png</file>
|
||||
<file>img/saveg.png</file>
|
||||
<file>img/soft.png</file>
|
||||
<file>img/undo.png</file>
|
||||
<file>img/unsaved.png</file>
|
||||
<file>img/writable.png</file>
|
||||
<file>img/author.png</file>
|
||||
<file alias="default_style.xml">QCodeEditor/default_style.xml</file>
|
||||
<file alias="drakula.xml">QCodeEditor/drakula.xml</file>
|
||||
<file alias="python.xml">QCodeEditor/python.xml</file>
|
||||
<file>img/file.png</file>
|
||||
<file>img/clearhis.png</file>
|
||||
<file>img/del.png</file>
|
||||
<file>img/closefile.png</file>
|
||||
<file>img/edit.png</file>
|
||||
<file>img/py.png</file>
|
||||
<file>img/pydb.png</file>
|
||||
<file>img/author.jpg</file>
|
||||
<file>img/README.md</file>
|
||||
</qresource>
|
||||
</RCC>
|
|
@ -0,0 +1,66 @@
|
|||
#include "scriptcenterwindow.h"
|
||||
#include <DPushButton>
|
||||
#include <DTextBrowser>
|
||||
#include <DTreeWidget>
|
||||
#include <QHBoxLayout>
|
||||
#include <QVBoxLayout>
|
||||
|
||||
ScriptCenterWindow::ScriptCenterWindow(DMainWindow *parent) : DDialog(parent) {
|
||||
setMinimumSize(700, 500);
|
||||
setWindowTitle(tr("ScriptCenter"));
|
||||
auto w = new QWidget(this);
|
||||
auto layout = new QHBoxLayout(w);
|
||||
auto tree = new QTreeWidget(this);
|
||||
tree->setHeaderHidden(true);
|
||||
m = ScriptManager::instance();
|
||||
m->loadTreeWidget(tree);
|
||||
layout->addWidget(tree);
|
||||
|
||||
auto vlayout = new QVBoxLayout;
|
||||
layout->addLayout(vlayout);
|
||||
auto txt = new QTextBrowser(this);
|
||||
vlayout->addWidget(txt);
|
||||
addContent(w);
|
||||
|
||||
auto runbtn = new DPushButton(tr("Run"), this);
|
||||
runbtn->setEnabled(false);
|
||||
connect(tree, &QTreeWidget::itemSelectionChanged, this, [=] {
|
||||
auto s = tree->selectedItems();
|
||||
if (s.count()) {
|
||||
auto si = s.first();
|
||||
auto meta = si->data(0, Qt::UserRole).value<ScriptMeta>();
|
||||
if (meta.name.length()) {
|
||||
txt->setMarkdown(QString("**%1** : %2\n\n**%3** : %4\n\n"
|
||||
"**%5** : %6\n\n**%7** : %8\n\n"
|
||||
"**%9** : %10\n\n")
|
||||
.arg(tr("Name"))
|
||||
.arg(meta.name)
|
||||
.arg(tr("Author"))
|
||||
.arg(meta.author)
|
||||
.arg(tr("License"))
|
||||
.arg(meta.license)
|
||||
.arg("Version")
|
||||
.arg(meta.version)
|
||||
.arg("Commnet")
|
||||
.arg(meta.commnet));
|
||||
runbtn->setEnabled(true);
|
||||
} else {
|
||||
txt->setMarkdown(
|
||||
QString("**%1** : %2\n\n").arg(tr("Catagory")).arg(si->text(0)));
|
||||
runbtn->setEnabled(false);
|
||||
}
|
||||
}
|
||||
});
|
||||
|
||||
connect(runbtn, &DPushButton::clicked, this, [=] {
|
||||
auto s = tree->selectedItems();
|
||||
if (s.count()) {
|
||||
auto si = s.first();
|
||||
auto meta = si->data(0, Qt::UserRole).value<ScriptMeta>();
|
||||
if (meta.name.length()) {
|
||||
emit this->sigRunScript(meta.filename);
|
||||
}
|
||||
}
|
||||
});
|
||||
vlayout->addWidget(runbtn);
|
||||
}
|