403 lines
12 KiB
C++
403 lines
12 KiB
C++
/***************************************************************************
|
|
* Copyright (c) 2004 Werner Mayer <wmayer[at]users.sourceforge.net> *
|
|
* *
|
|
* This file is part of the FreeCAD CAx development system. *
|
|
* *
|
|
* This library is free software; you can redistribute it and/or *
|
|
* modify it under the terms of the GNU Library General Public *
|
|
* License as published by the Free Software Foundation; either *
|
|
* version 2 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 Library General Public License for more details. *
|
|
* *
|
|
* You should have received a copy of the GNU Library General Public *
|
|
* License along with this library; see the file COPYING.LIB. If not, *
|
|
* write to the Free Software Foundation, Inc., 59 Temple Place, *
|
|
* Suite 330, Boston, MA 02111-1307, USA *
|
|
* *
|
|
***************************************************************************/
|
|
|
|
|
|
#ifndef GUI_WIDGETFACTORY_H
|
|
#define GUI_WIDGETFACTORY_H
|
|
|
|
#include <vector>
|
|
|
|
#include <Base/Factory.h>
|
|
#include "Dialogs/DlgCustomizeImp.h"
|
|
#include "Dialogs/DlgPreferencesImp.h"
|
|
#include "PropertyPage.h"
|
|
#include <CXX/Extensions.hxx>
|
|
|
|
QT_BEGIN_NAMESPACE
|
|
class QDir;
|
|
QT_END_NAMESPACE
|
|
|
|
namespace Gui {
|
|
namespace Dialog{
|
|
class PreferencePage;
|
|
}
|
|
|
|
/**
|
|
* The widget factory provides methods for the dynamic creation of widgets.
|
|
* To create these widgets once they must be registered to the factory.
|
|
* To register them use WidgetProducer or any subclasses; to register a
|
|
* preference page use PrefPageProducer instead.
|
|
* \author Werner Mayer
|
|
*/
|
|
class GuiExport WidgetFactoryInst : public Base::Factory
|
|
{
|
|
public:
|
|
static WidgetFactoryInst& instance();
|
|
static void destruct ();
|
|
|
|
QWidget* createWidget (const char* sName, QWidget* parent=nullptr) const;
|
|
Gui::Dialog::PreferencePage* createPreferencePage (const char* sName, QWidget* parent=nullptr) const;
|
|
QWidget* createPrefWidget(const char* sName, QWidget* parent, const char* sPref);
|
|
|
|
private:
|
|
static WidgetFactoryInst* _pcSingleton;
|
|
|
|
WidgetFactoryInst() = default;
|
|
~WidgetFactoryInst() override = default;
|
|
};
|
|
|
|
inline WidgetFactoryInst& WidgetFactory()
|
|
{
|
|
return WidgetFactoryInst::instance();
|
|
}
|
|
|
|
// --------------------------------------------------------------------
|
|
|
|
/**
|
|
* The WidgetProducer class is a value-based template class that provides
|
|
* the ability to create widgets dynamically.
|
|
* \author Werner Mayer
|
|
*/
|
|
template <class CLASS>
|
|
class WidgetProducer : public Base::AbstractProducer
|
|
{
|
|
public:
|
|
/**
|
|
* Register a special type of widget to the WidgetFactoryInst.
|
|
*/
|
|
WidgetProducer ()
|
|
{
|
|
const char* cname = CLASS::staticMetaObject.className();
|
|
WidgetFactoryInst::instance().AddProducer(cname, this);
|
|
}
|
|
|
|
~WidgetProducer () override = default;
|
|
|
|
/**
|
|
* Creates an instance of the specified widget.
|
|
*/
|
|
void* Produce () const override
|
|
{
|
|
return (new CLASS);
|
|
}
|
|
};
|
|
|
|
// --------------------------------------------------------------------
|
|
|
|
/**
|
|
* The PrefPageProducer class is a value-based template class that provides
|
|
* the ability to create preference pages dynamically.
|
|
* \author Werner Mayer
|
|
*/
|
|
template <class CLASS>
|
|
class PrefPageProducer : public Base::AbstractProducer
|
|
{
|
|
public:
|
|
/**
|
|
* Register a special type of preference page to the WidgetFactoryInst.
|
|
*/
|
|
PrefPageProducer (const char* group)
|
|
{
|
|
const char* cname = CLASS::staticMetaObject.className();
|
|
if (strcmp(cname, Gui::Dialog::PreferencePage::staticMetaObject.className()) == 0)
|
|
qWarning("The class '%s' lacks of Q_OBJECT macro", typeid(CLASS).name());
|
|
if (WidgetFactoryInst::instance().CanProduce(cname)) {
|
|
qWarning("The preference page class '%s' is already registered", cname);
|
|
}
|
|
else {
|
|
WidgetFactoryInst::instance().AddProducer(cname, this);
|
|
Gui::Dialog::DlgPreferencesImp::addPage(cname, group);
|
|
}
|
|
}
|
|
|
|
~PrefPageProducer () override = default;
|
|
|
|
/**
|
|
* Creates an instance of the specified widget.
|
|
*/
|
|
void* Produce () const override
|
|
{
|
|
return (new CLASS);
|
|
}
|
|
};
|
|
|
|
/**
|
|
* The PrefPageUiProducer class provides the ability to create preference pages
|
|
* dynamically from an external UI file.
|
|
* @author Werner Mayer
|
|
*/
|
|
class GuiExport PrefPageUiProducer : public Base::AbstractProducer
|
|
{
|
|
public:
|
|
/**
|
|
* Register a special type of preference page to the WidgetFactoryInst.
|
|
*/
|
|
PrefPageUiProducer (const char* filename, const char* group);
|
|
~PrefPageUiProducer () override;
|
|
/**
|
|
* Creates an instance of the specified widget.
|
|
*/
|
|
void* Produce () const override;
|
|
|
|
private:
|
|
QString fn;
|
|
};
|
|
|
|
/**
|
|
* The PrefPagePyProducer class provides the ability to create preference pages
|
|
* dynamically from a Python class.
|
|
* @author Werner Mayer
|
|
*/
|
|
class GuiExport PrefPagePyProducer : public Base::AbstractProducer
|
|
{
|
|
public:
|
|
/**
|
|
* Register a special type of preference page to the WidgetFactoryInst.
|
|
*/
|
|
PrefPagePyProducer (const Py::Object&, const char* group);
|
|
~PrefPagePyProducer () override;
|
|
/**
|
|
* Creates an instance of the specified widget.
|
|
*/
|
|
void* Produce () const override;
|
|
|
|
private:
|
|
Py::Object type;
|
|
};
|
|
|
|
// --------------------------------------------------------------------
|
|
|
|
/**
|
|
* The CustomPageProducer class is a value-based template class that provides
|
|
* the ability to create custom pages dynamically.
|
|
* \author Werner Mayer
|
|
*/
|
|
template <class CLASS>
|
|
class CustomPageProducer : public Base::AbstractProducer
|
|
{
|
|
public:
|
|
/**
|
|
* Register a special type of customize page to the WidgetFactoryInst.
|
|
*/
|
|
CustomPageProducer ()
|
|
{
|
|
const char* cname = CLASS::staticMetaObject.className();
|
|
if (strcmp(cname, Gui::Dialog::CustomizeActionPage::staticMetaObject.className()) == 0)
|
|
qWarning("The class '%s' lacks of Q_OBJECT macro", typeid(CLASS).name());
|
|
if (WidgetFactoryInst::instance().CanProduce(cname)) {
|
|
qWarning("The preference page class '%s' is already registered", cname);
|
|
}
|
|
else {
|
|
WidgetFactoryInst::instance().AddProducer(cname, this);
|
|
Gui::Dialog::DlgCustomizeImp::addPage(cname);
|
|
}
|
|
}
|
|
|
|
~CustomPageProducer () override = default;
|
|
|
|
/**
|
|
* Creates an instance of the specified widget.
|
|
*/
|
|
void* Produce () const override
|
|
{
|
|
return (new CLASS);
|
|
}
|
|
};
|
|
|
|
// --------------------------------------------------------------------
|
|
|
|
/**
|
|
* The widget factory supplier class registers all kinds of
|
|
* preference pages and widgets.
|
|
* \author Werner Mayer
|
|
*/
|
|
class WidgetFactorySupplier
|
|
{
|
|
private:
|
|
// Singleton
|
|
WidgetFactorySupplier();
|
|
static WidgetFactorySupplier *_pcSingleton;
|
|
|
|
public:
|
|
static WidgetFactorySupplier &instance();
|
|
static void destruct();
|
|
friend WidgetFactorySupplier &GetWidgetFactorySupplier();
|
|
};
|
|
|
|
inline WidgetFactorySupplier &GetWidgetFactorySupplier()
|
|
{
|
|
return WidgetFactorySupplier::instance();
|
|
}
|
|
|
|
// ----------------------------------------------------
|
|
|
|
/**
|
|
* The ContainerDialog class acts as a container to embed any kinds of widgets that
|
|
* do not inherit from QDialog. This class also provides an "Ok" and a "Cancel" button.
|
|
* At most this class is used to embed widgets which are created from .ui files.
|
|
* \author Werner Mayer
|
|
*/
|
|
class ContainerDialog : public QDialog
|
|
{
|
|
Q_OBJECT
|
|
|
|
public:
|
|
ContainerDialog( QWidget* templChild );
|
|
~ContainerDialog() override;
|
|
|
|
QPushButton* buttonOk; /**< The Ok button. */
|
|
QPushButton* buttonCancel; /**< The cancel button. */
|
|
|
|
private:
|
|
QGridLayout* MyDialogLayout;
|
|
};
|
|
|
|
// ----------------------------------------------------
|
|
|
|
/**
|
|
* The PyResource class provides an interface to create widgets or to load .ui files from Python.
|
|
* With
|
|
* \code
|
|
* d = Gui.createDialog("test.ui")
|
|
* \endcode
|
|
*
|
|
* you can create a PyResource object containing the widget. If a relative file name
|
|
* is given PyResource looks first in the current working directory and afterwards in
|
|
* the home path where FreeCAD resides.
|
|
*
|
|
* If the appropriate .ui file cannot be found or creation fails an exception is thrown.
|
|
* In case the widget in the .ui file does not inherit from QDialog it is embedded in a
|
|
* \ref ContainerDialog object.
|
|
* To show the widget you can call
|
|
* \code
|
|
* d.Show()
|
|
* \endcode
|
|
*
|
|
* Furthermore it is possible to get or set values from any widgets inside
|
|
* the parent widget or to connect a Python callback function with a widget.
|
|
* \remark The callback function must have exactly one parameter. This parameter
|
|
* points to the dialog you have just created.
|
|
* \code
|
|
* # define a callback function with one argument
|
|
* def TestCall(obj):
|
|
* # sets the value from lineedit if "Button_Name" was pressed
|
|
* obj.setValue("lineedit", "text", "Show this text here!")
|
|
* print "Button clicked"
|
|
*
|
|
* d = Gui.createDialog("test.ui")
|
|
* d.connect("Button_Name", "clicked()", TestCall)
|
|
* d.show()
|
|
* \endcode
|
|
*
|
|
* If the button with the name "Button_Name" is clicked the message "Button clicked" is
|
|
* printed.
|
|
* For example if you have a QLineEdit inside your widget you can set the text with
|
|
* \code
|
|
* # sets "Show this text here!" to the text property
|
|
* d.setValue("lineedit", "text", "Show this text here!")
|
|
* d.show()
|
|
* \endcode
|
|
*
|
|
* or retrieve the entered text with
|
|
* \code
|
|
* f = d.getValue("lineedit", "text")
|
|
* print f
|
|
* \endcode
|
|
*
|
|
* \author Werner Mayer
|
|
*/
|
|
|
|
class PyResource : public Py::PythonExtension<PyResource>
|
|
{
|
|
public:
|
|
static void init_type(); // announce properties and methods
|
|
|
|
PyResource();
|
|
~PyResource() override;
|
|
|
|
void load(const char* name);
|
|
bool connect(const char* sender, const char* signal, PyObject* cb);
|
|
|
|
Py::Object repr() override;
|
|
|
|
Py::Object value(const Py::Tuple&);
|
|
Py::Object setValue(const Py::Tuple&);
|
|
Py::Object show(const Py::Tuple&);
|
|
Py::Object connect(const Py::Tuple&);
|
|
|
|
private:
|
|
std::vector<class SignalConnect*> mySignals;
|
|
QDialog* myDlg;
|
|
};
|
|
|
|
/**
|
|
* The SignalConnect class provides the abitlity to make a connection
|
|
* between the callback function of a Python object and the slot onExecute().
|
|
* This mechanism is used in the Python/Qt framework.
|
|
* \author Werner Mayer
|
|
*/
|
|
class SignalConnect : public QObject
|
|
{
|
|
Q_OBJECT
|
|
|
|
public:
|
|
SignalConnect(PyObject* res, PyObject* cb);
|
|
~SignalConnect() override;
|
|
|
|
public Q_SLOTS:
|
|
void onExecute();
|
|
|
|
private:
|
|
PyObject* myResource;
|
|
PyObject* myCallback;
|
|
};
|
|
|
|
// ----------------------------------------------------
|
|
namespace Dialog {
|
|
|
|
/** Subclass that embeds a form from a Python class.
|
|
* \author Werner Mayer
|
|
*/
|
|
class GuiExport PreferencePagePython : public PreferencePage
|
|
{
|
|
Q_OBJECT
|
|
|
|
public:
|
|
PreferencePagePython(const Py::Object& dlg, QWidget* parent = nullptr);
|
|
~PreferencePagePython() override;
|
|
|
|
void loadSettings() override;
|
|
void saveSettings() override;
|
|
|
|
protected:
|
|
void changeEvent(QEvent *e) override;
|
|
|
|
private:
|
|
Py::Object page;
|
|
};
|
|
|
|
} // namespace Dialog
|
|
|
|
} // namespace Gui
|
|
|
|
#endif // GUI_WIDGETFACTORY_H
|