summaryrefslogtreecommitdiffstats
path: root/kexi/formeditor/widgetfactory.h
blob: 43736ebcde5463ff3d77694f345200381523e183 (plain)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
253
254
255
256
257
258
259
260
261
262
263
264
265
266
267
268
269
270
271
272
273
274
275
276
277
278
279
280
281
282
283
284
285
286
287
288
289
290
291
292
293
294
295
296
297
298
299
300
301
302
303
304
305
306
307
308
309
310
311
312
313
314
315
316
317
318
319
320
321
322
323
324
325
326
327
328
329
330
331
332
333
334
335
336
337
338
339
340
341
342
343
344
345
346
347
348
349
350
351
352
353
354
355
356
357
358
359
360
361
362
363
364
365
366
367
368
369
370
371
372
373
374
375
376
377
378
379
380
381
382
383
384
385
386
387
388
389
390
391
392
393
394
395
396
397
398
399
400
401
402
403
404
405
406
407
408
409
410
411
412
413
414
415
416
417
418
419
420
421
422
423
424
425
426
427
428
429
430
431
432
433
434
435
436
437
438
439
440
441
442
443
444
445
446
447
448
449
450
451
452
453
454
455
456
457
458
459
460
461
462
463
464
465
466
467
468
469
470
471
472
473
474
475
476
477
478
479
480
481
482
483
484
485
486
487
488
489
490
491
492
493
494
495
496
497
498
499
500
501
502
503
504
505
506
507
508
509
510
511
512
513
514
515
516
517
518
/* This file is part of the KDE project
   Copyright (C) 2003 Lucijan Busch <lucijan@gmx.at>
   Copyright (C) 2004 Cedric Pasteur <cedric.pasteur@free.fr>
   Copyright (C) 2004-2006 Jaroslaw Staniek <js@iidea.pl>

   This library is free software; you can redistribute it and/or
   modify it under the terms of the GNU Library General Public
   License as published by the Free Software Foundation; either
   version 2 of the License, or (at your option) any later version.

   This library is distributed in the hope that it will be useful,
   but WITHOUT ANY WARRANTY; without even the implied warranty of
   MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
   Library General Public License for more details.

   You should have received a copy of the GNU Library General Public License
   along with this library; see the file COPYING.LIB.  If not, write to
   the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor,
 * Boston, MA 02110-1301, USA.
*/

#ifndef KFORMDESIGNERWIDGETFACTORY_H
#define KFORMDESIGNERWIDGETFACTORY_H


#include <qobject.h>
#include <qguardedptr.h>
#include <qpixmap.h>
#include <qpopupmenu.h>
#include <qasciidict.h>

#include <kexiutils/tristate.h>

// class QPixmap;
template<class type> class QValueVector;
template<class type> class QPtrList;
template<class type> class QDict;
class QWidget;
class QDomElement;
class QDomDocument;
class QVariant;
class QListView;
class KActionCollection;
class KTextEdit;
class KLineEdit;
class KXMLGUIClient;

namespace KoProperty {
	class Set;
}

namespace KFormDesigner {

class WidgetFactory;
class WidgetLibrary;
class Container;
class ResizeHandleSet;
class ObjectTreeItem;
class WidgetPropertySet;
class Form;

/**
 * This class holds properties of widget classes provided by a factory.
 */
class KFORMEDITOR_EXPORT WidgetInfo
{
	public:
		typedef QPtrList<WidgetInfo> List;
		typedef QAsciiDict<WidgetInfo> Dict;

		WidgetInfo(WidgetFactory *f);

		WidgetInfo(WidgetFactory *f, const char* parentFactoryName, const char* inheritedClassName = 0);

		virtual ~WidgetInfo();

		//! \return a pixmap associated with the widget
		QString pixmap() const { return m_pixmap; }

		//! \return the class name of a widget e.g. 'QLineEdit'
		QCString className() const { return m_class; }

