WidgetFactory.cpp

Go to the documentation of this file.
00001 /***************************************************************************
00002  *   Copyright (c) 2004 Werner Mayer <wmayer[at]users.sourceforge.net>     *
00003  *                                                                         *
00004  *   This file is part of the FreeCAD CAx development system.              *
00005  *                                                                         *
00006  *   This library is free software; you can redistribute it and/or         *
00007  *   modify it under the terms of the GNU Library General Public           *
00008  *   License as published by the Free Software Foundation; either          *
00009  *   version 2 of the License, or (at your option) any later version.      *
00010  *                                                                         *
00011  *   This library  is distributed in the hope that it will be useful,      *
00012  *   but WITHOUT ANY WARRANTY; without even the implied warranty of        *
00013  *   MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the         *
00014  *   GNU Library General Public License for more details.                  *
00015  *                                                                         *
00016  *   You should have received a copy of the GNU Library General Public     *
00017  *   License along with this library; see the file COPYING.LIB. If not,    *
00018  *   write to the Free Software Foundation, Inc., 59 Temple Place,         *
00019  *   Suite 330, Boston, MA  02111-1307, USA                                *
00020  *                                                                         *
00021  ***************************************************************************/
00022 
00023 
00024 #include "PreCompiled.h"
00025 
00026 #include <App/Application.h>
00027 #include <Base/Console.h>
00028 #include <Base/Exception.h>
00029 
00030 
00031 #include "WidgetFactory.h"
00032 #include "PrefWidgets.h"
00033 #include "PropertyPage.h"
00034 
00035 
00036 using namespace Gui;
00037 
00038 
00039 Gui::WidgetFactoryInst* Gui::WidgetFactoryInst::_pcSingleton = NULL;
00040 
00041 WidgetFactoryInst& WidgetFactoryInst::instance()
00042 {
00043     if (_pcSingleton == 0L)
00044         _pcSingleton = new WidgetFactoryInst;
00045     return *_pcSingleton;
00046 }
00047 
00048 void WidgetFactoryInst::destruct ()
00049 {
00050     if (_pcSingleton != 0)
00051         delete _pcSingleton;
00052     _pcSingleton = 0;
00053 }
00054 
00060 QWidget* WidgetFactoryInst::createWidget (const char* sName, QWidget* parent) const
00061 {
00062     QWidget* w = (QWidget*)Produce(sName);
00063 
00064     // this widget class is not registered
00065     if (!w) {
00066 #ifdef FC_DEBUG
00067         Base::Console().Warning("\"%s\" is not registered\n", sName);
00068 #else
00069         Base::Console().Log("\"%s\" is not registered\n", sName);
00070 #endif
00071         return 0;
00072     }
00073 
00074     try {
00075 #ifdef FC_DEBUG
00076         const char* cName = dynamic_cast<QWidget*>(w)->metaObject()->className();
00077         Base::Console().Log("Widget of type '%s' created.\n", cName);
00078 #endif
00079     }
00080     catch (...) {
00081 #ifdef FC_DEBUG
00082         Base::Console().Error("%s does not inherit from \"QWidget\"\n", sName);
00083 #else
00084         Base::Console().Log("%s does not inherit from \"QWidget\"\n", sName);
00085 #endif
00086         delete w;
00087         return 0;
00088     }
00089 
00090     // set the parent to the widget
00091     if (parent)
00092         w->setParent(parent);
00093 
00094     return w;
00095 }
00096 
00102 Gui::Dialog::PreferencePage* WidgetFactoryInst::createPreferencePage (const char* sName, QWidget* parent) const
00103 {
00104     Gui::Dialog::PreferencePage* w = (Gui::Dialog::PreferencePage*)Produce(sName);
00105 
00106     // this widget class is not registered
00107     if (!w) {
00108 #ifdef FC_DEBUG
00109         Base::Console().Warning("\"%s\" is not registered\n", sName);
00110 #else
00111         Base::Console().Log("\"%s\" is not registered\n", sName);
00112 #endif
00113         return 0;
00114     }
00115 
00116     if (qobject_cast<Gui::Dialog::PreferencePage*>(w)) {
00117 #ifdef FC_DEBUG
00118         Base::Console().Log("Preference page of type '%s' created.\n", w->metaObject()->className());
00119 #endif
00120     }
00121     else {
00122 #ifdef FC_DEBUG
00123         Base::Console().Error("%s does not inherit from 'Gui::Dialog::PreferencePage'\n", sName);
00124 #endif
00125         delete w;
00126         return 0;
00127     }
00128 
00129     // set the parent to the widget
00130     if (parent)
00131         w->setParent(parent);
00132 
00133     return w;
00134 }
00135 
00143 QWidget* WidgetFactoryInst::createPrefWidget(const char* sName, QWidget* parent, const char* sPref)
00144 {
00145     QWidget* w = createWidget(sName);
00146     // this widget class is not registered
00147     if (!w)
00148         return 0; // no valid QWidget object
00149 
00150     // set the parent to the widget
00151     w->setParent(parent);
00152 
00153     try {
00154         dynamic_cast<PrefWidget*>(w)->setEntryName(sPref);
00155         dynamic_cast<PrefWidget*>(w)->restorePreferences();
00156     }
00157     catch (...) {
00158 #ifdef FC_DEBUG
00159         Base::Console().Error("%s does not inherit from \"PrefWidget\"\n", w->metaObject()->className());
00160 #endif
00161         delete w;
00162         return 0;
00163     }
00164 
00165     return w;
00166 }
00167 
00168 // ----------------------------------------------------
00169 
00170 UiLoader::UiLoader(QObject* parent)
00171   : QUiLoader(parent)
00172 {
00173     // do not use the plugins for additional widgets as we don't need them and
00174     // the application may crash under Linux (tested on Ubuntu 7.04 & 7.10).
00175     clearPluginPaths();
00176     this->cw = availableWidgets();
00177 }
00178 
00179 UiLoader::~UiLoader()
00180 {
00181 }
00182 
00183 QWidget* UiLoader::createWidget(const QString & className, QWidget * parent,
00184                                 const QString& name)
00185 {
00186     if (this->cw.contains(className))
00187         return QUiLoader::createWidget(className, parent, name);
00188     QWidget* w = 0;
00189     if (WidgetFactory().CanProduce((const char*)className.toAscii()))
00190         w = WidgetFactory().createWidget((const char*)className.toAscii(), parent);
00191     if (w) w->setObjectName(name);
00192     return w;
00193 }
00194 
00195 // ----------------------------------------------------
00196 
00197 WidgetFactorySupplier* WidgetFactorySupplier::_pcSingleton = 0L;
00198 
00199 WidgetFactorySupplier & WidgetFactorySupplier::instance()
00200 {
00201     // not initialized?
00202     if (!_pcSingleton)
00203         _pcSingleton = new WidgetFactorySupplier;
00204     return *_pcSingleton;
00205 }
00206 
00207 void WidgetFactorySupplier::destruct()
00208 {
00209     // delete the widget factory and all its producers first
00210     WidgetFactoryInst::destruct();
00211     delete _pcSingleton;
00212     _pcSingleton=0;
00213 }
00214 
00215 // ----------------------------------------------------
00216 
00217 PrefPageUiProducer::PrefPageUiProducer (const char* filename, const char* group)
00218   : fn(QString::fromUtf8(filename))
00219 {
00220     WidgetFactoryInst::instance().AddProducer(filename, this);
00221     Gui::Dialog::DlgPreferencesImp::addPage(filename, group);
00222 }
00223 
00224 PrefPageUiProducer::~PrefPageUiProducer()
00225 {
00226 }
00227 
00228 void* PrefPageUiProducer::Produce () const
00229 {
00230     QWidget* page = new Gui::Dialog::PreferenceUiForm(fn);
00231     return (void*)page;
00232 }
00233 
00234 // ----------------------------------------------------
00235 
00236 /* TRANSLATOR Gui::ContainerDialog */
00237 
00242 ContainerDialog::ContainerDialog( QWidget* templChild )
00243   : QDialog( QApplication::activeWindow())
00244 {
00245     setModal(true);
00246     setWindowTitle( templChild->objectName() );
00247     setObjectName( templChild->objectName() );
00248 
00249     setSizeGripEnabled( TRUE );
00250     MyDialogLayout = new QGridLayout(this);
00251 
00252     buttonOk = new QPushButton(this);
00253     buttonOk->setObjectName(QLatin1String("buttonOK"));
00254     buttonOk->setText( tr( "&OK" ) );
00255     buttonOk->setAutoDefault( TRUE );
00256     buttonOk->setDefault( TRUE );
00257 
00258     MyDialogLayout->addWidget( buttonOk, 1, 0 );
00259     QSpacerItem* spacer = new QSpacerItem( 210, 20, QSizePolicy::Expanding, QSizePolicy::Minimum );
00260     MyDialogLayout->addItem( spacer, 1, 1 );
00261 
00262     buttonCancel = new QPushButton(this);
00263     buttonCancel->setObjectName(QLatin1String("buttonCancel"));
00264     buttonCancel->setText( tr( "&Cancel" ) );
00265     buttonCancel->setAutoDefault( TRUE );
00266 
00267     MyDialogLayout->addWidget( buttonCancel, 1, 2 );
00268 
00269     templChild->setParent(this);
00270 
00271     MyDialogLayout->addWidget( templChild, 0, 0, 0, 2 );
00272     resize( QSize(307, 197).expandedTo(minimumSizeHint()) );
00273 
00274     // signals and slots connections
00275     connect( buttonOk, SIGNAL( clicked() ), this, SLOT( accept() ) );
00276     connect( buttonCancel, SIGNAL( clicked() ), this, SLOT( reject() ) );
00277 }
00278 
00280 ContainerDialog::~ContainerDialog()
00281 {
00282 }
00283 
00284 // ----------------------------------------------------
00285 
00286 //--------------------------------------------------------------------------
00287 // Type structure
00288 //--------------------------------------------------------------------------
00289 
00290 PyTypeObject PyResource::Type = {
00291                                     PyObject_HEAD_INIT(&PyType_Type)
00292                                     0,                    /*ob_size*/
00293                                     "PyResource",         /*tp_name*/
00294                                     sizeof(PyResource),   /*tp_basicsize*/
00295                                     0,                    /*tp_itemsize*/
00296                                     /* methods */
00297                                     PyDestructor,         /*tp_dealloc*/
00298                                     0,                    /*tp_print*/
00299                                     __getattr,            /*tp_getattr*/
00300                                     __setattr,            /*tp_setattr*/
00301                                     0,                    /*tp_compare*/
00302                                     __repr,               /*tp_repr*/
00303                                     0,                    /*tp_as_number*/
00304                                     0,                    /*tp_as_sequence*/
00305                                     0,                    /*tp_as_mapping*/
00306                                     0,                    /*tp_hash*/
00307                                     0,                    /*tp_call */
00308                                   };
00309 
00310 //--------------------------------------------------------------------------
00311 // Methods structure
00312 //--------------------------------------------------------------------------
00313 PyMethodDef PyResource::Methods[] = {
00314                                         {"GetValue",       (PyCFunction) svalue,    Py_NEWARGS},
00315                                         {"SetValue",       (PyCFunction) ssetValue, Py_NEWARGS},
00316                                         {"Show",           (PyCFunction) sshow,     Py_NEWARGS},
00317                                         {"Connect",        (PyCFunction) sconnect,  Py_NEWARGS},
00318 
00319                                         {NULL, NULL}      /* Sentinel */
00320                                       };
00321 
00322 //--------------------------------------------------------------------------
00323 // Parents structure
00324 //--------------------------------------------------------------------------
00325 PyParentObject PyResource::Parents[] = {&PyObjectBase::Type,&PyResource::Type, NULL};
00326 
00327 //--------------------------------------------------------------------------
00328 // constructor
00329 //--------------------------------------------------------------------------
00330 PyResource::PyResource(PyTypeObject *T)
00331     : PyObjectBase(0, T), myDlg(0L)
00332 {
00333 }
00334 
00335 PyObject *PyResource::PyMake(PyObject *ignored, PyObject *args) // Python wrapper
00336 {
00337     //return new FCPyResource();      // Make new Python-able object
00338     return 0;
00339 }
00340 
00341 //--------------------------------------------------------------------------
00342 //  FCPyResource destructor
00343 //--------------------------------------------------------------------------
00344 PyResource::~PyResource()
00345 {
00346     delete myDlg;
00347     for (std::vector<SignalConnect*>::iterator it = mySingals.begin(); it != mySingals.end(); ++it) {
00348         SignalConnect* sc = *it;
00349         delete sc;
00350     }
00351 }
00352 
00353 //--------------------------------------------------------------------------
00354 // FCPyParametrGrp Attributes
00355 //--------------------------------------------------------------------------
00356 PyObject *PyResource::_getattr(char *attr)        // __getattr__ function: note only need to handle new state
00357 {
00358     _getattr_up(PyObjectBase);            // send to parent
00359     return 0;
00360 }
00361 
00362 int PyResource::_setattr(char *attr, PyObject *value)   // __setattr__ function: note only need to handle new state
00363 {
00364     return PyObjectBase::_setattr(attr, value); // send up to parent
00365     return 0;
00366 }
00367 
00373 void PyResource::load( const char* name )
00374 {
00375     QString fn = QString::fromUtf8(name);
00376     QFileInfo fi(fn);
00377 
00378     // checks whether it's a relative path
00379     if (fi.isRelative()) {
00380         QString cwd = QDir::currentPath ();
00381         QString home= QDir(QString::fromUtf8(App::GetApplication().GetHomePath())).path();
00382 
00383         // search in cwd and home path for the file
00384         //
00385         // file does not reside in cwd, check home path now
00386         if (!fi.exists()) {
00387             if (cwd == home) {
00388                 QString what = QObject::tr("Cannot find file %1").arg(fi.absoluteFilePath());
00389                 throw Base::Exception(what.toUtf8().constData());
00390             }
00391             else {
00392                 fi.setFile( QDir(home), fn );
00393 
00394                 if (!fi.exists()) {
00395                     QString what = QObject::tr("Cannot find file %1 neither in %2 nor in %3")
00396                         .arg(fn).arg(cwd).arg(home);
00397                     throw Base::Exception(what.toUtf8().constData());
00398                 }
00399                 else {
00400                     fn = fi.absoluteFilePath(); // file resides in FreeCAD's home directory
00401                 }
00402             }
00403         }
00404     }
00405     else {
00406         if (!fi.exists()) {
00407             QString what = QObject::tr("Cannot find file %1").arg(fn);
00408             throw Base::Exception(what.toUtf8().constData());
00409         }
00410     }
00411 
00412     QWidget* w=0;
00413     try {
00414         UiLoader loader;
00415 #if QT_VERSION >= 0x040500
00416         loader.setLanguageChangeEnabled(true);
00417 #endif
00418         QFile file(fn);
00419         if (file.open(QFile::ReadOnly))
00420             w = loader.load(&file, QApplication::activeWindow());
00421         file.close();
00422     }
00423     catch (...) {
00424         throw Base::Exception("Cannot create resource");
00425     }
00426 
00427     if (!w)
00428         throw Base::Exception("Invalid widget.");
00429 
00430     if (w->inherits("QDialog")) {
00431         myDlg = (QDialog*)w;
00432     }
00433     else {
00434         myDlg = new ContainerDialog(w);
00435     }
00436 }
00437 
00444 bool PyResource::connect(const char* sender, const char* signal, PyObject* cb)
00445 {
00446     if ( !myDlg )
00447         return false;
00448 
00449     QObject* objS=0L;
00450     QList<QWidget*> list = myDlg->findChildren<QWidget*>();
00451     QList<QWidget*>::const_iterator it = list.begin();
00452     QObject *obj;
00453     QString sigStr = QString::fromAscii("2%1").arg(QString::fromAscii(signal));
00454 
00455     while ( it != list.end() ) {
00456         obj = *it;
00457         ++it;
00458         if (obj->objectName() == QLatin1String(sender)) {
00459             objS = obj;
00460             break;
00461         }
00462     }
00463 
00464     if (objS) {
00465         SignalConnect* sc = new SignalConnect(this, cb, objS);
00466         mySingals.push_back(sc);
00467         return QObject::connect(objS, sigStr.toAscii(), sc, SLOT ( onExecute() )  );
00468     }
00469     else
00470         qWarning( "'%s' does not exist.\n", sender );
00471 
00472     return false;
00473 }
00474 
00479 PyObject *PyResource::connect(PyObject *args)
00480 {
00481     char *psSender;
00482     char *psSignal;
00483 
00484     PyObject *result = NULL;
00485     PyObject *temp;
00486 
00487     if (PyArg_ParseTuple(args, "ssOset_callback", &psSender, &psSignal, &temp)) {
00488         if (!PyCallable_Check(temp)) {
00489             PyErr_SetString(PyExc_TypeError, "parameter must be callable");
00490             return NULL;
00491         }
00492 
00493         Py_XINCREF(temp);         /* Add a reference to new callback */
00494         std::string sSender = psSender;
00495         std::string sSignal = psSignal;
00496 
00497         if (!connect(psSender, psSignal, temp)) {
00498             // no signal object found => dispose the callback object
00499             Py_XDECREF(temp);  /* Dispose of callback */
00500         }
00501 
00502         /* Boilerplate to return "None" */
00503         Py_INCREF(Py_None);
00504         result = Py_None;
00505     }
00506 
00507     return result;
00508 }
00509 
00513 PyObject *PyResource::show(PyObject *args)
00514 {
00515     if (myDlg) {
00516         // small trick to get focus
00517         myDlg->showMinimized();
00518 
00519 #ifdef Q_WS_X11
00520         // On X11 this may not work. For further information see QWidget::showMaximized
00521         //
00522         // workaround for X11
00523         myDlg->hide();
00524         myDlg->show();
00525 #endif
00526 
00527         myDlg->showNormal();
00528         myDlg->exec();
00529     }
00530 
00531     Py_INCREF(Py_None);
00532     return Py_None;
00533 }
00534 
00540 PyObject *PyResource::value(PyObject *args)
00541 {
00542     char *psName;
00543     char *psProperty;
00544     if (!PyArg_ParseTuple(args, "ss", &psName, &psProperty))     // convert args: Python->C
00545         return NULL;                             // NULL triggers exception
00546 
00547     QVariant v;
00548     if (myDlg) {
00549         QList<QWidget*> list = myDlg->findChildren<QWidget*>();
00550         QList<QWidget*>::const_iterator it = list.begin();
00551         QObject *obj;
00552 
00553         bool fnd = false;
00554         while ( it != list.end() ) {
00555             obj = *it;
00556             ++it;
00557             if (obj->objectName() == QLatin1String(psName)) {
00558                 fnd = true;
00559                 v = obj->property(psProperty);
00560                 break;
00561             }
00562         }
00563 
00564         if ( !fnd )
00565             qWarning( "'%s' not found.\n", psName );
00566     }
00567 
00568     PyObject *pItem=0;
00569     switch (v.type())
00570     {
00571     case QVariant::StringList:
00572         {
00573             QStringList str = v.toStringList();
00574             int nSize = str.count();
00575             PyObject* slist = PyList_New(nSize);
00576             for (int i=0; i<nSize;++i) {
00577                 PyObject* item = PyString_FromString(str[i].toAscii());
00578                 PyList_SetItem(slist, i, item);
00579             }
00580         }   break;
00581     case QVariant::ByteArray:
00582         break;
00583     case QVariant::String:
00584         pItem = PyString_FromString(v.toString().toAscii());
00585         break;
00586     case QVariant::Double:
00587         pItem = PyFloat_FromDouble(v.toDouble());
00588         break;
00589     case QVariant::Bool:
00590         pItem = PyInt_FromLong(v.toBool() ? 1 : 0);
00591         break;
00592     case QVariant::UInt:
00593         pItem = PyLong_FromLong(v.toUInt());
00594         break;
00595     case QVariant::Int:
00596         pItem = PyInt_FromLong(v.toInt());
00597         break;
00598     default:
00599         pItem = PyString_FromString("");
00600         break;
00601     }
00602 
00603     return pItem;
00604 }
00605 
00611 PyObject *PyResource::setValue(PyObject *args)
00612 {
00613     char *psName;
00614     char *psProperty;
00615     PyObject *psValue;
00616     if (!PyArg_ParseTuple(args, "ssO", &psName, &psProperty, &psValue))     // convert args: Python->C
00617         return NULL;                             // NULL triggers exception
00618 
00619     QVariant v;
00620     if (PyString_Check(psValue)) {
00621         v = QString::fromAscii(PyString_AsString(psValue));
00622     }
00623     else if (PyInt_Check(psValue)) {
00624         int val = PyInt_AsLong(psValue);
00625         v = val;
00626     }
00627     else if (PyLong_Check(psValue)) {
00628         unsigned int val = PyLong_AsLong(psValue);
00629         v = val;
00630     }
00631     else if (PyFloat_Check(psValue)) {
00632         v = PyFloat_AsDouble(psValue);
00633     }
00634     else if (PyList_Check(psValue)) {
00635         QStringList str;
00636         int nSize = PyList_Size(psValue);
00637         for (int i=0; i<nSize;++i) {
00638             PyObject* item = PyList_GetItem(psValue, i);
00639             if (!PyString_Check(item))
00640                 continue;
00641 
00642             char* pItem = PyString_AsString(item);
00643             str.append(QString::fromAscii(pItem));
00644         }
00645 
00646         v = str;
00647     }
00648     else {
00649         PyErr_SetString(PyExc_AssertionError, "Unsupported type");
00650         return NULL;
00651     }
00652 
00653     if (myDlg) {
00654         QList<QWidget*> list = myDlg->findChildren<QWidget*>();
00655         QList<QWidget*>::const_iterator it = list.begin();
00656         QObject *obj;
00657 
00658         bool fnd = false;
00659         while ( it != list.end() ) {
00660             obj = *it;
00661             ++it;
00662             if (obj->objectName() == QLatin1String(psName)) {
00663                 fnd = true;
00664                 obj->setProperty(psProperty, v);
00665                 break;
00666             }
00667         }
00668 
00669         if ( !fnd )
00670             qWarning( "'%s' not found.\n", psName );
00671     }
00672 
00673     Py_INCREF(Py_None);
00674     return Py_None;
00675 }
00676 
00677 // ----------------------------------------------------
00678 
00679 SignalConnect::SignalConnect( Base::PyObjectBase* res, PyObject* cb, QObject* sender)
00680   : myResource(res), myCallback(cb), mySender(sender)
00681 {
00682 }
00683 
00684 SignalConnect::~SignalConnect()
00685 {
00686     Py_XDECREF(myCallback);  /* Dispose of callback */
00687 }
00688 
00692 void SignalConnect::onExecute()
00693 {
00694     PyObject *arglist;
00695     PyObject *result;
00696 
00697     /* Time to call the callback */
00698     arglist = Py_BuildValue("(O)", myResource);
00699     result = PyEval_CallObject(myCallback, arglist);
00700     (void)result;
00701     Py_DECREF(arglist);
00702 }
00703 
00704 #include "moc_WidgetFactory.cpp"

Generated on Wed Nov 23 19:01:02 2011 for FreeCAD by  doxygen 1.6.1