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