		/*! \return the name used to name widget, that will appear eg in scripts (must not contain spaces
		  nor non-latin1 characters) */
		QString namePrefix() const { return m_prefixName; }

		//! \return the real name e.g. 'Line Edit', showed eg in ObjectTreeView
		QString name() const { return m_name; }

		QString description() const { return m_desc; }
		QString includeFileName() const { return m_include; }
		QValueList<QCString> alternateClassNames() const { return m_alternateNames; }
		QString savingName() const { return m_saveName; }
		WidgetFactory *factory() const { return m_factory; }

		void setPixmap(const QString &p) { m_pixmap = p; }
		void setClassName(const QCString &s) { m_class = s; }
		void setName(const QString &n) { m_name = n; }
		void setNamePrefix(const QString &n) { m_prefixName = n; }
		void setDescription(const QString &desc) { m_desc = desc;}

		/*! Sets the C++ include file corresponding to this class,
		 that uic will need to add when creating the file. You don't have to set this for Qt std widgets.*/
		void setIncludeFileName(const QString &name) { m_include = name;}

		/*! Sets alternate names for this class.
		 If this name is found when loading a .ui file, the className() will be used instead.
		 It allows to support both KDE and Qt versions of widget, without duplicating code.
		 As a rule, className() should always return a class name which is inherited from
		 alternate class. For example KListView class has alternate QListView class.

		 \a override parameter overrides class name of a widget,
		 even if it was implemented in other factory.
		 By default it's set to false, what means that no other class is overridden
		 by this widget class if there is already a class implementing it
		 (no matter in which factory).
		 By forced overriding existing class with other - custom, user
		 will be able to see more or less properties and experience different behaviour.
		 For example, in Kexi application, KLineEdit class contains additional
		 "datasource" property for binding to database sources.
		*/
		void addAlternateClassName(const QCString& alternateName, bool override = false);

		/*! \return true is a class \a alternateName is defined as alternate name with
		 'override' flag set to true, using addAlternateClassName().
		 If this flag is set to false (the default) or there's no such alternate class
		 name defined. */
		bool isOverriddenClassName(const QCString& alternateName) const;

		/*! Sets the name that will be written in the .ui file when saving.
		 This name must be one of alternate names (or loading will be impossible).

		 On form data saving to XML .ui format, saveName is used instead,
		 so .ui format is not broken and still usable with other software as Qt Designer.
		 Custom properties are saved as well with 'stdset' attribute set to 0. */
		void setSavingName(const QString &saveName) { m_saveName = saveName; }

		/*! Sets autoSync flag for property \a propertyName.
		 This allows to override autoSync flag for certain widget's property, because
		 e.g. KoProperty::Editor can have autoSync flag set to false or true, but
		 not all properties have to comply with that.
		 \a flag equal to cancelled value means there is no overriding (the default). */
		void setAutoSyncForProperty(const char *propertyName, tristate flag);

		/*! \return autoSync override value (true or false) for \a propertyName.
		 If cancelled value is returned, there is no overriding (the default). */
		tristate autoSyncForProperty(const char *propertyName) const;

		QCString parentFactoryName() const { return m_parentFactoryName; }

		WidgetInfo* inheritedClass() const { return m_inheritedClass; }

		/*! Sets custom type \a type for property \a propertyName. 
		 This allows to override default type, especially when custom property 
		 and custom property editor item has to be used. */
		void setCustomTypeForProperty(const char *propertyName, int type);

		/*! \return custom type for property \a propertyName. If no specific custom type has been assigned,
		 KoProperty::Auto is returned. 
		 @see setCustomTypeForProperty() */
		int customTypeForProperty(const char *propertyName) const;

	protected:
		QCString m_parentFactoryName, m_inheritedClassName; //!< Used for inheriting widgets between factories
		WidgetInfo* m_inheritedClass;

