[QGIS Commit] r9956 - in docs/trunk/english_us/user_guide: .
creating_applications_screenies
svn_qgis at osgeo.org
svn_qgis at osgeo.org
Fri Jan 9 06:36:09 EST 2009
Author: dassau
Date: 2009-01-09 06:36:09 -0500 (Fri, 09 Jan 2009)
New Revision: 9956
Added:
docs/trunk/english_us/user_guide/creating_applications_screenies/cpp1_application.png
docs/trunk/english_us/user_guide/creating_applications_screenies/cpp2_application.png
docs/trunk/english_us/user_guide/creating_cpp_applications.tex
docs/trunk/english_us/user_guide/creating_pyqgis_applications.tex
Removed:
docs/trunk/english_us/user_guide/creating_applications.tex
Modified:
docs/trunk/english_us/user_guide/Makefile
docs/trunk/english_us/user_guide/creating_applications_screenies/Makefile
docs/trunk/english_us/user_guide/external_plugins.tex
docs/trunk/english_us/user_guide/user_guide.tex
Log:
added section from Tim about creating c++ applications
revised external_plugins section
Modified: docs/trunk/english_us/user_guide/Makefile
===================================================================
--- docs/trunk/english_us/user_guide/Makefile 2009-01-09 09:41:18 UTC (rev 9955)
+++ docs/trunk/english_us/user_guide/Makefile 2009-01-09 11:36:09 UTC (rev 9956)
@@ -94,7 +94,7 @@
(cd ./working_with_projections_screenies && make)
(cd ./grass_integration_screenies && make)
(cd ./print_composer_screenies && make)
-# (cd ./creating_applications_screenies && make)
+ (cd ./creating_applications_screenies && make)
# (cd ./help_and_support_screenies && make)
(cd ./operating_system_icons && make)
Deleted: docs/trunk/english_us/user_guide/creating_applications.tex
===================================================================
--- docs/trunk/english_us/user_guide/creating_applications.tex 2009-01-09 09:41:18 UTC (rev 9955)
+++ docs/trunk/english_us/user_guide/creating_applications.tex 2009-01-09 11:36:09 UTC (rev 9956)
@@ -1,394 +0,0 @@
-% vim: set textwidth=78 autoindent:
-
-\section{Creating PyQGIS Applications}
-
-% when the revision of a section has been finalized,
-% comment out the following line:
-\updatedisclaimer
-
-One of the goals of QGIS is to provide not only an application, but a set of
-libraries that can be used to create new applications. This goal has been
-realized with the refactoring of libraries that took place after the release
-of 0.8. Since the release of 0.9, development of standalone applications using
-either C++ or Python is possible. We recommend you use QGIS 1.0.0 or greater
-as the basis for your pythong applications because since this version we now
-provide a stable consistent API.
-
-In this chapter we'll take a brief look at the process for creating a
-standalone Python application. The QGIS blog has several examples of creating
-PyQGIS\footnote{An application created using Python and the QGIS bindings}
-applications. We'll use one of them as a starting point to get a look at how
-to create an application.
-
-The features we want in the application are:
-
-\begin{itemize}
-\item Load a vector layer
-\item Pan
-\item Zoom in and out
-\item Zoom to the full extent of the layer
-\item Set custom colors when the layer is loaded
-\end{itemize}
-
-This is a pretty minimal feature set. Let's start by designing the GUI using
-Qt Designer.
-
-\subsection{Designing the GUI}
-
-Since we are creating a minimalistic application, we'll take the same
-approach with the GUI. Using Qt Designer, we create a simple MainWindow with
-no menu or toolbars. This gives us a blank slate to work with. To create the
-MainWindow:
-
-\begin{enumerate}
-\item Create a directory for developing the application and change to it
-\item Run Qt Designer
-\item The \qtdialog{New Form} dialog should appear. If it doesn't, choose
-\qtdropmenuopt{New Form...} from the \qtmainmenuopt{File} menu.
-\item Choose \qtdropmenuopt{Main Window} from
-the \qtdropmenuopt{templates/forms} list
-\item Click \qtdropmenuopt{Create}
-\item Resize the new window to something manageable
-\item Find the \qtdropmenuopt{Frame} widget in the list
-(under \qtdropmenuopt{Containers}) and drag it to
-the main window you just created
-\item Click outside the frame to select the main window area
-\item Click on the \qtdropmenuopt{Lay Out in a Grid} tool. When you do, the frame
-will expand to fill your entire main window
-\item Save the form as \usertext{mainwindow.ui}
-\item \qtdropmenuopt{Exit} Qt Designer
-\end{enumerate}
-
-Now compile the form using the PyQt interface compiler:
-
-\begin{verbatim}
- pyuic4 -o mainwindow_ui.py mainwindow.ui
-\end{verbatim}
-
-This creates the Python source for the main window GUI. Next we need to create
-the application code to fill the blank slate with some tools we can use.
-
-\subsection{Creating the MainWindow}
-
-Now we are ready to write the \classname{MainWindow} class that will do the real work.
-Since it takes up quite a few lines, we'll look at it in chunks, starting
-with the import section and environment setup:
-
-\begin{verbatim}
-1 # Loosely based on:
-2 # Original C++ Tutorial 2 by Tim Sutton
-3 # ported to Python by Martin Dobias
-4 # with enhancements by Gary Sherman for FOSS4G2007
-5 # Licensed under the terms of GNU GPL 2
-6
-7 from PyQt4.QtCore import *
-8 from PyQt4.QtGui import *
-9 from qgis.core import *
-10 from qgis.gui import *
-11 import sys
-12 import os
-13 # Import our GUI
-14 from mainwindow_ui import Ui_MainWindow
-15
-16 # Environment variable QGISHOME must be set to the 1.0 install directory
-17 # before running this application
-18 qgis_prefix = os.getenv("QGISHOME")
-\end{verbatim}
-
-Some of this should look familiar from our plugin, especially the PyQt4 and
-QGIS imports. Some specific things to note are the import of our GUI in line
-14 and the import of our CORE library on line 9.
-
-Our application needs to know where to find the QGIS installation. Because
-of this, we set the \usertext{QGISHOME} environment variable to point to the
-install directory of QGIS 1.x In line 20 we store this value from
-the environment for later use.
-
-Next we need to create our \classname{MainWindow} class which will contain
-all the logic of our application.
-\begin{verbatim}
-21 class MainWindow(QMainWindow, Ui_MainWindow):
-22
-23 def __init__(self):
-24 QMainWindow.__init__(self)
-25
-26 # Required by Qt4 to initialize the UI
-27 self.setupUi(self)
-28
-29 # Set the title for the app
-30 self.setWindowTitle("QGIS Demo App")
-31
-32 # Create the map canvas
-33 self.canvas = QgsMapCanvas()
-34 # Set the background color to light blue something
-35 self.canvas.setCanvasColor(QColor(200,200,255))
-36 self.canvas.enableAntiAliasing(True)
-37 self.canvas.useQImageToRender(False)
-38 self.canvas.show()
-39
-40 # Lay our widgets out in the main window using a
-41 # vertical box layout
-42 self.layout = QVBoxLayout(self.frame)
-43 self.layout.addWidget(self.canvas)
-44
-45 # Create the actions for our tools and connect each to the appropriate
-46 # method
-47 self.actionAddLayer = QAction(QIcon("(qgis_prefix + "/share/qgis/themes/classic/mActionAddLayer.png"),
-48 \
-49 "Add Layer", self.frame)
-50 self.connect(self.actionAddLayer, SIGNAL("activated()"), self.addLayer)
-51 self.actionZoomIn = QAction(QIcon("(qgis_prefix + "/share/qgis/themes/classic/mActionZoomIn.png"), \
-52 "Zoom In", self.frame)
-53 self.connect(self.actionZoomIn, SIGNAL("activated()"), self.zoomIn)
-54 self.actionZoomOut = QAction(QIcon("(qgis_prefix + "/share/qgis/themes/classic/mActionZoomOut.png"), \
-55 "Zoom Out", self.frame)
-56 self.connect(self.actionZoomOut, SIGNAL("activated()"), self.zoomOut)
-57 self.actionPan = QAction(QIcon("(qgis_prefix + "/share/qgis/themes/classic/mActionPan.png"), \
-58 "Pan", self.frame)
-59 self.connect(self.actionPan, SIGNAL("activated()"), self.pan)
-60 self.actionZoomFull = QAction(QIcon("(qgis_prefix + "/share/qgis/themes/classic/mActionZoomFullExtent.png"), \
-61 "Zoom Full Extent", self.frame)
-62 self.connect(self.actionZoomFull, SIGNAL("activated()"),
-63 self.zoomFull)
-64
-65 # Create a toolbar
-66 self.toolbar = self.addToolBar("Map")
-67 # Add the actions to the toolbar
-68 self.toolbar.addAction(self.actionAddLayer)
-69 self.toolbar.addAction(self.actionZoomIn)
-70 self.toolbar.addAction(self.actionZoomOut);
-71 self.toolbar.addAction(self.actionPan);
-72 self.toolbar.addAction(self.actionZoomFull);
-73
-74 # Create the map tools
-75 self.toolPan = QgsMapToolPan(self.canvas)
-76 self.toolZoomIn = QgsMapToolZoom(self.canvas, False) # false = in
-77 self.toolZoomOut = QgsMapToolZoom(self.canvas, True) # true = out
-\end{verbatim}
-
-Lines 21 through 27 are the basic declaration and initialization of the
-\classname{MainWindow} and the set up of the user interface using the
-\method{setupUi} method. This is required for all applications.
-
-Next we set the title for the application so it says something more
-interesting than \usertext{MainWindow} (line 30). Once that is
-complete, we are ready to complete the user interface. When we created it in
-Designer, we left it very sparse---just a main window and a frame. You could
-have added a menu and the toolbar using Designer, however we'll do it with
-Python.
-
-In lines 33 through 38 we set up the map canvas, set the background color to a
-light blue, and enable antialiasing. We also tell it not to use a
-\classname{QImage} for rendering (trust me on this one) and then set the
-canvas to visible by calling the \method{show} method.
-
-Next we set the layer to use a vertical box layout within the frame and add
-the map canvas to it in line 43.
-
-Lines 48 to 63 set up the actions and connections for the tools in our
-toolbar. For each tool, we create a \classname{QAction} using the icon we
-defined in the QGIS classic theme. Then we connect up the
-\usertext{activated} signal from the tool to the method in our class that will
-handle the action. This is similar to how we set things up in the plugin
-example.
-
-Once we have the actions and connections, we need to add them to the toolbar.
-In lines 66 through 72 we create the toolbar and add each tool to it.
-
-Lastly we create the three map tools for the application (lines 75 through
-77). We'll use the map tools in a moment when we define the methods to make
-our application functional. Let's look at the methods for the map tools.
-
-\begin{verbatim}
-78 # Set the map tool to zoom in
-79 def zoomIn(self):
-80 self.canvas.setMapTool(self.toolZoomIn)
-81
-82 # Set the map tool to zoom out
-83 def zoomOut(self):
-84 self.canvas.setMapTool(self.toolZoomOut)
-85
-86 # Set the map tool to
-87 def pan(self):
-88 self.canvas.setMapTool(self.toolPan)
-89
-90 # Zoom to full extent of layer
-91 def zoomFull(self):
-92 self.canvas.zoomFullExtent()
-\end{verbatim}
-
-For each map tool, we need a method that corresponds to the connection we made
-for each action. In lines 79 through 88 we set up a method for each of the
- three tools that interact with the map. When a tool is activated by clicking
- on it in the toolbar, the corresponding method is called that ``tells'' the
- map canvas it is the active tool. The active tool governs what happens when
- the mouse is clicked on the canvas.
-
-The \usertext{zoom to full extent} tool isn't a map tool---it does its job
-without requiring a click on the map. When it is activated, we call the
-\method{zoomFullExtent} method of the map canvas (line 92). This completes
-the implementation of all our tools except one---the \usertext{Add Layer}
-tool. %FIXME
-Let's look at it next:
-
-\begin{verbatim}
-93 # Add an OGR layer to the map
-94 def addLayer(self):
-95 file = QFileDialog.getOpenFileName(self, "Open Shapefile", ".", "Shapefiles
-96 (*.shp)")
-97 fileInfo = QFileInfo(file)
-98
-99 # Add the layer
-100 layer = QgsVectorLayer(file, fileInfo.fileName(), "ogr")
-101
-102 if not layer.isValid():
-103 return
-104
-105 # Change the color of the layer to gray
-106 symbols = layer.renderer().symbols()
-107 symbol = symbols[0]
-108 symbol.setFillColor(QColor.fromRgb(192,192,192))
-109
-110 # Add layer to the registry
-111 QgsMapLayerRegistry.instance().addMapLayer(layer);
-112
-113 # Set extent to the extent of our layer
-114 self.canvas.setExtent(layer.extent())
-115
-116 # Set up the map canvas layer set
-117 cl = QgsMapCanvasLayer(layer)
-118 layers = [cl]
-119 self.canvas.setLayerSet(layers)
-\end{verbatim}
-
-In the \method{addLayer} method we use a \classname{QFileDialog} to get the
-name of the shapefile to load. This is done in line 96.
-Notice that we specify a ``filter'' so the dialog will only show files of
-type \filename{.shp}.
-
-Next in line 97 we create a \classname{QFileInfo} object from the shapefile
-path. Now the layer is ready to be created in line 100. Using the
-\classname{QFileInfo} object to get the file name from the path we specify it
-for the name of the layer when it is created. To make sure that the layer is
-valid and won't cause any problems when loading, we check it in line 102. If
-it's bad, we bail out and don't add it to the map canvas.
-
-Normally layers are added with a random color. Here we want to tweak the
-colors for the layer to make a more pleasing display. Plus we know we are
-going to add the \filename{world\_borders} layer to the map and this will make
-it look nice on our blue background. To change the color, we need to get the
-symbol used for rendering and use it to set a new fill color. This is done in
-lines 106 through 108.
-
-All that's left is to actually add the layer to the registry and a few other
-housekeeping items (lines 111 through 119). This stuff is standard for adding
-a layer and the end result is the world borders on a light blue background.
-The only thing you may not want to do is set the extent to the layer, if you
-are going to be adding more than one layer in your application.
-
-That's the heart of the application and completes the \classname{MainWindow} class.
-
-\subsection{Finishing Up}
-
-The remainder of the code shown below creates the \object{QgsApplication}
-object, sets the path to the QGIS install, sets up the \method{main} method
-and then starts the application. The only other thing to note is that we move
-the application window to the upper left of the display. We could get fancy
-and use the Qt API to center it on the screen.
-
-\begin{verbatim}
-120 def main(argv):
-121 # create Qt application
-122 app = QApplication(argv)
-123
-124 # Initialize qgis libraries
-125 QgsApplication.setPrefixPath(qgis_prefix, True)
-126 QgsApplication.initQgis()
-127
-128 # create main window
-129 wnd = MainWindow()
-130 # Move the app window to upper left
-131 wnd.move(100,100)
-132 wnd.show()
-133
-134 # run!
-135 retval = app.exec_()
-136
-137 # exit
-138 QgsApplication.exitQgis()
-139 sys.exit(retval)
-140
-141
-142 if __name__ == "__main__":
-143 main(sys.argv)
-\end{verbatim}
-
-\subsection{Running the Application}
-
-Now we can run the application and see what happens. Of course if you are like
-most developers, you've been testing it out as you went along.
-
-Before we can run the application, we need to set some environment variables.
-
-\nix{}\osx{}
-\begin{verbatim}
-export LD_LIBRARY_PATH=$HOME/qgis/lib%$
-export PYTHONPATH=$HOME/qgis/share/qgis/python
-export QGISHOME=$HOME/qgis%$
-\end{verbatim}
-
-\win{}
-\begin{verbatim}
-set PATH=C:\qgis;%PATH%
-set PYTHONPATH=C:\qgis\python
-set QGISHOME=C:\qgis
-\end{verbatim}
-
-We assume
-\begin{itemize}
-\item\nix{}\osx{}QGIS is installed in
-your home directory in
-\filename{qgis}.
-\item\win{}QGIS is installed in \filename{C:\textbackslash qgis}.
-\end{itemize}
-
-When the application starts up, it looks like this:
-
-%\begin{figure}[ht]
-%\begin{center}
-% \caption{Starting the new demo application}\label{fig:demo_app_startup}%\smallskip
-% \includegraphics[scale=0.8]{getdsn}
-%\end{center}
-%\end{figure}
-
-To add the \filename{world\_borders} layer, click on the
-\usertext{Add Layer} tool and navigate to the data directory.
-Select the shapefile and click \button{Open} to add it to the map.
-Our custom fill color is applied and the result is:
-
-%\begin{figure}[ht]
-%\begin{center}
-% \caption{Adding a layer the demo application}\label{fig:demo_app_done}%\smallskip
-% \includegraphics[scale=0.8]{getdsn}
-%\end{center}
-%\end{figure}
-
-Creating a PyQGIS application is really pretty simple. In less than 150 lines
-of code we have an application that can load a shapefile and navigate the map.
-If you play around with the map, you'll notice that some of the built-in
-features of the canvas also work, including mouse wheel scrolling and panning
-by holding down the \keystroke{Space} bar and moving the mouse.
-
-Some sophisticated applications have been created with PyQGIS and more are in
-the works. This is pretty impressive, considering that this development has
-taken place even before the official release of QGIS 1.0.
-
-\begin{Tip}\caption{\textsc{Documentation For PyQGIS}}
-\qgistip{Whether you are writing a plugin or a PyQGIS application, you are
-going to need to refer to both the QGIS API documentation
-(\url{http://doc.qgis.org}) and the PyQt Python Bindings Reference Guide
-(\url{http://www.riverbankcomputing.com/Docs/PyQt4/pyqt4ref.html}). These
-documents provide information about the classes and methods you'll use to
-bring your Python creation to life.
-}
-\end{Tip}
Modified: docs/trunk/english_us/user_guide/creating_applications_screenies/Makefile
===================================================================
--- docs/trunk/english_us/user_guide/creating_applications_screenies/Makefile 2009-01-09 09:41:18 UTC (rev 9955)
+++ docs/trunk/english_us/user_guide/creating_applications_screenies/Makefile 2009-01-09 11:36:09 UTC (rev 9956)
@@ -10,9 +10,10 @@
# with .eps extension:
# JPG=qgis_icon_new_verylarge.eps\
-#PNG=getdsn.eps\
+PNG=cpp1_application.eps\
+ cpp2_application.eps\
+
-
##### TARGETS #####
all: $(PNG) $(JPG)
Added: docs/trunk/english_us/user_guide/creating_applications_screenies/cpp1_application.png
===================================================================
(Binary files differ)
Property changes on: docs/trunk/english_us/user_guide/creating_applications_screenies/cpp1_application.png
___________________________________________________________________
Name: svn:mime-type
+ application/octet-stream
Added: docs/trunk/english_us/user_guide/creating_applications_screenies/cpp2_application.png
===================================================================
(Binary files differ)
Property changes on: docs/trunk/english_us/user_guide/creating_applications_screenies/cpp2_application.png
___________________________________________________________________
Name: svn:mime-type
+ application/octet-stream
Added: docs/trunk/english_us/user_guide/creating_cpp_applications.tex
===================================================================
--- docs/trunk/english_us/user_guide/creating_cpp_applications.tex (rev 0)
+++ docs/trunk/english_us/user_guide/creating_cpp_applications.tex 2009-01-09 11:36:09 UTC (rev 9956)
@@ -0,0 +1,320 @@
+\section{Creating C++ Applications}
+
+Not everyone wants a full blown GIS desktop application. Sometimes you want
+to just have a widget inside your application that displays a map while the
+main goal of the application lies elsewhere. Perhaps a database frontend with
+a map display? This Section provides two simple code examples by Tim Sutton.
+They are available in the qgis subversion repository together with more
+interesting tutorials. Check out the whole repository from:
+\filename{https://svn.osgeo.org/qgis/trunk/code\_examples/}
+
+\subsection{Creating a simple mapping widget}\label{subsec:simple_widget}
+
+With this first tutorial we take a little walk through creating a simple mapping
+widget. It won't do anything much - just load a shape file and display it in
+a random colour.
+But it should give you an idea of the potential for using QGIS as an embedded
+mapping component. Before we carry on, many thanks to Francis Bolduc who wrote
+the beginnings of this demo. He kindly agreed to make his work generally
+available.
+
+We start with typical adding the neccessary includes for our app:
+
+\begin{verbatim}
+//
+// QGIS Includes
+//
+#include <qgsapplication.h>
+#include <qgsproviderregistry.h>
+#include <qgssinglesymbolrenderer.h>
+#include <qgsmaplayerregistry.h>
+#include <qgsvectorlayer.h>
+#include <qgsmapcanvas.h>
+//
+// Qt Includes
+//
+#include <QString>
+#include <QApplication>
+#include <QWidget>
+\end{verbatim}
+
+We use QgsApplication instead of Qt's QApplication, and get some added
+benifits of various static methods that can be used to locate library paths
+and so on.
+
+The provider registry is a singleton that keeps track of vector data provider
+plugins. It does all the work for you of loading the plugins and so on. The
+single symbol renderer is the most basic symbology class. It renders points,
+lines or polygons in a single colour which is chosen at random by default
+(though you can set it yourself). Every vector layer must have a symbology
+associated with it.
+
+The map layer registry keeps track of all the layers you are using. The
+vector layer class inherits from maplayer and extends it to include
+specialist functionality for vector data.
+
+Finally the mapcanvas is really the nub of the matter. Its the drawable
+widget that our map will be drawn onto.
+
+Now we can move on to initialising our application....
+
+\begin{verbatim}
+int main(int argc, char ** argv)
+{
+ // Start the Application
+ QgsApplication app(argc, argv, true);
+
+ QString myPluginsDir = "/home/timlinux/apps/lib/qgis";
+ QString myLayerPath = "/home/timlinux/gisdata/brazil/BR_Cidades/";
+ QString myLayerBaseName = "Brasil_Cap";
+ QString myProviderName = "ogr";
+
+\end{verbatim}
+
+So now we have a qgsapplication and we have defined some variables. Since I
+tested this on the Ubuntu 8.10, I just specified the location of the vector
+provider plugins as being inside the my development install directory. It
+would probaby make more sense in general to keep the QGIS libs in one of the
+standard library search paths on your system (e.g. /usr/lib) but this way
+will do for now.
+
+The next two variables defined here just point to the shapefile I am going to
+be using (and you should substitute your own data here).
+
+The provider name is important - it tells qgis which data provider to use to
+load the file. Typically you will use 'ogr' or 'postgres'.
+
+Now we can go on to actually create our layer object.
+
+\begin{verbatim}
+ // Instantiate Provider Registry
+ QgsProviderRegistry::instance(myPluginsDir);
+\end{verbatim}
+
+First we get the provider registry initialised. Its a singleton class so we
+use the static instance call and pass it the provider lib search path. As it
+initialises it will scan this path for provider libs.
+
+Now we go on to create a layer...
+
+\begin{verbatim}
+ QgsVectorLayer * mypLayer =
+ new QgsVectorLayer(myLayerPath, myLayerBaseName, myProviderName);
+ QgsSingleSymbolRenderer *mypRenderer = new
+QgsSingleSymbolRenderer(mypLayer->geometryType());
+ QList <QgsMapCanvasLayer> myLayerSet;
+
+ mypLayer->setRenderer(mypRenderer);
+ if (mypLayer->isValid())
+ {
+ qDebug("Layer is valid");
+ }
+ else
+ {
+ qDebug("Layer is NOT valid");
+ }
+
+ // Add the Vector Layer to the Layer Registry
+ QgsMapLayerRegistry::instance()->addMapLayer(mypLayer, TRUE);
+ // Add the Layer to the Layer Set
+ myLayerSet.append(QgsMapCanvasLayer(mypLayer, TRUE));
+
+\end{verbatim}
+
+The code is fairly self explanatory here. We create a layer using the
+variables
+we defined earlier. Then we assign the layer a renderer. When we create a
+renderer, we need to specify the geometry type, which do do by asking the
+vector layer for its geometry type. Next we add the layer to a layerset
+(which
+is used by the QgsMapCanvas to keep track of which layers to render and in
+what
+order) and to the maplayer registry. Finally we make sure the layer will be
+visible.
+
+Now we create a map canvas on to which we can draw the layer.
+
+\begin{verbatim}
+ // Create the Map Canvas
+ QgsMapCanvas * mypMapCanvas = new QgsMapCanvas(0, 0);
+ mypMapCanvas->setExtent(mypLayer->extent());
+ mypMapCanvas->enableAntiAliasing(true);
+ mypMapCanvas->setCanvasColor(QColor(255, 255, 255));
+ mypMapCanvas->freeze(false);
+ // Set the Map Canvas Layer Set
+ mypMapCanvas->setLayerSet(myLayerSet);
+ mypMapCanvas->setVisible(true);
+ mypMapCanvas->refresh();
+
+\end{verbatim}
+
+Once again there is nothing particularly tricky here. We create the canvas
+and then we set its extents to those of our layer. Next we tweak the canvas a bit
+to draw antialiased vectors. Next we set the background colour, unfreeze the
+canvas, make it visible and then refresh it.
+
+\begin{verbatim}
+ // Start the Application Event Loop
+ return app.exec();
+}
+
+\end{verbatim}
+
+In the last step we simply start the Qt event loop and we are all done. You
+can check out, compile and run this example using cmake like this:
+
+\begin{verbatim}
+svn co
+https://svn.osgeo.org/qgis/trunk/code_examples/1_hello_world_qgis_style
+cd 1_hello_world_qgis_style
+mkdir build
+#optionally specify where your QGIS is installed (should work on all
+platforms)
+#if your QGIS is installed to /usr or /usr/local you can leave this next step
+out
+export LIB_DIR=/home/timlinux/apps
+cmake ..
+make
+./timtut1
+\end{verbatim}
+
+When we compile and run it here is what the running app looks like:
+
+\begin{figure}[ht]
+ \begin{center}
+ \caption{Simple C++ Application \osxcaption}\label{fig:cpp1_application}\smallskip
+ \includegraphics[clip=true]{cpp1_application}
+\end{center}
+\end{figure}
+
+\subsection{Working with QgsMapCanvas}
+
+In Section~\ref{subsec:simple_widget} we showed you the usage of the
+QgsMapCanvas api to create a simple application that loads a shapefile and
+displays the points in it. But what good is a map that you can't interact
+with?
+
+In this second tutorial I will extend the last tutorial by making it a
+QMainWindow application with a menu, toolbar and canvas area. We show you how
+to use QgsMapTool - the base class for all tools that need to interact with
+the map canvas.
+The purpose is to provide a demonstrator project, so I wont promise to write the most
+elegant or robust C++ code. The project will provide 4 toolbar icons for
+
+\begin{itemize}
+ \item loading a map layer (layer name is hard coded in the application
+ \item zooming in
+ \item zooming out
+ \item panning
+\end{itemize}
+
+In the working directory for the tutorial code you will find a number of files
+including c++ sources, icons and a simple data file under data. There is also
+the .ui file for the main window.
+
+\textbf{Note:} You will need to edit the .pro file in the above svn directory to
+match your system.
+
+Since much of the code is the same as the previous tutorial, I will focus on
+the MapTool specifics - the rest of the implementation details can be
+investigated by checking out the project form SVN. A QgsMapTool is a class that
+interacts with the MapCanvas using the mouse pointer. QGIS has a number of
+QgsMapTools implemented, and you can subclass QgsMapTool to create your own. In
+mainwindow.cpp you will see I include the headers for the QgsMapTools near the
+start of the file:
+
+\begin{verbatim}
+ //
+ // QGIS Map tools
+ //
+ #include "qgsmaptoolpan.h"
+ #include "qgsmaptoolzoom.h"
+ //
+ // These are the other headers for available map tools
+ // (not used in this example)
+ //
+ //#include "qgsmaptoolcapture.h"
+ //#include "qgsmaptoolidentify.h"
+ //#include "qgsmaptoolselect.h"
+ //#include "qgsmaptoolvertexedit.h"
+ //#include "qgsmeasure.h"
+\end{verbatim}
+
+As you can see, I am only using two types of MapTool subclasses for this
+tutorial, but there are more available in the QGIS library. Hooking up our
+MapTools to the canvas is very easy using the normal Qt4 signal/slot mechanism:
+
+\begin{verbatim}
+ //create the action behaviours
+ connect(mActionPan, SIGNAL(triggered()), this, SLOT(panMode()));
+ connect(mActionZoomIn, SIGNAL(triggered()), this, SLOT(zoomInMode()));
+ connect(mActionZoomOut, SIGNAL(triggered()), this, SLOT(zoomOutMode()));
+ connect(mActionAddLayer, SIGNAL(triggered()), this, SLOT(addLayer()));
+\end{verbatim}
+
+Next we make a small toolbar to hold our toolbuttons. Note that the mpAction*
+actions were created in designer.
+
+\begin{verbatim}
+ //create a little toolbar
+ mpMapToolBar = addToolBar(tr("File"));
+ mpMapToolBar->addAction(mpActionAddLayer);
+ mpMapToolBar->addAction(mpActionZoomIn);
+ mpMapToolBar->addAction(mpActionZoomOut);
+ mpMapToolBar->addAction(mpActionPan);
+\end{verbatim}
+
+Thats really pretty straightforward Qt stuff too. Now we create our three map
+tools:
+
+\begin{verbatim}
+ //create the maptools
+ mpPanTool = new QgsMapToolPan(mpMapCanvas);
+ mpPanTool->setAction(mpActionPan);
+ mpZoomInTool = new QgsMapToolZoom(mpMapCanvas, FALSE); // false = in
+ mpZoomInTool->setAction(mpActionZoomIn);
+ mpZoomOutTool = new QgsMapToolZoom(mpMapCanvas, TRUE ); //true = out
+ mpZoomOutTool->setAction(mpActionZoomOut);
+\end{verbatim}
+
+Again nothing here is very complicated - we are creating tool instances, each
+of which is associated with the same mapcanvas, and a different QAction. When
+the user selects one of the toolbar icons, the active MapTool for the canvas is
+set. For example when the pan icon is clicked, we do this:
+
+\begin{verbatim}
+ void MainWindow::panMode()
+ {
+ mpMapCanvas->setMapTool(mpPanTool);
+ }
+\end{verbatim}
+
+\begin{figure}[ht]
+ \begin{center}
+ \caption{QMainWindow application with a menu, toolbar and canvas area
+\osxcaption}\label{fig:cpp2_application}\smallskip
+ \includegraphics[clip=true, width=\textwidth]{cpp2_application}
+\end{center}
+\end{figure}
+
+\minisec{Conclusion}
+
+As you can see extending our previous example into something more functional
+using MapTools is really easy and only requires a few lines of code for each
+MapTool you want to provide.
+
+You can check out and build this tutorial using SVN and CMake using the following steps:
+
+\begin{verbatim}
+svn co https://svn.osgeo.org/qgis/trunk/code_examples/2_basic_main_window
+cd 2_basic_main_window
+mkdir build
+#optionally specify where your QGIS is installed (should work on all platforms)
+#if your QGIS is installed to /usr or /usr/local you can leave this next step out
+export LIB_DIR=/home/timlinux/apps
+cmake ..
+make
+./timtut2
+\end{verbatim}
+
+
Added: docs/trunk/english_us/user_guide/creating_pyqgis_applications.tex
===================================================================
--- docs/trunk/english_us/user_guide/creating_pyqgis_applications.tex (rev 0)
+++ docs/trunk/english_us/user_guide/creating_pyqgis_applications.tex 2009-01-09 11:36:09 UTC (rev 9956)
@@ -0,0 +1,394 @@
+% vim: set textwidth=78 autoindent:
+
+\section{Creating PyQGIS Applications}
+
+% when the revision of a section has been finalized,
+% comment out the following line:
+% \updatedisclaimer
+
+One of the goals of QGIS is to provide not only an application, but a set of
+libraries that can be used to create new applications. This goal has been
+realized with the refactoring of libraries that took place after the release
+of 0.8. Since the release of 0.9, development of standalone applications using
+either C++ or Python is possible. We recommend you use QGIS 1.0.0 or greater
+as the basis for your pythong applications because since this version we now
+provide a stable consistent API.
+
+In this chapter we'll take a brief look at the process for creating a
+standalone Python application. The QGIS blog has several examples of creating
+PyQGIS\footnote{An application created using Python and the QGIS bindings}
+applications. We'll use one of them as a starting point to get a look at how
+to create an application.
+
+The features we want in the application are:
+
+\begin{itemize}
+\item Load a vector layer
+\item Pan
+\item Zoom in and out
+\item Zoom to the full extent of the layer
+\item Set custom colors when the layer is loaded
+\end{itemize}
+
+This is a pretty minimal feature set. Let's start by designing the GUI using
+Qt Designer.
+
+\subsection{Designing the GUI}
+
+Since we are creating a minimalistic application, we'll take the same
+approach with the GUI. Using Qt Designer, we create a simple MainWindow with
+no menu or toolbars. This gives us a blank slate to work with. To create the
+MainWindow:
+
+\begin{enumerate}
+\item Create a directory for developing the application and change to it
+\item Run Qt Designer
+\item The \qtdialog{New Form} dialog should appear. If it doesn't, choose
+\qtdropmenuopt{New Form...} from the \qtmainmenuopt{File} menu.
+\item Choose \qtdropmenuopt{Main Window} from
+the \qtdropmenuopt{templates/forms} list
+\item Click \qtdropmenuopt{Create}
+\item Resize the new window to something manageable
+\item Find the \qtdropmenuopt{Frame} widget in the list
+(under \qtdropmenuopt{Containers}) and drag it to
+the main window you just created
+\item Click outside the frame to select the main window area
+\item Click on the \qtdropmenuopt{Lay Out in a Grid} tool. When you do, the frame
+will expand to fill your entire main window
+\item Save the form as \usertext{mainwindow.ui}
+\item \qtdropmenuopt{Exit} Qt Designer
+\end{enumerate}
+
+Now compile the form using the PyQt interface compiler:
+
+\begin{verbatim}
+ pyuic4 -o mainwindow_ui.py mainwindow.ui
+\end{verbatim}
+
+This creates the Python source for the main window GUI. Next we need to create
+the application code to fill the blank slate with some tools we can use.
+
+\subsection{Creating the MainWindow}
+
+Now we are ready to write the \classname{MainWindow} class that will do the real work.
+Since it takes up quite a few lines, we'll look at it in chunks, starting
+with the import section and environment setup:
+
+\begin{verbatim}
+1 # Loosely based on:
+2 # Original C++ Tutorial 2 by Tim Sutton
+3 # ported to Python by Martin Dobias
+4 # with enhancements by Gary Sherman for FOSS4G2007
+5 # Licensed under the terms of GNU GPL 2
+6
+7 from PyQt4.QtCore import *
+8 from PyQt4.QtGui import *
+9 from qgis.core import *
+10 from qgis.gui import *
+11 import sys
+12 import os
+13 # Import our GUI
+14 from mainwindow_ui import Ui_MainWindow
+15
+16 # Environment variable QGISHOME must be set to the 1.0 install directory
+17 # before running this application
+18 qgis_prefix = os.getenv("QGISHOME")
+\end{verbatim}
+
+Some of this should look familiar from our plugin, especially the PyQt4 and
+QGIS imports. Some specific things to note are the import of our GUI in line
+14 and the import of our CORE library on line 9.
+
+Our application needs to know where to find the QGIS installation. Because
+of this, we set the \usertext{QGISHOME} environment variable to point to the
+install directory of QGIS 1.x In line 20 we store this value from
+the environment for later use.
+
+Next we need to create our \classname{MainWindow} class which will contain
+all the logic of our application.
+\begin{verbatim}
+21 class MainWindow(QMainWindow, Ui_MainWindow):
+22
+23 def __init__(self):
+24 QMainWindow.__init__(self)
+25
+26 # Required by Qt4 to initialize the UI
+27 self.setupUi(self)
+28
+29 # Set the title for the app
+30 self.setWindowTitle("QGIS Demo App")
+31
+32 # Create the map canvas
+33 self.canvas = QgsMapCanvas()
+34 # Set the background color to light blue something
+35 self.canvas.setCanvasColor(QColor(200,200,255))
+36 self.canvas.enableAntiAliasing(True)
+37 self.canvas.useQImageToRender(False)
+38 self.canvas.show()
+39
+40 # Lay our widgets out in the main window using a
+41 # vertical box layout
+42 self.layout = QVBoxLayout(self.frame)
+43 self.layout.addWidget(self.canvas)
+44
+45 # Create the actions for our tools and connect each to the appropriate
+46 # method
+47 self.actionAddLayer = QAction(QIcon("(qgis_prefix + "/share/qgis/themes/classic/mActionAddLayer.png"),
+48 \
+49 "Add Layer", self.frame)
+50 self.connect(self.actionAddLayer, SIGNAL("activated()"), self.addLayer)
+51 self.actionZoomIn = QAction(QIcon("(qgis_prefix + "/share/qgis/themes/classic/mActionZoomIn.png"), \
+52 "Zoom In", self.frame)
+53 self.connect(self.actionZoomIn, SIGNAL("activated()"), self.zoomIn)
+54 self.actionZoomOut = QAction(QIcon("(qgis_prefix + "/share/qgis/themes/classic/mActionZoomOut.png"), \
+55 "Zoom Out", self.frame)
+56 self.connect(self.actionZoomOut, SIGNAL("activated()"), self.zoomOut)
+57 self.actionPan = QAction(QIcon("(qgis_prefix + "/share/qgis/themes/classic/mActionPan.png"), \
+58 "Pan", self.frame)
+59 self.connect(self.actionPan, SIGNAL("activated()"), self.pan)
+60 self.actionZoomFull = QAction(QIcon("(qgis_prefix + "/share/qgis/themes/classic/mActionZoomFullExtent.png"), \
+61 "Zoom Full Extent", self.frame)
+62 self.connect(self.actionZoomFull, SIGNAL("activated()"),
+63 self.zoomFull)
+64
+65 # Create a toolbar
+66 self.toolbar = self.addToolBar("Map")
+67 # Add the actions to the toolbar
+68 self.toolbar.addAction(self.actionAddLayer)
+69 self.toolbar.addAction(self.actionZoomIn)
+70 self.toolbar.addAction(self.actionZoomOut);
+71 self.toolbar.addAction(self.actionPan);
+72 self.toolbar.addAction(self.actionZoomFull);
+73
+74 # Create the map tools
+75 self.toolPan = QgsMapToolPan(self.canvas)
+76 self.toolZoomIn = QgsMapToolZoom(self.canvas, False) # false = in
+77 self.toolZoomOut = QgsMapToolZoom(self.canvas, True) # true = out
+\end{verbatim}
+
+Lines 21 through 27 are the basic declaration and initialization of the
+\classname{MainWindow} and the set up of the user interface using the
+\method{setupUi} method. This is required for all applications.
+
+Next we set the title for the application so it says something more
+interesting than \usertext{MainWindow} (line 30). Once that is
+complete, we are ready to complete the user interface. When we created it in
+Designer, we left it very sparse---just a main window and a frame. You could
+have added a menu and the toolbar using Designer, however we'll do it with
+Python.
+
+In lines 33 through 38 we set up the map canvas, set the background color to a
+light blue, and enable antialiasing. We also tell it not to use a
+\classname{QImage} for rendering (trust me on this one) and then set the
+canvas to visible by calling the \method{show} method.
+
+Next we set the layer to use a vertical box layout within the frame and add
+the map canvas to it in line 43.
+
+Lines 48 to 63 set up the actions and connections for the tools in our
+toolbar. For each tool, we create a \classname{QAction} using the icon we
+defined in the QGIS classic theme. Then we connect up the
+\usertext{activated} signal from the tool to the method in our class that will
+handle the action. This is similar to how we set things up in the plugin
+example.
+
+Once we have the actions and connections, we need to add them to the toolbar.
+In lines 66 through 72 we create the toolbar and add each tool to it.
+
+Lastly we create the three map tools for the application (lines 75 through
+77). We'll use the map tools in a moment when we define the methods to make
+our application functional. Let's look at the methods for the map tools.
+
+\begin{verbatim}
+78 # Set the map tool to zoom in
+79 def zoomIn(self):
+80 self.canvas.setMapTool(self.toolZoomIn)
+81
+82 # Set the map tool to zoom out
+83 def zoomOut(self):
+84 self.canvas.setMapTool(self.toolZoomOut)
+85
+86 # Set the map tool to
+87 def pan(self):
+88 self.canvas.setMapTool(self.toolPan)
+89
+90 # Zoom to full extent of layer
+91 def zoomFull(self):
+92 self.canvas.zoomFullExtent()
+\end{verbatim}
+
+For each map tool, we need a method that corresponds to the connection we made
+for each action. In lines 79 through 88 we set up a method for each of the
+ three tools that interact with the map. When a tool is activated by clicking
+ on it in the toolbar, the corresponding method is called that ``tells'' the
+ map canvas it is the active tool. The active tool governs what happens when
+ the mouse is clicked on the canvas.
+
+The \usertext{zoom to full extent} tool isn't a map tool---it does its job
+without requiring a click on the map. When it is activated, we call the
+\method{zoomFullExtent} method of the map canvas (line 92). This completes
+the implementation of all our tools except one---the \usertext{Add Layer}
+tool. %FIXME
+Let's look at it next:
+
+\begin{verbatim}
+93 # Add an OGR layer to the map
+94 def addLayer(self):
+95 file = QFileDialog.getOpenFileName(self, "Open Shapefile", ".", "Shapefiles
+96 (*.shp)")
+97 fileInfo = QFileInfo(file)
+98
+99 # Add the layer
+100 layer = QgsVectorLayer(file, fileInfo.fileName(), "ogr")
+101
+102 if not layer.isValid():
+103 return
+104
+105 # Change the color of the layer to gray
+106 symbols = layer.renderer().symbols()
+107 symbol = symbols[0]
+108 symbol.setFillColor(QColor.fromRgb(192,192,192))
+109
+110 # Add layer to the registry
+111 QgsMapLayerRegistry.instance().addMapLayer(layer);
+112
+113 # Set extent to the extent of our layer
+114 self.canvas.setExtent(layer.extent())
+115
+116 # Set up the map canvas layer set
+117 cl = QgsMapCanvasLayer(layer)
+118 layers = [cl]
+119 self.canvas.setLayerSet(layers)
+\end{verbatim}
+
+In the \method{addLayer} method we use a \classname{QFileDialog} to get the
+name of the shapefile to load. This is done in line 96.
+Notice that we specify a ``filter'' so the dialog will only show files of
+type \filename{.shp}.
+
+Next in line 97 we create a \classname{QFileInfo} object from the shapefile
+path. Now the layer is ready to be created in line 100. Using the
+\classname{QFileInfo} object to get the file name from the path we specify it
+for the name of the layer when it is created. To make sure that the layer is
+valid and won't cause any problems when loading, we check it in line 102. If
+it's bad, we bail out and don't add it to the map canvas.
+
+Normally layers are added with a random color. Here we want to tweak the
+colors for the layer to make a more pleasing display. Plus we know we are
+going to add the \filename{world\_borders} layer to the map and this will make
+it look nice on our blue background. To change the color, we need to get the
+symbol used for rendering and use it to set a new fill color. This is done in
+lines 106 through 108.
+
+All that's left is to actually add the layer to the registry and a few other
+housekeeping items (lines 111 through 119). This stuff is standard for adding
+a layer and the end result is the world borders on a light blue background.
+The only thing you may not want to do is set the extent to the layer, if you
+are going to be adding more than one layer in your application.
+
+That's the heart of the application and completes the \classname{MainWindow} class.
+
+\subsection{Finishing Up}
+
+The remainder of the code shown below creates the \object{QgsApplication}
+object, sets the path to the QGIS install, sets up the \method{main} method
+and then starts the application. The only other thing to note is that we move
+the application window to the upper left of the display. We could get fancy
+and use the Qt API to center it on the screen.
+
+\begin{verbatim}
+120 def main(argv):
+121 # create Qt application
+122 app = QApplication(argv)
+123
+124 # Initialize qgis libraries
+125 QgsApplication.setPrefixPath(qgis_prefix, True)
+126 QgsApplication.initQgis()
+127
+128 # create main window
+129 wnd = MainWindow()
+130 # Move the app window to upper left
+131 wnd.move(100,100)
+132 wnd.show()
+133
+134 # run!
+135 retval = app.exec_()
+136
+137 # exit
+138 QgsApplication.exitQgis()
+139 sys.exit(retval)
+140
+141
+142 if __name__ == "__main__":
+143 main(sys.argv)
+\end{verbatim}
+
+\subsection{Running the Application}
+
+Now we can run the application and see what happens. Of course if you are like
+most developers, you've been testing it out as you went along.
+
+Before we can run the application, we need to set some environment variables.
+
+\nix{}\osx{}
+\begin{verbatim}
+export LD_LIBRARY_PATH=$HOME/qgis/lib%$
+export PYTHONPATH=$HOME/qgis/share/qgis/python
+export QGISHOME=$HOME/qgis%$
+\end{verbatim}
+
+\win{}
+\begin{verbatim}
+set PATH=C:\qgis;%PATH%
+set PYTHONPATH=C:\qgis\python
+set QGISHOME=C:\qgis
+\end{verbatim}
+
+We assume
+\begin{itemize}
+\item\nix{}\osx{}QGIS is installed in
+your home directory in
+\filename{qgis}.
+\item\win{}QGIS is installed in \filename{C:\textbackslash qgis}.
+\end{itemize}
+
+When the application starts up, it looks like this:
+
+%\begin{figure}[ht]
+%\begin{center}
+% \caption{Starting the new demo application}\label{fig:demo_app_startup}%\smallskip
+% \includegraphics[scale=0.8]{getdsn}
+%\end{center}
+%\end{figure}
+
+To add the \filename{world\_borders} layer, click on the
+\usertext{Add Layer} tool and navigate to the data directory.
+Select the shapefile and click \button{Open} to add it to the map.
+Our custom fill color is applied and the result is:
+
+%\begin{figure}[ht]
+%\begin{center}
+% \caption{Adding a layer the demo application}\label{fig:demo_app_done}%\smallskip
+% \includegraphics[scale=0.8]{getdsn}
+%\end{center}
+%\end{figure}
+
+Creating a PyQGIS application is really pretty simple. In less than 150 lines
+of code we have an application that can load a shapefile and navigate the map.
+If you play around with the map, you'll notice that some of the built-in
+features of the canvas also work, including mouse wheel scrolling and panning
+by holding down the \keystroke{Space} bar and moving the mouse.
+
+Some sophisticated applications have been created with PyQGIS and more are in
+the works. This is pretty impressive, considering that this development has
+taken place even before the official release of QGIS 1.0.
+
+\begin{Tip}\caption{\textsc{Documentation For PyQGIS}}
+\qgistip{Whether you are writing a plugin or a PyQGIS application, you are
+going to need to refer to both the QGIS API documentation
+(\url{http://doc.qgis.org}) and the PyQt Python Bindings Reference Guide
+(\url{http://www.riverbankcomputing.com/Docs/PyQt4/pyqt4ref.html}). These
+documents provide information about the classes and methods you'll use to
+bring your Python creation to life.
+}
+\end{Tip}
Modified: docs/trunk/english_us/user_guide/external_plugins.tex
===================================================================
--- docs/trunk/english_us/user_guide/external_plugins.tex 2009-01-09 09:41:18 UTC (rev 9955)
+++ docs/trunk/english_us/user_guide/external_plugins.tex 2009-01-09 11:36:09 UTC (rev 9956)
@@ -4,7 +4,7 @@
% when the revision of a section has been finalized,
% comment out the following line:
-\updatedisclaimer
+% \updatedisclaimer
External QGIS plugins are written in python. They are stored in
an official, moderated repository and maintained by the individual
@@ -14,18 +14,19 @@
\footnote{The Python Plugin Installer is also an external Python Plugin, but
it is part of the QGIS sources and automatically loaded and selectable inside
the QGIS Plugin Manager (see Section~\ref{sec:load_external_plugin}).}
-An up-to-date list of moderated external plugins is available in the
-QGIS Official Repository of the
-\dropmenuopttwo{plugin_installer}{Fetch Python Plugins...}) and at
-\url{http://qgis.osgeo.org/download/plugins.html}.
-A detailed documentation about the usage, the author and other important
-information are provided with the external plugin itself and not part of this
-manual.
+When this manual was released, the external moderated QGIS plugin repository
+was not fully established. A detailed documentation about the usage, the
+author and other important information are provided with the external plugin
+itself and is not part of this manual.
+You find an up-to-date list of moderated external plugins in the QGIS
+Official Repository of the \dropmenuopttwo{plugin_installer}{Fetch Python
+Plugins...}) and at \url{http://qgis.osgeo.org/download/plugins.html}.
+
\begin{table}[H]
\centering
-\caption{QGIS moderated external Plugins}\label{tab:external_plugins}\medskip
+\caption{Current moderated external QGIS Plugins}\label{tab:external_plugins}\medskip
\small
\begin{tabular}{|l|l|p{4in}|}
\hline \textbf{Icon} & \textbf{external Plugin} & \textbf{Description}\\
Modified: docs/trunk/english_us/user_guide/user_guide.tex
===================================================================
--- docs/trunk/english_us/user_guide/user_guide.tex 2009-01-09 09:41:18 UTC (rev 9955)
+++ docs/trunk/english_us/user_guide/user_guide.tex 2009-01-09 11:36:09 UTC (rev 9956)
@@ -44,11 +44,10 @@
\include{plugins_writing_in_cpp}
\include{plugins_writing_in_python}
%end of plugin docs
-\include{creating_applications}
+\include{creating_cpp_applications}
+\include{creating_pyqgis_applications}
\include{help_and_support}
-
\appendix
-
\include{appendices/supported_data_formats}
\include{appendices/grass_toolbox_modules}
%install guide is a special case because we are extracting it
More information about the QGIS-commit
mailing list