Quantum GIS API Documentation  1.8
src/gui/qgsquickprint.cpp
Go to the documentation of this file.
00001 /***************************************************************************
00002   qgsquickprint.cpp
00003   A class to quickly print a map with minimal effort.
00004   -------------------
00005          begin                : Jan 2008
00006          copyright            : (c) Tim Sutton, 2008
00007          email                : [email protected]
00008 
00009  ***************************************************************************
00010  *                                                                         *
00011  *   This program is free software; you can redistribute it and/or modify  *
00012  *   it under the terms of the GNU General Public License as published by  *
00013  *   the Free Software Foundation; either version 2 of the License, or     *
00014  *   (at your option) any later version.                                   *
00015  *                                                                         *
00016  ***************************************************************************/
00017 
00018 //
00019 // QGIS Specific includes
00020 //
00021 
00022 #include <qgisinterface.h>
00023 #include <qgisgui.h>
00024 #include "qgsquickprint.h"
00025 #include <qgsapplication.h>
00026 #include <qgsmaplayerregistry.h>
00027 #include <qgsvectorlayer.h>
00028 #include <qgssymbol.h>
00029 #include <qgsmapcanvas.h>
00030 #include <qgsrenderer.h>
00031 #include <qgslogger.h>
00032 #include <qgslabelattributes.h>
00033 #include <qgslabel.h>
00034 
00035 //
00036 // Qt4 Related Includes
00037 //
00038 
00039 #include <QAction>
00040 #include <QToolBar>
00041 #include <QColor>
00042 #include <QPainter>
00043 #include <QDate>
00044 #include <QPixmap>
00045 #include <QString>
00046 #include <QSettings>
00047 #include <QSvgRenderer>
00048 #include <QLinearGradient>
00049 
00050 //other includes
00051 #include <cmath>
00052 
00053 #ifdef _MSC_VER
00054 #define round(x)  ((x) >= 0 ? floor((x)+0.5) : floor((x)-0.5))
00055 #endif
00056 
00057 QgsQuickPrint::QgsQuickPrint()
00058 {
00059   mPageSize = QPrinter::A4;
00060 }
00061 
00062 QgsQuickPrint::~QgsQuickPrint()
00063 {
00064 
00065 }
00066 void QgsQuickPrint::setTitle( QString theText )
00067 {
00068   mTitleText = theText;
00069 }
00070 void QgsQuickPrint::setName( QString theText )
00071 {
00072   mNameText = theText;
00073 }
00074 void QgsQuickPrint::setCopyright( QString theText )
00075 {
00076   mCopyrightText = theText;
00077 }
00078 void QgsQuickPrint::setNorthArrow( QString theFileName )
00079 {
00080   mNorthArrowFile = theFileName;
00081 }
00082 void QgsQuickPrint::setLogo1( QString theFileName )
00083 {
00084   mLogo1File = theFileName;
00085   QgsDebugMsg( QString( "Logo1 set to: %1" ).arg( mLogo1File ) );
00086 }
00087 void QgsQuickPrint::setLogo2( QString theFileName )
00088 {
00089   mLogo2File = theFileName;
00090   QgsDebugMsg( QString( "Logo2 set to: %1" ).arg( mLogo2File ) );
00091 }
00092 void QgsQuickPrint::setOutputPdf( QString theFileName )
00093 {
00094   mOutputFileName = theFileName;
00095 }
00096 void QgsQuickPrint::setMapCanvas( QgsMapCanvas * thepMapCanvas )
00097 {
00098   mpMapRenderer = thepMapCanvas->mapRenderer();
00099   mMapBackgroundColor = thepMapCanvas->canvasColor();
00100 }
00101 void QgsQuickPrint::setMapRenderer( QgsMapRenderer * thepMapRenderer )
00102 {
00103   mpMapRenderer = thepMapRenderer;
00104 }
00105 void QgsQuickPrint::setMapBackgroundColor( QColor theColor )
00106 {
00107   mMapBackgroundColor = theColor;
00108 }
00109 void QgsQuickPrint::setPageSize( QPrinter::PageSize theSize )
00110 {
00111   mPageSize = theSize;
00112 }
00113 
00114 void QgsQuickPrint::printMap()
00115 {
00116   if ( mOutputFileName.isEmpty() )
00117   {
00118     return;
00119   }
00120   if ( mpMapRenderer == NULL )
00121   {
00122     return;
00123   }
00124   //ensure the user never omitted the extension from the file name
00125   if ( !mOutputFileName.toUpper().endsWith( ".PDF" ) )
00126   {
00127     mOutputFileName += ".pdf";
00128   }
00129 
00130   // Initialising the printer this way lets us find out what
00131   // the screen resolution is which we store and then
00132   // reset the resolution of the printer after that...
00133   QPrinter myPrinter( QPrinter::ScreenResolution );
00134 
00135   // Try to force the printer resolution to 300dpi
00136   // to get past platform specific defaults in printer
00137   // resolution...
00138   //
00139   int myPrintResolutionDpi = 300;
00140   myPrinter.setResolution( myPrintResolutionDpi );
00141   myPrinter.setOutputFormat( QPrinter::PdfFormat );
00142   QgsDebugMsg( QString( "Printing to page size %1" ).arg( pageSizeToString( mPageSize ) ) );
00143   myPrinter.setPageSize( mPageSize );
00144   myPrinter.setOutputFileName( mOutputFileName );
00145   myPrinter.setOrientation( QPrinter::Landscape );
00146   myPrinter.setDocName( "quickprint Report" );
00147   QPainter myPrintPainter( &myPrinter );
00148   myPrintPainter.setPen( Qt::gray );
00149   myPrintPainter.setBrush( Qt::white );
00150   // This is what we are aiming for:
00151   // a
00152   // +-(1)------ Acme Maps (2) --------------------------------------+
00153   // |b         12/01/2007 (3)                                         |
00154   // |                           Earthquakes (4)                       |
00155   // | +--(5)--------------------------------------------------------+ |
00156   // | |c                                                            | |
00157   // | | +-(6)---------------------------------------+  +~(7)~~~~~~+ | |
00158   // | | |                                           |  |          | | |
00159   // | | |                                           |  |          | | |
00160   // | | |                                           |  |          | | |
00161   // | | |                                           |  |          | | |
00162   // | | |                                           |  |          | | |
00163   // | | |                                           |  |          | | |
00164   // | | |                                           |  |          | | |
00165   // | | |                                           |  |          | | |
00166   // | | |                                           |  |          | | |
00167   // | | |                                           |  |          | | |
00168   // | | |                                           |  |          | | |
00169   // | | +-------------------------------------------+  +~~~~~~~~~~+ | |
00170   // | |                                                             | |
00171   // | +-------------------------------------------------------------+ |
00172   // |                                                                 |
00173   // |   +-(8)-----+ +-(9-)----+ +-(10)----+                 /|\       |
00174   // |   |         | |Copyright| |         |                / | \      |
00175   // |   |         | |  2008   | |         |                  |(11)    |
00176   // |   +---------+ +---------+ +---------+                           |
00177   // |                                                  +~(12)~~~~~~+  |
00178   // +-----------------------------------------------------------------+
00179   //
00180   // 1) PageBorder              8) Logo1
00181   // 2) PageTitle               9) CopyrightText
00182   // 3) MapDate                 10) Logo2
00183   // 4) MapTitle                11) NorthArrow
00184   // 5) MapFrame                12) ScaleBar
00185   // 6) MapPixmap
00186   // 7) LegendPixmap
00187   // a OriginXY
00188   // b HorizontalSpacing
00189   // c VerticalSpacing
00190 
00191   //
00192   // Note: Different operating systems will use different
00193   // page resolutions for QPrinter::HighResolution so I'm
00194   // working all coordinates out as percentages of page
00195   // size so that we can hopefully get comarable print
00196   // results on all platforms.
00197   //
00198 
00199   //
00200   // Note #2: Im defining all measurements here as my plan
00201   // is to later support templates with different page
00202   // layouts and paper sizes etc.
00203   //
00204 
00205 
00206   //set the top left origin for the print layout
00207   int myOriginX = myPrinter.pageRect().left();
00208   int myOriginY = myPrinter.pageRect().top();
00209   int myDrawableWidth = myPrinter.pageRect().width() - myOriginX;
00210   int myDrawableHeight = myPrinter.pageRect().height() - myOriginY;
00211 
00212   //define the spacing between layout elements
00213   int myHorizontalSpacing = myDrawableWidth / 100; // 1%
00214   int myVerticalSpacing = myDrawableHeight / 100; // 1%
00215 
00216   //define the proportions for the page layout
00217   int myMapWidthPercent = 65;
00218   int myMapHeightPercent = 71;
00219   int myLegendWidthPercent = 25;
00220   int myLegendHeightPercent = 65;
00221   int myLogoWidthPercent = 23;
00222   int myLogoHeightPercent = 17;
00223   //
00224   // Remember the size and dpi of the maprender
00225   // so we can restore it properly
00226   //
00227   int myOriginalDpi = mpMapRenderer->outputDpi();
00228   //sensible default to prevent divide by zero
00229   if ( 0 == myOriginalDpi )
00230     myOriginalDpi = 96;
00231   QSize myOriginalSize = mpMapRenderer->outputSize();
00232 
00233   //define the font sizes and family
00234   int myMapTitleFontSize = 24;
00235   int myMapDateFontSize = 16;
00236   int myMapNameFontSize = 32;
00237   int myLegendFontSize = 12;
00238 #ifdef Q_OS_LINUX//this sucks...
00239   myLegendFontSize -= 2;
00240 #endif
00241 
00242 #ifdef WIN32 //this sucks too...
00243   myMapTitleFontSize /= 2;
00244   myMapDateFontSize /= 2;
00245   myMapNameFontSize /= 2;
00246   myLegendFontSize /= 2;
00247 #endif
00248   QString myFontFamily = "Arial";
00249 
00250   //
00251   // Draw the PageBorder
00252   //
00253   myPrintPainter.drawRect(
00254     myOriginX, myOriginY, myDrawableWidth, myDrawableHeight );
00255   //
00256   // Draw the PageTitle
00257   //
00258   QFont myTitleFont( myFontFamily, myMapTitleFontSize );
00259   myPrintPainter.setFont( myTitleFont );
00260   QFontMetrics myTitleMetrics( myTitleFont, &myPrinter );
00261   int myPageTitleHeight = myTitleMetrics.height();
00262   int myPageTitleWidth = myTitleMetrics.width( mTitleText );
00263   myOriginX += myHorizontalSpacing;
00264   myOriginY -= ( myPageTitleHeight / 2 );
00265   QRect myPageTitleRect( myOriginX,
00266                          myOriginY,
00267                          myPageTitleWidth,
00268                          myPageTitleHeight );
00269   // make sure the title goes onto a white background
00270   myPrintPainter.setPen( Qt::white );
00271   myPrintPainter.drawRect( myPageTitleRect );
00272   myPrintPainter.setPen( Qt::black );
00273   myPrintPainter.drawText( myPageTitleRect, Qt::AlignCenter, mTitleText );
00274 
00275   //
00276   // Draw the MapDate
00277   //
00278   QFont myDateFont( myFontFamily, myMapDateFontSize );
00279   QString myDateText( QDate::currentDate().toString( Qt::LocalDate ) );
00280   myPrintPainter.setFont( myDateFont );
00281   QFontMetrics myDateMetrics( myDateFont, &myPrinter );
00282   int myDateHeight = myDateMetrics.height();
00283   //int myDateWidth = myDateMetrics.width(myDateText);
00284   myOriginX += myHorizontalSpacing;
00285   myOriginY += myPageTitleHeight  + myVerticalSpacing ;
00286   QRect myDateRect( myOriginX,
00287                     myOriginY,
00288                     myPageTitleWidth, //use same width as page title for centering
00289                     myDateHeight );
00290   // make sure the title goes onto a white background
00291   myPrintPainter.setPen( Qt::white );
00292   myPrintPainter.drawRect( myDateRect );
00293   myPrintPainter.setPen( Qt::black );
00294   myPrintPainter.drawText( myDateRect, Qt::AlignCenter, myDateText );
00295 
00296   //
00297   // Draw the MapName
00298   //
00299   QFont myNameFont( myFontFamily, myMapNameFontSize );
00300   myPrintPainter.setFont( myNameFont );
00301   QFontMetrics myNameMetrics( myNameFont, &myPrinter );
00302   int myNameHeight = myNameMetrics.height();
00303   int myNameWidth = myNameMetrics.width( mNameText );
00304   myOriginX = myPrinter.pageRect().left() + myDrawableWidth / 2; //page center
00305   myOriginX -= myNameWidth / 2;
00306   myOriginY = myPrinter.pageRect().top() + ( myPageTitleHeight / 2 )  + myVerticalSpacing ;
00307   QRect myNameRect( myOriginX,
00308                     myOriginY,
00309                     myNameWidth,
00310                     myNameHeight );
00311   // make sure the title goes onto a white background
00312   myPrintPainter.setPen( Qt::white );
00313   myPrintPainter.drawRect( myNameRect );
00314   myPrintPainter.setPen( Qt::black );
00315   myPrintPainter.drawText( myNameRect, Qt::AlignCenter, mNameText );
00316 
00317   //
00318   // Draw the MapFrame (top)
00319   //
00320   int myMapFrameWidth = myDrawableWidth ;
00321   myOriginX = myPrinter.pageRect().left() + myHorizontalSpacing;
00322   myOriginY += myNameHeight + myVerticalSpacing;
00323   QLine myMapFrameTopLine( myOriginX,
00324                            myOriginY,
00325                            myMapFrameWidth,
00326                            myOriginY );
00327   myPrintPainter.setPen( Qt::black );
00328   myPrintPainter.drawLine( myMapFrameTopLine );
00329 
00330 
00331   // Draw the map onto a pixmap
00332   // @TODO: we need to save teh extent of the screen map and
00333   // then set them again for the print map so that the map scales
00334   // properly in the print
00335   int myMapDimensionX = ( myDrawableWidth / 100 ) * myMapHeightPercent;
00336   int myMapDimensionY = ( myDrawableHeight / 100 ) * myMapWidthPercent;
00337 
00338   QImage myMapImage( QSize( myMapDimensionX, myMapDimensionY ), QImage::Format_ARGB32 );
00339   myMapImage.setDotsPerMeterX(( double )( myPrinter.logicalDpiX() ) / 25.4 * 1000.0 );
00340   myMapImage.setDotsPerMeterY(( double )( myPrinter.logicalDpiY() ) / 25.4 * 1000.0 );
00341   myMapImage.fill( 0 );
00342   QPainter myMapPainter;
00343   myMapPainter.begin( &myMapImage );
00344   // Now resize for print
00345   mpMapRenderer->setOutputSize( QSize( myMapDimensionX, myMapDimensionY ), ( myPrinter.logicalDpiX() + myPrinter.logicalDpiY() ) / 2 );
00346   mpMapRenderer->render( &myMapPainter );
00347 
00348   myMapPainter.end();
00349   //draw the map pixmap onto our pdf print device
00350   myOriginX = myPrinter.pageRect().left() + myHorizontalSpacing;
00351   myOriginY += myVerticalSpacing * 2;
00352 
00353   myPrintPainter.drawImage( myOriginX, myOriginY, myMapImage );
00354 
00355   //
00356   // Draw the legend
00357   //
00358   QFont myLegendFont( myFontFamily, myLegendFontSize );
00359   //myPrintPainter.setFont(myLegendFont);
00360   int myLegendDimensionX = ( myDrawableWidth / 100 ) * myLegendWidthPercent;
00361   int myLegendDimensionY = ( myDrawableHeight / 100 ) * myLegendHeightPercent;
00362 
00363 
00364   // Create a viewport to make coordinate conversions easier
00365   // The viewport has the same dimensions as the page(otherwise items
00366   // drawn into it will appear squashed), but a different origin.
00367   QRect myOriginalViewport = myPrintPainter.viewport(); //for restoring later
00368   myOriginX += myMapDimensionX + myHorizontalSpacing;
00369   myPrintPainter.setViewport( myOriginX,
00370                               myOriginY,
00371                               myOriginalViewport.width(),
00372                               myOriginalViewport.height() );
00373   //draw a rectangale around the legend frame
00374   //@TODO make this user settable
00375   if ( 0 == 1 ) //put some real logic here
00376   {
00377     myPrintPainter.drawRect( 0, 0, myLegendDimensionX, myLegendDimensionY );
00378   }
00379   //get font metric and other vars needed
00380   QFontMetrics myLegendFontMetrics( myLegendFont, &myPrinter );
00381   int myLegendFontHeight = myLegendFontMetrics.height();
00382   int myLegendXPos = 0;
00383   int myLegendYPos = 0;
00384   int myLegendSpacer = myLegendFontHeight / 2; //for vertical and horizontal spacing
00385   int myLegendVerticalSpacer = myLegendFontHeight / 3; //for vertical between rows
00386   int myIconWidth = myLegendFontHeight;
00387   myPrintPainter.setFont( myLegendFont );
00388   QStringList myLayerSet = mpMapRenderer->layerSet();
00389   QStringListIterator myLayerIterator( myLayerSet );
00390   //second clause below is to prevent legend spilling out the bottom
00391   while ( myLayerIterator.hasNext() &&
00392           myLegendYPos < myLegendDimensionY )
00393   {
00394     QString myLayerId = myLayerIterator.next();
00395     QgsMapLayer * mypLayer =
00396       QgsMapLayerRegistry::instance()->mapLayer( myLayerId );
00397     if ( mypLayer )
00398     {
00399       QgsVectorLayer *mypVectorLayer  =
00400         qobject_cast<QgsVectorLayer *>( mypLayer );
00401       // TODO: add support for symbology-ng renderers
00402       if ( mypVectorLayer && mypVectorLayer->renderer() )
00403       {
00404         QString myLayerName = mypVectorLayer->name();
00405         QIcon myIcon;
00406         QPixmap myPixmap( QSize( myIconWidth, myIconWidth ) );   //square
00407         //based on code from qgslegendlayer.cpp - see that file for more info
00408         const QgsRenderer* mypRenderer = mypVectorLayer->renderer();
00409         const QList<QgsSymbol*> mySymbolList = mypRenderer->symbols();
00410         //
00411         // Single symbol
00412         //
00413         double widthScale = ( myPrinter.logicalDpiX() + myPrinter.logicalDpiY() ) / 2.0 / 25.4;
00414 
00415         if ( 1 == mySymbolList.size() )
00416         {
00417           QgsSymbol * mypSymbol = mySymbolList.at( 0 );
00418           myPrintPainter.setPen( mypSymbol->pen() );
00419           myPrintPainter.setBrush( mypSymbol->brush() );
00420           myLegendXPos = 0 ;
00421           if ( mypSymbol->type() == QGis::Point )
00422           {
00423             QImage myImage;
00424             myImage = mypSymbol->getPointSymbolAsImage( widthScale );
00425             myPrintPainter.drawImage( myLegendXPos, myLegendYPos, myImage );
00426           }
00427           else if ( mypSymbol->type() == QGis::Line )
00428           {
00429             myPrintPainter.drawLine( myLegendXPos, myLegendYPos,
00430                                      myLegendXPos + myIconWidth,
00431                                      myLegendYPos + myIconWidth );
00432           }
00433           else //polygon
00434           {
00435             myPrintPainter.drawRect( myLegendXPos, myLegendYPos, myIconWidth, myIconWidth );
00436           }
00437           myLegendXPos += myIconWidth + myLegendSpacer;
00438           myPrintPainter.setPen( Qt::black );
00439           QStringList myWrappedLayerNameList = wordWrap( myLayerName,
00440                                                myLegendFontMetrics,
00441                                                myLegendDimensionX - myIconWidth );
00442           //
00443           // Loop through wrapped legend label lines
00444           //
00445           QStringListIterator myLineWrapIterator( myWrappedLayerNameList );
00446           while ( myLineWrapIterator.hasNext() )
00447           {
00448             QString myLine = myLineWrapIterator.next();
00449             QRect myLegendItemRect( myLegendXPos,
00450                                     myLegendYPos,
00451                                     myLegendDimensionX - myIconWidth,
00452                                     myLegendFontHeight );
00453             myPrintPainter.drawText( myLegendItemRect, Qt::AlignLeft, myLine );
00454             myLegendYPos += myLegendVerticalSpacer + myLegendFontHeight;
00455           }
00456         }
00457         else  //class breaks
00458         {
00459           // draw in the layer name first, after we loop for the class breaks
00460           QStringList myWrappedLayerNameList = wordWrap( myLayerName,
00461                                                myLegendFontMetrics,
00462                                                myLegendDimensionX - myIconWidth );
00463           // Check the wrapped layer name wont overrun the space we have
00464           // for the legend ...
00465           int myLabelHeight = myLegendFontHeight *
00466                               myWrappedLayerNameList.count();
00467           if ( myLegendYPos + myLabelHeight > myLegendDimensionY )
00468           {
00469             continue;
00470           }
00471 
00472           //
00473           // Loop through wrapped legend label lines
00474           //
00475           QStringListIterator myLineWrapIterator( myWrappedLayerNameList );
00476           while ( myLineWrapIterator.hasNext() )
00477           {
00478             QString myLine = myLineWrapIterator.next();
00479             myLegendXPos = myIconWidth;
00480             QRect myLegendItemRect( myLegendXPos,
00481                                     myLegendYPos,
00482                                     myLegendFontMetrics.width( myLine ),
00483                                     myLegendFontHeight );
00484             myPrintPainter.setPen( Qt::black );
00485             myPrintPainter.drawText( myLegendItemRect, Qt::AlignLeft, myLine );
00486             myLegendYPos += myLegendVerticalSpacer + myLegendFontHeight;
00487           }
00488           //
00489           // Loop through the class breaks
00490           //
00491           QListIterator<QgsSymbol *> myIterator( mySymbolList );
00492           while ( myIterator.hasNext() && myLegendYPos < myLegendDimensionY )
00493           {
00494             QgsSymbol * mypSymbol = myIterator.next();
00495             myPrintPainter.setPen( mypSymbol->pen() );
00496             myPrintPainter.setBrush( mypSymbol->brush() );
00497             myLegendXPos = myLegendSpacer * 3; //extra indent for class breaks
00498             if ( mypSymbol->type() == QGis::Point )
00499             {
00500               QImage myImage;
00501               myImage = mypSymbol->getPointSymbolAsImage( widthScale );
00502               myPrintPainter.drawImage( myLegendXPos, myLegendYPos, myImage );
00503             }
00504             else if ( mypSymbol->type() == QGis::Line )
00505             {
00506               myPrintPainter.drawLine( myLegendXPos, myLegendYPos,
00507                                        myLegendXPos + myIconWidth,
00508                                        myLegendYPos + myIconWidth );
00509             }
00510             else //polygon
00511             {
00512               myPrintPainter.drawRect(
00513                 myLegendXPos, myLegendYPos, myIconWidth, myIconWidth );
00514             }
00515             //
00516             // Now work out the class break label
00517             //
00518             QString myLabel;
00519             QString myLower = mypSymbol->lowerValue();
00520             if ( !myLower.isEmpty() )
00521             {
00522               myLabel = myLower;
00523             }
00524             QString myUpper = mypSymbol->upperValue();
00525             if ( !myUpper.isEmpty() )
00526             {
00527               myLabel += " - ";
00528               myLabel += myUpper;
00529             }
00530             QString myText = mypSymbol->label();
00531             if ( !myText.isEmpty() )
00532             {
00533               myLabel += " ";
00534               myLabel += myText;
00535             }
00536             myLabel = myLabel.trimmed();
00537             myLegendXPos += myIconWidth + myLegendSpacer;
00538             myPrintPainter.setPen( Qt::black );
00539 
00540             QStringList myWrappedLayerNameList = wordWrap( myLabel,
00541                                                  myLegendFontMetrics,
00542                                                  myLegendDimensionX - myLegendXPos );
00543             //
00544             // Loop through wrapped legend label lines
00545             //
00546             QStringListIterator myLineWrapIterator( myWrappedLayerNameList );
00547             while ( myLineWrapIterator.hasNext() )
00548             {
00549               QString myLine = myLineWrapIterator.next();
00550               // check if the text will overflow the space we have
00551               QRect myLegendItemRect( myLegendXPos,
00552                                       myLegendYPos,
00553                                       myLegendDimensionX - myIconWidth,
00554                                       myLegendFontHeight );
00555               myPrintPainter.drawText( myLegendItemRect, Qt::AlignLeft, myLine );
00556               myLegendYPos += myLegendVerticalSpacer + myLegendFontHeight;
00557             } //wordwrap loop
00558           } //symbol loop
00559         } //class breaks
00560       } //if vectorlayer
00561     } //if maplayer
00562   } //layer iterator
00563 
00564   //reinstate the viewport
00565   myPrintPainter.setViewport( myOriginalViewport );
00566 
00567 
00568   //
00569   // Draw the MapFrame (bottom)
00570   //
00571   myOriginX = myPrinter.pageRect().left() + myHorizontalSpacing;
00572   myOriginY += myMapDimensionY + ( myVerticalSpacing * 2 );
00573   QLine myMapFrameBottomLine( myOriginX,
00574                               myOriginY,
00575                               myMapFrameWidth,
00576                               myOriginY );
00577   myPrintPainter.setPen( Qt::black );
00578   myPrintPainter.drawLine( myMapFrameBottomLine );
00579 
00580 
00581   //
00582   // Draw logo 1
00583   //
00584   int myLogoXDim = ( myDrawableWidth / 100 ) * myLogoWidthPercent;
00585   int myLogoYDim = ( myDrawableHeight / 100 ) * myLogoHeightPercent;
00586   QPixmap myLogo1;
00587   QgsDebugMsg( QString( "Logo1: %1" ).arg( mLogo1File ) );
00588   myLogo1.fill( Qt::white );
00589   myLogo1.load( mLogo1File );
00590   myLogo1 = myLogo1.scaled( myLogoXDim, myLogoYDim, Qt::KeepAspectRatio );
00591   myOriginX = myPrinter.pageRect().left() + myHorizontalSpacing;
00592   myOriginY += myVerticalSpacing ;
00593   myPrintPainter.drawPixmap( myOriginX,
00594                              myOriginY,
00595                              myLogo1 );
00596 
00597   //
00598   // Draw Copyright Text
00599   //
00600   myOriginX += myHorizontalSpacing + myLogoXDim;
00601   QRect myCopyrightRect( myOriginX, myOriginY, myLogoXDim, myLogoYDim );
00602   myPrintPainter.setPen( Qt::black );
00603   QFont myCopyrightFont( myFontFamily, myMapDateFontSize );
00604   myPrintPainter.setFont( myCopyrightFont );
00605   //myPrintPainter.drawRect( myCopyrightRect );
00606   myPrintPainter.drawText( myCopyrightRect, Qt::AlignCenter | Qt::TextWordWrap, mCopyrightText );
00607 
00608   //
00609   // Draw logo 2
00610   //
00611   QPixmap myLogo2;
00612   myLogo2.fill( Qt::white );
00613   myLogo2.load( mLogo2File );
00614   myLogo2 = myLogo2.scaled( myLogoXDim, myLogoYDim, Qt::KeepAspectRatio );
00615   myOriginX += myHorizontalSpacing + myLogoXDim;
00616   myPrintPainter.drawPixmap( myOriginX,
00617                              myOriginY,
00618                              myLogo2 );
00619 
00620   //
00621   // Draw the north arrow
00622   //
00623   myOriginX += myHorizontalSpacing + myLogoXDim;
00624   // use half the available space for the n.arrow
00625   // and the rest for the scale bar (see below)
00626   QPixmap myNorthArrow( myLogoYDim / 2, myLogoYDim / 2 );
00627   myNorthArrow.fill( Qt::white );
00628   QPainter myNorthPainter( &myNorthArrow );
00629   QSvgRenderer mySvgRenderer( mNorthArrowFile );
00630   mySvgRenderer.render( &myNorthPainter );
00631   myPrintPainter.drawPixmap( myOriginX + (( myLogoXDim / 2 ) ),
00632                              myOriginY,
00633                              myNorthArrow );
00634 
00635   //
00636   // Draw the scale bar
00637   //
00638   myOriginY += myLogoYDim / 2 + myVerticalSpacing;
00639   myPrintPainter.setViewport( myOriginX,
00640                               myOriginY,
00641                               myOriginalViewport.width(),
00642                               myOriginalViewport.height() );
00643   renderPrintScaleBar( &myPrintPainter, mpMapRenderer, myLogoXDim );
00644   myPrintPainter.setViewport( myOriginalViewport );
00645 
00646   //
00647   // Finish up
00648   //
00649 
00650 
00651   myPrintPainter.end();
00652 #if 0
00653   mProgressDialog.setValue( 0 );
00654   mProgressDialog.setLabelText( tr( "Please wait while your report is generated", "COMMENTED OUT" ) );
00655   mProgressDialog.show();
00656   mProgressDialog.setWindowModality( Qt::WindowModal );
00657   mProgressDialog.setAutoClose( true );
00658 #endif
00659   //
00660   // Restore the map render to its former glory
00661   //
00662   mpMapRenderer->setOutputSize( myOriginalSize, myOriginalDpi );
00663 }
00664 
00665 void QgsQuickPrint::scaleTextLabels( int theScaleFactor, SymbolScalingType theDirection )
00666 {
00667   if ( 0 >= theScaleFactor )
00668   {
00669     QgsDebugMsg( "invalid scale factor" );
00670     return;
00671   }
00672   QStringList myLayerSet = mpMapRenderer->layerSet();
00673   QStringListIterator myLayerIterator( myLayerSet );
00674   while ( myLayerIterator.hasNext() )
00675   {
00676     QString myLayerId = myLayerIterator.next();
00677     QgsDebugMsg( "Scaling text labels for print for " + myLayerId );
00678     QgsMapLayer * mypLayer =
00679       QgsMapLayerRegistry::instance()->mapLayer( myLayerId );
00680     if ( mypLayer )
00681     {
00682       QgsVectorLayer *mypVectorLayer  =
00683         qobject_cast<QgsVectorLayer *>( mypLayer );
00684       if ( mypVectorLayer )
00685       {
00686         QgsLabel * mypLabel = mypVectorLayer->label();
00687         QgsLabelAttributes * mypLabelAttributes = mypLabel->labelAttributes();
00688         if ( theDirection == ScaleUp )
00689         {
00690           mypLabelAttributes->setSize(
00691             mypLabelAttributes->size() * theScaleFactor,
00692             mypLabelAttributes->sizeType() );
00693         }
00694         else //scale down
00695         {
00696           mypLabelAttributes->setSize(
00697             mypLabelAttributes->size() / theScaleFactor,
00698             mypLabelAttributes->sizeType() );
00699         }
00700       } //if vectorlayer
00701     } //if maplayer
00702   } //layer iterator
00703 }
00704 
00705 void QgsQuickPrint::scalePointSymbols( int theScaleFactor, SymbolScalingType theDirection )
00706 {
00707   if ( 0 >= theScaleFactor )
00708   {
00709     QgsDebugMsg( "invalid scale factor" );
00710     return;
00711   }
00712   QStringList myLayerSet = mpMapRenderer->layerSet();
00713   QStringListIterator myLayerIterator( myLayerSet );
00714   while ( myLayerIterator.hasNext() )
00715   {
00716     QString myLayerId = myLayerIterator.next();
00717     QgsDebugMsg( "Scaling point symbols for print for " + myLayerId );
00718     QgsMapLayer * mypLayer =
00719       QgsMapLayerRegistry::instance()->mapLayer( myLayerId );
00720     if ( mypLayer )
00721     {
00722       QgsVectorLayer *mypVectorLayer  =
00723         qobject_cast<QgsVectorLayer *>( mypLayer );
00724       if ( mypVectorLayer )
00725       {
00726         const QgsRenderer* mypRenderer = mypVectorLayer->renderer();
00727         const QList<QgsSymbol*> mySymbolList = mypRenderer->symbols();
00728         //
00729         // Single symbol
00730         //
00731         if ( 1 == mySymbolList.size() )
00732         {
00733           QgsSymbol * mypSymbol = mySymbolList.at( 0 );
00734           if ( mypSymbol->type() == QGis::Point )
00735           {
00736             if ( theDirection == ScaleUp )
00737             {
00738               mypSymbol->setPointSize( mypSymbol->pointSize() * theScaleFactor );
00739             }
00740             else //Scale Down
00741             {
00742               mypSymbol->setPointSize( mypSymbol->pointSize() / theScaleFactor );
00743             }
00744           }
00745         }
00746         else  //class breaks
00747         {
00748           QListIterator<QgsSymbol *> myIterator( mySymbolList );
00749           while ( myIterator.hasNext() )
00750           {
00751             QgsSymbol * mypSymbol = myIterator.next();
00752             if ( mypSymbol->type() == QGis::Point )
00753             {
00754               if ( theDirection == ScaleUp )
00755               {
00756                 mypSymbol->setPointSize( mypSymbol->pointSize() * theScaleFactor );
00757               }
00758               else //Scale Down
00759               {
00760                 mypSymbol->setPointSize( mypSymbol->pointSize() / theScaleFactor );
00761               }
00762             }
00763           } //symbol loop
00764         } //class breaks
00765       } //if vectorlayer
00766     } //if maplayer
00767   } //layer iterator
00768 }
00769 
00770 
00771 
00772 void QgsQuickPrint::renderPrintScaleBar( QPainter * thepPainter,
00773     QgsMapRenderer * thepMapRenderer,
00774     int theMaximumWidth )
00775 {
00776   //hard coding some options for now
00777   bool mySnappingFlag = true;
00778   QColor mColor = Qt::black;
00779   // Hard coded sizes
00780   int myTextOffsetX = 0;
00781   int myTextOffsetY = 5;
00782   int myXMargin = 20;
00783   int myYMargin = 20;
00784   int myPreferredSize = theMaximumWidth - ( myXMargin * 2 );
00785   double myActualSize = 0;
00786   int myBufferSize = 1; //softcode this later
00787   QColor myBackColor = Qt::white; //used for text
00788   QColor myForeColor = Qt::black; //used for text
00789 
00790   //Get canvas dimensions
00791   //int myCanvasHeight = thepMapCanvas->height();
00792 
00793   //Get map units per pixel. This can be negative at times (to do with
00794   //projections) and that just confuses the rest of the code in this
00795   //function, so force to a positive number.
00796   double myMapUnitsPerPixelDouble = qAbs( thepMapRenderer->mapUnitsPerPixel() );
00797   //
00798   // Exit if the canvas width is 0 or layercount is 0 or QGIS will freeze
00799   int myLayerCount = thepMapRenderer->layerSet().count();
00800   if ( !myLayerCount || !myMapUnitsPerPixelDouble )
00801     return;
00802 
00803   //Calculate size of scale bar for preferred number of map units
00804   double myScaleBarWidth = myPreferredSize;
00805   myActualSize = myScaleBarWidth * myMapUnitsPerPixelDouble;
00806 
00807 
00808   // Work out the exponent for the number - e.g, 1234 will give 3,
00809   // and .001234 will give -3
00810   double myPowerOf10 = floor( log10( myActualSize ) );
00811 
00812   // snap to integer < 10 times power of 10
00813   if ( mySnappingFlag )
00814   {
00815     double scaler = pow( 10.0, myPowerOf10 );
00816     myActualSize = round( myActualSize / scaler ) * scaler;
00817     myScaleBarWidth = myActualSize / myMapUnitsPerPixelDouble;
00818   }
00819 
00820   //Get type of map units and set scale bar unit label text
00821   QGis::UnitType myMapUnits = thepMapRenderer->mapUnits();
00822   QString myScaleBarUnitLabel;
00823   switch ( myMapUnits )
00824   {
00825     case QGis::Meters:
00826       if ( myActualSize > 1000.0 )
00827       {
00828         myScaleBarUnitLabel = tr( " km" );
00829         myActualSize = myActualSize / 1000;
00830       }
00831       else if ( myActualSize < 0.01 )
00832       {
00833         myScaleBarUnitLabel = tr( " mm" );
00834         myActualSize = myActualSize * 1000;
00835       }
00836       else if ( myActualSize < 0.1 )
00837       {
00838         myScaleBarUnitLabel = tr( " cm" );
00839         myActualSize = myActualSize * 100;
00840       }
00841       else
00842         myScaleBarUnitLabel = tr( " m" );
00843       break;
00844     case QGis::Feet:
00845       if ( myActualSize > 5280.0 ) //5280 feet to the mile
00846       {
00847         myScaleBarUnitLabel = tr( " miles" );
00848         myActualSize = myActualSize / 5280;
00849       }
00850       else if ( myActualSize == 5280.0 ) //5280 feet to the mile
00851       {
00852         myScaleBarUnitLabel = tr( " mile" );
00853         myActualSize = myActualSize / 5280;
00854       }
00855       else if ( myActualSize < 1 )
00856       {
00857         myScaleBarUnitLabel = tr( " inches" );
00858         myActualSize = myActualSize * 12;
00859       }
00860       else if ( myActualSize == 1.0 )
00861       {
00862         myScaleBarUnitLabel = tr( " foot" );
00863       }
00864       else
00865       {
00866         myScaleBarUnitLabel = tr( " feet" );
00867       }
00868       break;
00869     case QGis::Degrees:
00870       if ( myActualSize == 1.0 )
00871         myScaleBarUnitLabel = tr( " degree" );
00872       else
00873         myScaleBarUnitLabel = tr( " degrees" );
00874       break;
00875     case QGis::UnknownUnit:
00876       myScaleBarUnitLabel = tr( " unknown" );
00877     default:
00878       QgsDebugMsg( "Error: not picked up map units - actual value = "
00879                    + QString::number( myMapUnits ) );
00880   };
00881 
00882   //Set font and calculate width of unit label
00883   int myFontSize = 10; //we use this later for buffering
00884   QFont myFont( "helvetica", myFontSize );
00885   thepPainter->setFont( myFont );
00886   QFontMetrics myFontMetrics( myFont );
00887   double myFontWidth = myFontMetrics.width( myScaleBarUnitLabel );
00888   double myFontHeight = myFontMetrics.height();
00889 
00890   //Set the maximum label
00891   QString myScaleBarMaxLabel = QString::number( myActualSize );
00892 
00893   //Calculate total width of scale bar and label
00894   //we divide by 2 because the max scale label
00895   //will be centered over the endpoint of the scale bar
00896   double myTotalScaleBarWidth = myScaleBarWidth + ( myFontWidth / 2 );
00897 
00898   //determine the origin of scale bar (bottom right)
00899   //for x origin set things up so the scalebar is centered
00900   int myOriginX = ( theMaximumWidth - myTotalScaleBarWidth ) / 2;
00901   int myOriginY = myYMargin;
00902 
00903   //Set pen to draw with
00904   QPen myForegroundPen( mColor, 2 );
00905   QPen myBackgroundPen( Qt::white, 3 );
00906 
00907   //Cast myScaleBarWidth to int for drawing
00908   int myScaleBarWidthInt = ( int ) myScaleBarWidth;
00909 
00910   //now draw the bar itself in user selected color
00911   thepPainter->setPen( myForegroundPen );
00912   //make a glossygradient for the background
00913   QGradientStops myStops;
00914   myStops << QGradientStop( 0.0, QColor( "#616161" ) );
00915   myStops << QGradientStop( 0.5, QColor( "#505050" ) );
00916   myStops << QGradientStop( 0.6, QColor( "#434343" ) );
00917   myStops << QGradientStop( 1.0, QColor( "#656565" ) );
00918   //draw again with the brush in the revers direction to complete teh glossiness
00919   QLinearGradient myReverseGlossyBrush(
00920     QPointF( myOriginX, myOriginY +  myFontHeight*3 ),
00921     QPointF( myOriginX, myOriginY ) );
00922   thepPainter->setBrush( myReverseGlossyBrush );
00923   thepPainter->drawRect(
00924     myOriginX,
00925     myOriginY,
00926     myOriginX + myScaleBarWidthInt,
00927     myOriginY + myFontHeight
00928   );
00929 
00930   //
00931   //Do drawing of scale bar text
00932   //
00933 
00934 
00935   //Draw the minimum label buffer
00936   thepPainter->setPen( myBackColor );
00937   myFontWidth = myFontMetrics.width( "0" );
00938 
00939   for ( int i = 0 - myBufferSize; i <= myBufferSize; i++ )
00940   {
00941     for ( int j = 0 - myBufferSize; j <= myBufferSize; j++ )
00942     {
00943       thepPainter->drawText( int( i + ( myOriginX - ( myFontWidth / 2 ) ) ),
00944                              int( j + ( myOriginY - ( myFontHeight / 4 ) ) ) - myTextOffsetY,
00945                              "0" );
00946     }
00947   }
00948 
00949   //Draw minimum label
00950   thepPainter->setPen( myForeColor );
00951 
00952   thepPainter->drawText(
00953     int( myOriginX - ( myFontWidth / 2 ) ),
00954     int( myOriginY - ( myFontHeight / 4 ) ) - myTextOffsetY,
00955     "0"
00956   );
00957 
00958   //
00959   //Draw maximum label
00960   //
00961   thepPainter->setPen( myBackColor );
00962   myFontWidth = myFontMetrics.width( myScaleBarMaxLabel );
00963   myFontHeight = myFontMetrics.height();
00964   //first the buffer
00965   for ( int i = 0 - myBufferSize; i <= myBufferSize; i++ )
00966   {
00967     for ( int j = 0 - myBufferSize; j <= myBufferSize; j++ )
00968     {
00969       thepPainter->drawText( int( i + ( myOriginX + myScaleBarWidthInt - ( myFontWidth / 2 ) ) ),
00970                              int( j + ( myOriginY - ( myFontHeight / 4 ) ) ) - myTextOffsetY,
00971                              myScaleBarMaxLabel );
00972     }
00973   }
00974   //then the text itself
00975   thepPainter->setPen( myForeColor );
00976   thepPainter->drawText(
00977     int( myOriginX + myScaleBarWidthInt - ( myFontWidth / 2 ) ),
00978     int( myOriginY - ( myFontHeight / 4 ) ) - myTextOffsetY,
00979     myScaleBarMaxLabel
00980   );
00981 
00982   //
00983   //Draw unit label
00984   //
00985   thepPainter->setPen( myBackColor );
00986   myFontWidth = myFontMetrics.width( myScaleBarUnitLabel );
00987   //first the buffer
00988   for ( int i = 0 - myBufferSize; i <= myBufferSize; i++ )
00989   {
00990     for ( int j = 0 - myBufferSize; j <= myBufferSize; j++ )
00991     {
00992       thepPainter->drawText( i + ( myOriginX + myScaleBarWidthInt + myTextOffsetX ),
00993                              j + myOriginY + myFontHeight + ( myFontHeight*2.5 ) + myTextOffsetY,
00994                              myScaleBarUnitLabel );
00995     }
00996   }
00997   //then the text itself
00998   thepPainter->setPen( myForeColor );
00999   thepPainter->drawText(
01000     myOriginX + myScaleBarWidthInt + myTextOffsetX,
01001     myOriginY + myFontHeight + ( myFontHeight*2.5 ) +  myTextOffsetY,
01002     myScaleBarUnitLabel
01003   );
01004 }
01005 
01006 QStringList QgsQuickPrint::wordWrap( QString theString,
01007                                      QFontMetrics theMetrics,
01008                                      int theWidth )
01009 {
01010   //iterate the string
01011   QStringList myList;
01012   QString myCumulativeLine = "";
01013   QString myStringToPreviousSpace = "";
01014   int myPreviousSpacePos = 0;
01015   for ( int i = 0; i < theString.count(); ++i )
01016   {
01017     QChar myChar = theString.at( i );
01018     if ( myChar == QChar( ' ' ) )
01019     {
01020       myStringToPreviousSpace = myCumulativeLine;
01021       myPreviousSpacePos = i;
01022     }
01023     myCumulativeLine += myChar;
01024     if ( theMetrics.width( myCumulativeLine ) >= theWidth )
01025     {
01026       //time to wrap
01027       //@todo deal with long strings that have no spaces
01028       //forcing a break at current pos...
01029       myList << myStringToPreviousSpace.trimmed();
01030       i = myPreviousSpacePos;
01031       myStringToPreviousSpace = "";
01032       myCumulativeLine = "";
01033     }
01034   }//end of i loop
01035   //add whatever is left in the string to the list
01036   if ( !myCumulativeLine.trimmed().isEmpty() )
01037   {
01038     myList << myCumulativeLine.trimmed();
01039   }
01040 
01041   //qDebug("Wrapped legend entry: %s\n%s", theString, myList.join("\n").toLocal8Bit().constData() );
01042   return myList;
01043 
01044 }
01045 QString QgsQuickPrint::pageSizeToString( QPrinter::PageSize theSize )
01046 {
01047   if ( theSize == QPrinter::A0 ) return "QPrinter::A0";
01048   if ( theSize == QPrinter::A1 ) return "QPrinter::A1";
01049   if ( theSize == QPrinter::A2 ) return "QPrinter::A2";
01050   if ( theSize == QPrinter::A3 ) return "QPrinter::A3";
01051   if ( theSize == QPrinter::A4 ) return "QPrinter::A4";
01052   if ( theSize == QPrinter::A5 ) return "QPrinter::A5";
01053   if ( theSize == QPrinter::A6 ) return "QPrinter::A6";
01054   if ( theSize == QPrinter::A7 ) return "QPrinter::A7";
01055   if ( theSize == QPrinter::A8 ) return "QPrinter::A8";
01056   if ( theSize == QPrinter::A9 ) return "QPrinter::A9";
01057   if ( theSize == QPrinter::B0 ) return "QPrinter::B0";
01058   if ( theSize == QPrinter::B1 ) return "QPrinter::B1";
01059   if ( theSize == QPrinter::B10 ) return "QPrinter::B10";
01060   if ( theSize == QPrinter::B2 ) return "QPrinter::B2";
01061   if ( theSize == QPrinter::B3 ) return "QPrinter::B3";
01062   if ( theSize == QPrinter::B4 ) return "QPrinter::B4";
01063   if ( theSize == QPrinter::B5 ) return "QPrinter::B5";
01064   if ( theSize == QPrinter::B6 ) return "QPrinter::B6";
01065   if ( theSize == QPrinter::B7 ) return "QPrinter::B7";
01066   if ( theSize == QPrinter::B8 ) return "QPrinter::B8";
01067   if ( theSize == QPrinter::B9 ) return "QPrinter::B9";
01068   if ( theSize == QPrinter::C5E ) return "QPrinter::C5E";
01069   if ( theSize == QPrinter::Comm10E ) return "QPrinter::Comm10E";
01070   if ( theSize == QPrinter::DLE ) return "QPrinter::DLE";
01071   if ( theSize == QPrinter::Executive ) return "QPrinter::Executive";
01072   if ( theSize == QPrinter::Folio ) return "QPrinter::Folio";
01073   if ( theSize == QPrinter::Ledger ) return "QPrinter::Ledger";
01074   if ( theSize == QPrinter::Legal ) return "QPrinter::Legal";
01075   if ( theSize == QPrinter::Letter ) return "QPrinter::Letter";
01076   //fallback
01077   return "QPrinter::A4";
01078 }
01079 
01080 QPrinter::PageSize QgsQuickPrint::stringToPageSize( QString theSize )
01081 {
01082   if ( theSize == "QPrinter::A0" ) return QPrinter::A0;
01083   if ( theSize == "QPrinter::A1" ) return QPrinter::A1;
01084   if ( theSize == "QPrinter::A2" ) return QPrinter::A2;
01085   if ( theSize == "QPrinter::A3" ) return QPrinter::A3;
01086   if ( theSize == "QPrinter::A4" ) return QPrinter::A4;
01087   if ( theSize == "QPrinter::A5" ) return QPrinter::A5;
01088   if ( theSize == "QPrinter::A6" ) return QPrinter::A6;
01089   if ( theSize == "QPrinter::A7" ) return QPrinter::A7;
01090   if ( theSize == "QPrinter::A8" ) return QPrinter::A8;
01091   if ( theSize == "QPrinter::A9" ) return QPrinter::A9;
01092   if ( theSize == "QPrinter::B0" ) return QPrinter::B0;
01093   if ( theSize == "QPrinter::B1" ) return QPrinter::B1;
01094   if ( theSize == "QPrinter::B10" ) return QPrinter::B10;
01095   if ( theSize == "QPrinter::B2" ) return QPrinter::B2;
01096   if ( theSize == "QPrinter::B3" ) return QPrinter::B3;
01097   if ( theSize == "QPrinter::B4" ) return QPrinter::B4;
01098   if ( theSize == "QPrinter::B5" ) return QPrinter::B5;
01099   if ( theSize == "QPrinter::B6" ) return QPrinter::B6;
01100   if ( theSize == "QPrinter::B7" ) return QPrinter::B7;
01101   if ( theSize == "QPrinter::B8" ) return QPrinter::B8;
01102   if ( theSize == "QPrinter::B9" ) return QPrinter::B9;
01103   if ( theSize == "QPrinter::C5E" ) return QPrinter::C5E;
01104   if ( theSize == "QPrinter::Comm10E" ) return QPrinter::Comm10E;
01105   if ( theSize == "QPrinter::DLE" ) return QPrinter::DLE;
01106   if ( theSize == "QPrinter::Executive" ) return QPrinter::Executive;
01107   if ( theSize == "QPrinter::Folio" ) return QPrinter::Folio;
01108   if ( theSize == "QPrinter::Ledger" ) return QPrinter::Ledger;
01109   if ( theSize == "QPrinter::Legal" ) return QPrinter::Legal;
01110   if ( theSize == "QPrinter::Letter" ) return QPrinter::Letter;
01111   //fallback
01112   return QPrinter::A4;
01113 }
 All Classes Namespaces Files Functions Variables Typedefs Enumerations Enumerator Friends Defines