doc/src/examples/plugandpaint.qdoc
changeset 0 1918ee327afb
equal deleted inserted replaced
-1:000000000000 0:1918ee327afb
       
     1 /****************************************************************************
       
     2 **
       
     3 ** Copyright (C) 2009 Nokia Corporation and/or its subsidiary(-ies).
       
     4 ** All rights reserved.
       
     5 ** Contact: Nokia Corporation (qt-info@nokia.com)
       
     6 **
       
     7 ** This file is part of the documentation of the Qt Toolkit.
       
     8 **
       
     9 ** $QT_BEGIN_LICENSE:LGPL$
       
    10 ** No Commercial Usage
       
    11 ** This file contains pre-release code and may not be distributed.
       
    12 ** You may use this file in accordance with the terms and conditions
       
    13 ** contained in the Technology Preview License Agreement accompanying
       
    14 ** this package.
       
    15 **
       
    16 ** GNU Lesser General Public License Usage
       
    17 ** Alternatively, this file may be used under the terms of the GNU Lesser
       
    18 ** General Public License version 2.1 as published by the Free Software
       
    19 ** Foundation and appearing in the file LICENSE.LGPL included in the
       
    20 ** packaging of this file.  Please review the following information to
       
    21 ** ensure the GNU Lesser General Public License version 2.1 requirements
       
    22 ** will be met: http://www.gnu.org/licenses/old-licenses/lgpl-2.1.html.
       
    23 **
       
    24 ** In addition, as a special exception, Nokia gives you certain additional
       
    25 ** rights.  These rights are described in the Nokia Qt LGPL Exception
       
    26 ** version 1.1, included in the file LGPL_EXCEPTION.txt in this package.
       
    27 **
       
    28 ** If you have questions regarding the use of this file, please contact
       
    29 ** Nokia at qt-info@nokia.com.
       
    30 **
       
    31 **
       
    32 **
       
    33 **
       
    34 **
       
    35 **
       
    36 **
       
    37 **
       
    38 ** $QT_END_LICENSE$
       
    39 **
       
    40 ****************************************************************************/
       
    41 
       
    42 /*!
       
    43     \example tools/plugandpaint
       
    44     \title Plug & Paint Example
       
    45 
       
    46     The Plug & Paint example demonstrates how to write Qt
       
    47     applications that can be extended through plugins.
       
    48 
       
    49     \image plugandpaint.png Screenshot of the Plug & Paint example
       
    50 
       
    51     A plugin is a dynamic library that can be loaded at run-time to
       
    52     extend an application. Qt makes it possible to create custom
       
    53     plugins and to load them using QPluginLoader. To ensure that
       
    54     plugins don't get lost, it is also possible to link them
       
    55     statically to the executable. The Plug & Paint example uses
       
    56     plugins to support custom brushes, shapes, and image filters. A
       
    57     single plugin can provide multiple brushes, shapes, and/or
       
    58     filters.
       
    59 
       
    60     If you want to learn how to make your own application extensible
       
    61     through plugins, we recommend that you start by reading this
       
    62     overview, which explains how to make an application use plugins.
       
    63     Afterward, you can read the
       
    64     \l{tools/plugandpaintplugins/basictools}{Basic Tools} and
       
    65     \l{tools/plugandpaintplugins/extrafilters}{Extra Filters}
       
    66     overviews, which show how to implement static and dynamic
       
    67     plugins, respectively.
       
    68 
       
    69     Plug & Paint consists of the following classes:
       
    70 
       
    71     \list
       
    72     \o \c MainWindow is a QMainWindow subclass that provides the menu
       
    73        system and that contains a \c PaintArea as the central widget.
       
    74     \o \c PaintArea is a QWidget that allows the user to draw using a
       
    75        brush and to insert shapes.
       
    76     \o \c PluginDialog is a dialog that shows information about the
       
    77        plugins detected by the application.
       
    78     \o \c BrushInterface, \c ShapeInterface, and \c FilterInterface are
       
    79        abstract base classes that can be implemented by plugins to
       
    80        provide custom brushes, shapes, and image filters.
       
    81     \endlist
       
    82 
       
    83     \section1 The Plugin Interfaces
       
    84 
       
    85     We will start by reviewing the interfaces defined in \c
       
    86     interfaces.h. These interfaces are used by the Plug & Paint
       
    87     application to access extra functionality. They are implemented
       
    88     in the plugins.
       
    89 
       
    90 
       
    91     \snippet examples/tools/plugandpaint/interfaces.h 0
       
    92 
       
    93     The \c BrushInterface class declares four pure virtual functions.
       
    94     The first pure virtual function, \c brushes(), returns a list of
       
    95     strings that identify the brushes provided by the plugin. By
       
    96     returning a QStringList instead of a QString, we make it possible
       
    97     for a single plugin to provide multiple brushes. The other
       
    98     functions have a \c brush parameter to identify which brush
       
    99     (among those returned by \c brushes()) is used.
       
   100 
       
   101     \c mousePress(), \c mouseMove(), and \c mouseRelease() take a
       
   102     QPainter and one or two \l{QPoint}s, and return a QRect
       
   103     identifying which portion of the image was altered by the brush.
       
   104 
       
   105     The class also has a virtual destructor. Interface classes
       
   106     usually don't need such a destructor (because it would make
       
   107     little sense to \c delete the object that implements the
       
   108     interface through a pointer to the interface), but some compilers
       
   109     emit a warning for classes that declare virtual functions but no
       
   110     virtual destructor. We provide the destructor to keep these
       
   111     compilers happy.
       
   112 
       
   113     \snippet examples/tools/plugandpaint/interfaces.h 1
       
   114 
       
   115     The \c ShapeInterface class declares a \c shapes() function that
       
   116     works the same as \c{BrushInterface}'s \c brushes() function, and
       
   117     a \c generateShape() function that has a \c shape parameter.
       
   118     Shapes are represented by a QPainterPath, a data type that can
       
   119     represent arbitrary 2D shapes or combinations of shapes. The \c
       
   120     parent parameter can be used by the plugin to pop up a dialog
       
   121     asking the user to specify more information.
       
   122 
       
   123     \snippet examples/tools/plugandpaint/interfaces.h 2
       
   124 
       
   125     The \c FilterInterface class declares a \c filters() function
       
   126     that returns a list of filter names, and a \c filterImage()
       
   127     function that applies a filter to an image.
       
   128 
       
   129     \snippet examples/tools/plugandpaint/interfaces.h 4
       
   130 
       
   131     To make it possible to query at run-time whether a plugin
       
   132     implements a given interface, we must use the \c
       
   133     Q_DECLARE_INTERFACE() macro. The first argument is the name of
       
   134     the interface. The second argument is a string identifying the
       
   135     interface in a unique way. By convention, we use a "Java package
       
   136     name" syntax to identify interfaces. If we later change the
       
   137     interfaces, we must use a different string to identify the new
       
   138     interface; otherwise, the application might crash. It is therefore
       
   139     a good idea to include a version number in the string, as we did
       
   140     above.
       
   141 
       
   142     The \l{tools/plugandpaintplugins/basictools}{Basic Tools} plugin
       
   143     and the \l{tools/plugandpaintplugins/extrafilters}{Extra Filters}
       
   144     plugin shows how to derive from \c BrushInterface, \c
       
   145     ShapeInterface, and \c FilterInterface.
       
   146 
       
   147     A note on naming: It might have been tempting to give the \c
       
   148     brushes(), \c shapes(), and \c filters() functions a more generic
       
   149     name, such as \c keys() or \c features(). However, that would
       
   150     have made multiple inheritance impractical. When creating
       
   151     interfaces, we should always try to give unique names to the pure
       
   152     virtual functions.
       
   153 
       
   154     \section1 The MainWindow Class
       
   155 
       
   156     The \c MainWindow class is a standard QMainWindow subclass, as
       
   157     found in many of the other examples (e.g.,
       
   158     \l{mainwindows/application}{Application}). Here, we'll
       
   159     concentrate on the parts of the code that are related to plugins.
       
   160 
       
   161     \snippet examples/tools/plugandpaint/mainwindow.cpp 4
       
   162 
       
   163     The \c loadPlugins() function is called from the \c MainWindow
       
   164     constructor to detect plugins and update the \gui{Brush},
       
   165     \gui{Shapes}, and \gui{Filters} menus. We start by handling static
       
   166     plugins (available through QPluginLoader::staticInstances())
       
   167 
       
   168     To the application that uses the plugin, a Qt plugin is simply a
       
   169     QObject. That QObject implements plugin interfaces using multiple
       
   170     inheritance.
       
   171 
       
   172     \snippet examples/tools/plugandpaint/mainwindow.cpp 5
       
   173 
       
   174     The next step is to load dynamic plugins. We initialize the \c
       
   175     pluginsDir member variable to refer to the \c plugins
       
   176     subdirectory of the Plug & Paint example. On Unix, this is just a
       
   177     matter of initializing the QDir variable with
       
   178     QApplication::applicationDirPath(), the path of the executable
       
   179     file, and to do a \l{QDir::cd()}{cd()}. On Windows and Mac OS X,
       
   180     this file is usually located in a subdirectory, so we need to
       
   181     take this into account.
       
   182 
       
   183     \snippet examples/tools/plugandpaint/mainwindow.cpp 6
       
   184     \snippet examples/tools/plugandpaint/mainwindow.cpp 7
       
   185     \snippet examples/tools/plugandpaint/mainwindow.cpp 8
       
   186 
       
   187     We use QDir::entryList() to get a list of all files in that
       
   188     directory. Then we iterate over the result using \l foreach and
       
   189     try to load the plugin using QPluginLoader.
       
   190 
       
   191     The QObject provided by the plugin is accessible through
       
   192     QPluginLoader::instance(). If the dynamic library isn't a Qt
       
   193     plugin, or if it was compiled against an incompatible version of
       
   194     the Qt library, QPluginLoader::instance() returns a null pointer.
       
   195 
       
   196     If QPluginLoader::instance() is non-null, we add it to the menus.
       
   197 
       
   198     \snippet examples/tools/plugandpaint/mainwindow.cpp 9
       
   199 
       
   200     At the end, we enable or disable the \gui{Brush}, \gui{Shapes},
       
   201     and \gui{Filters} menus based on whether they contain any items.
       
   202 
       
   203     \snippet examples/tools/plugandpaint/mainwindow.cpp 10
       
   204 
       
   205     For each plugin (static or dynamic), we check which interfaces it
       
   206     implements using \l qobject_cast(). First, we try to cast the
       
   207     plugin instance to a \c BrushInterface; if it works, we call the
       
   208     private function \c addToMenu() with the list of brushes returned
       
   209     by \c brushes(). Then we do the same with the \c ShapeInterface
       
   210     and the \c FilterInterface.
       
   211 
       
   212     \snippet examples/tools/plugandpaint/mainwindow.cpp 3
       
   213 
       
   214     The \c aboutPlugins() slot is called on startup and can be
       
   215     invoked at any time through the \gui{About Plugins} action. It
       
   216     pops up a \c PluginDialog, providing information about the loaded
       
   217     plugins.
       
   218 
       
   219     \image plugandpaint-plugindialog.png Screenshot of the Plugin dialog
       
   220 
       
   221 
       
   222     The \c addToMenu() function is called from \c loadPlugin() to
       
   223     create \l{QAction}s for custom brushes, shapes, or filters and
       
   224     add them to the relevant menu. The QAction is created with the
       
   225     plugin from which it comes from as the parent; this makes it
       
   226     convenient to get access to the plugin later.
       
   227 
       
   228     \snippet examples/tools/plugandpaint/mainwindow.cpp 0
       
   229 
       
   230     The \c changeBrush() slot is invoked when the user chooses one of
       
   231     the brushes from the \gui{Brush} menu. We start by finding out
       
   232     which action invoked the slot using QObject::sender(). Then we
       
   233     get the \c BrushInterface out of the plugin (which we
       
   234     conveniently passed as the QAction's parent) and we call \c
       
   235     PaintArea::setBrush() with the \c BrushInterface and the string
       
   236     identifying the brush. Next time the user draws on the paint
       
   237     area, \c PaintArea will use this brush.
       
   238 
       
   239     \snippet examples/tools/plugandpaint/mainwindow.cpp 1
       
   240 
       
   241     The \c insertShape() is invoked when the use chooses one of the
       
   242     shapes from the \gui{Shapes} menu. We retrieve the QAction that
       
   243     invoked the slot, then the \c ShapeInterface associated with that
       
   244     QAction, and finally we call \c ShapeInterface::generateShape()
       
   245     to obtain a QPainterPath.
       
   246 
       
   247     \snippet examples/tools/plugandpaint/mainwindow.cpp 2
       
   248 
       
   249     The \c applyFilter() slot is similar: We retrieve the QAction
       
   250     that invoked the slot, then the \c FilterInterface associated to
       
   251     that QAction, and finally we call \c
       
   252     FilterInterface::filterImage() to apply the filter onto the
       
   253     current image.
       
   254 
       
   255     \section1 The PaintArea Class
       
   256 
       
   257     The \c PaintArea class contains some code that deals with \c
       
   258     BrushInterface, so we'll review it briefly.
       
   259 
       
   260     \snippet examples/tools/plugandpaint/paintarea.cpp 0
       
   261 
       
   262     In \c setBrush(), we simply store the \c BrushInterface and the
       
   263     brush that are given to us by \c MainWindow.
       
   264 
       
   265     \snippet examples/tools/plugandpaint/paintarea.cpp 1
       
   266 
       
   267     In the \l{QWidget::mouseMoveEvent()}{mouse move event handler},
       
   268     we call the \c BrushInterface::mouseMove() function on the
       
   269     current \c BrushInterface, with the current brush. The mouse
       
   270     press and mouse release handlers are very similar.
       
   271 
       
   272     \section1 The PluginDialog Class
       
   273 
       
   274     The \c PluginDialog class provides information about the loaded
       
   275     plugins to the user. Its constructor takes a path to the plugins
       
   276     and a list of plugin file names. It calls \c findPlugins()
       
   277     to fill the QTreeWdiget with information about the plugins:
       
   278 
       
   279     \snippet examples/tools/plugandpaint/plugindialog.cpp 0
       
   280 
       
   281     The \c findPlugins() is very similar to \c
       
   282     MainWindow::loadPlugins(). It uses QPluginLoader to access the
       
   283     static and dynamic plugins. Its helper function \c
       
   284     populateTreeWidget() uses \l qobject_cast() to find out which
       
   285     interfaces are implemented by the plugins:
       
   286 
       
   287     \snippet examples/tools/plugandpaint/plugindialog.cpp 1
       
   288 
       
   289     \section1 Importing Static Plugins
       
   290 
       
   291     The \l{tools/plugandpaintplugins/basictools}{Basic Tools} plugin
       
   292     is built as a static plugin, to ensure that it is always
       
   293     available to the application. This requires using the
       
   294     Q_IMPORT_PLUGIN() macro somewhere in the application (in a \c
       
   295     .cpp file) and specifying the plugin in the \c .pro file.
       
   296 
       
   297     For Plug & Paint, we have chosen to put Q_IMPORT_PLUGIN() in \c
       
   298     main.cpp:
       
   299 
       
   300     \snippet examples/tools/plugandpaint/main.cpp 0
       
   301 
       
   302     The argument to Q_IMPORT_PLUGIN() is the plugin's name, as
       
   303     specified with Q_EXPORT_PLUGIN2() in the \l{Exporting the
       
   304     Plugin}{plugin}.
       
   305 
       
   306     In the \c .pro file, we need to specify the static library.
       
   307     Here's the project file for building Plug & Paint:
       
   308 
       
   309     \snippet examples/tools/plugandpaint/plugandpaint.pro 0
       
   310 
       
   311     The \c LIBS line variable specifies the library \c pnp_basictools
       
   312     located in the \c ../plugandpaintplugins/basictools directory.
       
   313     (Although the \c LIBS syntax has a distinct Unix flavor, \c qmake
       
   314     supports it on all platforms.)
       
   315 
       
   316     The \c CONFIG() code at the end is necessary for this example
       
   317     because the example is part of the Qt distribution and Qt can be
       
   318     configured to be built simultaneously in debug and in release
       
   319     modes. You don't need to for your own plugin applications.
       
   320 
       
   321     This completes our review of the Plug & Paint application. At
       
   322     this point, you might want to take a look at the
       
   323     \l{tools/plugandpaintplugins/basictools}{Basic Tools} example
       
   324     plugin.
       
   325 */
       
   326 
       
   327 /*!
       
   328     \example tools/plugandpaintplugins/basictools
       
   329     \title Plug & Paint Basic Tools Example
       
   330 
       
   331     The Basic Tools example is a static plugin for the
       
   332     \l{tools/plugandpaint}{Plug & Paint} example. It provides a set
       
   333     of basic brushes, shapes, and filters. Through the Basic Tools
       
   334     example, we will review the four steps involved in writing a Qt
       
   335     plugin:
       
   336 
       
   337     \list 1
       
   338     \o Declare a plugin class.
       
   339     \o Implement the interfaces provided by the plugin.
       
   340     \o Export the plugin using the Q_EXPORT_PLUGIN2() macro.
       
   341     \o Build the plugin using an adequate \c .pro file.
       
   342     \endlist
       
   343 
       
   344     \section1 Declaration of the Plugin Class
       
   345 
       
   346     \snippet examples/tools/plugandpaintplugins/basictools/basictoolsplugin.h 0
       
   347 
       
   348     We start by including \c interfaces.h, which defines the plugin
       
   349     interfaces for the \l{tools/plugandpaint}{Plug & Paint}
       
   350     application. For the \c #include to work, we need to add an \c
       
   351     INCLUDEPATH entry to the \c .pro file with the path to Qt's \c
       
   352     examples/tools directory.
       
   353 
       
   354     The \c BasicToolsPlugin class is a QObject subclass that
       
   355     implements the \c BrushInterface, the \c ShapeInterface, and the
       
   356     \c FilterInterface. This is done through multiple inheritance.
       
   357     The \c Q_INTERFACES() macro is necessary to tell \l{moc}, Qt's
       
   358     meta-object compiler, that the base classes are plugin
       
   359     interfaces. Without the \c Q_INTERFACES() macro, we couldn't use
       
   360     \l qobject_cast() in the \l{tools/plugandpaint}{Plug & Paint}
       
   361     application to detect interfaces.
       
   362 
       
   363     \snippet examples/tools/plugandpaintplugins/basictools/basictoolsplugin.h 2
       
   364 
       
   365     In the \c public section of the class, we declare all the
       
   366     functions from the three interfaces.
       
   367 
       
   368     \section1 Implementation of the Brush Interface
       
   369 
       
   370     Let's now review the implementation of the \c BasicToolsPlugin
       
   371     member functions inherited from \c BrushInterface.
       
   372 
       
   373     \snippet examples/tools/plugandpaintplugins/basictools/basictoolsplugin.cpp 0
       
   374 
       
   375     The \c brushes() function returns a list of brushes provided by
       
   376     this plugin. We provide three brushes: \gui{Pencil}, \gui{Air
       
   377     Brush}, and \gui{Random Letters}.
       
   378 
       
   379     \snippet examples/tools/plugandpaintplugins/basictools/basictoolsplugin.cpp 1
       
   380 
       
   381     On a mouse press event, we just call \c mouseMove() to draw the
       
   382     spot where the event occurred.
       
   383 
       
   384     \snippet examples/tools/plugandpaintplugins/basictools/basictoolsplugin.cpp 2
       
   385 
       
   386     In \c mouseMove(), we start by saving the state of the QPainter
       
   387     and we compute a few variables that we'll need later.
       
   388 
       
   389     \snippet examples/tools/plugandpaintplugins/basictools/basictoolsplugin.cpp 3
       
   390 
       
   391     Then comes the brush-dependent part of the code:
       
   392 
       
   393     \list
       
   394     \o If the brush is \gui{Pencil}, we just call
       
   395        QPainter::drawLine() with the current QPen.
       
   396 
       
   397     \o If the brush is \gui{Air Brush}, we start by setting the
       
   398        painter's QBrush to Qt::Dense6Pattern to obtain a dotted
       
   399        pattern. Then we draw a circle filled with that QBrush several
       
   400        times, resulting in a thick line.
       
   401 
       
   402     \o If the brush is \gui{Random Letters}, we draw a random letter
       
   403        at the new cursor position. Most of the code is for setting
       
   404        the font to be bold and larger than the default font and for
       
   405        computing an appropriate bounding rect.
       
   406     \endlist
       
   407 
       
   408     At the end, we restore the painter state to what it was upon
       
   409     entering the function and we return the bounding rectangle.
       
   410 
       
   411     \snippet examples/tools/plugandpaintplugins/basictools/basictoolsplugin.cpp 4
       
   412 
       
   413     When the user releases the mouse, we do nothing and return an
       
   414     empty QRect.
       
   415 
       
   416     \section1 Implementation of the Shape Interface
       
   417 
       
   418     \snippet examples/tools/plugandpaintplugins/basictools/basictoolsplugin.cpp 5
       
   419 
       
   420     The plugin provides three shapes: \gui{Circle}, \gui{Star}, and
       
   421     \gui{Text...}. The three dots after \gui{Text} are there because
       
   422     the shape pops up a dialog asking for more information. We know
       
   423     that the shape names will end up in a menu, so we include the
       
   424     three dots in the shape name.
       
   425 
       
   426     A cleaner but more complicated design would have been to
       
   427     distinguish between the internal shape name and the name used in
       
   428     the user interface.
       
   429 
       
   430     \snippet examples/tools/plugandpaintplugins/basictools/basictoolsplugin.cpp 6
       
   431 
       
   432     The \c generateShape() creates a QPainterPath for the specified
       
   433     shape. If the shape is \gui{Text}, we pop up a QInputDialog to
       
   434     let the user enter some text.
       
   435 
       
   436     \section1 Implementation of the Filter Interface
       
   437 
       
   438     \snippet examples/tools/plugandpaintplugins/basictools/basictoolsplugin.cpp 7
       
   439 
       
   440     The plugin provides three filters: \gui{Invert Pixels}, \gui{Swap
       
   441     RGB}, and \gui{Grayscale}.
       
   442 
       
   443     \snippet examples/tools/plugandpaintplugins/basictools/basictoolsplugin.cpp 8
       
   444 
       
   445     The \c filterImage() function takes a filter name and a QImage as
       
   446     parameters and returns an altered QImage. The first thing we do
       
   447     is to convert the image to a 32-bit RGB format, to ensure that
       
   448     the algorithms will work as expected. For example,
       
   449     QImage::invertPixels(), which is used to implement the
       
   450     \gui{Invert Pixels} filter, gives counterintuitive results for
       
   451     8-bit images, because they invert the indices into the color
       
   452     table instead of inverting the color table's entries.
       
   453 
       
   454     \section1 Exporting the Plugin
       
   455 
       
   456     Whereas applications have a \c main() function as their entry
       
   457     point, plugins need to contain exactly one occurrence of the
       
   458     Q_EXPORT_PLUGIN2() macro to specify which class provides the
       
   459     plugin:
       
   460 
       
   461     \snippet examples/tools/plugandpaintplugins/basictools/basictoolsplugin.cpp 9
       
   462 
       
   463     This line may appear in any \c .cpp file that is part of the
       
   464     plugin's source code.
       
   465 
       
   466     \section1 The .pro File
       
   467 
       
   468     Here's the project file for building the Basic Tools plugin:
       
   469 
       
   470     \snippet examples/tools/plugandpaintplugins/basictools/basictools.pro 0
       
   471 
       
   472     The \c .pro file differs from typical \c .pro files in many
       
   473     respects. First, it starts with a \c TEMPLATE entry specifying \c
       
   474     lib. (The default template is \c app.) It also adds \c plugin to
       
   475     the \c CONFIG variable. This is necessary on some platforms to
       
   476     avoid generating symbolic links with version numbers in the file
       
   477     name, which is appropriate for most dynamic libraries but not for
       
   478     plugins.
       
   479 
       
   480     To make the plugin a static plugin, all that is required is to
       
   481     specify \c static in addition to \c plugin. The
       
   482     \l{tools/plugandpaintplugins/extrafilters}{Extra Filters} plugin,
       
   483     which is compiled as a dynamic plugin, doesn't specify \c static
       
   484     in its \c .pro file.
       
   485 
       
   486     The \c INCLUDEPATH variable sets the search paths for global
       
   487     headers (i.e., header files included using \c{#include <...>}).
       
   488     We add Qt's \c examples/tools directory (strictly speaking,
       
   489     \c{examples/tools/plugandpaintplugins/basictools/../..}) to the
       
   490     list, so that we can include \c <plugandpaint/interfaces.h>.
       
   491 
       
   492     The \c TARGET variable specifies which name we want to give the
       
   493     target library. We use \c pnp_ as the prefix to show that the
       
   494     plugin is designed to work with Plug & Paint. On Unix, \c lib is
       
   495     also prepended to that name. On all platforms, a
       
   496     platform-specific suffix is appended (e.g., \c .dll on Windows,
       
   497     \c .a on Linux).
       
   498 
       
   499     The \c CONFIG() code at the end is necessary for this example
       
   500     because the example is part of the Qt distribution and Qt can be
       
   501     configured to be built simultaneously in debug and in release
       
   502     modes. You don't need to for your own plugins.
       
   503 */
       
   504 
       
   505 /*!
       
   506     \example tools/plugandpaintplugins/extrafilters
       
   507     \title Plug & Paint Extra Filters Example
       
   508 
       
   509     The Extra Filters example is a plugin for the
       
   510     \l{tools/plugandpaint}{Plug & Paint} example. It provides a set
       
   511     of filters in addition to those provided by the
       
   512     \l{tools/plugandpaintplugins/basictools}{Basic Tools} plugin.
       
   513 
       
   514     Since the approach is identical to
       
   515     \l{tools/plugandpaintplugins/basictools}{Basic Tools}, we won't
       
   516     review the code here. The only part of interes is the
       
   517     \c .pro file, since Extra Filters is a dynamic plugin
       
   518     (\l{tools/plugandpaintplugins/basictools}{Basic Tools} is
       
   519     linked statically into the Plug & Paint executable).
       
   520 
       
   521     Here's the project file for building the Extra Filters plugin:
       
   522 
       
   523     \snippet examples/tools/plugandpaintplugins/extrafilters/extrafilters.pro 0
       
   524 
       
   525     The \c .pro file differs from typical \c .pro files in many
       
   526     respects. First, it starts with a \c TEMPLATE entry specifying \c
       
   527     lib. (The default template is \c app.) It also adds \c plugin to
       
   528     the \c CONFIG variable. This is necessary on some platforms to
       
   529     avoid generating symbolic links with version numbers in the file
       
   530     name, which is appropriate for most dynamic libraries but not for
       
   531     plugins.
       
   532 
       
   533     The \c INCLUDEPATH variable sets the search paths for global
       
   534     headers (i.e., header files included using \c{#include <...>}).
       
   535     We add Qt's \c examples/tools directory (strictly speaking,
       
   536     \c{examples/tools/plugandpaintplugins/basictools/../..}) to the
       
   537     list, so that we can include \c <plugandpaint/interfaces.h>.
       
   538 
       
   539     The \c TARGET variable specifies which name we want to give the
       
   540     target library. We use \c pnp_ as the prefix to show that the
       
   541     plugin is designed to work with Plug & Paint. On Unix, \c lib is
       
   542     also prepended to that name. On all platforms, a
       
   543     platform-specific suffix is appended (e.g., \c .dll on Windows,
       
   544     \c .so on Linux).
       
   545 
       
   546     The \c DESTDIR variable specifies where we want to install the
       
   547     plugin. We put it in Plug & Paint's \c plugins subdirectory,
       
   548     since that's where the application looks for dynamic plugins.
       
   549 
       
   550     The \c CONFIG() code at the end is necessary for this example
       
   551     because the example is part of the Qt distribution and Qt can be
       
   552     configured to be built simultaneously in debug and in release
       
   553     modes. You don't need to for your own plugins.
       
   554 */