source: trunk/doc/src/examples/containerextension.qdoc@ 357

Last change on this file since 357 was 2, checked in by Dmitry A. Kuminov, 16 years ago

Initially imported qt-all-opensource-src-4.5.1 from Trolltech.

File size: 23.9 KB
Line 
1/****************************************************************************
2**
3** Copyright (C) 2009 Nokia Corporation and/or its subsidiary(-ies).
4** Contact: Qt Software Information (qt-info@nokia.com)
5**
6** This file is part of the documentation of the Qt Toolkit.
7**
8** $QT_BEGIN_LICENSE:LGPL$
9** Commercial Usage
10** Licensees holding valid Qt Commercial licenses may use this file in
11** accordance with the Qt Commercial License Agreement provided with the
12** Software or, alternatively, in accordance with the terms contained in
13** a written agreement between you and Nokia.
14**
15** GNU Lesser General Public License Usage
16** Alternatively, this file may be used under the terms of the GNU Lesser
17** General Public License version 2.1 as published by the Free Software
18** Foundation and appearing in the file LICENSE.LGPL included in the
19** packaging of this file. Please review the following information to
20** ensure the GNU Lesser General Public License version 2.1 requirements
21** will be met: http://www.gnu.org/licenses/old-licenses/lgpl-2.1.html.
22**
23** In addition, as a special exception, Nokia gives you certain
24** additional rights. These rights are described in the Nokia Qt LGPL
25** Exception version 1.0, included in the file LGPL_EXCEPTION.txt in this
26** package.
27**
28** GNU General Public License Usage
29** Alternatively, this file may be used under the terms of the GNU
30** General Public License version 3.0 as published by the Free Software
31** Foundation and appearing in the file LICENSE.GPL included in the
32** packaging of this file. Please review the following information to
33** ensure the GNU General Public License version 3.0 requirements will be
34** met: http://www.gnu.org/copyleft/gpl.html.
35**
36** If you are unsure which license is appropriate for your use, please
37** contact the sales department at qt-sales@nokia.com.
38** $QT_END_LICENSE$
39**
40****************************************************************************/
41
42/*!
43 \example designer/containerextension
44 \title Container Extension Example
45
46 The Container Extension example shows how to create a custom
47 multi-page plugin for Qt Designer using the
48 QDesignerContainerExtension class.
49
50 \image containerextension-example.png
51
52 To provide a custom widget that can be used with \QD, we need to
53 supply a self-contained implementation. In this example we use a
54 custom multi-page widget designed to show the container extension
55 feature.
56
57 An extension is an object which modifies the behavior of \QD. The
58 QDesignerContainerExtension enables \QD to manage and manipulate a
59 custom multi-page widget, i.e. adding and deleting pages to the
60 widget.
61
62 There are four available types of extensions in \QD:
63
64 \list
65 \o QDesignerMemberSheetExtension provides an extension that allows
66 you to manipulate a widget's member functions which is displayed
67 when configuring connections using Qt Designer's mode for editing
68 signals and slots.
69 \o QDesignerPropertySheetExtension provides an extension that
70 allows you to manipulate a widget's properties which is displayed
71 in Qt Designer's property editor.
72 \o QDesignerTaskMenuExtension provides an extension that allows
73 you to add custom menu entries to \QD's task menu.
74 \o QDesignerContainerExtension provides an extension that allows
75 you to add (and delete) pages to a multi-page container plugin
76 in \QD.
77 \endlist
78
79 You can use all the extensions following the same pattern as in
80 this example, only replacing the respective extension base
81 class. For more information, see the \l {QtDesigner Module}.
82
83 The Container Extension example consists of four classes:
84
85 \list
86 \o \c MultiPageWidget is a custom container widget that lets the user
87 manipulate and populate its pages, and navigate among these
88 using a combobox.
89 \o \c MultiPageWidgetPlugin exposes the \c MultiPageWidget class
90 to \QD.
91 \o \c MultiPageWidgetExtensionFactory creates a
92 \c MultiPageWidgetContainerExtension object.
93 \o \c MultiPageWidgetContainerExtension provides the container
94 extension.
95 \endlist
96
97 The project file for custom widget plugins needs some additional
98 information to ensure that they will work within \QD. For example,
99 custom widget plugins rely on components supplied with \QD, and
100 this must be specified in the project file that we use. We will
101 first take a look at the plugin's project file.
102
103 Then we will continue by reviewing the \c MultiPageWidgetPlugin
104 class, and take a look at the \c MultiPageWidgetExtensionFactory
105 and \c MultiPageWidgetContainerExtension classes. Finally, we will
106 take a quick look at the \c MultiPageWidget class definition.
107
108 \section1 The Project File: containerextension.pro
109
110 The project file must contain some additional information to
111 ensure that the plugin will work as expected:
112
113 \snippet examples/designer/containerextension/containerextension.pro 0
114 \snippet examples/designer/containerextension/containerextension.pro 1
115
116 The \c TEMPLATE variable's value makes \c qmake create the custom
117 widget as a library. Later, we will ensure that the widget will be
118 recognized as a plugin by Qt by using the Q_EXPORT_PLUGIN2() macro
119 to export the relevant widget information.
120
121 The \c CONFIG variable contains two values, \c designer and \c
122 plugin:
123
124 \list
125 \o \c designer: Since custom widgets plugins rely on components
126 supplied with \QD, this value ensures that our plugin links against
127 \QD's library (\c libQtDesigner.so).
128
129 \o \c plugin: We also need to ensure that \c qmake considers the
130 custom widget a \e plugin library.
131 \endlist
132
133 When Qt is configured to build in both debug and release modes,
134 \QD will be built in release mode. When this occurs, it is
135 necessary to ensure that plugins are also built in release
136 mode. For that reason we add a \c debug_and_release value to the
137 \c CONFIG variable. Otherwise, if a plugin is built in a mode that
138 is incompatible with \QD, it won't be loaded and installed.
139
140 The header and source files for the widget are declared in the
141 usual way:
142
143 \snippet examples/designer/containerextension/containerextension.pro 2
144
145 We provide an implementation of the plugin interface so that \QD
146 can use the custom widget. In this particular example we also
147 provide implementations of the container extension interface and
148 the extension factory.
149
150 It is important to ensure that the plugin is installed in a
151 location that is searched by \QD. We do this by specifying a
152 target path for the project and adding it to the list of items to
153 install:
154
155 \snippet doc/src/snippets/code/doc_src_examples_containerextension.qdoc 0
156
157 The container extension is created as a library, and will be
158 installed alongside the other \QD plugins when the project is
159 installed (using \c{make install} or an equivalent installation
160 procedure).
161
162 Note that if you want the plugins to appear in a Visual Studio
163 integration, the plugins must be built in release mode and their
164 libraries must be copied into the plugin directory in the install
165 path of the integration (for an example, see \c {C:/program
166 files/trolltech as/visual studio integration/plugins}).
167
168 For more information about plugins, see the \l {How to Create Qt
169 Plugins} documentation.
170
171 \section1 MultiPageWidgetPlugin Class Definition
172
173 The \c MultiPageWidgetPlugin class exposes the \c MultiPageWidget
174 class to \QD. Its definition is similar to the \l
175 {designer/customwidgetplugin}{Custom Widget Plugin} example's
176 plugin class which is explained in detail. The parts of the class
177 definition that is specific to this particular custom widget is
178 the class name and a couple of private slots:
179
180 \snippet examples/designer/containerextension/multipagewidgetplugin.h 0
181
182 The plugin class provides \QD with basic information about our
183 plugin, such as its class name and its include file. Furthermore
184 it knows how to create instances of the \c MultiPageWidget widget.
185 \c MultiPageWidgetPlugin also defines the \l
186 {QDesignerCustomWidgetInterface::initialize()}{initialize()}
187 function which is called after the plugin is loaded into \QD. The
188 function's QDesignerFormEditorInterface parameter provides the
189 plugin with a gateway to all of \QD's API's.
190
191 In the case of a multipage widget such as ours, we must also implement
192 two private slots, currentIndexChanged() and pageTitleChanged(),
193 to be able to update \QD's property editor whenever the user views
194 another page or changes one of the page titles. To be able to give
195 each page their own title, we have chosen to use the
196 QWidget::windowTitle property to store the page title (for more
197 information see the MultiPageWidget class \l
198 {designer/containerextension/multipagewidget.cpp}{implementation}). Note
199 that currently there is no way of adding a custom property (e.g.,
200 a page title) to the pages without using a predefined property as
201 placeholder.
202
203 The \c MultiPageWidgetPlugin class inherits from both QObject and
204 QDesignerCustomWidgetInterface. It is important to remember, when
205 using multiple inheritance, to ensure that all the interfaces
206 (i.e. the classes that doesn't inherit Q_OBJECT) are made known to
207 the meta object system using the Q_INTERFACES() macro. This
208 enables \QD to use \l qobject_cast() to query for supported
209 interfaces using nothing but a QObject pointer.
210
211 \section1 MultiPageWidgetPlugin Class Implementation
212
213 The MultiPageWidgetPlugin class implementation is in most parts
214 equivalent to the \l {designer/customwidgetplugin}{Custom Widget
215 Plugin} example's plugin class:
216
217 \snippet examples/designer/containerextension/multipagewidgetplugin.cpp 0
218 \codeline
219 \snippet examples/designer/containerextension/multipagewidgetplugin.cpp 3
220
221 One of the functions that differ is the isContainer() function
222 which returns true in this example since our custom widget is
223 intended to be used as a container.
224
225 \snippet examples/designer/containerextension/multipagewidgetplugin.cpp 1
226
227 Another function that differ is the function creating our custom widget:
228
229 \snippet examples/designer/containerextension/multipagewidgetplugin.cpp 2
230
231 In addition to create and return the widget, we connect our custom
232 container widget's currentIndexChanged() signal to the plugin's
233 currentIndexChanged() slot to ensure that \QD's property editor is
234 updated whenever the user views another page. We also connect the
235 widget's pageTitleChanged() signal to the plugin's
236 pageTitleChanged() slot.
237
238 The currentIndexChanged() slot is called whenever our custom
239 widget's currentIndexChanged() \e signal is emitted, i.e. whenever
240 the user views another page:
241
242 \snippet examples/designer/containerextension/multipagewidgetplugin.cpp 8
243
244 First, we retrieve the object emitting the signal using the
245 QObject::sender() and qobject_cast() functions. If it's called in
246 a slot activated by a signal, QObject::sender() returns a pointer
247 to the object that sent the signal; otherwise it returns 0.
248
249 \snippet examples/designer/containerextension/multipagewidgetplugin.cpp 9
250
251 Once we have the widget we can update the property editor. \QD
252 uses the QDesignerPropertySheetExtension class to feed its
253 property editor, and whenever a widget is selected in its
254 workspace, Qt Designer will query for the widget's property sheet
255 extension and update the property editor.
256
257 So what we want to achieve is to notify \QD that our widget's \e
258 internal selection has changed: First we use the static
259 QDesignerFormWindowInterface::findFormWindow() function to
260 retrieve the QDesignerFormWindowInterface object containing the
261 widget. The QDesignerFormWindowInterface class allows you to query
262 and manipulate form windows appearing in Qt Designer's
263 workspace. Then, all we have to do is to emit its \l
264 {QDesignerFormWindowInterface::emitSelectionChanged()}{emitSelectionChanged()}
265 signal, forcing an update of the property editor.
266
267 When changing a page title a generic refresh of the property
268 editor is not enough because it is actually the page's property
269 extension that needs to be updated. For that reason we need to
270 access the QDesignerPropertySheetExtension object for the page
271 which title we want to change. The QDesignerPropertySheetExtension
272 class also allows you to manipulate a widget's properties, but to
273 get hold of the extension we must first retrieve access to \QD's
274 extension manager:
275
276 \snippet examples/designer/containerextension/multipagewidgetplugin.cpp 10
277 \snippet examples/designer/containerextension/multipagewidgetplugin.cpp 11
278
279 Again we first retrieve the widget emitting the signal, using the
280 QObject::sender() and qobject_cast() functions. Then we retrieve
281 the current page from the widget that emitted the signal, and we
282 use the static QDesignerFormWindowInterface::findFormWindow()
283 function to retrieve the form containing our widget.
284
285 \snippet examples/designer/containerextension/multipagewidgetplugin.cpp 12
286
287 Now that we have the form window, the QDesignerFormWindowInterface
288 class provides the \l
289 {QDesignerFormWindowInterface::core()}{core()} function which
290 returns the current QDesignerFormEditorInterface object. The
291 QDesignerFormEditorInterface class allows you to access Qt
292 Designer's various components. In particular, the
293 QDesignerFormEditorInterface::extensionManager() function returns
294 a reference to the current extension manager.
295
296 \snippet examples/designer/containerextension/multipagewidgetplugin.cpp 13
297
298 Once we have the extension manager we can update the extension
299 sheet: First we retrieve the property extension for the page which
300 title we want to change, using the qt_extension() function. Then
301 we retrieve the index for the page title using the
302 QDesignerPropertySheetExtension::indexOf() function. As previously
303 mentioned, we have chosen to use the QWidget::windowTitle property
304 to store the page title (for more information see the
305 MultiPageWidget class \l
306 {designer/containerextension/multipagewidget.cpp}{implementation}).
307 Finally, we implicitly force an update of the page's property
308 sheet by calling the the
309 QDesignerPropertySheetExtension::setChanged() function.
310
311 \snippet examples/designer/containerextension/multipagewidgetplugin.cpp 4
312
313 Note also the initialize() function: The \c initialize() function
314 takes a QDesignerFormEditorInterface object as argument.
315
316 \snippet examples/designer/containerextension/multipagewidgetplugin.cpp 5
317
318 When creating extensions associated with custom widget plugins, we
319 need to access \QD's current extension manager which we retrieve
320 from the QDesignerFormEditorInterface parameter.
321
322 In addition to allowing you to manipulate a widget's properties,
323 the QExtensionManager class provides extension management
324 facilities for \QD. Using \QD's current extension manager you can
325 retrieve the extension for a given object. You can also register
326 and unregister an extension for a given object. Remember that an
327 extension is an object which modifies the behavior of \QD.
328
329 When registrering an extension, it is actually the associated
330 extension factory that is registered. In \QD, extension factories
331 are used to look up and create named extensions as they are
332 required. So, in this example, the container extension itself is
333 not created until \QD must know whether the associated widget is a
334 container, or not.
335
336 \snippet examples/designer/containerextension/multipagewidgetplugin.cpp 6
337
338 We create a \c MultiPageWidgetExtensionFactory object that we
339 register using \QD's current \l {QExtensionManager}{extension
340 manager} retrieved from the QDesignerFormEditorInterface
341 parameter. The first argument is the newly created factory and the
342 second argument is an extension identifier which is a string. The
343 \c Q_TYPEID() macro simply convert the string into a
344 QLatin1String.
345
346 The \c MultiPageWidgetExtensionFactory class is a subclass of
347 QExtensionFactory. When \QD must know whether a widget is a
348 container, or not, \QD's extension manager will run through all
349 its registered factories invoking the first one which is able to
350 create a container extension for that widget. This factory will in
351 turn create a \c MultiPageWidgetExtension object.
352
353 \snippet examples/designer/containerextension/multipagewidgetplugin.cpp 7
354
355 Finally, take a look at the \c domXml() function. This function
356 includes default settings for the widget in the standard XML
357 format used by \QD. In this case, we specify the container's first
358 page; any inital pages of a multi-page widget must be specified
359 within this function.
360
361 \snippet examples/designer/containerextension/multipagewidgetplugin.cpp 14
362
363 Remember to use the Q_EXPORT_PLUGIN2() macro to export the
364 MultiPageWidgetPlugin class for use with Qt's plugin handling
365 classes: This macro ensures that \QD can access and construct the
366 custom widget. Without this macro, there is no way for \QD to use
367 the widget.
368
369 \section1 MultiPageWidgetExtensionFactory Class Definition
370
371 The \c MultiPageWidgetExtensionFactory class inherits QExtensionFactory
372 which provides a standard extension factory for \QD.
373
374 \snippet examples/designer/containerextension/multipagewidgetextensionfactory.h 0
375
376 The subclass's purpose is to reimplement the
377 QExtensionFactory::createExtension() function, making it able to
378 create a \c MultiPageWidget container extension.
379
380
381 \section1 MultiPageWidgetExtensionFactory Class Implementation
382
383 The class constructor simply calls the QExtensionFactory base
384 class constructor:
385
386 \snippet examples/designer/containerextension/multipagewidgetextensionfactory.cpp 0
387
388 As described above, the factory is invoked when \QD must know
389 whether the associated widget is a container, or not.
390
391 \snippet examples/designer/containerextension/multipagewidgetextensionfactory.cpp 1
392
393 \QD's behavior is the same whether the requested extension is
394 associated with a container, a member sheet, a property sheet or a
395 task menu: Its extension manager runs through all its registered
396 extension factories calling \c createExtension() for each until
397 one responds by creating the requested extension.
398
399 So the first thing we do in \c
400 MultiPageWidgetExtensionFactory::createExtension() is to check if
401 the QObject, for which the extension is requested, is in fact a \c
402 MultiPageWidget object. Then we check if the requested extension
403 is a container extension.
404
405 If the object is a MultiPageWidget requesting a container
406 extension, we create and return a \c MultiPageWidgetExtension
407 object. Otherwise, we simply return a null pointer, allowing \QD's
408 extension manager to continue its search through the registered
409 factories.
410
411
412 \section1 MultiPageWidgetContainerExtension Class Definition
413
414 The \c MultiPageWidgetContainerExtension class inherits
415 QDesignerContainerExtension which allows you to add (and delete)
416 pages to a multi-page container plugin in \QD.
417
418 \snippet examples/designer/containerextension/multipagewidgetcontainerextension.h 0
419
420 It is important to recognize that the QDesignerContainerExtension
421 class only is intended to provide \QD access to your custom
422 multi-page widget's functionality; your custom multi-page widget
423 must implement functionality corresponding to the extension's
424 functions.
425
426 Note also that we implement a constructor that takes \e two
427 arguments: the parent widget, and the \c MultiPageWidget object
428 for which the task menu is requested.
429
430 QDesignerContainerExtension provides a couple of menu entries in
431 \QD's task menu by default, enabling the user to add or delete
432 pages to the associated custom multi-page widget in \QD's
433 workspace.
434
435 \section1 MultiPageWidgetContainerExtension Class Implementation
436
437 In the constructor we save the reference to the \c MultiPageWidget
438 object sent as parameter, i.e the widget associated with the
439 extension. We will need this later to access the custom multi-page
440 widget performing the requested actions.
441
442 \snippet examples/designer/containerextension/multipagewidgetcontainerextension.cpp 0
443
444 To fully enable \QD to manage and manipulate your custom
445 multi-page widget, you must reimplement all the functions of
446 QDesignerContainerExtension:
447
448 \snippet examples/designer/containerextension/multipagewidgetcontainerextension.cpp 1
449 \codeline
450 \snippet examples/designer/containerextension/multipagewidgetcontainerextension.cpp 2
451 \codeline
452 \snippet examples/designer/containerextension/multipagewidgetcontainerextension.cpp 3
453
454 You must reimplement \l
455 {QDesignerContainerExtension::addWidget()}{addWidget()} adding a
456 given page to the container, \l
457 {QDesignerContainerExtension::count()}{count()} returning the
458 number of pages in the container, and \l
459 {QDesignerContainerExtension::currentIndex()}{currentIndex()}
460 returning the index of the currently selected page.
461
462 \snippet examples/designer/containerextension/multipagewidgetcontainerextension.cpp 4
463 \codeline
464 \snippet examples/designer/containerextension/multipagewidgetcontainerextension.cpp 5
465 \codeline
466 \snippet examples/designer/containerextension/multipagewidgetcontainerextension.cpp 6
467 \codeline
468 \snippet examples/designer/containerextension/multipagewidgetcontainerextension.cpp 7
469
470 You must reimplement \l
471 {QDesignerContainerExtension::insertWidget()}{insertWidget()}
472 adding a given page to the container at a given index, \l
473 {QDesignerContainerExtension::remove()}{remove()} deleting the
474 page at a given index, \l
475 {QDesignerContainerExtension::setCurrentIndex()}{setCurrentIndex()}
476 setting the index of the currently selected page, and finally \l
477 {QDesignerContainerExtension::widget()}{widget()} returning the
478 page at a given index.
479
480 \section1 MultiPageWidget Class Definition
481
482 The MultiPageWidget class is a custom container widget that lets
483 the user manipulate and populate its pages, and navigate among
484 these using a combobox.
485
486 \snippet examples/designer/containerextension/multipagewidget.h 0
487
488 The main detail to observe is that your custom multi-page widget
489 must implement functionality corresponding to the
490 QDesignerContainerExtension's member functions since the
491 QDesignerContainerExtension class only is intended to provide Qt
492 Designer access to your custom multi-page widget's functionality.
493
494 In addition, we declare the \c currentIndex and \c pageTitle
495 properties, and their associated set and get functions. By
496 declaring these attributes as properties, we allow \QD to manage
497 them in the same way it manages the properties the MultiPageWidget
498 widget inherits from QWidget and QObject, for example featuring
499 the property editor.
500
501 Note the \c STORED attribute in the declaration of the \c
502 pageTitle property: The \c STORED attribute indicates persistence,
503 i.e. it declares whether the property's value must be remembered
504 when storing an object's state. As mentioned above, we have chosen
505 to store the page title using the QWidget::windowTitle property to
506 be able to give each page their own title. For that reason the \c
507 pageTitle property is a "fake" property, provided for editing
508 purposes, and doesn't need to be stored.
509
510 We must also implement and emit the currentIndexChanged() and
511 pageTitleChanged() signals to ensure that \QD's property editor is
512 updated whenever the user views another page or changes one of the
513 page titles.
514
515 See the MultiPageWidget class \l
516 {designer/containerextension/multipagewidget.cpp}{implementation}
517 for more details.
518*/
Note: See TracBrowser for help on using the repository browser.