| /**************************************************************************** |
| ** |
| ** Copyright (C) 2016 The Qt Company Ltd. |
| ** Contact: https://www.qt.io/licensing/ |
| ** |
| ** This file is part of the documentation of the Qt Toolkit. |
| ** |
| ** $QT_BEGIN_LICENSE:FDL$ |
| ** Commercial License Usage |
| ** Licensees holding valid commercial Qt licenses may use this file in |
| ** accordance with the commercial license agreement provided with the |
| ** Software or, alternatively, in accordance with the terms contained in |
| ** a written agreement between you and The Qt Company. For licensing terms |
| ** and conditions see https://www.qt.io/terms-conditions. For further |
| ** information use the contact form at https://www.qt.io/contact-us. |
| ** |
| ** GNU Free Documentation License Usage |
| ** Alternatively, this file may be used under the terms of the GNU Free |
| ** Documentation License version 1.3 as published by the Free Software |
| ** Foundation and appearing in the file included in the packaging of |
| ** this file. Please review the following information to ensure |
| ** the GNU Free Documentation License version 1.3 requirements |
| ** will be met: https://www.gnu.org/licenses/fdl-1.3.html. |
| ** $QT_END_LICENSE$ |
| ** |
| ****************************************************************************/ |
| |
| /*! |
| \example containerextension |
| \ingroup examples-designer |
| \title Container Extension Example |
| |
| \brief Creating a custom multi-page plugin for \QD. |
| |
| The Container Extension example shows how to create a custom multi-page |
| plugin for \QD using the |
| QDesignerContainerExtension class. |
| |
| \image containerextension-example.png |
| |
| To provide a custom widget that can be used with \QD, we need to |
| supply a self-contained implementation. In this example we use a |
| custom multi-page widget designed to show the container extension |
| feature. |
| |
| An extension is an object which modifies the behavior of \QD. The |
| QDesignerContainerExtension enables \QD to manage and manipulate a |
| custom multi-page widget, i.e. adding and deleting pages to the |
| widget. |
| |
| There are four available types of extensions in \QD: |
| |
| \list |
| \li QDesignerMemberSheetExtension provides an extension that allows |
| you to manipulate a widget's member functions which is displayed |
| when configuring connections using Qt Designer's mode for editing |
| signals and slots. |
| \li QDesignerPropertySheetExtension provides an extension that |
| allows you to manipulate a widget's properties which is displayed |
| in Qt Designer's property editor. |
| \li QDesignerTaskMenuExtension provides an extension that allows |
| you to add custom menu entries to \QD's task menu. |
| \li QDesignerContainerExtension provides an extension that allows |
| you to add (and delete) pages to a multi-page container plugin |
| in \QD. |
| \endlist |
| |
| You can use all the extensions following the same pattern as in |
| this example, only replacing the respective extension base |
| class. For more information, see \l{Qt Designer C++ Classes}. |
| |
| The Container Extension example consists of four classes: |
| |
| \list |
| \li \c MultiPageWidget is a custom container widget that lets the user |
| manipulate and populate its pages, and navigate among these |
| using a combobox. |
| \li \c MultiPageWidgetPlugin exposes the \c MultiPageWidget class |
| to \QD. |
| \li \c MultiPageWidgetExtensionFactory creates a |
| \c MultiPageWidgetContainerExtension object. |
| \li \c MultiPageWidgetContainerExtension provides the container |
| extension. |
| \endlist |
| |
| The project file for custom widget plugins needs some additional |
| information to ensure that they will work within \QD. For example, |
| custom widget plugins rely on components supplied with \QD, and |
| this must be specified in the project file that we use. We will |
| first take a look at the plugin's project file. |
| |
| Then we will continue by reviewing the \c MultiPageWidgetPlugin |
| class, and take a look at the \c MultiPageWidgetExtensionFactory |
| and \c MultiPageWidgetContainerExtension classes. Finally, we will |
| take a quick look at the \c MultiPageWidget class definition. |
| |
| \section1 The Project File: containerextension.pro |
| |
| The project file must contain some additional information to |
| ensure that the plugin will work as expected: |
| |
| \snippet containerextension/containerextension.pro 0 |
| \snippet containerextension/containerextension.pro 1 |
| |
| The \c TEMPLATE variable's value makes \c qmake create the custom |
| widget as a library. Later, we will ensure that the widget will be |
| recognized as a plugin by Qt by using the Q_PLUGIN_METADATA() macro |
| to export the relevant widget information. |
| |
| The \c CONFIG variable is set to \c plugin, which ensures that \c qmake |
| considers the custom widget a plugin library. |
| |
| The \c QT variable contains the value \c designer. Since the plugin uses |
| components supplied with \QD that require linkage, this value ensures |
| that our plugin links against \QD's library (\c libQtDesigner.so). |
| |
| The header and source files for the widget are declared in the |
| usual way: |
| |
| \snippet containerextension/containerextension.pro 2 |
| |
| We provide an implementation of the plugin interface so that \QD |
| can use the custom widget. In this particular example we also |
| provide implementations of the container extension interface and |
| the extension factory. |
| |
| It is important to ensure that the plugin is installed in a |
| location that is searched by \QD. We do this by specifying a |
| target path for the project and adding it to the list of items to |
| install: |
| |
| \snippet doc/snippets/doc_src_examples_containerextension.pro 0 |
| |
| The container extension is created as a library, and will be |
| installed alongside the other \QD plugins when the project is |
| installed (using \c{make install} or an equivalent installation |
| procedure). |
| |
| Note that if you want the plugins to appear in a Visual Studio |
| integration, the plugins must be built in release mode and their |
| libraries must be copied into the plugin directory in the install |
| path of the integration (for an example, see \c {C:/program |
| files/trolltech as/visual studio integration/plugins}). |
| |
| For more information about plugins, see the \l {How to Create Qt |
| Plugins} documentation. |
| |
| \section1 MultiPageWidgetPlugin Class Definition |
| |
| The \c MultiPageWidgetPlugin class exposes the \c MultiPageWidget |
| class to \QD. Its definition is similar to the \l |
| {customwidgetplugin}{Custom Widget Plugin} example's |
| plugin class which is explained in detail. The parts of the class |
| definition that is specific to this particular custom widget is |
| the class name and a couple of private slots: |
| |
| \snippet containerextension/multipagewidgetplugin.h 0 |
| |
| The plugin class provides \QD with basic information about our |
| plugin, such as its class name and its include file. Furthermore |
| it knows how to create instances of the \c MultiPageWidget widget. |
| \c MultiPageWidgetPlugin also defines the \l |
| {QDesignerCustomWidgetInterface::initialize()}{initialize()} |
| function which is called after the plugin is loaded into \QD. The |
| function's QDesignerFormEditorInterface parameter provides the |
| plugin with a gateway to all of \QD's API's. |
| |
| In the case of a multipage widget such as ours, we must also implement |
| two private slots, currentIndexChanged() and pageTitleChanged(), |
| to be able to update \QD's property editor whenever the user views |
| another page or changes one of the page titles. To be able to give |
| each page their own title, we have chosen to use the |
| QWidget::windowTitle property to store the page title (for more |
| information see the MultiPageWidget class implementation in |
| \e containerextension/multipagewidget.cpp. Note that currently there |
| is no way of adding a custom property (for example, a page title) to |
| the pages without using a predefined property as placeholder. |
| |
| The \c MultiPageWidgetPlugin class inherits from both QObject and |
| QDesignerCustomWidgetInterface. It is important to remember, when |
| using multiple inheritance, to ensure that all the interfaces |
| (i.e. the classes that doesn't inherit Q_OBJECT) are made known to |
| the meta object system using the Q_INTERFACES() macro. This |
| enables \QD to use \l {qobject_cast(QObject * object)} to query for supported |
| interfaces using nothing but a QObject pointer. |
| |
| \section1 MultiPageWidgetPlugin Class Implementation |
| |
| The MultiPageWidgetPlugin class implementation is in most parts |
| equivalent to the \l {customwidgetplugin}{Custom Widget |
| Plugin} example's plugin class: |
| |
| \snippet containerextension/multipagewidgetplugin.cpp 0 |
| \codeline |
| \snippet containerextension/multipagewidgetplugin.cpp 3 |
| |
| One of the functions that differ is the isContainer() function |
| which returns true in this example since our custom widget is |
| intended to be used as a container. |
| |
| \snippet containerextension/multipagewidgetplugin.cpp 1 |
| |
| Another function that differ is the function creating our custom widget: |
| |
| \snippet containerextension/multipagewidgetplugin.cpp 2 |
| |
| In addition to create and return the widget, we connect our custom |
| container widget's currentIndexChanged() signal to the plugin's |
| currentIndexChanged() slot to ensure that \QD's property editor is |
| updated whenever the user views another page. We also connect the |
| widget's pageTitleChanged() signal to the plugin's |
| pageTitleChanged() slot. |
| |
| The currentIndexChanged() slot is called whenever our custom |
| widget's currentIndexChanged() \e signal is emitted, i.e. whenever |
| the user views another page: |
| |
| \snippet containerextension/multipagewidgetplugin.cpp 8 |
| |
| First, we retrieve the object emitting the signal using the |
| QObject::sender() and qobject_cast() functions. If it's called in |
| a slot activated by a signal, QObject::sender() returns a pointer |
| to the object that sent the signal; otherwise it returns 0. |
| |
| \snippet containerextension/multipagewidgetplugin.cpp 9 |
| |
| Once we have the widget we can update the property editor. \QD |
| uses the QDesignerPropertySheetExtension class to feed its |
| property editor, and whenever a widget is selected in its |
| workspace, Qt Designer will query for the widget's property sheet |
| extension and update the property editor. |
| |
| So what we want to achieve is to notify \QD that our widget's \e |
| internal selection has changed: First we use the static |
| QDesignerFormWindowInterface::findFormWindow() function to |
| retrieve the QDesignerFormWindowInterface object containing the |
| widget. The QDesignerFormWindowInterface class allows you to query |
| and manipulate form windows appearing in Qt Designer's |
| workspace. Then, all we have to do is to emit its \l |
| {QDesignerFormWindowInterface::emitSelectionChanged()}{emitSelectionChanged()} |
| signal, forcing an update of the property editor. |
| |
| When changing a page title a generic refresh of the property |
| editor is not enough because it is actually the page's property |
| extension that needs to be updated. For that reason we need to |
| access the QDesignerPropertySheetExtension object for the page |
| which title we want to change. The QDesignerPropertySheetExtension |
| class also allows you to manipulate a widget's properties, but to |
| get hold of the extension we must first retrieve access to \QD's |
| extension manager: |
| |
| \snippet containerextension/multipagewidgetplugin.cpp 10 |
| \snippet containerextension/multipagewidgetplugin.cpp 11 |
| |
| Again we first retrieve the widget emitting the signal, using the |
| QObject::sender() and qobject_cast() functions. Then we retrieve |
| the current page from the widget that emitted the signal, and we |
| use the static QDesignerFormWindowInterface::findFormWindow() |
| function to retrieve the form containing our widget. |
| |
| \snippet containerextension/multipagewidgetplugin.cpp 12 |
| |
| Now that we have the form window, the QDesignerFormWindowInterface |
| class provides the \l |
| {QDesignerFormWindowInterface::core()}{core()} function which |
| returns the current QDesignerFormEditorInterface object. The |
| QDesignerFormEditorInterface class allows you to access Qt |
| Designer's various components. In particular, the |
| QDesignerFormEditorInterface::extensionManager() function returns |
| a reference to the current extension manager. |
| |
| \snippet containerextension/multipagewidgetplugin.cpp 13 |
| |
| Once we have the extension manager we can update the extension |
| sheet: First we retrieve the property extension for the page which |
| title we want to change, using the qt_extension() function. Then |
| we retrieve the index for the page title using the |
| QDesignerPropertySheetExtension::indexOf() function. As previously |
| mentioned, we have chosen to use the QWidget::windowTitle property |
| to store the page title (for more information see the |
| MultiPageWidget class implementation in |
| \e containerextension/multipagewidget.cpp. |
| Finally, we implicitly force an update of the page's property |
| sheet by calling the |
| QDesignerPropertySheetExtension::setChanged() function. |
| |
| \snippet containerextension/multipagewidgetplugin.cpp 4 |
| |
| Note also the initialize() function: The \c initialize() function |
| takes a QDesignerFormEditorInterface object as argument. |
| |
| \snippet containerextension/multipagewidgetplugin.cpp 5 |
| |
| When creating extensions associated with custom widget plugins, we |
| need to access \QD's current extension manager which we retrieve |
| from the QDesignerFormEditorInterface parameter. |
| |
| In addition to allowing you to manipulate a widget's properties, |
| the QExtensionManager class provides extension management |
| facilities for \QD. Using \QD's current extension manager you can |
| retrieve the extension for a given object. You can also register |
| and unregister an extension for a given object. Remember that an |
| extension is an object which modifies the behavior of \QD. |
| |
| When registrering an extension, it is actually the associated |
| extension factory that is registered. In \QD, extension factories |
| are used to look up and create named extensions as they are |
| required. So, in this example, the container extension itself is |
| not created until \QD must know whether the associated widget is a |
| container, or not. |
| |
| \snippet containerextension/multipagewidgetplugin.cpp 6 |
| |
| We create a \c MultiPageWidgetExtensionFactory object that we |
| register using \QD's current \l {QExtensionManager}{extension |
| manager} retrieved from the QDesignerFormEditorInterface |
| parameter. The first argument is the newly created factory and the |
| second argument is an extension identifier which is a string. The |
| \c Q_TYPEID() macro simply convert the string into a |
| QLatin1String. |
| |
| The \c MultiPageWidgetExtensionFactory class is a subclass of |
| QExtensionFactory. When \QD must know whether a widget is a |
| container, or not, \QD's extension manager will run through all |
| its registered factories invoking the first one which is able to |
| create a container extension for that widget. This factory will in |
| turn create a \c MultiPageWidgetExtension object. |
| |
| \snippet containerextension/multipagewidgetplugin.cpp 7 |
| |
| Finally, take a look at the \c domXml() function. This function |
| includes default settings for the widget in the standard XML |
| format used by \QD. In this case, we specify the container's first |
| page; any inital pages of a multi-page widget must be specified |
| within this function. |
| |
| \snippet containerextension/multipagewidgetplugin.h 1 |
| |
| Remember to use the Q_PLUGIN_METADATA() macro to export the |
| MultiPageWidgetPlugin class for use with Qt's plugin handling |
| classes: This macro ensures that \QD can access and construct the |
| custom widget. Without this macro, there is no way for \QD to use |
| the widget. |
| |
| \section1 MultiPageWidgetExtensionFactory Class Definition |
| |
| The \c MultiPageWidgetExtensionFactory class inherits QExtensionFactory |
| which provides a standard extension factory for \QD. |
| |
| \snippet containerextension/multipagewidgetextensionfactory.h 0 |
| |
| The subclass's purpose is to reimplement the |
| QExtensionFactory::createExtension() function, making it able to |
| create a \c MultiPageWidget container extension. |
| |
| |
| \section1 MultiPageWidgetExtensionFactory Class Implementation |
| |
| The class constructor simply calls the QExtensionFactory base |
| class constructor: |
| |
| \snippet containerextension/multipagewidgetextensionfactory.cpp 0 |
| |
| As described above, the factory is invoked when \QD must know |
| whether the associated widget is a container, or not. |
| |
| \snippet containerextension/multipagewidgetextensionfactory.cpp 1 |
| |
| \QD's behavior is the same whether the requested extension is |
| associated with a container, a member sheet, a property sheet or a |
| task menu: Its extension manager runs through all its registered |
| extension factories calling \c createExtension() for each until |
| one responds by creating the requested extension. |
| |
| So the first thing we do in \c |
| MultiPageWidgetExtensionFactory::createExtension() is to check if |
| the QObject, for which the extension is requested, is in fact a \c |
| MultiPageWidget object. Then we check if the requested extension |
| is a container extension. |
| |
| If the object is a MultiPageWidget requesting a container |
| extension, we create and return a \c MultiPageWidgetExtension |
| object. Otherwise, we simply return a null pointer, allowing \QD's |
| extension manager to continue its search through the registered |
| factories. |
| |
| |
| \section1 MultiPageWidgetContainerExtension Class Definition |
| |
| The \c MultiPageWidgetContainerExtension class inherits |
| QDesignerContainerExtension which allows you to add (and delete) |
| pages to a multi-page container plugin in \QD. |
| |
| \snippet containerextension/multipagewidgetcontainerextension.h 0 |
| |
| It is important to recognize that the QDesignerContainerExtension |
| class only is intended to provide \QD access to your custom |
| multi-page widget's functionality; your custom multi-page widget |
| must implement functionality corresponding to the extension's |
| functions. |
| |
| Note also that we implement a constructor that takes \e two |
| arguments: the parent widget, and the \c MultiPageWidget object |
| for which the task menu is requested. |
| |
| QDesignerContainerExtension provides a couple of menu entries in |
| \QD's task menu by default, enabling the user to add or delete |
| pages to the associated custom multi-page widget in \QD's |
| workspace. |
| |
| \section1 MultiPageWidgetContainerExtension Class Implementation |
| |
| In the constructor we save the reference to the \c MultiPageWidget |
| object sent as parameter, i.e the widget associated with the |
| extension. We will need this later to access the custom multi-page |
| widget performing the requested actions. |
| |
| \snippet containerextension/multipagewidgetcontainerextension.cpp 0 |
| |
| To fully enable \QD to manage and manipulate your custom |
| multi-page widget, you must reimplement all the functions of |
| QDesignerContainerExtension: |
| |
| \snippet containerextension/multipagewidgetcontainerextension.cpp 1 |
| \codeline |
| \snippet containerextension/multipagewidgetcontainerextension.cpp 2 |
| \codeline |
| \snippet containerextension/multipagewidgetcontainerextension.cpp 3 |
| |
| You must reimplement \l |
| {QDesignerContainerExtension::addWidget()}{addWidget()} adding a |
| given page to the container, \l |
| {QDesignerContainerExtension::count()}{count()} returning the |
| number of pages in the container, and \l |
| {QDesignerContainerExtension::currentIndex()}{currentIndex()} |
| returning the index of the currently selected page. |
| |
| \snippet containerextension/multipagewidgetcontainerextension.cpp 4 |
| \codeline |
| \snippet containerextension/multipagewidgetcontainerextension.cpp 5 |
| \codeline |
| \snippet containerextension/multipagewidgetcontainerextension.cpp 6 |
| \codeline |
| \snippet containerextension/multipagewidgetcontainerextension.cpp 7 |
| |
| You must reimplement \l |
| {QDesignerContainerExtension::insertWidget()}{insertWidget()} |
| adding a given page to the container at a given index, \l |
| {QDesignerContainerExtension::remove()}{remove()} deleting the |
| page at a given index, \l |
| {QDesignerContainerExtension::setCurrentIndex()}{setCurrentIndex()} |
| setting the index of the currently selected page, and finally \l |
| {QDesignerContainerExtension::widget()}{widget()} returning the |
| page at a given index. |
| |
| \section1 MultiPageWidget Class Definition |
| |
| The MultiPageWidget class is a custom container widget that lets |
| the user manipulate and populate its pages, and navigate among |
| these using a combobox. |
| |
| \snippet containerextension/multipagewidget.h 0 |
| |
| The main detail to observe is that your custom multi-page widget |
| must implement functionality corresponding to the |
| QDesignerContainerExtension's member functions since the |
| QDesignerContainerExtension class only is intended to provide Qt |
| Designer access to your custom multi-page widget's functionality. |
| |
| In addition, we declare the \c currentIndex and \c pageTitle |
| properties, and their associated set and get functions. By |
| declaring these attributes as properties, we allow \QD to manage |
| them in the same way it manages the properties the MultiPageWidget |
| widget inherits from QWidget and QObject, for example featuring |
| the property editor. |
| |
| Note the \c STORED attribute in the declaration of the \c |
| pageTitle property: The \c STORED attribute indicates persistence, |
| i.e. it declares whether the property's value must be remembered |
| when storing an object's state. As mentioned above, we have chosen |
| to store the page title using the QWidget::windowTitle property to |
| be able to give each page their own title. For that reason the \c |
| pageTitle property is a "fake" property, provided for editing |
| purposes, and doesn't need to be stored. |
| |
| We must also implement and emit the currentIndexChanged() and |
| pageTitleChanged() signals to ensure that \QD's property editor is |
| updated whenever the user views another page or changes one of the |
| page titles. |
| |
| See the MultiPageWidget class implementation in |
| \e containerextension/multipagewidget.cpp for more details. |
| */ |