	private:
		QString m_pixmap;
		QCString m_class;
		QString m_name;
		QString m_prefixName;
		QString m_desc;
		QString m_include;
		QValueList<QCString> m_alternateNames;
		QAsciiDict<char> *m_overriddenAlternateNames;
		QString m_saveName;
		QGuardedPtr<WidgetFactory> m_factory;
		QAsciiDict<char> *m_propertiesWithDisabledAutoSync;
		QMap<QCString,int> *m_customTypesForProperty;

	friend class WidgetLibrary;
};

//! The base class for all widget Factories
/*! This is the class you need to inherit to create a new Factory. There are few
 virtuals you need to implement, and some other functions
 to implement if you want more features.\n \n

  <b>Widget Creation</b>\n
  To be able to create widgets, you need to implement the create() function, an classes(),
  which should return all the widgets supported by this factory.\n \n

  <b>GUI Integration</b>\n
  The following functions allow you to customize even more the look-n-feel of your widgets inside KFormDesigner.
  You can use createMenuActions() to add custom items in widget's context menu. The previewWidget()
  is called when the Form gets in Preview mode, and you have a last opportunity to remove all editing-related
  stuff (see eg \ref Spring class).\n
  You can also choose which properties to show in the Property Editor. 
  By default, most all properties are shown (see implementation for details),
  but you can hide some reimplementing isPropertyVisibleInternal() (don't forget to call superclass' method)
  To add new properties, just define new Q_PROPERTY in widget class definition.\n \n

  <b>Inline editing</b>\n
  KFormDesigner allow you to edit the widget's contents inside Form, without using a dialog.
  You can of course customize the behaviour of your widgets, using startEditing(). There are some editing
  modes already implemented in WidgetFactroy, but you can create your own if you want:
  \li Editing using a line edit (createEditor()): a line edit is created on top of widget,
  where the user inputs text. As the text changes, changeText() is called
  (where you should set your widget's text and resize widget to fit the text if needed) and resizeEditor()
  to update editor's position when widget is moved/resized.\n
  \li Editing by disabling event filter: if you call disableFilter(), the event filter
   on the object is temporarily disabled, so the widget behaves as usual. This
  can be used for more complex widgets, such as spinbox, date/time edit, etc.
  \li Other modes: there are 3 other modes, to edit a string list: editList()
  (for combo box, listbox), to edit rich text: editRichText() (for labels, etc.)
  and to edit a listview: editListView(). \n \n

  <b>Widget saving/loading</b>\n
  You can also control how your widget are saved/loaded. You can choose which properties to save
   (see autoSaveProperties()), and save/load custom properties, ie
  properties that are not Q_PROPERTY but you want to save in the UI file. This is used eg to
   save combo box or listview contents (see saveSpecialProperty() and
  readSpecialProperty()). \n \n

  <b>Special internal properties</b>\n
  Use void setInternalProperty(const QCString& classname, const QCString& property, const QString& value);
  to set values of special internal properties.
  Currently these properties are used for customizing popup menu items used for orientation selection.
  Customization for class ClassName should look like:
  <code> void setInternalProperty("ClassName", "orientationSelectionPopup", "myicon"); </code>
  Available internal properties:
  * "orientationSelectionPopup" - set it to "1" if you want a given class to offer orientation selection,
     so orientation selection popup will be displayed when needed.
  * "orientationSelectionPopup:horizontalIcon" - sets a name of icon for "Horizontal" item
    for objects of class 'ClassName'. Set this property only for classes supporting orientations.
  * "orientationSelectionPopup:verticalIcon" - the same for "Vertical" item.
    Set this property only for classes supporting orientations.
  * "orientationSelectionPopup:horizontalText" - sets a i18n'd text for "Horizontal" item
    for objects of class 'ClassName', e.g. i18n("Insert Horizontal Line").
    Set this property only for classes supporting orientations.
  * "orientationSelectionPopup:verticalText" - the same for "Vertical" item,
    e.g. i18n("Insert Vertical Line"). Set this property only for classes supporting orientations.
  * "dontStartEditingOnInserting" - if not empty, WidgetFactory::startEditing() will not be executed upon
    widget inseting by a user.
  * "forceShowAdvancedProperty:{propertyname}" - set it to "1" for "{propertyname}" advanced property 
    if you want to force it to be visible even if WidgetLibrary::setAdvancedPropertiesVisible(false) 
    has been called. For example, setting "forceShowAdvancedProperty:pixmap" to "1" 
    unhides "pixmap" property for a given class.

  See StdWidgetFactory::StdWidgetFactory() for properties like
  "Line:orientationSelectionPopup:horizontalIcon".

  \n\n
  See the standard factories in formeditor/factories for an example of factories,
  and how to deal with complex widgets (eg tabwidget).
  */
class KFORMEDITOR_EXPORT WidgetFactory : public QObject
{
	Q_OBJECT
	public:
		//! Options used in createWidget()
		enum CreateWidgetOptions { 
			AnyOrientation = 1, //!< any orientation hint
			HorizontalOrientation = 2,  //!< horizontal orientation hint
			VerticalOrientation = 4, //!< vertical orientation hint
			DesignViewMode = 8, //!< create widget in design view mode, otherwise preview mode
			DefaultOptions = AnyOrientation | DesignViewMode
		};

