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