1 /* This file is part of the KDE project
2    Copyright (C) 2004 Cedric Pasteur <cedric.pasteur@free.fr>
3    Copyright (C) 2004-2016 Jarosław Staniek <staniek@kde.org>
4 
5    This library is free software; you can redistribute it and/or
6    modify it under the terms of the GNU Library General Public
7    License as published by the Free Software Foundation; either
8    version 2 of the License, or (at your option) any later version.
9 
10    This library is distributed in the hope that it will be useful,
11    but WITHOUT ANY WARRANTY; without even the implied warranty of
12    MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
13    Library General Public License for more details.
14 
15    You should have received a copy of the GNU Library General Public License
16    along with this library; see the file COPYING.LIB.  If not, write to
17    the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor,
18  * Boston, MA 02110-1301, USA.
19 */
20 
21 #include "KexiMainFormWidgetsFactory.h"
22 #include <KexiIcon.h>
23 #include <formeditor/container.h>
24 #include <formeditor/form.h>
25 #include <formeditor/formIO.h>
26 #include <formeditor/objecttree.h>
27 #include <formeditor/utils.h>
28 #include <formeditor/widgetlibrary.h>
29 #include <core/kexi.h>
30 #include <core/kexipart.h>
31 #include <core/KexiMainWindowIface.h>
32 #include <kexiutils/utils.h>
33 #include <kexiutils/KexiCommandLinkButton.h>
34 #include <widget/properties/KexiCustomPropertyFactory.h>
35 #include <widget/utils/kexicontextmenuutils.h>
36 #include <kexi_global.h>
37 #include "kexiformview.h"
38 #include "KexiStandardContainerFormWidgets.h"
39 #include "KexiStandardFormWidgets.h"
40 #include "kexidbcheckbox.h"
41 #include "kexidbimagebox.h"
42 #include "kexiframe.h"
43 #include "kexidblabel.h"
44 #include "kexidblineedit.h"
45 #include "kexidbtextedit.h"
46 #include "kexidbcombobox.h"
47 #include "KexiDBPushButton.h"
48 #include "kexidbform.h"
49 #include "kexidbcommandlinkbutton.h"
50 #include "kexidbslider.h"
51 #include "kexidbprogressbar.h"
52 #include "kexidbdatepicker.h"
53 #include "kexidataawarewidgetinfo.h"
54 #include <widget/dataviewcommon/kexiformdataiteminterface.h>
55 
56 #include <KDbConnection>
57 
58 #include <KPropertySet>
59 
60 #include <KActionCollection>
61 #include <KLocalizedString>
62 
63 #include <QDomElement>
64 #include <QStyle>
65 #include <QFontMetrics>
66 
67 KEXI_PLUGIN_FACTORY(KexiMainFormWidgetsFactory, "kexiforms_mainwidgetsplugin.json")
68 
KexiMainFormWidgetsFactory(QObject * parent,const QVariantList &)69 KexiMainFormWidgetsFactory::KexiMainFormWidgetsFactory(QObject *parent, const QVariantList &)
70         : KexiDBFactoryBase(parent)
71         , m_assignAction(0)
72 {
73     {
74         KexiDataAwareWidgetInfo *wi = new KexiDataAwareWidgetInfo(this);
75         wi->setIconName(KexiIconName("form"));
76         wi->setClassName("KexiDBForm");
77         wi->setName(xi18nc("Form widget", "Form"));
78         wi->setNamePrefix(
79             I18NC_NOOP("A prefix for identifiers of forms. Based on that, identifiers such as "
80                 "form1, form2 are generated. "
81                 "This string can be used to refer the widget object as variables in programming "
82                 "languages or macros so it must _not_ contain white spaces and non latin1 characters, "
83                 "should start with lower case letter and if there are subsequent words, these should "
84                 "start with upper case letter. Example: smallCamelCase. "
85                 "Moreover, try to make this prefix as short as possible.",
86                 "form"));
87         wi->setDescription(xi18n("A form widget"));
88         addClass(wi);
89     }
90 
91     {
92         KFormDesigner::WidgetInfo *wi = new KFormDesigner::WidgetInfo(this);
93         wi->setIconName(KexiIconName("unknown-widget"));
94         wi->setClassName("CustomWidget");
95         wi->setName(/* no i18n needed */ "Custom Widget");
96         wi->setNamePrefix(nullptr, /* no i18n needed */ "customWidget");
97         wi->setDescription(/* no i18n needed */ "A custom or non-supported widget");
98         addClass(wi);
99     }
100 
101     {
102         KexiDataAwareWidgetInfo* wi = new KexiDataAwareWidgetInfo(this);
103         wi->setIconName(KexiIconName("lineedit"));
104         wi->setClassName("KexiDBLineEdit");
105         wi->addAlternateClassName("QLineEdit", true/*override*/);
106         wi->addAlternateClassName("KLineEdit", true/*override*/);
107         wi->setName(xi18nc("Text Box widget", "Text Box"));
108         wi->setNamePrefix(
109             I18NC_NOOP("A prefix for identifiers of text box widgets. Based on that, identifiers such as "
110                 "textBox1, textBox2 are generated. "
111                 "This string can be used to refer the widget object as variables in programming "
112                 "languages or macros so it must _not_ contain white spaces and non latin1 characters, "
113                 "should start with lower case letter and if there are subsequent words, these should "
114                 "start with upper case letter. Example: smallCamelCase. "
115                 "Moreover, try to make this prefix as short as possible.",
116                 "textBox"));
117         wi->setDescription(xi18n("A widget for entering and displaying line of text text"));
118         wi->setInternalProperty("dontStartEditingOnInserting", true); // because we are most probably assign data source to this widget
119         wi->setInlineEditingEnabledWhenDataSourceSet(false);
120         addClass(wi);
121     }
122     {
123         KexiDataAwareWidgetInfo* wi = new KexiDataAwareWidgetInfo(this);
124         wi->setIconName(KexiIconName("textedit"));
125         wi->setClassName("KexiDBTextEdit");
126         wi->addAlternateClassName("QTextEdit", true/*override*/);
127         wi->addAlternateClassName("KTextEdit", true/*override*/);
128         wi->setName(xi18nc("Text Editor widget", "Text Editor"));
129         wi->setNamePrefix(
130             I18NC_NOOP("A prefix for identifiers of text editor widgets. Based on that, identifiers such as "
131                 "textEditor1, textEditor2 are generated. "
132                 "This string can be used to refer the widget object as variables in programming "
133                 "languages or macros so it must _not_ contain white spaces and non latin1 characters, "
134                 "should start with lower case letter and if there are subsequent words, these should "
135                 "start with upper case letter. Example: smallCamelCase. "
136                 "Moreover, try to make this prefix as short as possible.",
137                 "textEditor"));
138         wi->setDescription(xi18n("A multiline text editor"));
139         wi->setInternalProperty("dontStartEditingOnInserting", true); // because we are most probably assign data source to this widget
140         wi->setInlineEditingEnabledWhenDataSourceSet(false);
141         addClass(wi);
142     }
143     {
144         KexiDataAwareWidgetInfo* wi = new KexiDataAwareWidgetInfo(this);
145         wi->setIconName(KexiIconName("label"));
146         wi->setClassName("KexiDBLabel");
147         wi->addAlternateClassName("QLabel", true/*override*/);
148         wi->addAlternateClassName("KexiLabel", true/*override*/); //older
149         wi->setName(xi18nc("Text Label widget", "Label"));
150         wi->setNamePrefix(
151             I18NC_NOOP("A prefix for identifiers of label widgets. Based on that, identifiers such as "
152                 "label1, label2 are generated. "
153                 "This string can be used to refer the widget object as variables in programming "
154                 "languages or macros so it must _not_ contain white spaces and non latin1 characters, "
155                 "should start with lower case letter and if there are subsequent words, these should "
156                 "start with upper case letter. Example: smallCamelCase. "
157                 "Moreover, try to make this prefix as short as possible.",
158                 "label"));
159         wi->setDescription(xi18n("A widget for displaying text"));
160         wi->setInlineEditingEnabledWhenDataSourceSet(false);
161         addClass(wi);
162     }
163 
164     {
165         KexiDataAwareWidgetInfo* wi = new KexiDataAwareWidgetInfo(this);
166         wi->setIconName(KexiIconName("imagebox"));
167         wi->setClassName("KexiDBImageBox");
168         wi->addAlternateClassName("KexiPictureLabel", true/*override*/);
169         wi->addAlternateClassName("KexiImageBox", true/*override*/); //older
170         wi->setName(xi18nc("Image Box widget", "Image Box"));
171         wi->setNamePrefix(
172             I18NC_NOOP("A prefix for identifiers of image box widgets. Based on that, identifiers such as "
173                 "image1, image2 are generated. "
174                 "This string can be used to refer the widget object as variables in programming "
175                 "languages or macros so it must _not_ contain white spaces and non latin1 characters, "
176                 "should start with lower case letter and if there are subsequent words, these should "
177                 "start with upper case letter. Example: smallCamelCase. "
178                 "Moreover, try to make this prefix as short as possible.",
179                 "image"));
180         wi->setDescription(xi18n("A widget for displaying images"));
181     // wi->setCustomTypeForProperty("pixmapData", KexiCustomPropertyFactory::PixmapData);
182         wi->setCustomTypeForProperty("pixmapId", KexiCustomPropertyFactory::PixmapId);
183         wi->setInternalProperty("dontStartEditingOnInserting", true);
184         wi->setAutoSaveProperties(QList<QByteArray>() << "pixmap");
185         wi->setSupportedAlignmentFlags(Qt::AlignLeft | Qt::AlignRight | Qt::AlignHCenter
186                                        | Qt::AlignTop | Qt::AlignBottom | Qt::AlignVCenter);
187         addClass(wi);
188     }
189 
190     {
191         KexiDataAwareWidgetInfo* wi = new KexiDataAwareWidgetInfo(this);
192         wi->setIconName(KexiIconName("combobox"));
193         wi->setClassName("KexiDBComboBox");
194         wi->addAlternateClassName("QComboBox", true/*override*/);
195         wi->addAlternateClassName("KComboBox", true/*override*/);
196         wi->setName(xi18nc("Combo Box widget", "Combo Box"));
197         wi->setNamePrefix(
198             I18NC_NOOP("A prefix for identifiers of combo box widgets. Based on that, identifiers such as "
199                 "comboBox1, comboBox2 are generated. "
200                 "This string can be used to refer the widget object as variables in programming "
201                 "languages or macros so it must _not_ contain white spaces and non latin1 characters, "
202                 "should start with lower case letter and if there are subsequent words, these should "
203                 "start with upper case letter. Example: smallCamelCase. "
204                 "Moreover, try to make this prefix as short as possible.",
205                 "comboBox"));
206         wi->setDescription(xi18n("A combo box widget"));
207         addClass(wi);
208     }
209     {
210         KexiDataAwareWidgetInfo* wi = new KexiDataAwareWidgetInfo(this);
211         wi->setIconName(KexiIconName("checkbox"));
212         wi->setClassName("KexiDBCheckBox");
213         wi->addAlternateClassName("QCheckBox", true/*override*/);
214         wi->setName(xi18nc("Check Box widget", "Check Box"));
215         wi->setNamePrefix(
216             I18NC_NOOP("A prefix for identifiers of combo box widgets. Based on that, identifiers such as "
217                 "checkBox1, checkBox2 are generated. "
218                 "This string can be used to refer the widget object as variables in programming "
219                 "languages or macros so it must _not_ contain white spaces and non latin1 characters, "
220                 "should start with lower case letter and if there are subsequent words, these should "
221                 "start with upper case letter. Example: smallCamelCase. "
222                 "Moreover, try to make this prefix as short as possible.",
223                 "checkBox"));
224         wi->setDescription(xi18n("A check box with text label"));
225         addClass(wi);
226     }
227 #ifdef KEXI_AUTOFIELD_FORM_WIDGET_SUPPORT
228     {
229 // Unused, commented-out in Kexi 2.9 to avoid unnecessary translations:
230 //         KexiDataAwareWidgetInfo* wi = new KexiDataAwareWidgetInfo(this);
231 //         wi->setIconName(KexiIconName("autofield"));
232 //         wi->setClassName("KexiDBAutoField");
233 //         wi->addAlternateClassName("KexiDBFieldEdit", true/*override*/); //older
234 //         wi->setName(xi18n("Auto Field"));
235 //         wi->setNamePrefix(
236 //             i18nc("Widget name. This string will be used to name widgets of this class. "
237 //                   "It must _not_ contain white spaces and non latin1 characters", "autoField"));
238 //         wi->setDescription(xi18n("A widget containing an automatically selected editor "
239 //                                 "and a label to edit the value of a database field of any type."));
240 //         addClass(wi);
241     }
242 #endif
243 
244     {
245         KFormDesigner::WidgetInfo* wi = new KFormDesigner::WidgetInfo(this);
246         wi->setClassName("KexiDBPushButton");
247         wi->setIconName(KexiIconName("button"));
248         wi->addAlternateClassName("KexiPushButton", true/*override*/);
249         wi->addAlternateClassName("QPushButton", true/*override*/);
250         wi->setName(xi18nc("Button widget", "Button"));
251         wi->setNamePrefix(
252             I18NC_NOOP("A prefix for identifiers of button widgets. Based on that, identifiers such as "
253                 "button1, button2 are generated. "
254                 "This string can be used to refer the widget object as variables in programming "
255                 "languages or macros so it must _not_ contain white spaces and non latin1 characters, "
256                 "should start with lower case letter and if there are subsequent words, these should "
257                 "start with upper case letter. Example: smallCamelCase. "
258                 "Moreover, try to make this prefix as short as possible.",
259                 "button"));
260         wi->setDescription(xi18n("A button for executing actions"));
261         addClass(wi);
262     }
263     {
264         KFormDesigner::WidgetInfo* wi = new KFormDesigner::WidgetInfo(this);
265         wi->setClassName("KexiDBCommandLinkButton");
266         wi->setIconName(KexiIconName("button"));
267         wi->setName(xi18nc("Link Button widget", "Link Button"));
268         wi->setNamePrefix(
269             I18NC_NOOP("A prefix for identifiers of link button widgets. Based on that, identifiers such as "
270                 "linkButton1, linkButton2 are generated. "
271                 "This string can be used to refer the widget object as variables in programming "
272                 "languages or macros so it must _not_ contain white spaces and non latin1 characters, "
273                 "should start with lower case letter and if there are subsequent words, these should "
274                 "start with upper case letter. Example: smallCamelCase. "
275                 "Moreover, try to make this prefix as short as possible.",
276                 "linkButton"));
277         wi->setDescription(xi18n("A Link button for executing actions"));
278         addClass(wi);
279     }
280     //! @todo radio button
281 #ifdef KEXI_SHOW_UNFINISHED
282     {
283         KFormDesigner::WidgetInfo *wi = new KFormDesigner::WidgetInfo(this);
284         wi->setIconName(KexiIconName("radiobutton"));
285         wi->setClassName("QRadioButton");
286         wi->setName(/* no i18n needed */ "Option Button");
287         wi->setNamePrefix(/* no i18n needed */ "option");
288         wi->setDescription(/* no i18n needed */ "An option button with text or pixmap label");
289         addClass(wi);
290     }
291     {
292         KFormDesigner::WidgetInfo *wi = new KFormDesigner::WidgetInfo(this);
293         wi->setIconName(KexiIconName("spinbox"));
294         wi->setClassName("QSpinBox");
295         wi->addAlternateClassName("KIntSpinBox");
296         wi->setName(/* no i18n needed */ "Spin Box");
297         wi->setNamePrefix(/* no i18n needed */ "spinBox");
298         wi->setDescription(/* no i18n needed */ "A spin box widget");
299         addClass(wi);
300     }
301 #endif
302     {
303         KexiDataAwareWidgetInfo* wi = new KexiDataAwareWidgetInfo(this);
304         wi->setClassName("KexiDBSlider");
305         wi->setIconName(KexiIconName("slider"));
306         wi->addAlternateClassName("QSlider", true/*override*/);
307         wi->setName(xi18nc("Slider widget", "Slider"));
308         wi->setNamePrefix(
309             I18NC_NOOP("A prefix for identifiers of slider widgets. Based on that, identifiers such as "
310                 "slider1, slider2 are generated. "
311                 "This string can be used to refer the widget object as variables in programming "
312                 "languages or macros so it must _not_ contain white spaces and non latin1 characters, "
313                 "should start with lower case letter and if there are subsequent words, these should "
314                 "start with upper case letter. Example: smallCamelCase. "
315                 "Moreover, try to make this prefix as short as possible.",
316                 "slider"));
317         wi->setDescription(xi18n("A Slider widget"));
318         addClass(wi);
319     }
320     {
321         KexiDataAwareWidgetInfo* wi = new KexiDataAwareWidgetInfo(this);
322         wi->setClassName("KexiDBProgressBar");
323         wi->setIconName(KexiIconName("progressbar"));
324         wi->addAlternateClassName("QProgressBar", true/*override*/);
325         wi->setName(xi18nc("Progress Bar widget", "Progress Bar"));
326         wi->setNamePrefix(
327             I18NC_NOOP("A prefix for identifiers of progress bar widgets. Based on that, identifiers such as "
328                 "progressBar1, progressBar2 are generated. "
329                 "This string can be used to refer the widget object as variables in programming "
330                 "languages or macros so it must _not_ contain white spaces and non latin1 characters, "
331                 "should start with lower case letter and if there are subsequent words, these should "
332                 "start with upper case letter. Example: smallCamelCase. "
333                 "Moreover, try to make this prefix as short as possible.",
334                 "progressBar"));
335         wi->setDescription(xi18n("A Progress Bar widget"));
336         addClass(wi);
337     }
338     {
339         KFormDesigner::WidgetInfo *wi = new KFormDesigner::WidgetInfo(this);
340         wi->setIconName(KexiIconName("line-horizontal"));
341         wi->setClassName("KexiLineWidget");
342         wi->addAlternateClassName("Line", true/*override*/);
343         wi->setName(xi18n("Line"));
344         wi->setNamePrefix(
345             I18NC_NOOP("A prefix for identifiers of line widgets. Based on that, identifiers such as "
346                 "line1, line2 are generated. "
347                 "This string can be used to refer the widget object as variables in programming "
348                 "languages or macros so it must _not_ contain white spaces and non latin1 characters, "
349                 "should start with lower case letter and if there are subsequent words, these should "
350                 "start with upper case letter. Example: smallCamelCase. "
351                 "Moreover, try to make this prefix as short as possible.",
352                 "line"));
353         wi->setDescription(xi18n("A line to be used as a separator"));
354         wi->setAutoSaveProperties(QList<QByteArray>() << "orientation");
355         wi->setInternalProperty("orientationSelectionPopup", true);
356         wi->setInternalProperty("orientationSelectionPopup:horizontalIcon", KexiIconName("line-horizontal"));
357         wi->setInternalProperty("orientationSelectionPopup:verticalIcon", KexiIconName("line-vertical"));
358         wi->setInternalProperty("orientationSelectionPopup:horizontalText", xi18n("Insert &Horizontal Line"));
359         wi->setInternalProperty("orientationSelectionPopup:verticalText", xi18n("Insert &Vertical Line"));
360         addClass(wi);
361     }
362     {
363         KexiDataAwareWidgetInfo* wi = new KexiDataAwareWidgetInfo(this);
364         wi->setClassName("KexiDBDatePicker");
365         wi->setIconName(KexiIconName("dateedit"));
366         wi->addAlternateClassName("QDateEdit", true/*override*/);
367         wi->addAlternateClassName("KDateWidget", true/*override*/);
368         wi->setName(xi18nc("Date Picker widget", "Date Picker"));
369         wi->setNamePrefix(
370             I18NC_NOOP("A prefix for identifiers of date picker widgets. Based on that, identifiers such as "
371                 "datePicker1, datePicker2 are generated. "
372                 "This string can be used to refer the widget object as variables in programming "
373                 "languages or macros so it must _not_ contain white spaces and non latin1 characters, "
374                 "should start with lower case letter and if there are subsequent words, these should "
375                 "start with upper case letter. Example: smallCamelCase. "
376                 "Moreover, try to make this prefix as short as possible.",
377                 "datePicker"));
378         wi->setDescription(xi18n("A Date Picker widget"));
379         addClass(wi);
380     }
381     //! @todo time edit
382 #ifdef KEXI_SHOW_UNFINISHED
383     {
384         KFormDesigner::WidgetInfo *wi = new KFormDesigner::WidgetInfo(this);
385         wi->setIconName(KexiIconName("timeedit"));
386         wi->setClassName("QTimeEdit");
387         wi->addAlternateClassName("KTimeWidget");
388         wi->setName(/* no i18n needed */ "Time Widget");
389         wi->setNamePrefix(/* no i18n needed */ "timeWidget");
390         wi->setDescription(/* no i18n needed */ "A widget to input and display a time");
391         wi->setAutoSaveProperties(QList<QByteArray>() << "time");
392         addClass(wi);
393     }
394 #endif
395     //! @todo datetime edit
396 #ifdef KEXI_SHOW_UNFINISHED
397     {
398         KFormDesigner::WidgetInfo *wi = new KFormDesigner::WidgetInfo(this);
399         wi->setIconName(KexiIconName("datetimeedit"));
400         wi->setClassName("QDateTimeEdit");
401         wi->addAlternateClassName("KDateTimeWidget");
402         wi->setName(/* no i18n needed */ "Date/Time Widget");
403         wi->setNamePrefix(/* no i18n needed */ "dateTimeWidget");
404         wi->setDescription(/* no i18n needed */ "A widget to input and display a time and a date");
405         wi->setAutoSaveProperties(QList<QByteArray>() << "dateTime");
406         addClass(wi);
407     }
408 #endif
409 
410     setPropertyDescription("echoMode",
411         xi18nc("Property: Echo mode for Line Edit widget eg. Normal, NoEcho, Password", "Echo Mode"));
412     setPropertyDescription("indent", xi18n("Indent"));
413 
414     setPropertyDescription("invertedAppearance", xi18n("Inverted"));
415     setPropertyDescription("minimum", xi18n("Minimum"));
416     setPropertyDescription("maximum", xi18n("Maximum"));
417     setPropertyDescription("format", xi18n("Format"));
418     setPropertyDescription("orientation", xi18n("Orientation"));
419     setPropertyDescription("textDirection", xi18n("Text Direction"));
420     setPropertyDescription("textVisible", xi18n("Text Visible"));
421     setPropertyDescription("value", xi18n("Value"));
422     setPropertyDescription("date", xi18n("Date"));
423     setPropertyDescription("arrowVisible", xi18n("Arrow Visible"));
424     setPropertyDescription("description", xi18n("Description"));
425     setPropertyDescription("pageStep", xi18nc("Property of slider widgets", "Page Step"));
426     setPropertyDescription("singleStep", xi18nc("Property of slider widgets", "Single Step"));
427     setPropertyDescription("tickInterval", xi18nc("Property of slider widgets", "Tick Interval"));
428     setPropertyDescription("tickPosition", xi18nc("Property of slider widgets", "Tick Position"));
429     setPropertyDescription("showEditor", xi18n("Show Editor"));
430     setPropertyDescription("formName", xi18n("Form Name"));
431     setPropertyDescription("onClickAction", xi18n("On Click"));
432     setPropertyDescription("onClickActionOption", xi18n("On Click Option"));
433     setPropertyDescription("autoTabStops", xi18n("Auto Tab Order"));
434     setPropertyDescription("checkSpellingEnabled", xi18n("Spell Checking"));
435     setPropertyDescription("html", xi18nc("Widget Property", "HTML"));
436     setPropertyDescription("lineWrapColumnOrWidth", xi18n("Line Wrap At"));
437     setPropertyDescription("lineWrapMode", xi18n("Line Wrap Mode"));
438     setPropertyDescription("spellCheckingLanguage", xi18n("Spell Checking Language"));
439 
440     setPropertyDescription("widgetType", xi18n("Editor Type"));
441 #ifdef KEXI_AUTOFIELD_FORM_WIDGET_SUPPORT
442     //for autofield's type: inherit i18n from KDb
443     setValueDescription("Auto", futureI18nc("AutoField editor's type", "Auto"));
444     setValueDescription("Text", KDbField::typeName(KDbField::Text));
445     setValueDescription("Integer", KDbField::typeName(KDbField::Integer));
446     setValueDescription("Double", KDbField::typeName(KDbField::Double));
447     setValueDescription("Boolean", KDbField::typeName(KDbField::Boolean));
448     setValueDescription("Date", KDbField::typeName(KDbField::Date));
449     setValueDescription("Time", KDbField::typeName(KDbField::Time));
450     setValueDescription("DateTime", KDbField::typeName(KDbField::DateTime));
451     setValueDescription("MultiLineText", xi18nc("AutoField editor's type", "Multiline Text"));
452     setValueDescription("ComboBox", xi18nc("AutoField editor's type", "Drop-Down List"));
453     setValueDescription("Image", xi18nc("AutoField editor's type", "Image"));
454 #endif
455 
456     setValueDescription("NoTicks", xi18nc("Possible value of slider widget's \"Tick position\" property", "No Ticks"));
457     setValueDescription("TicksAbove", xi18nc("Possible value of slider widget's \"Tick position\" property", "Above"));
458     setValueDescription("TicksLeft", xi18nc("Possible value of slider widget's \"Tick position\" property", "Left"));
459     setValueDescription("TicksBelow", xi18nc("Possible value of slider widget's \"Tick position\" property", "Below"));
460     setValueDescription("TicksRight", xi18nc("Possible value of slider widget's \"Tick position\" property", "Right"));
461     setValueDescription("TicksBothSides", xi18nc("Possible value of slider widget's \"Tick position\" property", "Both Sides"));
462 
463 // auto field:
464 //    setPropertyDescription("autoCaption", futureI18n("Auto Label"));
465 //    setPropertyDescription("foregroundLabelColor", futureI18n("Label Text Color"));
466 //    setPropertyDescription("backgroundLabelColor", futureI18nc("(a property name, keep the text narrow!)",
467 //                                         "Label Background\nColor"));
468 
469 //    setPropertyDescription("labelPosition", futureI18n("Label Position"));
470 //    setValueDescription("Left", futureI18nc("Label Position", "Left"));
471 //    setValueDescription("Top", futureI18nc("Label Position", "Top"));
472 //    setValueDescription("NoLabel", futureI18nc("Label Position", "No Label"));
473 
474     setPropertyDescription("sizeInternal", xi18n("Size"));
475     setPropertyDescription("pixmapId", xi18n("Image"));
476     setPropertyDescription("scaledContents", xi18n("Scaled Contents"));
477     setPropertyDescription("smoothTransformation", xi18nc("Property: Smoothing when contents are scaled", "Smoothing"));
478     setPropertyDescription("keepAspectRatio", xi18nc("Property: Keep Aspect Ratio (keep short)", "Keep Ratio"));
479 
480     //used in labels, frames...
481     setPropertyDescription("dropDownButtonVisible",
482         xi18nc("Drop-Down Button for Image Box Visible (a property name, keep the text narrow!)",
483               "Drop-Down\nButton Visible"));
484 
485     //for checkbox
486     setPropertyDescription("checked", xi18nc("Property: Checked checkbox", "Checked"));
487     setPropertyDescription("tristate", xi18nc("Property: Tristate checkbox", "Tristate"));
488     setValueDescription("TristateDefault", xi18nc("Value of \"Tristate\" property in checkbox: default", "Default"));
489     setValueDescription("TristateOn", xi18nc("Value of \"Tristate\" property in checkbox: yes", "Yes"));
490     setValueDescription("TristateOff", xi18nc("Value of \"Tristate\" property in checkbox: no", "No"));
491 
492     //for combobox
493     setPropertyDescription("editable", xi18nc("Editable combobox", "Editable"));
494 
495     //for button
496     setPropertyDescription("checkable", xi18nc("Property: Button is checkable", "On/Off"));
497     setPropertyDescription("autoRepeat", xi18nc("Property: Button", "Auto Repeat"));
498     setPropertyDescription("autoRepeatDelay", xi18nc("Property: Auto Repeat Button's Delay", "Auto Rep. Delay"));
499     setPropertyDescription("autoRepeatInterval", xi18nc("Property: Auto Repeat Button's Interval", "Auto Rep. Interval"));
500     // unused (too advanced) setPropertyDescription("autoDefault", xi18n("Auto Default"));
501     // unused (too advanced) setPropertyDescription("default", xi18nc("Property: Button is default", "Default"));
502     setPropertyDescription("flat", xi18nc("Property: Button is flat", "Flat"));
503     setPropertyDescription("hyperlink" , xi18nc("Hyperlink address", "Hyperlink"));
504     setPropertyDescription("hyperlinkType", xi18nc("Type of hyperlink", "Hyperlink Type"));
505     setPropertyDescription("hyperlinkTool", xi18nc("Tool used for opening a hyperlink", "Hyperlink Tool"));
506     setPropertyDescription("remoteHyperlink", xi18nc("Allow to open remote hyperlinks", "Remote Hyperlink"));
507     setPropertyDescription("hyperlinkExecutable", xi18nc("Allow to open executables", "Executable Hyperlink"));
508 
509     setValueDescription("NoHyperlink", xi18nc("Hyperlink type, NoHyperlink", "No Hyperlink"));
510     setValueDescription("StaticHyperlink", xi18nc("Hyperlink type, StaticHyperlink", "Static"));
511     setValueDescription("DynamicHyperlink", xi18nc("Hyperlink type, DynamicHyperlink", "Dynamic"));
512 
513     setValueDescription("DefaultHyperlinkTool", xi18nc("Hyperlink tool, DefaultTool", "Default"));
514     setValueDescription("BrowserHyperlinkTool", xi18nc("Hyperlink tool, BrowserTool", "Browser"));
515     setValueDescription("MailerHyperlinkTool", xi18nc("Hyperlink tool, MailerTool", "Mailer"));
516 
517     //for label
518     setPropertyDescription("textFormat", xi18n("Text Format"));
519     setValueDescription("PlainText", xi18nc("For Text Format", "Plain"));
520     setValueDescription("RichText", xi18nc("For Text Format", "Hypertext"));
521     setValueDescription("AutoText", xi18nc("For Text Format", "Auto"));
522     setValueDescription("LogText", xi18nc("For Text Format", "Log"));
523     setPropertyDescription("openExternalLinks", xi18nc("property: Can open external links in label", "Open Ext. Links"));
524 
525     //for line edit
526     setPropertyDescription("placeholderText", xi18nc("Property: line edit's placeholder text", "Placeholder Text"));
527     setPropertyDescription("clearButtonEnabled", xi18nc("Property: Clear Button Enabled", "Clear Button"));
528     //for EchoMode
529     setPropertyDescription("passwordMode", xi18nc("Property: Password Mode for line edit", "Password Mode"));
530     setPropertyDescription("squeezedTextEnabled", xi18nc("Property: Squeezed Text Mode for line edit", "Squeezed Text"));
531 
532     // text edit
533     setPropertyDescription("tabStopWidth", xi18n("Tab Stop Width"));
534     setPropertyDescription("tabChangesFocus", xi18n("Tab Changes Focus"));
535     setPropertyDescription("wrapPolicy", xi18n("Word Wrap Policy"));
536     setValueDescription("AtWordBoundary", xi18nc("Property: For Word Wrap Policy", "At Word Boundary"));
537     setValueDescription("Anywhere", xi18nc("Property: For Word Wrap Policy", "Anywhere"));
538     setValueDescription("AtWordOrDocumentBoundary", xi18nc("Property: For Word Wrap Policy", "At Word Boundary If Possible"));
539     setPropertyDescription("wordWrap", xi18n("Word Wrapping"));
540     setPropertyDescription("wrapColumnOrWidth", xi18n("Word Wrap Position"));
541     setValueDescription("NoWrap", xi18nc("Property: For Word Wrap Position", "None"));
542     setValueDescription("WidgetWidth", xi18nc("Property: For Word Wrap Position", "Widget's Width"));
543     setValueDescription("FixedPixelWidth", xi18nc("Property: For Word Wrap Position", "In Pixels"));
544     setValueDescription("FixedColumnWidth", xi18nc("Property: For Word Wrap Position", "In Columns"));
545     setPropertyDescription("linkUnderline", xi18n("Links Underlined"));
546     setPropertyDescription("horizontalScrollBarPolicy", xi18n("Horizontal Scroll Bar"));
547     setPropertyDescription("verticalScrollBarPolicy", xi18n("Vertical Scroll Bar"));
548     //ScrollBarPolicy
549     setValueDescription("ScrollBarAsNeeded", xi18nc("Property: Show Scroll Bar As Needed", "As Needed"));
550     setValueDescription("ScrollBarAlwaysOff", xi18nc("Property: Scroll Bar Always Off", "Always Off"));
551     setValueDescription("ScrollBarAlwaysOn", xi18nc("Property: Scroll Bar Always On", "Always On"));
552     setPropertyDescription("acceptRichText", xi18nc("Property: Text Edit accepts rich text", "Rich Text"));
553     setPropertyDescription("HTML", xi18nc("Property: HTML value of text edit", "HTML"));
554 
555     // --- containers ---
556     {
557         KFormDesigner::WidgetInfo *wi = new KFormDesigner::WidgetInfo(this);
558         wi->setIconName(KexiIconName("tabwidget"));
559         wi->setClassName("KFDTabWidget");
560         wi->addAlternateClassName("KTabWidget");
561         wi->addAlternateClassName("QTabWidget");
562         wi->setSavingName("QTabWidget");
563         wi->setName(xi18n("Tab Widget"));
564         wi->setNamePrefix(
565             I18NC_NOOP("A prefix for identifiers of tab widgets. Based on that, identifiers such as "
566                   "tab1, tab2 are generated. "
567                   "This string can be used to refer the widget object as variables in programming "
568                   "languages or macros so it must _not_ contain white spaces and non latin1 characters, "
569                   "should start with lower case letter and if there are subsequent words, these should "
570                   "start with upper case letter. Example: smallCamelCase. "
571                   "Moreover, try to make this prefix as short as possible.",
572                   "tabWidget"));
573         wi->setDescription(xi18n("A widget to display multiple pages using tabs"));
574         addClass(wi);
575     }
576     {
577         KFormDesigner::WidgetInfo *wi = new KFormDesigner::WidgetInfo(this);
578         wi->setIconName(KexiIconName("frame"));
579         wi->setClassName("QWidget");
580         wi->addAlternateClassName("ContainerWidget");
581         wi->setName(/* no i18n needed */ "Basic container");
582         wi->setNamePrefix(nullptr, /* no i18n needed */ "container");
583         wi->setDescription(/* no i18n needed */ "An empty container with no frame");
584         addClass(wi);
585     }
586     {
587         KFormDesigner::WidgetInfo* wi = new KFormDesigner::WidgetInfo(this);
588         wi->setIconName(KexiIconName("frame"));
589         wi->setClassName("KexiFrame");
590         wi->addAlternateClassName("QFrame", true/*override*/);
591         wi->addAlternateClassName("Q3Frame", true/*override*/);
592         wi->setName(xi18nc("Frame widget", "Frame"));
593         wi->setNamePrefix(
594             I18NC_NOOP("A prefix for identifiers of frame widgets. Based on that, identifiers such as "
595                 "frame1, frame2 are generated. "
596                 "This string can be used to refer the widget object as variables in programming "
597                 "languages or macros so it must _not_ contain white spaces and non latin1 characters, "
598                 "should start with lower case letter and if there are subsequent words, these should "
599                 "start with upper case letter. Example: smallCamelCase. "
600                 "Moreover, try to make this prefix as short as possible.",
601                 "frame"));
602         wi->setDescription(xi18n("A frame widget"));
603         addClass(wi);
604     }
605     {
606         KFormDesigner::WidgetInfo *wi = new KFormDesigner::WidgetInfo(this);
607         wi->setIconName(KexiIconName("groupbox"));
608         wi->setClassName("QGroupBox");
609         wi->addAlternateClassName("GroupBox");
610         wi->setName(xi18n("Group Box"));
611         wi->setNamePrefix(
612             I18NC_NOOP("A prefix for identifiers of group box widgets. Based on that, identifiers such as "
613                   "groupBox1, groupBox2 are generated. "
614                   "This string can be used to refer the widget object as variables in programming "
615                   "languages or macros so it must _not_ contain white spaces and non latin1 characters, "
616                   "should start with lower case letter and if there are subsequent words, these should "
617                   "start with upper case letter. Example: smallCamelCase. "
618                   "Moreover, try to make this prefix as short as possible.",
619                   "groupBox"));
620         wi->setDescription(xi18n("A container to group some widgets"));
621         addClass(wi);
622     }
623 
624     //groupbox
625     setPropertyDescription("title", xi18nc("'Title' property for group box", "Title"));
626     setPropertyDescription("flat", xi18nc("'Flat' property for group box", "Flat"));
627 
628     //tab widget
629     setPropertyDescription("tabBarAutoHide", xi18n("Auto-hide Tabs"));
630     setPropertyDescription("tabPosition", xi18n("Tab Position"));
631     setPropertyDescription("currentIndex", xi18nc("'Current page' property for tab widget", "Current Page"));
632     setPropertyDescription("tabShape", xi18n("Tab Shape"));
633     setPropertyDescription("elideMode", xi18nc("Tab Widget's Elide Mode property", "Elide Mode"));
634     setPropertyDescription("usesScrollButtons",
635                            xi18nc("Tab Widget's property: true if can use scroll buttons", "Scroll Buttons"));
636 
637     setPropertyDescription("tabsClosable", xi18n("Closable Tabs"));
638     setPropertyDescription("movable", xi18n("Movable Tabs"));
639     setPropertyDescription("documentMode", xi18n("Document Mode"));
640 
641     setValueDescription("Rounded", xi18nc("Property value for Tab Shape", "Rounded"));
642     setValueDescription("Triangular", xi18nc("Property value for Tab Shape", "Triangular"));
643 }
644 
~KexiMainFormWidgetsFactory()645 KexiMainFormWidgetsFactory::~KexiMainFormWidgetsFactory()
646 {
647 }
648 
649 QWidget*
createWidget(const QByteArray & c,QWidget * p,const char * n,KFormDesigner::Container * container,CreateWidgetOptions options)650 KexiMainFormWidgetsFactory::createWidget(const QByteArray &c, QWidget *p, const char *n,
651                             KFormDesigner::Container *container,
652                             CreateWidgetOptions options)
653 {
654     QWidget *w = 0;
655     const QString text(container->form()->library()->textForWidgetName(n, c));
656     const bool designMode = options & KFormDesigner::WidgetFactory::DesignViewMode;
657     bool createContainer = false;
658 
659     if (c == "KexiDBLineEdit" || c == "QLineEdit") {
660         w = new KexiDBLineEdit(p);
661     }
662     else if (c == "KexiDBTextEdit" || c == "KTextEdit") {
663         w = new KexiDBTextEdit(p);
664     }
665     else if (c == "Q3Frame" || c == "QFrame" || c == "KexiFrame") {
666         w = new KexiFrame(p);
667         createContainer = true;
668     } else if (c == "KexiDBLabel" || c == "QLabel") {
669         w = new KexiDBLabel(text, p);
670     }
671     else if (c == "KexiDBImageBox" || c == "KexiPictureLabel") {
672         w = new KexiDBImageBox(designMode, p);
673         connect(w, SIGNAL(idChanged(long)), this, SLOT(slotImageBoxIdChanged(long)));
674     }
675 #ifdef KEXI_AUTOFIELD_FORM_WIDGET_SUPPORT
676     else if (c == "KexiDBAutoField") {
677         w = new KexiDBAutoField(p);
678     }
679 #endif
680     else if (c == "KexiDBCheckBox" || c == "QCheckBox") {
681         w = new KexiDBCheckBox(text, p);
682     }
683     else if (c == "KexiDBSlider" || c == "QSlider") {
684         w = new KexiDBSlider(p);
685     } else if (c == "KexiDBProgressBar" || c == "QProgressBar") {
686         w = new KexiDBProgressBar(p);
687     } else if (c == "KexiDBDatePicker" || c == "KDateWidget" || c == "QDateEdit") {
688         w = new KexiDBDatePicker(p);
689     }
690     else if (c == "KexiDBComboBox" || c == "KComboBox") {
691         w = new KexiDBComboBox(p);
692     }
693     else if (c == "QPushButton" || c == "KPushButton" || c == "KexiDBPushButton" || c == "KexiPushButton") {
694         w = new KexiDBPushButton(text, p);
695     }
696     else if (c == "KexiDBCommandLinkButton" || c == "KexiCommandLinkButton") {
697         w = new KexiDBCommandLinkButton(text, QString(), p);
698     }
699 #ifdef KEXI_SHOW_UNFINISHED
700     else if (c == "QRadioButton") {
701         w = new QRadioButton(text, p);
702     } else if (c == "KIntSpinBox" || c == "QSpinBox") {
703         w = new QSpinBox(p);
704     }
705 #endif
706 #ifdef KEXI_LIST_FORM_WIDGET_SUPPORT
707     else if (c == "QTreeWidget") {
708             QTreeWidget *tw = new QTreeWidget(p);
709             w = tw;
710             if (container->form()->interactiveMode()) {
711                 tw->setColumnCount(1);
712                 tw->setHeaderItem(new QTreeWidetItem(tw));
713                 tw->headerItem()->setText(1, futureI18n("Column 1"));
714             }
715             lw->setRootIsDecorated(true);
716     } else if (c == "KTimeWidget" || c == "QTimeEdit") {
717        w = new QTimeEdit(QTime::currentTime(), p);
718     } else if (c == "KDateTimeWidget" || c == "QDateTimeEdit") {
719         w = new QDateTimeEdit(QDateTime::currentDateTime(), p);
720     }
721 #endif
722     else if (c == "KexiLineWidget" || c == "Line") {
723         w = new KexiLineWidget(options & WidgetFactory::VerticalOrientation
724                 ? Qt::Vertical : Qt::Horizontal, p);
725     } // --- containers ---
726     else if (c == "KFDTabWidget") {
727         KFDTabWidget *tab = new KFDTabWidget(container, p);
728         w = tab;
729 #if defined(USE_KTabWidget)
730         tab->setTabReorderingEnabled(true);
731         connect(tab, SIGNAL(movedTab(int,int)), this, SLOT(reorderTabs(int,int)));
732 #endif
733         //qDebug() << "Creating ObjectTreeItem:";
734         container->form()->objectTree()->addItem(container->objectTree(),
735             new KFormDesigner::ObjectTreeItem(
736                 container->form()->library()->displayName(c), n, tab, container));
737     } else if (c == "QWidget") {
738         w = new ContainerWidget(p);
739         w->setObjectName(n);
740         (void)new KFormDesigner::Container(container, w, p);
741         return w;
742     } else if (c == "QGroupBox") {
743         w = new GroupBox(text, p);
744         createContainer = true;
745     }
746 
747     if (w)
748         w->setObjectName(n);
749     if (createContainer) {
750         (void)new KFormDesigner::Container(container, w, container);
751     }
752     if (c == "KFDTabWidget") {
753         // if we are loading, don't add this tab
754         if (container->form()->interactiveMode()) {
755             TabWidgetBase *tab = qobject_cast<TabWidgetBase*>(w);
756             AddTabAction(container, tab, 0).slotTriggered();
757         }
758     }
759     return w;
760 }
761 
createMenuActions(const QByteArray & classname,QWidget * w,QMenu * menu,KFormDesigner::Container * container)762 bool KexiMainFormWidgetsFactory::createMenuActions(const QByteArray &classname, QWidget *w,
763         QMenu *menu, KFormDesigner::Container *container)
764 {
765     QWidget *pw = w->parentWidget();
766     if (m_assignAction->isEnabled()) {
767         /*! @todo also call createMenuActions() for inherited factory! */
768         menu->addAction(m_assignAction);
769         return true;
770     } else if (classname == "KexiDBImageBox") {
771         KexiDBImageBox *imageBox = static_cast<KexiDBImageBox*>(w);
772         imageBox->contextMenu()->updateActionsAvailability();
773         KActionCollection *ac = imageBox->contextMenu()->actionCollection();
774         QMenu *subMenu = menu->addMenu(xi18n("&Image"));
775 //! @todo make these actions undoable/redoable
776         subMenu->addAction(ac->action("insert"));
777         subMenu->addAction(ac->action("file_save_as"));
778         subMenu->addSeparator();
779         subMenu->addAction(ac->action("edit_cut"));
780         subMenu->addAction(ac->action("edit_copy"));
781         subMenu->addAction(ac->action("edit_paste"));
782         subMenu->addAction(ac->action("delete"));
783         if (ac->action("properties")) {
784             subMenu->addSeparator();
785             subMenu->addAction(ac->action("properties"));
786         }
787     } else if (classname == "KexiDBLabel" || classname == "KexiDBTextEdit") {
788         menu->addAction( new EditRichTextAction(container, w, menu, this) );
789         return true;
790     }
791 #ifdef KEXI_LIST_FORM_WIDGET_SUPPORT
792     else if (classname == "QTreeWidget") {
793         menu->addAction(koIcon("document-properties"), futureI18n("Edit Contents of List Widget"),
794             this, SLOT(editListContents()));
795         return true;
796     }
797 #endif
798     else if (classname == "KFDTabWidget" || pw->parentWidget()->inherits("QTabWidget")) {
799 //! @todo KEXI3 port this: setWidget(pw->parentWidget(), m_container->toplevel());
800 #if 0
801         if (pw->parentWidget()->inherits("QTabWidget")) {
802             setWidget(pw->parentWidget(), m_container->toplevel());
803         }
804 #endif
805         TabWidgetBase *tab = qobject_cast<TabWidgetBase*>(w);
806         if (tab) {
807             menu->addAction( new AddTabAction(container, tab, menu) );
808             menu->addAction( new RenameTabAction(container, tab, menu) );
809             menu->addAction( new RemoveTabAction(container, tab, menu) );
810         }
811         return true;
812     }
813     return false;
814 }
815 
816 void
createCustomActions(KActionCollection * col)817 KexiMainFormWidgetsFactory::createCustomActions(KActionCollection* col)
818 {
819     //this will create shared instance action for design mode (special collection is provided)
820     col->addAction("widget_assign_action",
821                    m_assignAction = new QAction(KexiIcon("form-action"), xi18n("&Assign Action..."), this));
822 }
823 
824 bool
startInlineEditing(InlineEditorCreationArguments & args)825 KexiMainFormWidgetsFactory::startInlineEditing(InlineEditorCreationArguments& args)
826 {
827     const KFormDesigner::WidgetInfo* wclass = args.container->form()->library()->widgetInfoForClassName(args.classname);
828     const KexiDataAwareWidgetInfo* wDataAwareClass = dynamic_cast<const KexiDataAwareWidgetInfo*>(wclass);
829     if (wDataAwareClass && !wDataAwareClass->inlineEditingEnabledWhenDataSourceSet()) {
830         KexiFormDataItemInterface* iface = dynamic_cast<KexiFormDataItemInterface*>(args.widget);
831         if (iface && !iface->dataSource().isEmpty()) {
832 //! @todo reimplement inline editing for KexiDBLineEdit using combobox with data sources
833             return false;
834         }
835     }
836 
837     if (args.classname == "KexiDBLineEdit") {
838         QLineEdit *lineedit = static_cast<QLineEdit*>(args.widget);
839         args.text = lineedit->text();
840         args.alignment = lineedit->alignment();
841         args.useFrame = true;
842         return true;
843     }
844     else if (args.classname == "KexiDBTextEdit") {
845         KTextEdit *textedit = static_cast<KTextEdit*>(args.widget);
846 //! @todo rich text?
847         args.text = textedit->toPlainText();
848         args.alignment = textedit->alignment();
849         args.useFrame = true;
850         args.multiLine = true;
851 //! @todo
852 #if 0
853         //copy a few properties
854         KTextEdit *ed = dynamic_cast<KTextEdit *>(editor(w));
855         ed->setLineWrapMode(textedit->lineWrapMode());
856         ed->setLineWrapColumnOrWidth(textedit->lineWrapColumnOrWidth());
857         ed->setWordWrapMode(textedit->wordWrapMode());
858         ed->setTabStopWidth(textedit->tabStopWidth());
859         ed->setTextFormat(textedit->textFormat());
860         ed->setHorizontalScrollBarPolicy(textedit->horizontalScrollBarPolicy());
861         ed->setVerticalScrollBarPolicy(textedit->verticalScrollBarPolicy());
862 #endif
863         return true;
864     }
865     else if (args.classname == "KexiDBPushButton") {
866         KexiDBPushButton *push = static_cast<KexiDBPushButton*>(args.widget);
867         QStyleOptionButton option;
868         option.initFrom(push);
869         args.text = push->text();
870         const QRect r(push->style()->subElementRect(
871                           QStyle::SE_PushButtonContents, &option, push));
872         args.geometry = QRect(push->x() + r.x(), push->y() + r.y(), r.width(), r.height());
873 //! @todo this is typical alignment, can we get actual from the style?
874         args.alignment = Qt::AlignCenter;
875         //args.transparentBackground = true;
876         return true;
877     }
878     else if (args.classname == "KexiDBCommandLinkButton" ){
879         KexiDBCommandLinkButton *linkButton = static_cast<KexiDBCommandLinkButton*>(args.widget);
880         QStyleOptionButton option;
881         option.initFrom(linkButton);
882         args.text = linkButton->text();
883         const QRect r(linkButton->style()->subElementRect(
884                         QStyle::SE_PushButtonContents, &option, linkButton));
885 
886         QFontMetrics fm(linkButton->font());
887         args.geometry = QRect(linkButton->x() + linkButton->iconSize().width() + 6,
888                               linkButton->y() + r.y(),
889                               r.width()  - 6 - linkButton->iconSize().width(),
890                               std::min(fm.height() + 14, linkButton->height() - 4));
891         return true;
892     }
893 #ifdef KEXI_SHOW_UNFINISHED
894     else if (args.classname == "QRadioButton") {
895         QRadioButton *radio = static_cast<QRadioButton*>(args.widget);
896         QStyleOptionButton option;
897         option.initFrom(radio);
898         args.text = radio->text();
899         const QRect r(radio->style()->subElementRect(
900                           QStyle::SE_RadioButtonContents, &option, radio));
901         args.geometry = QRect(
902             radio->x() + r.x(), radio->y() + r.y(), r.width(), r.height());
903         return true;
904     }
905 #endif
906     else if (args.classname == "KexiDBLabel") {
907         KexiDBLabel *label = static_cast<KexiDBLabel*>(args.widget);
908         if (label->textFormat() == Qt::RichText) {
909             args.execute = false;
910             EditRichTextAction(args.container, label, nullptr, this).trigger();
911 //! @todo
912         } else {
913             args.text = label->text();
914             args.alignment = label->alignment();
915             args.multiLine = label->wordWrap();
916         }
917         return true;
918     }
919     else if (   args.classname == "KexiDBDateEdit" || args.classname == "KexiDBDateTimeEdit"
920              /*|| args.classname == "KexiDBTimeEdit" || classname == "KexiDBIntSpinBox" || classname == "KexiDBDoubleSpinBox"*/)
921     {
922         disableFilter(args.widget, args.container);
923         return true;
924     }
925 #ifdef KEXI_AUTOFIELD_FORM_WIDGET_SUPPORT
926     else if (args.classname == "KexiDBAutoField") {
927         if (static_cast<KexiDBAutoField*>(args.widget)->hasAutoCaption())
928             return false; // caption is auto, abort editing
929         QLabel *label = static_cast<KexiDBAutoField*>(args.widget)->label();
930         args.text = label->text();
931         args.widget = label;
932         args.geometry = label->geometry();
933         args.alignment = label->alignment();
934         return true;
935     }
936 #endif
937     else if (args.classname == "KexiDBCheckBox") {
938         KexiDBCheckBox *cb = static_cast<KexiDBCheckBox*>(args.widget);
939         QStyleOptionButton option;
940         option.initFrom(cb);
941         QRect r(cb->geometry());
942         r.setLeft(
943             r.left() + 2
944             + cb->style()->subElementRect(QStyle::SE_CheckBoxIndicator, &option, cb).width());
945         args.text = cb->text();
946         args.geometry = r;
947         return true;
948     }
949     else if (args.classname == "KexiDBImageBox") {
950         KexiDBImageBox *image = static_cast<KexiDBImageBox*>(args.widget);
951         image->insertFromFile();
952         args.execute = false;
953         return true;
954     }
955     return false;
956 }
957 
958 bool
previewWidget(const QByteArray &,QWidget *,KFormDesigner::Container *)959 KexiMainFormWidgetsFactory::previewWidget(const QByteArray &, QWidget *, KFormDesigner::Container *)
960 {
961     return false;
962 }
963 
964 bool
clearWidgetContent(const QByteArray &,QWidget * w)965 KexiMainFormWidgetsFactory::clearWidgetContent(const QByteArray & /*classname*/, QWidget *w)
966 {
967     KexiFormDataItemInterface *iface = dynamic_cast<KexiFormDataItemInterface*>(w);
968     if (iface) {
969         iface->clear();
970     }
971     return true;
972 }
973 
974 bool
isPropertyVisibleInternal(const QByteArray & classname,QWidget * w,const QByteArray & property,bool isTopLevel)975 KexiMainFormWidgetsFactory::isPropertyVisibleInternal(const QByteArray& classname, QWidget *w,
976         const QByteArray& property, bool isTopLevel)
977 {
978     //general
979     bool ok = true;
980     if (classname == "KexiDBPushButton" || classname == "KexiPushButton") {
981         ok = property != "isDragEnabled"
982 #ifndef KEXI_SHOW_UNFINISHED
983              && property != "onClickAction" /*! @todo reenable */
984              && property != "onClickActionOption" /*! @todo reenable */
985              && property != "iconSet" /*! @todo reenable */
986              && property != "iconSize" /*! @todo reenable */
987              && property != "stdItem" /*! @todo reenable stdItem */
988 #endif
989              ;
990         ok = KFormDesigner::WidgetFactory::advancedPropertiesVisible()
991              || (ok && property != "autoDefault" && property != "default");
992      } else if (classname == "KexiDBCommandLinkButton") {
993         ok = property != "isDragEnabled"
994              && property != "default"
995              && property != "checkable"
996              && property != "autoDefault"
997              && property != "autoRepeat"
998              && property != "autoRepeatDelay"
999              && property != "autoRepeatInterval"
1000 #ifndef KEXI_SHOW_UNFINISHED
1001              && property != "onClickAction" /*! @todo reenable */
1002              && property != "onClickActionOption" /*! @todo reenable */
1003              && property != "iconSet" /*! @todo reenable */
1004              && property != "iconSize" /*! @todo reenable */
1005              && property != "stdItem" /*! @todo reenable stdItem */
1006 #endif
1007              ;
1008      } else if (classname == "KexiDBSlider") {
1009         ok = property != "sliderPosition"
1010              && property != "tracking";
1011      } else if (classname == "KexiDBProgressBar") {
1012         ok = property != "focusPolicy"
1013              && property != "value";
1014      } else if (classname == "KexiDBLineEdit" || classname == "QLineEdit")
1015         ok = property != "urlDropsEnabled"
1016              && property != "echoMode"
1017              && property != "clickMessage" // Replaced by placeholderText in 2.9,
1018                                            // kept for backward compatibility Kexi projects created with Qt < 4.7.
1019              && property != "showClearButton" // Replaced by clearButtonEnabled in 3.0,
1020                                               // kept for backward compatibility Kexi projects created with Qt 4.
1021 #ifndef KEXI_SHOW_UNFINISHED
1022              && property != "inputMask"
1023              && property != "maxLength" //!< we may want to integrate this with db schema
1024 #endif
1025              ;
1026     else if (classname == "KexiDBComboBox")
1027         ok = property != "autoCaption"
1028              && property != "labelPosition"
1029              && property != "widgetType"
1030              && property != "fieldTypeInternal"
1031              && property != "fieldCaptionInternal" //hide properties that come with KexiDBAutoField
1032 #ifndef KEXI_AUTOFIELD_FORM_WIDGET_SUPPORT
1033              && property != "foregroundLabelColor"
1034              && property != "backgroundLabelColor"
1035 #endif
1036              ;
1037     else if (classname == "KexiDBTextEdit" || classname == "KTextEdit")
1038         ok = KFormDesigner::WidgetFactory::advancedPropertiesVisible()
1039              || (property != "undoDepth"
1040                  && property != "undoRedoEnabled" //always true!
1041                  && property != "dragAutoScroll" //always true!
1042                  && property != "overwriteMode" //always false!
1043                  && property != "resizePolicy"
1044                  && property != "autoFormatting" //too complex
1045                  && property != "documentTitle"
1046                  && property != "cursorWidth"
1047 #ifndef KEXI_SHOW_UNFINISHED
1048                  && property != "paper"
1049 #endif
1050                  && property != "textInteractionFlags"
1051 //! @todo support textInteractionFlags property of QLabel and QTextEdit
1052              );
1053     else if (classname == "KexiDBForm")
1054         ok = property != "iconText"
1055              && property != "geometry" /*nonsense for toplevel widget; for size, "size" property is used*/;
1056     else if (classname == "KexiDBLabel" || classname == "QLabel")
1057         ok = property != "focusPolicy"
1058              && property != "textInteractionFlags"
1059              && property != "pixmap";
1060 //! @todo support textInteractionFlags property of QLabel
1061     else if (classname == "KexiLineWidget" || classname == "Line") {
1062         ok = property != "frameShape" && property != "font" && property != "margin";
1063     }
1064 #ifdef KEXI_AUTOFIELD_FORM_WIDGET_SUPPORT
1065     else if (classname == "KexiDBAutoField") {
1066         if (!isTopLevel && property == "caption")
1067             return true; //force
1068         if (property == "fieldTypeInternal" || property == "fieldCaptionInternal"
1069 //! @todo unhide in 2.0
1070                 || property == "widgetType")
1071             return false;
1072         ok = property != "text"; /* "text" is not needed as "caption" is used instead */
1073     }
1074 #endif
1075     else if (classname == "KexiDBImageBox" || classname == "KexiPictureLabel") {
1076         ok = property != "font" && property != "pixmapId"
1077              && property != "text" && property != "indent" && property != "textFormat";
1078     }
1079     else if (classname == "KexiDBCheckBox" || classname == "QCheckBox") {
1080         //hide text property if the widget is a child of an autofield beause there's already "caption" for this purpose
1081         if (property == "text" && w && dynamic_cast<KFormDesigner::WidgetWithSubpropertiesInterface*>(w->parentWidget()))
1082             return false;
1083         ok = KFormDesigner::WidgetFactory::advancedPropertiesVisible() || property != "autoRepeat";
1084     }
1085 #ifdef KEXI_SHOW_UNFINISHED
1086     else if (classname == "QRadioButton") {
1087         ok = KFormDesigner::WidgetFactory::advancedPropertiesVisible() || (property != "autoRepeat");
1088     }
1089 #endif
1090     else if (classname == "KexiDBDatePicker") {
1091         ok = property != "closeButton"
1092              && property != "fontSize";
1093     } else if (classname == "QGroupBox") {
1094         ok =
1095 #ifndef KEXI_SHOW_UNFINISHED
1096             /*! @todo Hidden for now in Kexi. "checkable" and "checked" props need adding
1097             a fake properties which will allow to properly work in design mode, otherwise
1098             child widgets become frozen when checked==true */
1099             (KFormDesigner::WidgetFactory::advancedPropertiesVisible() || (property != "checkable" && property != "checked")) &&
1100 #endif
1101             true;
1102     } else if (classname == "KFDTabWidget") {
1103         ok = (KFormDesigner::WidgetFactory::advancedPropertiesVisible()
1104              || (property != "tabReorderingEnabled"
1105                  && property != "hoverCloseButton"
1106                  && property != "hoverCloseButtonDelayed"));
1107     }
1108     return ok && KexiDBFactoryBase::isPropertyVisibleInternal(classname, w, property, isTopLevel);
1109 }
1110 
1111 bool
propertySetShouldBeReloadedAfterPropertyChange(const QByteArray & classname,QWidget * w,const QByteArray & property)1112 KexiMainFormWidgetsFactory::propertySetShouldBeReloadedAfterPropertyChange(const QByteArray& classname,
1113         QWidget *w, const QByteArray& property)
1114 {
1115     Q_UNUSED(classname);
1116     Q_UNUSED(w);
1117     return property == "fieldTypeInternal" || property == "widgetType"
1118            || property == "paletteBackgroundColor" || property == "autoFillBackground";
1119 }
1120 
changeInlineText(KFormDesigner::Form * form,QWidget * widget,const QString & text,QString & oldText)1121 bool KexiMainFormWidgetsFactory::changeInlineText(KFormDesigner::Form *form, QWidget *widget,
1122     const QString &text, QString &oldText)
1123 {
1124     const QByteArray n(widget->metaObject()->className());
1125     if (false) {
1126     }
1127 #ifdef KEXI_AUTOFIELD_FORM_WIDGET_SUPPORT
1128     else if (n == "KexiDBAutoField") {
1129         oldText = widget->property("caption").toString();
1130         changeProperty(form, widget, "caption", text);
1131         return true;
1132     }
1133 #endif
1134 #ifdef KEXI_SHOW_UNFINISHED
1135     else if (n == "KIntSpinBox") {
1136         oldText = QString::number(qobject_cast<QSpinBox*>(widget)->value());
1137         qobject_cast<QSpinBox*>(widget)->setValue(text.toInt());
1138     }
1139 #endif
1140     else {
1141         oldText = widget->property("text").toString();
1142         changeProperty(form, widget, "text", text);
1143         return true;
1144     }
1145 //! @todo check field's geometry
1146     return false;
1147 }
1148 
1149 void
resizeEditor(QWidget * editor,QWidget * w,const QByteArray & classname)1150 KexiMainFormWidgetsFactory::resizeEditor(QWidget *editor, QWidget *w, const QByteArray &classname)
1151 {
1152     QSize s = w->size();
1153     QPoint p = w->pos();
1154     QRect r;
1155 
1156     if (classname == "KexiDBCheckBox") {
1157         QStyleOptionButton option;
1158         option.initFrom(w);
1159         r = w->style()->subElementRect(QStyle::SE_CheckBoxContents, &option, w);
1160         p += r.topLeft();
1161         s.setWidth(r.width());
1162     } else if (classname == "KexiDBPushButton") {
1163         QStyleOptionButton option;
1164         option.initFrom(w);
1165         r = w->style()->subElementRect(QStyle::SE_PushButtonContents, &option, w);
1166         p += r.topLeft();
1167         s = r.size();
1168     }
1169 #ifdef KEXI_SHOW_UNFINISHED
1170     else if (classname == "QRadioButton") {
1171         QStyleOptionButton option;
1172         option.initFrom(w);
1173         r = w->style()->subElementRect(
1174                 QStyle::SE_RadioButtonContents, &option, w);
1175         p += r.topLeft();
1176         s.setWidth(r.width());
1177 #endif
1178 
1179     editor->resize(s);
1180     editor->move(p);
1181 
1182     //! @todo KEXI3
1183     /* from ContainerFactory::resizeEditor(QWidget *editor, QWidget *widget, const QByteArray &):
1184         QSize s = w->size();
1185         editor->move(w->x() + 2, w->y() - 5);
1186         editor->resize(s.width() - 20, w->fontMetrics().height() + 10); */
1187 
1188 #ifdef KEXI_AUTOFIELD_FORM_WIDGET_SUPPORT
1189     if (classname == "KexiDBAutoField") {
1190         editor->setGeometry(static_cast<KexiDBAutoField*>(w)->label()->geometry());
1191     }
1192 #endif
1193 }
1194 
1195 bool KexiMainFormWidgetsFactory::saveSpecialProperty(const QByteArray &classname,
1196     const QString &name, const QVariant &, QWidget *w, QDomElement &parentNode,
1197     QDomDocument &domDoc)
1198 {
1199     Q_UNUSED(classname)
1200     if (false) {
1201     }
1202 /* TODO
1203     else if (name == "list_items" && classname == "KexiDBComboBox") {
1204         KexiDBComboBox *combo = qobject_cast<KexiDBComboBox*>(w);
1205         for (int i = 0; i < combo->row; i++) {
1206             QDomElement item = domDoc.createElement("item");
1207             KFormDesigner::FormIO::savePropertyElement(item, domDoc, "property", "text", combo->itemText(i));
1208             parentNode.appendChild(item);
1209         }
1210         return true;
1211     }
1212 */
1213 #ifdef KEXI_LIST_FORM_WIDGET_SUPPORT
1214     else if (name == "list_contents" && classname == "QTreeWidget") {
1215         QTreeWidget *treewidget = qobject_cast<QTreeWidget*>(w);
1216         // First we save the columns
1217         QTreeWidgetItem *headerItem = treewidget->headerItem();
1218         if (headerItem) {
1219             for (int i = 0; i < treewidget->columnCount(); i++) {
1220                 QDomElement item = domDoc.createElement("column");
1221                 KFormDesigner::FormIO::savePropertyElement(
1222                     item, domDoc, "property", "text", headerItem->text(i));
1223                 KFormDesigner::FormIO::savePropertyElement(
1224                     item, domDoc, "property", "width", treewidget->columnWidth(i));
1225                 KFormDesigner::FormIO::savePropertyElement(
1226                     item, domDoc, "property", "resizable", treewidget->header()->isResizeEnabled(i));
1227                 KFormDesigner::FormIO::savePropertyElement(
1228                     item, domDoc, "property", "clickable", treewidget->header()->isClickEnabled(i));
1229                 KFormDesigner::FormIO::savePropertyElement(
1230                     item, domDoc, "property", "fullwidth", treewidget->header()->isStretchEnabled(i));
1231                 parentNode.appendChild(item);
1232             }
1233         }
1234         // Then we save the list view items
1235         QTreeWidgetItem *item = listwidget->firstChild();
1236         while (item) {
1237             saveListItem(item, parentNode, domDoc);
1238             item = item->nextSibling();
1239         }
1240         return true;
1241     }
1242 #endif
1243     else if (name == "title" && w->parentWidget()->parentWidget()->inherits("QTabWidget")) {
1244         TabWidgetBase *tab = qobject_cast<TabWidgetBase*>(w->parentWidget()->parentWidget());
1245         KFormDesigner::FormIO::savePropertyElement(
1246             parentNode, domDoc, "attribute", "title", tab->tabText(tab->indexOf(w)));
1247     }
1248     return true;
1249 }
1250 
1251 #ifdef KEXI_LIST_FORM_WIDGET_SUPPORT
1252 void KexiMainFormWidgetsFactory::saveListItem(QListWidgetItem *item,
1253                                               QDomNode &parentNode, QDomDocument &domDoc)
1254 {
1255     QDomElement element = domDoc.createElement("item");
1256     parentNode.appendChild(element);
1257 
1258     // We save the text of each column
1259     for (int i = 0; i < item->listWidget()->columns(); i++) {
1260         KFormDesigner::FormIO::savePropertyElement(
1261             element, domDoc, "property", "text", item->text(i));
1262     }
1263 
1264     // Then we save every sub items
1265     QListWidgetItem *child = item->firstChild();
1266     while (child) {
1267         saveListItem(child, element, domDoc);
1268         child = child->nextSibling();
1269     }
1270 }
1271 
1272 void KexiMainFormWidgetsFactory::readTreeItem(
1273     QDomElement &node, QTreeWidgetItem *parent, QTreeWidget *treewidget)
1274 {
1275     QTreeWidgetItem *item;
1276     if (parent)
1277         item = new QTreeWidgetItem(parent);
1278     else
1279         item = new QTreeWidgetItem(treewidget);
1280 
1281     // We need to move the item at the end of the list
1282     QTreeWidgetItem *last;
1283     if (parent)
1284         last = parent->firstChild();
1285     else
1286         last = treewidget->firstChild();
1287 
1288     while (last->nextSibling())
1289         last = last->nextSibling();
1290     item->moveItem(last);
1291 
1292     int i = 0;
1293     for (QDomNode n = node.firstChild(); !n.isNull(); n = n.nextSibling()) {
1294         QDomElement childEl = n.toElement();
1295         QString prop = childEl.attribute("name");
1296         QString tag = childEl.tagName();
1297 
1298         // We read sub items
1299         if (tag == "item") {
1300             item->setOpen(true);
1301             readListItem(childEl, item, treewidget);
1302         }
1303         // and column texts
1304         else if (tag == "property" && prop == "text") {
1305             QVariant val = KFormDesigner::FormIO::readPropertyValue(
1306                 n.firstChild(), treewidget, "item");
1307             item->setText(i, val.toString());
1308             i++;
1309         }
1310     }
1311 }
1312 
1313 void KexiMainFormWidgetsFactory::editListContents()
1314 {
1315     if (widget()->inherits("QTreeWidget"))
1316         editTreeWidget(qobject_cast<QTreeWidget*>(widget()));
1317 }
1318 #endif
1319 
1320 bool KexiMainFormWidgetsFactory::readSpecialProperty(const QByteArray &classname,
1321                                                      QDomElement &node, QWidget *w,
1322                                                      KFormDesigner::ObjectTreeItem *item)
1323 {
1324     Q_UNUSED(classname)
1325     const QString tag(node.tagName());
1326     const QString name(node.attribute("name"));
1327 //    KFormDesigner::Form *form = item->container()
1328 //            ? item->container()->form() : item->parent()->container()->form();
1329 
1330     if (false) {
1331     }
1332 /* TODO
1333     else if (tag == "item" && classname == "KComboBox") {
1334         KComboBox *combo = qobject_cast<KComboBox*>(w);
1335         QVariant val = KFormDesigner::FormIO::readPropertyValue(
1336                     form, node.firstChild().firstChild(), w, name);
1337         if (val.canConvert(QVariant::Pixmap))
1338             combo->addItem(val.value<QPixmap>(), QString());
1339         else
1340             combo->addItem(val.toString());
1341         return true;
1342     }*/
1343 #ifdef KEXI_LIST_FORM_WIDGET_SUPPORT
1344     else if (tag == "column" && classname == "QTreeWidget") {
1345         QTreeWidget *tw = qobject_cast<QTreeWidget*>(w);
1346         int id = 0;
1347         for (QDomNode n = node.firstChild(); !n.isNull(); n = n.nextSibling()) {
1348             QString prop = n.toElement().attribute("name");
1349             QVariant val = KFormDesigner::FormIO::readPropertyValue(n.firstChild(), w, name);
1350             if (prop == "text")
1351                 id = tw->addColumn(val.toString());
1352             else if (prop == "width")
1353                 tw->setColumnWidth(id, val.toInt());
1354             else if (prop == "resizable")
1355                 tw->header()->setResizeEnabled(val.toBool(), id);
1356             else if (prop == "clickable")
1357                 tw->header()->setClickEnabled(val.toBool(), id);
1358             else if (prop == "fullwidth")
1359                 tw->header()->setStretchEnabled(val.toBool(), id);
1360         }
1361         return true;
1362     }
1363     else if (tag == "item" && classname == "QTreeWidget") {
1364         QTreeWidget *tw = qobject_cast<QTreeWidget*>(w);
1365         readListItem(node, 0, tw);
1366         return true;
1367     }
1368 #endif
1369     else if (name == "title" && item->parent()->widget()->inherits("QTabWidget")) {
1370         TabWidgetBase *tab = qobject_cast<TabWidgetBase*>(w->parentWidget());
1371         tab->addTab(w, node.firstChild().toElement().text());
1372         item->addModifiedProperty("title", node.firstChild().toElement().text());
1373         return true;
1374     }
1375     return false;
1376 }
1377 
1378 void KexiMainFormWidgetsFactory::setPropertyOptions(KPropertySet& set,
1379                                                     const KFormDesigner::WidgetInfo& info,
1380                                                     QWidget *w)
1381 {
1382     Q_UNUSED(info);
1383     Q_UNUSED(w);
1384     if (set.contains("indent")) {
1385         set["indent"].setOption("min", -1);
1386         set["indent"].setOption("minValueText", xi18nc("default indent value", "default"));
1387     }
1388 }
1389 
1390 void KexiMainFormWidgetsFactory::reorderTabs(int oldpos, int newpos)
1391 {
1392     KFDTabWidget *tabWidget = qobject_cast<KFDTabWidget*>(sender());
1393     KFormDesigner::ObjectTreeItem *tab
1394             = tabWidget->container()->form()->objectTree()->lookup(tabWidget->objectName());
1395     if (!tab)
1396         return;
1397 
1398     tab->children()->move(oldpos, newpos);
1399 }
1400 
1401 KFormDesigner::ObjectTreeItem* KexiMainFormWidgetsFactory::selectableItem(
1402                                                 KFormDesigner::ObjectTreeItem* item)
1403 {
1404     if (item->parent() && item->parent()->widget()) {
1405         if (qobject_cast<QTabWidget*>(item->parent()->widget())) {
1406             // tab widget's page
1407             return item->parent();
1408         }
1409     }
1410     return item;
1411 }
1412 
1413 void KexiMainFormWidgetsFactory::slotImageBoxIdChanged(KexiBLOBBuffer::Id_t id)
1414 {
1415     KexiFormView *formView = KDbUtils::findParent<KexiFormView*>((QWidget*)sender());
1416     if (formView) {
1417         changeProperty(formView->form(), formView, "pixmapId", int(/*! @todo unsafe */id));
1418         formView->setUnsavedLocalBLOB(formView->form()->selectedWidget(), id);
1419     }
1420 }
1421 
1422 #include "KexiMainFormWidgetsFactory.moc"
1423