		WidgetFactory(QObject *parent=0, const char *name=0);
		virtual ~WidgetFactory();

		/*! Adds a new class described by \a w. */
		void addClass(WidgetInfo *w);

		/*! This method allows to force a class \a classname to hidden.
		 It is useful if you do not want a class to be available
		 (e.g. because it is not implemented well yet for our purposes).
		 All widget libraries are affected by this setting. */
		void hideClass(const char *classname);

		/**
		 * \return all classes which are provided by this factory
		 */
		const WidgetInfo::Dict classes() const { return m_classesByName; }

		/**
		 * Creates a widget (and if needed a KFormDesigner::Container)
		 * \return the created widget
		 * \param classname the classname of the widget, which should get created
		 * \param parent the parent for the created widget
		 * \param name the name of the created widget
		 * \param container the toplevel Container (if a container should get created)
		 * \param options options for the created widget: orientation and view mode (see CreateWidgetOptions)
		 */
		virtual QWidget* createWidget(const QCString &classname, QWidget *parent, const char *name,
			KFormDesigner::Container *container, 
			int options = DefaultOptions) = 0;

		/*! Creates custom actions. Reimplement this if you need to add some 
		 actions coming from the factory. */
		virtual void createCustomActions(KActionCollection *col) { Q_UNUSED(col); };

		/*! This function can be used to add custom items in widget \a w context
		menu \a menu. */
		virtual bool createMenuActions(const QCString &classname, QWidget *w, QPopupMenu *menu,
		    KFormDesigner::Container *container)=0;

		/*! Creates (if necessary) an editor to edit the contents of the widget directly in the Form
		   (eg creates a line edit to change the text of a label). \a classname is
		   the class the widget belongs to, \a w is the widget to edit
		   and \a container is the parent container of this widget (to access Form etc.).
		 */
		virtual bool startEditing(const QCString &classname, QWidget *w, Container *container)=0;

		/*! This function is called just before the Form is previewed. It allows widgets
		 to make changes before switching (ie for a Spring, hiding the cross) */
		virtual bool previewWidget(const QCString &classname, QWidget *widget, Container *container)=0;

		virtual bool clearWidgetContent(const QCString &classname, QWidget *w);

		/*! This function is called when FormIO finds a property, at save time,
		 that it cannot handle (ie not a normal property).
		This way you can save special properties, for example the contents of a listbox.
		  \sa readSpecialProperty()
		 */
		virtual bool saveSpecialProperty(const QCString &classname, const QString &name,
			const QVariant &value, QWidget *w,
			QDomElement &parentNode, QDomDocument &parent);

		/*! This function is called when FormIO finds a property or an unknown
		element in a .ui file. You can this way load a special property, for
		  example the contents of a listbox.
		   \sa saveSpecialProperty()
		*/
		virtual bool readSpecialProperty(const QCString &classname, QDomElement &node,
			QWidget *w, ObjectTreeItem *item);

