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