1 /* This file is part of the KDE project
2    Copyright (C) 2003 Lucijan Busch <lucijan@gmx.at>
3    Copyright (C) 2004 Cedric Pasteur <cedric.pasteur@free.fr>
4    Copyright (C) 2004-2015 Jarosław Staniek <staniek@kde.org>
5 
6    This library is free software; you can redistribute it and/or
7    modify it under the terms of the GNU Library General Public
8    License as published by the Free Software Foundation; either
9    version 2 of the License, or (at your option) any later version.
10 
11    This library is distributed in the hope that it will be useful,
12    but WITHOUT ANY WARRANTY; without even the implied warranty of
13    MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
14    Library General Public License for more details.
15 
16    You should have received a copy of the GNU Library General Public License
17    along with this library; see the file COPYING.LIB.  If not, write to
18    the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor,
19  * Boston, MA 02110-1301, USA.
20 */
21 
22 #include "widgetlibrary.h"
23 #include <KexiIcon.h>
24 #include "WidgetInfo.h"
25 #include "widgetfactory.h"
26 #include "libactionwidget.h"
27 #include "container.h"
28 #include "form.h"
29 #include "formIO.h"
30 #include "FormWidgetInterface.h"
31 #include "objecttree.h"
32 #include "KexiJsonTrader.h"
33 #include "KexiFormWidgetsPluginMetaData.h"
34 #include "KexiVersion.h"
35 #include <core/kexiguimsghandler.h>
36 #define KEXI_SKIP_SETUPBREEZEICONTHEME
37 #define KEXI_SKIP_REGISTERRESOURCE
38 #include <main/KexiRegisterResource_p.h>
39 
40 #include <KActionCollection>
41 #include <KLocalizedString>
42 
43 #include <QDomDocument>
44 #include <QMenu>
45 #include <QDebug>
46 
47 namespace KFormDesigner
48 {
49 
50 Q_GLOBAL_STATIC_WITH_ARGS(KexiJsonTrader, KexiFormWidgetsPluginTrader_instance, (KEXI_BASE_PATH "/forms/widgets"))
51 
52 //! @internal
53 class Q_DECL_HIDDEN WidgetLibrary::Private
54 {
55 public:
Private(WidgetLibrary * library,const QStringList & supportedFactoryGroups)56     Private(WidgetLibrary *library, const QStringList& supportedFactoryGroups)
57             : showAdvancedProperties(true)
58             , q(library)
59             , m_couldNotFindAnyFormWidgetPluginsErrorDisplayed(false)
60             , m_supportedFactoryGroups(supportedFactoryGroups.toSet())
61             , m_lookupDone(false)
62             , m_lookupResult(false)
63             , m_loadFactoriesDone(false)
64     {
65         q->setMessageHandler(&messageHandler);
66         m_advancedProperties.insert("acceptDrops");
67         m_advancedProperties.insert("accessibleDescription");
68         m_advancedProperties.insert("accessibleName");
69         m_advancedProperties.insert("autoMask");
70         m_advancedProperties.insert("backgroundOrigin");
71         m_advancedProperties.insert("backgroundMode");//this is rather useless
72         m_advancedProperties.insert("baseSize");
73         m_advancedProperties.insert("contextMenuEnabled");
74         m_advancedProperties.insert("contextMenuPolicy");
75         m_advancedProperties.insert("cursorPosition");
76         m_advancedProperties.insert("cursorMoveStyle");
77         m_advancedProperties.insert("dragEnabled");
78         m_advancedProperties.insert("enableSqueezedText");
79         m_advancedProperties.insert("layout");// too large risk to break things
80         m_advancedProperties.insert("layoutDirection");
81         m_advancedProperties.insert("locale");
82         m_advancedProperties.insert("mouseTracking");
83 /*! @todo: reenable */ m_advancedProperties.insert("palette");
84         m_advancedProperties.insert("sizeAdjustPolicy"); //QAbstractScrollArea
85         m_advancedProperties.insert("sizeIncrement");
86         m_advancedProperties.insert("sizePolicy");
87         m_advancedProperties.insert("statusTip");
88         m_advancedProperties.insert("toolTipDuration");
89         m_advancedProperties.insert("trapEnterKeyEvent");
90         m_advancedProperties.insert("windowModality");
91         m_advancedProperties.insert("autoExclusive");
92         // by providing this in propeditor
93         m_advancedProperties.insert("minimumSize");
94         m_advancedProperties.insert("maximumSize");
95         m_advancedProperties.insert("clickMessage"); // for backward compatibility Kexi projects created with Qt < 4.7
96         m_advancedProperties.insert("showClearButton"); // for backward compatibility Kexi projects created with Qt 4
97 #ifndef KEXI_SHOW_UNFINISHED
98 /*! @todo reenable */
99         m_advancedProperties.insert("accel");
100         m_advancedProperties.insert("icon");
101         m_advancedProperties.insert("paletteBackgroundPixmap");
102         m_advancedProperties.insert("pixmap");
103         m_advancedProperties.insert("shortcut"); // renamed from "accel" in Qt 4
104         m_advancedProperties.insert("windowIcon"); // renamed from "icon" in Qt 4
105 #endif
106     }
~Private()107     ~Private() {
108         qDeleteAll(m_factories);
109         m_factories.clear();
110         qDeleteAll(m_pluginsMetaData);
111         m_pluginsMetaData.clear();
112     }
113 
widgets()114     QHash<QByteArray, WidgetInfo*> widgets() {
115         KDbMessageGuard mg(q);
116         (void)loadFactories();
117         return m_widgets;
118     }
119 
factories()120     QHash<QByteArray, WidgetFactory*> factories() {
121         KDbMessageGuard mg(q);
122         (void)loadFactories();
123         return m_factories;
124     }
125 
isAdvancedProperty(const QByteArray & property) const126     bool isAdvancedProperty(const QByteArray &property) const {
127         return m_advancedProperties.contains(property);
128     }
129 
130     bool showAdvancedProperties;
131 
132 private:
133     //! Performs a form widget plugins lookup. @return true on success.
134     //! @todo This method generates a few warnings, maybe we want to optionally display them somewhere (via the message handler)?
lookup()135     bool lookup() {
136         //! @todo Allow refreshing
137         if (m_lookupDone) {
138             return m_lookupResult;
139         }
140         m_lookupDone = true;
141         m_lookupResult = false;
142         q->clearResult();
143 
144         QStringList serviceTypes;
145         serviceTypes << "Kexi/FormWidget";
146         QList<QPluginLoader*> offers = KexiFormWidgetsPluginTrader_instance->query(serviceTypes);
147         foreach(const QPluginLoader *loader, offers) {
148             QScopedPointer<KexiFormWidgetsPluginMetaData> metaData(new KexiFormWidgetsPluginMetaData(*loader));
149             if (metaData->id().isEmpty()) {
150                 qWarning() << "No plugin ID specified for Kexi Form Widgets plugin"
151                            << metaData->fileName() << "-- skipping!";
152                 continue;
153             }
154             // check version
155             const QString expectedVersion = KFormDesigner::version();
156             if (metaData->version() != expectedVersion) {
157                 qWarning() << "Kexi Form Widgets plugin" << metaData->id() << "has version"
158                            << metaData->majorVersion() << "but required version is" << KFormDesigner::version()
159                            << "-- skipping!";
160                 continue;
161             }
162             // skip duplicates
163             if (m_pluginsMetaData.contains(metaData->id())) {
164                 qWarning() << "More than one Kexi Form Widgets plugin with ID"
165                            << metaData->id() << metaData->fileName() << "-- skipping this one";
166                 continue;
167             }
168             //qDebug() << "found factory:" << ptr->name();
169 
170             if (!metaData->group().isEmpty() && !m_supportedFactoryGroups.contains(metaData->group())) {
171                 qDebug() << "Factory group" << metaData->group()
172                          << "for Form Widgets plugin"
173                          << metaData->id() << metaData->fileName()
174                          << "is not supported -- skipping!";
175                 continue;
176             }
177             if (!setupPrivateIconsResourceWithMessage(
178                 QLatin1String(KEXI_BASE_PATH),
179                 QString::fromLatin1("icons/%1_%2.rcc")
180                     .arg(metaData->id()).arg(supportedIconTheme),
181                 QtWarningMsg,
182                 QString::fromLatin1(":/icons/%1").arg(metaData->id())))
183             {
184                 continue;
185             }
186 
187             m_pluginsMetaData.insert(metaData->id(), metaData.data());
188             metaData.take();
189         }
190         qDeleteAll(offers);
191         offers.clear();
192         if (m_pluginsMetaData.isEmpty()) {
193             q->m_result = KDbResult(i18n("Could not find any form widget plugins."));
194             m_couldNotFindAnyFormWidgetPluginsErrorDisplayed = true;
195             return false;
196         }
197         m_lookupResult = true;
198         return true;
199     }
200 
201     //! Loads all factory plugins
loadFactories()202     bool loadFactories() {
203         if (m_loadFactoriesDone) {
204             if (m_couldNotFindAnyFormWidgetPluginsErrorDisplayed) {
205                 q->clearResult(); // show the warning only once
206             }
207             return m_loadFactoriesResult;
208         }
209         m_loadFactoriesDone = true;
210         m_loadFactoriesResult = false;
211         if (!lookup()) {
212             return false;
213         }
214         foreach (KexiFormWidgetsPluginMetaData *pluginMetaData, m_pluginsMetaData) {
215             WidgetFactory *factory = loadFactory(pluginMetaData);
216             if (!factory) {
217                 continue;
218             }
219             //collect information about classes to be hidden
220             if (factory->hiddenClasses()) {
221                 foreach (const QByteArray &c, *factory->hiddenClasses()) {
222                     m_hiddenClasses.insert(c);
223                 }
224             }
225         }
226 
227         //now we have factories instantiated: load widgets
228         QList<WidgetFactory*> loadLater;
229         foreach (WidgetFactory *factory, m_factories) {
230             //ONE LEVEL, FLAT INHERITANCE, but works!
231             //if this factory inherits from something, load its witgets later
232     //! @todo improve
233             if (factory->inheritsFactories())
234                 loadLater.append(factory);
235             else
236                 loadFactoryWidgets(factory);
237         }
238         //load now the rest
239         foreach (WidgetFactory* f, loadLater) {
240             loadFactoryWidgets(f);
241         }
242         m_loadFactoriesResult = true;
243         return true;
244     }
245 
246     //! Loads of a single factory. @return true on success
loadFactory(KexiFormWidgetsPluginMetaData * pluginMetaData)247     WidgetFactory *loadFactory(KexiFormWidgetsPluginMetaData *pluginMetaData) {
248         KPluginFactory *factory = qobject_cast<KPluginFactory*>(pluginMetaData->instantiate());
249         if (!factory) {
250             q->m_result = KDbResult(ERR_CANNOT_LOAD_OBJECT,
251                                     xi18nc("@info", "Could not load Kexi Form Widgets plugin file <filename>%1</filename>.",
252                                            pluginMetaData->fileName()));
253             q->setErrorMessage(pluginMetaData, q->result().message());
254             qWarning() << q->result().message();
255             return 0;
256         }
257         WidgetFactory *widgetFactory = factory->create<WidgetFactory>(q);
258         if (!widgetFactory) {
259             q->m_result = KDbResult(ERR_CANNOT_LOAD_OBJECT,
260                                     xi18nc("@info",
261                                            "Could not open Kexi Form Widgets plugin <filename>%1</filename>.",
262                                            pluginMetaData->fileName()));
263             qWarning() << q->m_result.message();
264             return 0;
265         }
266         widgetFactory->setLibrary(q);
267         widgetFactory->setObjectName(pluginMetaData->id());
268         widgetFactory->setAdvancedPropertiesVisible(showAdvancedProperties); //inherit this flag from the library
269         m_factories.insert(pluginMetaData->id().toLatin1(), widgetFactory);
270         return widgetFactory;
271     }
272 
273     //! Loads widgets for factory @a f
loadFactoryWidgets(WidgetFactory * f)274     void loadFactoryWidgets(WidgetFactory *f) {
275         QHash<QByteArray, WidgetInfo*> widgetsForFactory(f->classes());
276         foreach (WidgetInfo *w, widgetsForFactory) {
277             if (m_hiddenClasses.contains( w->className() ))
278                 continue; //this class is hidden
279             // check if we want to inherit a widget from a different factory
280             if (!w->parentFactoryName().isEmpty() && !w->inheritedClassName().isEmpty()) {
281                 WidgetFactory *parentFactory = m_factories.value(w->parentFactoryName().toLower());
282                 if (!parentFactory) {
283                     qWarning() << "class" << w->className() << ": no such parent factory" << w->parentFactoryName();
284                     continue;
285                 }
286                 WidgetInfo* inheritedClass = parentFactory->widgetInfoForClassName(w->inheritedClassName());
287                 if (!inheritedClass) {
288                     qWarning() << "class" << w->inheritedClassName() << " - no such class to inherit in factory"
289                         << w->parentFactoryName();
290                     continue;
291                 }
292                 //ok: inherit properties:
293                 w->setInheritedClass( inheritedClass );
294                 if (w->iconName().isEmpty())
295                     w->setIconName(inheritedClass->iconName());
296                 //ok?
297                 foreach(const QByteArray& alternateName, inheritedClass->alternateClassNames()) {
298                     w->addAlternateClassName(
299                         alternateName, inheritedClass->isOverriddenClassName(alternateName));
300                 }
301                 if (w->includeFileName().isEmpty())
302                     w->setIncludeFileName(inheritedClass->includeFileName());
303                 if (w->name().isEmpty())
304                     w->setName(inheritedClass->name());
305                 if (w->namePrefix().isEmpty())
306                     w->setNamePrefix(nullptr, qPrintable(inheritedClass->namePrefix()));
307                 if (w->description().isEmpty())
308                     w->setDescription(inheritedClass->description());
309             }
310 
311             QList<QByteArray> cnames( w->alternateClassNames() );
312             cnames.prepend(w->className());
313             foreach (const QByteArray &wname, cnames) {
314                 WidgetInfo *widgetForClass = widgetsForFactory.value(wname);
315                 if (!widgetForClass || (widgetForClass && !widgetForClass->isOverriddenClassName(wname))) {
316                     //insert a widgetinfo, if:
317                     //1) this class has no alternate class assigned yet, or
318                     //2) this class has alternate class assigned but without 'override' flag
319                     m_widgets.insert(wname, w);
320                 }
321             }
322         }
323     }
324 
325     WidgetLibrary *q;
326     KexiGUIMessageHandler messageHandler;
327     //! A map which associates a class name with a Widget class
328     QHash<QString, KexiFormWidgetsPluginMetaData*> m_pluginsMetaData; //!< owner
329     bool m_couldNotFindAnyFormWidgetPluginsErrorDisplayed;
330     QSet<QString> m_supportedFactoryGroups;
331     QHash<QByteArray, WidgetFactory*> m_factories; //!< owner
332     QHash<QByteArray, WidgetInfo*> m_widgets; //!< owner
333     QSet<QByteArray> m_advancedProperties;
334     QSet<QByteArray> m_hiddenClasses;
335     bool m_lookupDone;
336     bool m_lookupResult;
337     bool m_loadFactoriesDone;
338     bool m_loadFactoriesResult;
339 };
340 }
341 
342 using namespace KFormDesigner;
343 
344 //-------------------------------------------
345 
WidgetLibrary(QObject * parent,const QStringList & supportedFactoryGroups)346 WidgetLibrary::WidgetLibrary(QObject *parent, const QStringList& supportedFactoryGroups)
347         : QObject(parent)
348         , KDbResultable()
349         , d(new Private(this, supportedFactoryGroups))
350 {
351 }
352 
~WidgetLibrary()353 WidgetLibrary::~WidgetLibrary()
354 {
355     delete d;
356 }
357 
createWidgetActions(ActionGroup * group)358 void WidgetLibrary::createWidgetActions(ActionGroup *group)
359 {
360     foreach (WidgetInfo *winfo, d->widgets()) {
361         LibActionWidget *a = new LibActionWidget(group, winfo);
362         connect(a, SIGNAL(toggled(QByteArray)), this, SIGNAL(widgetActionToggled(QByteArray)));
363     }
364 }
365 
366 void
addCustomWidgetActions(KActionCollection * col)367 WidgetLibrary::addCustomWidgetActions(KActionCollection *col)
368 {
369     if (!col)
370         return;
371     foreach (WidgetFactory *factory, d->factories()) {
372         factory->createCustomActions(col);
373     }
374 }
375 
createWidget(const QByteArray & classname,QWidget * parent,const char * name,Container * c,WidgetFactory::CreateWidgetOptions options)376 QWidget* WidgetLibrary::createWidget(const QByteArray &classname, QWidget *parent,
377                                      const char *name, Container *c,
378                                      WidgetFactory::CreateWidgetOptions options)
379 {
380     WidgetInfo *wclass = d->widgets().value(classname);
381     if (!wclass)
382         return 0;
383 
384     QWidget *widget = wclass->factory()->createWidget(wclass->className(), parent, name, c, options);
385     if (!widget) {
386         //try to instantiate from inherited class
387         if (wclass->inheritedClass())
388             widget = wclass->inheritedClass()->factory()->createWidget(
389                          wclass->className(), parent, name, c, options);
390         if (!widget)
391             return 0;
392     }
393     widget->setAcceptDrops(true);
394     if (options & WidgetFactory::DesignViewMode) {
395         FormWidgetInterface* fwiface = dynamic_cast<FormWidgetInterface*>(widget);
396         if (fwiface)
397             fwiface->setDesignMode(true);
398     }
399     emit widgetCreated(widget);
400     return widget;
401 }
402 
createMenuActions(const QByteArray & c,QWidget * w,QMenu * menu,KFormDesigner::Container * container)403 bool WidgetLibrary::createMenuActions(const QByteArray &c, QWidget *w, QMenu *menu,
404                                       KFormDesigner::Container *container)
405 {
406     WidgetInfo *wclass = d->widgets().value(c);
407     if (!wclass)
408         return false;
409 
410     if (wclass->factory()->createMenuActions(c, w, menu, container)) {
411         return true;
412     }
413     //try from inherited class
414     if (wclass->inheritedClass()) {
415         return wclass->inheritedClass()->factory()->createMenuActions(
416                    wclass->className(), w, menu, container);
417     }
418     return false;
419 }
420 
startInlineEditing(const QByteArray & classname,QWidget * w,Container * container)421 bool WidgetLibrary::startInlineEditing(const QByteArray &classname, QWidget *w,
422                                        Container *container)
423 {
424     WidgetInfo *wclass = d->widgets().value(classname);
425     if (!wclass)
426         return false;
427 
428     FormWidgetInterface* fwiface = dynamic_cast<FormWidgetInterface*>(w);
429     {
430         KFormDesigner::WidgetFactory::InlineEditorCreationArguments args(classname, w, container);
431         if (wclass->factory()->startInlineEditing(args)) {
432             args.container->form()->createInlineEditor(args);
433             if (fwiface)
434                 fwiface->setEditingMode(true);
435             return true;
436         }
437     }
438     if (wclass->inheritedClass()) {
439         //try from inherited class
440         KFormDesigner::WidgetFactory::InlineEditorCreationArguments args(wclass->className(), w, container);
441         if (wclass->inheritedClass()->factory()->startInlineEditing(args)) {
442             args.container->form()->createInlineEditor(args);
443             if (fwiface)
444                 fwiface->setEditingMode(true);
445             return true;
446         }
447     }
448     return false;
449 }
450 
previewWidget(const QByteArray & classname,QWidget * widget,Container * container)451 bool WidgetLibrary::previewWidget(const QByteArray &classname, QWidget *widget, Container *container)
452 {
453     WidgetInfo *wclass = d->widgets().value(classname);
454     if (!wclass)
455         return false;
456 
457     FormWidgetInterface* fwiface = dynamic_cast<FormWidgetInterface*>(widget);
458     if (fwiface)
459         fwiface->setDesignMode(false);
460     if (wclass->factory()->previewWidget(classname, widget, container))
461         return true;
462     //try from inherited class
463     if (wclass->inheritedClass())
464         return wclass->inheritedClass()->factory()->previewWidget(wclass->className(), widget, container);
465     return false;
466 }
467 
clearWidgetContent(const QByteArray & classname,QWidget * w)468 bool WidgetLibrary::clearWidgetContent(const QByteArray &classname, QWidget *w)
469 {
470     WidgetInfo *wclass = d->widgets().value(classname);
471     if (!wclass)
472         return false;
473 
474     if (wclass->factory()->clearWidgetContent(classname, w))
475         return true;
476     //try from inherited class
477     if (wclass->inheritedClass())
478         return wclass->inheritedClass()->factory()->clearWidgetContent(wclass->className(), w);
479     return false;
480 }
481 
displayName(const QByteArray & classname)482 QString WidgetLibrary::displayName(const QByteArray &classname)
483 {
484     WidgetInfo *wi = d->widgets().value(classname);
485     if (wi)
486         return wi->name();
487 
488     return classname;
489 }
490 
savingName(const QByteArray & classname)491 QString WidgetLibrary::savingName(const QByteArray &classname)
492 {
493     WidgetInfo *wi = d->widgets().value(classname);
494     if (wi && !wi->savingName().isEmpty())
495         return wi->savingName();
496 
497     return classname;
498 }
499 
namePrefix(const QByteArray & classname)500 QString WidgetLibrary::namePrefix(const QByteArray &classname)
501 {
502     WidgetInfo *wi = d->widgets().value(classname);
503     if (wi)
504         return wi->namePrefix();
505 
506     return classname;
507 }
508 
textForWidgetName(const QByteArray & name,const QByteArray & className)509 QString WidgetLibrary::textForWidgetName(const QByteArray &name, const QByteArray &className)
510 {
511     WidgetInfo *widget = d->widgets().value(className);
512     if (!widget)
513         return QString();
514 
515     QString newName = name;
516     newName.remove(widget->namePrefix());
517     newName = widget->name() + (newName.isEmpty() ? QString() : (QLatin1String(" ") + newName));
518     return newName;
519 }
520 
521 QByteArray
classNameForAlternate(const QByteArray & classname)522 WidgetLibrary::classNameForAlternate(const QByteArray &classname)
523 {
524     if (d->widgets().value(classname))
525         return classname;
526 
527     WidgetInfo *wi =  d->widgets().value(classname);
528     if (wi) {
529         return wi->className();
530     }
531 
532     // widget not supported
533     return "CustomWidget";
534 }
535 
includeFileName(const QByteArray & classname)536 QString WidgetLibrary::includeFileName(const QByteArray &classname)
537 {
538     WidgetInfo *wi = d->widgets().value(classname);
539     if (wi)
540         return wi->includeFileName();
541 
542     return QString();
543 }
544 
545 QString
iconName(const QByteArray & classname)546 WidgetLibrary::iconName(const QByteArray &classname)
547 {
548     WidgetInfo *wi = d->widgets().value(classname);
549     if (wi)
550         return wi->iconName();
551 
552     return KexiIconName("unknown-widget");
553 }
554 
555 bool
saveSpecialProperty(const QByteArray & classname,const QString & name,const QVariant & value,QWidget * w,QDomElement & parentNode,QDomDocument & parent)556 WidgetLibrary::saveSpecialProperty(const QByteArray &classname,
557     const QString &name, const QVariant &value, QWidget *w,
558     QDomElement &parentNode, QDomDocument &parent)
559 {
560     WidgetInfo *wi = d->widgets().value(classname);
561     if (!wi)
562         return false;
563 
564     if (wi->factory()->saveSpecialProperty(classname, name, value, w, parentNode, parent))
565         return true;
566     //try from inherited class
567     if (wi->inheritedClass())
568         return wi->inheritedClass()->factory()->saveSpecialProperty(wi->className(), name, value, w, parentNode, parent);
569     return false;
570 }
571 
572 bool
readSpecialProperty(const QByteArray & classname,QDomElement & node,QWidget * w,ObjectTreeItem * item)573 WidgetLibrary::readSpecialProperty(const QByteArray &classname,
574     QDomElement &node, QWidget *w, ObjectTreeItem *item)
575 {
576     WidgetInfo *wi = d->widgets().value(classname);
577     if (!wi)
578         return false;
579     if (wi->factory()->readSpecialProperty(classname, node, w, item))
580         return true;
581     //try from inherited class
582     if (wi->inheritedClass())
583         return wi->inheritedClass()->factory()->readSpecialProperty(wi->className(), node, w, item);
584     return false;
585 }
586 
setAdvancedPropertiesVisible(bool set)587 void WidgetLibrary::setAdvancedPropertiesVisible(bool set)
588 {
589     d->showAdvancedProperties = set;
590 }
591 
advancedPropertiesVisible() const592 bool WidgetLibrary::advancedPropertiesVisible() const
593 {
594     return d->showAdvancedProperties;
595 }
596 
597 bool
isPropertyVisible(const QByteArray & classname,QWidget * w,const QByteArray & property,bool multiple,bool isTopLevel)598 WidgetLibrary::isPropertyVisible(const QByteArray &classname, QWidget *w,
599                                  const QByteArray &property, bool multiple, bool isTopLevel)
600 {
601     if (isTopLevel) {
602         // no focus policy for top-level form widget...
603         if (!d->showAdvancedProperties && property == "focusPolicy")
604             return false;
605     }
606 
607     WidgetInfo *wi = d->widgets().value(classname);
608     if (!wi)
609         return false;
610     if (!d->showAdvancedProperties && d->isAdvancedProperty(property)) {
611         //this is advanced property, should we hide it?
612         if (!wi->internalProperty("forceShowAdvancedProperty:" + property).toBool()
613                 && (!wi->inheritedClass() || !wi->inheritedClass()->internalProperty("forceShowAdvancedProperty:" + property).toBool())) {
614             return false; //hide it
615         }
616     }
617 
618     if (!wi->factory()->isPropertyVisible(classname, w, property, multiple, isTopLevel))
619         return false;
620     //try from inherited class
621     if (wi->inheritedClass()
622             && !wi->inheritedClass()->factory()->isPropertyVisible(wi->className(), w, property, multiple, isTopLevel))
623         return false;
624 
625     return true;
626 }
627 
autoSaveProperties(const QByteArray & classname)628 QList<QByteArray> WidgetLibrary::autoSaveProperties(const QByteArray &classname)
629 {
630     WidgetInfo *wi = d->widgets().value(classname);
631     if (!wi)
632         return QList<QByteArray>();
633     return wi->autoSaveProperties();
634 }
635 
636 WidgetInfo*
widgetInfoForClassName(const char * classname)637 WidgetLibrary::widgetInfoForClassName(const char* classname)
638 {
639     return d->widgets().value(classname);
640 }
641 
642 WidgetFactory*
factoryForClassName(const char * classname)643 WidgetLibrary::factoryForClassName(const char* classname)
644 {
645     WidgetInfo *wi = widgetInfoForClassName(classname);
646     return wi ? wi->factory() : 0;
647 }
648 
propertyDescForName(WidgetInfo * winfo,const QByteArray & propertyName)649 QString WidgetLibrary::propertyDescForName(WidgetInfo *winfo, const QByteArray& propertyName)
650 {
651     if (!winfo || !winfo->factory())
652         return QString();
653     QString desc(winfo->factory()->propertyDescription(propertyName));
654     if (!desc.isEmpty())
655         return desc;
656     if (winfo->parentFactoryName().isEmpty())
657         return QString();
658 
659     //try in parent factory, if exists
660     WidgetFactory *parentFactory = d->factories().value(winfo->parentFactoryName());
661     if (!parentFactory)
662         return QString();
663 
664     return parentFactory->propertyDescription(propertyName);
665 }
666 
propertyDescForValue(WidgetInfo * winfo,const QByteArray & name)667 QString WidgetLibrary::propertyDescForValue(WidgetInfo *winfo, const QByteArray& name)
668 {
669     if (!winfo->factory())
670         return QString();
671     QString desc(winfo->factory()->valueDescription(name));
672     if (!desc.isEmpty())
673         return desc;
674     if (winfo->parentFactoryName().isEmpty())
675         return QString();
676 
677     //try in parent factory, if exists
678     WidgetFactory *parentFactory = d->factories().value(winfo->parentFactoryName());
679     if (!parentFactory)
680         return QString();
681 
682     return parentFactory->valueDescription(name);
683 }
684 
setPropertyOptions(KPropertySet & set,const WidgetInfo & winfo,QWidget * w)685 void WidgetLibrary::setPropertyOptions(KPropertySet& set, const WidgetInfo& winfo, QWidget* w)
686 {
687     if (!winfo.factory())
688         return;
689     winfo.factory()->setPropertyOptions(set, winfo, w);
690     if (winfo.parentFactoryName().isEmpty())
691         return;
692     WidgetFactory *parentFactory = d->factories().value(winfo.parentFactoryName());
693     if (!parentFactory)
694         return;
695     parentFactory->setPropertyOptions(set, winfo, w);
696 }
697 
factory(const char * factoryName) const698 WidgetFactory* WidgetLibrary::factory(const char* factoryName) const
699 {
700     return d->factories().value(factoryName);
701 }
702 
internalProperty(const QByteArray & classname,const QByteArray & property)703 QVariant WidgetLibrary::internalProperty(const QByteArray& classname, const QByteArray& property)
704 {
705     WidgetInfo *wclass = d->widgets().value(classname);
706     if (!wclass)
707         return QString();
708     QVariant value(wclass->internalProperty(property));
709     if (value.isNull() && wclass->inheritedClass())
710         return wclass->inheritedClass()->internalProperty(property);
711     return value;
712 }
713 
showOrientationSelectionPopup(const QByteArray & classname,QWidget * parent,const QPoint & pos)714 WidgetFactory::CreateWidgetOption WidgetLibrary::showOrientationSelectionPopup(
715     const QByteArray &classname, QWidget* parent, const QPoint& pos)
716 {
717     WidgetInfo *wclass = d->widgets().value(classname);
718     if (!wclass)
719         return WidgetFactory::AnyOrientation;
720 
721     //get custom icons and strings
722     QIcon iconHorizontal, iconVertical;
723     QString iconName(wclass->internalProperty("orientationSelectionPopup:horizontalIcon").toString());
724     if (iconName.isEmpty() && wclass->inheritedClass())
725         iconName = wclass->inheritedClass()->internalProperty("orientationSelectionPopup:horizontalIcon").toString();
726     if (!iconName.isEmpty())
727         iconHorizontal = QIcon::fromTheme(iconName);
728 
729     iconName = wclass->internalProperty("orientationSelectionPopup:verticalIcon").toString();
730     if (iconName.isEmpty() && wclass->inheritedClass())
731         iconName = wclass->inheritedClass()->internalProperty("orientationSelectionPopup:verticalIcon").toString();
732     if (!iconName.isEmpty())
733         iconVertical = QIcon::fromTheme(iconName);
734 
735     QString textHorizontal = wclass->internalProperty("orientationSelectionPopup:horizontalText").toString();
736     if (textHorizontal.isEmpty() && wclass->inheritedClass())
737         iconName = wclass->inheritedClass()->internalProperty("orientationSelectionPopup:horizontalText").toString();
738     if (textHorizontal.isEmpty()) //default
739         textHorizontal = xi18nc("Insert Horizontal Widget", "Insert Horizontal");
740 
741     QString textVertical = wclass->internalProperty("orientationSelectionPopup:verticalText").toString();
742     if (textVertical.isEmpty() && wclass->inheritedClass())
743         iconName = wclass->inheritedClass()->internalProperty("orientationSelectionPopup:verticalText").toString();
744     if (textVertical.isEmpty()) //default
745         textVertical = xi18nc("Insert Vertical Widget", "Insert Vertical");
746 
747     QMenu popup(parent);
748     popup.setObjectName("orientationSelectionPopup");
749     popup.addSection(QIcon::fromTheme(wclass->iconName()), xi18n("Insert Widget: %1", wclass->name()));
750     QAction* horizAction = popup.addAction(iconHorizontal, textHorizontal);
751     QAction* vertAction = popup.addAction(iconVertical, textVertical);
752     popup.addSeparator();
753     popup.addAction(koIcon("dialog-cancel"), xi18n("Cancel"));
754     QAction *a = popup.exec(pos);
755     if (a == horizAction)
756         return WidgetFactory::HorizontalOrientation;
757     else if (a == vertAction)
758         return WidgetFactory::VerticalOrientation;
759 
760     return WidgetFactory::AnyOrientation; //means "cancelled"
761 }
762 
propertySetShouldBeReloadedAfterPropertyChange(const QByteArray & classname,QWidget * w,const QByteArray & property)763 bool WidgetLibrary::propertySetShouldBeReloadedAfterPropertyChange(
764     const QByteArray& classname, QWidget *w, const QByteArray& property)
765 {
766     WidgetInfo *winfo = widgetInfoForClassName(classname);
767     if (!winfo)
768         return false;
769     return winfo->factory()->propertySetShouldBeReloadedAfterPropertyChange(classname, w, property);
770 }
771 
selectableItem(ObjectTreeItem * item)772 ObjectTreeItem* WidgetLibrary::selectableItem(ObjectTreeItem* item)
773 {
774     //qDebug() << item->widget()->metaObject()->className();
775     WidgetInfo *wi = d->widgets().value(item->widget()->metaObject()->className());
776     if (!wi)
777         return item;
778     return wi->factory()->selectableItem(item);
779 }
780 
781 
setErrorMessage(KexiFormWidgetsPluginMetaData * pluginMetaData,const QString & errorMessage)782 void WidgetLibrary::setErrorMessage(KexiFormWidgetsPluginMetaData *pluginMetaData, const QString& errorMessage)
783 {
784     pluginMetaData->setErrorMessage(errorMessage);
785 }
786