		/*! This function is used to know whether the \a property for the widget \a w
		should be shown or not in the PropertyEditor. If \a multiple is true,
		then multiple widgets of the same class are selected, and you should
		only show properties shared by widgets (eg font, color). By default,
		all properties are shown if multiple == true, and none if multiple == false. */
		bool isPropertyVisible(const QCString &classname, QWidget *w,
			const QCString &property, bool multiple, bool isTopLevel);

		/*! You need to return here a list of the properties that should automatically be saved
		for a widget belonging to \a classname, and your custom properties (eg "text"
		for label or button, "contents" for combobox...). */
		virtual QValueList<QCString> autoSaveProperties(const QCString &classname)=0;

		/*! \return The i18n'ed name of the property whose name is \a name,
		 that will be displayed in PropertyEditor. */
		inline QString propertyDescForName(const QCString &name) { return m_propDesc[name]; };

		/*! \return The i18n'ed name of the property's value whose name is \a name. */
		inline QString propertyDescForValue(const QCString &name) { return m_propValDesc[name]; };

		/*! This method is called after WidgetPropertySet was filled with properties
		 of a widget \a w, of class defined by \a info.
		 Default implementation does nothing.
		 Implement this if you need to set options for properties within the set \a buf. */
		virtual void setPropertyOptions( WidgetPropertySet& buf, const WidgetInfo& info, QWidget *w );

		/*! \return internal property \a property for a class \a classname.
		 Internal properties are not stored within objects, but can be just provided
		 to describe classes' details. */
		inline QString internalProperty(const QCString& classname, const QCString& property) const {
			return m_internalProp[classname+":"+property];
		}

	protected:
		/*! This function is called when we want to know whether the property should be visible.
		 Implement it in the factory; don't forget to call implementation in the superclass. 
		 Default implementation hides "caption", "icon", "sizeIncrement" and "iconText" properties. */
		virtual bool isPropertyVisibleInternal(const QCString &classname, QWidget *w,
			const QCString &property, bool isTopLevel);

		/*! Sometimes property sets should be reloaded when a given property value changed.
		 Implement it in the factory. Default implementation always returns false. */
		virtual bool propertySetShouldBeReloadedAfterPropertyChange(const QCString& classname, QWidget *w, 
			const QCString& property);

		/*! This function creates a KLineEdit to input some text and edit a widget's contents.
		 This can be used in startEditing(). \a text is the text to display by default
		  in the line edit, \a w is the edited widget, \a geometry is the geometry the new line
		   edit should have, and \a align is Qt::AlignmentFlags of the new line edit. */
		void createEditor(const QCString &classname, const QString &text,
			QWidget *w, Container *container, QRect geometry,
			int align, bool useFrame=false, bool multiLine = false,
			BackgroundMode background = Qt::NoBackground);

		/*! This function provides a simple editing mode : it justs disable event filtering
		for the widget, and it install it again when
		  the widget loose focus or Enter is pressed.
		*/
		void disableFilter(QWidget *w, Container *container);

		/*! This function creates a little dialog (a KEditListBox) to modify the contents
		 of a list (of strings). It can be used to modify the contents
		 of a combo box for instance. The modified list is copied
		 into \a list when the user presses "Ok".*/
		bool editList(QWidget *w, QStringList &list);

		/*! This function creates a little editor to modify rich text. It supports alignment,
		 subscript and superscript and all basic formatting properties.
		  If the user presses "Ok", the edited text is put in \a text.
		  If he presses "Cancel", nothing happens. */
		bool editRichText(QWidget *w, QString &text);

		/*! This function creates a dialog to modify the contents of a ListView. You can modify both
		columns and list items. The listview is automatically  updated if the user presses "Ok".*/
		void editListView(QListView *listview);

		/*! This function destroys the editor when it loses focus or Enter is pressed. */
		virtual bool  eventFilter(QObject *obj, QEvent *ev);

		/*! This function is used to modify a property of a widget (eg after editing it).
		Please use it instead of w->setProperty() to allow sync inside PropertyEditor.
		*/
		void changeProperty(const char *name, const QVariant &value, Form *form);

		/*! This function is called when the widget is resized,
		 and the \a editor size needs to be updated. */
		virtual void resizeEditor(QWidget *editor, QWidget *widget, const QCString &classname);

//		/*! Adds the i18n'ed description of a property, which will be shown in PropertyEditor. */
//		void  addPropertyDescription(Container *container, const char *prop, const QString &desc);

//		/*! Adds the i18n'ed description of a property value, which will be shown in PropertyEditor. */
//		void  addValueDescription(Container *container, const char *value, const QString &desc);

		/*! \return true if at least one class defined by this factory inherits
		 a class from other factory. Used in WidgetLibrary::loadFactories()
		 to load factories in proper order. */
		bool inheritsFactories();

	public slots:

		/*! @internal. This slot is called when the editor has lost focus or the user pressed Enter.
		It destroys the editor or installs again the event filter on the widget. */
		void resetEditor();

	protected slots:
		/*!
		Default implementation changes "text" property.
		You have to reimplement this function for editing inside the Form to work if your widget's
		property you want to change isn't named "text".
		This slot is called when the line edit text changes, and you have to make
		it really change the good property of the widget using changeProperty() (text, or title, etc.).
		*/
		virtual bool changeText(const QString &newText);

		void changeTextInternal(const QString& text);

		void slotTextChanged();

		/*! This slot is called when the editor is destroyed.*/
		void editorDeleted();
		void widgetDestroyed();

	protected:
		QString editorText() const;
		void setEditorText(const QString& text);
		void setEditor(QWidget *widget, QWidget *editor);
		QWidget *editor(QWidget *widget) const;
		void setWidget(QWidget *widget, Container *container);
		QWidget *widget() const;

		/*! Assigns \a value for internal property \a property for a class \a classname.
		 Internal properties are not stored within objects, but can be provided
		 to describe classes' details. */
		void setInternalProperty(const QCString& classname, const QCString& property, const QString& value);

		WidgetLibrary *m_library;
		QCString m_editedWidgetClass;
//#ifdef KEXI_KTEXTEDIT
//		QGuardedPtr<KTextEdit>  m_editor;
//#else
//		QGuardedPtr<KLineEdit>  m_editor;
//#endif
		QString m_firstText;
		QGuardedPtr<ResizeHandleSet> m_handles;
		QGuardedPtr<Container> m_container;
//		WidgetInfo::List m_classes;
		WidgetInfo::Dict m_classesByName;
		QAsciiDict<char>* m_hiddenClasses;

		//! i18n stuff
		QMap<QCString, QString> m_propDesc;
		QMap<QCString, QString> m_propValDesc;
		//! internal properties
		QMap<QCString, QString> m_internalProp;

		/*! flag useful to decide whether to hide some properties.
		 It's value is inherited from WidgetLibrary. */
		bool m_showAdvancedProperties;

		/*! Contains name of an XMLGUI file providing toolbar buttons 
		 (and menu items in the future?) for the factory. 
		 Can be empty, e.g. for the main factory which has XMLGUI defined in the shell window itself
		 (e.g. kexiformpartinstui.rc for Kexi Forms). This name is set in WidgetLibrary::loadFactories() */
		QString m_xmlGUIFileName;

		KXMLGUIClient *m_guiClient;

		QGuardedPtr<QWidget> m_widget;
		QGuardedPtr<QWidget> m_editor;

	friend class WidgetLibrary;
};

//! macro to declare KFormDesigner-compatible widget factory as a KDE Component factory
#define KFORMDESIGNER_WIDGET_FACTORY(factoryClassName, libraryName) \
	K_EXPORT_COMPONENT_FACTORY(kformdesigner_ ## libraryName, KGenericFactory<factoryClassName>("kformdesigner_" # libraryName))

}
#endif