Quantum GIS API Documentation  1.7.5-Wroclaw
 All Classes Namespaces Files Functions Variables Typedefs Enumerations Enumerator Friends Macros Groups Pages
qgsquickprint.cpp
Go to the documentation of this file.
1 /***************************************************************************
2  qgsquickprint.cpp
3  A class to quickly print a map with minimal effort.
4  -------------------
5  begin : Jan 2008
6  copyright : (c) Tim Sutton, 2008
7  email : tim@linfiniti.com
8 
9  ***************************************************************************
10  * *
11  * This program is free software; you can redistribute it and/or modify *
12  * it under the terms of the GNU General Public License as published by *
13  * the Free Software Foundation; either version 2 of the License, or *
14  * (at your option) any later version. *
15  * *
16  ***************************************************************************/
17 /* $Id: plugin.cpp 7796 2007-12-16 22:11:38Z homann $ */
18 
19 //
20 // QGIS Specific includes
21 //
22 
23 #include <qgisinterface.h>
24 #include <qgisgui.h>
25 #include "qgsquickprint.h"
26 #include <qgsapplication.h>
27 #include <qgsmaplayerregistry.h>
28 #include <qgsvectorlayer.h>
29 #include <qgssymbol.h>
30 #include <qgsmapcanvas.h>
31 #include <qgsrenderer.h>
32 #include <qgslogger.h>
33 #include <qgslabelattributes.h>
34 #include <qgslabel.h>
35 
36 //
37 // Qt4 Related Includes
38 //
39 
40 #include <QAction>
41 #include <QToolBar>
42 #include <QColor>
43 #include <QPainter>
44 #include <QDate>
45 #include <QPixmap>
46 #include <QString>
47 #include <QSettings>
48 #include <QSvgRenderer>
49 #include <QLinearGradient>
50 
51 //other includes
52 #include <cmath>
53 
54 #ifdef _MSC_VER
55 #define round(x) ((x) >= 0 ? floor((x)+0.5) : floor((x)-0.5))
56 #endif
57 
59 {
60  mPageSize = QPrinter::A4;
61 }
62 
64 {
65 
66 }
67 void QgsQuickPrint::setTitle( QString theText )
68 {
69  mTitleText = theText;
70 }
71 void QgsQuickPrint::setName( QString theText )
72 {
73  mNameText = theText;
74 }
75 void QgsQuickPrint::setCopyright( QString theText )
76 {
77  mCopyrightText = theText;
78 }
79 void QgsQuickPrint::setNorthArrow( QString theFileName )
80 {
81  mNorthArrowFile = theFileName;
82 }
83 void QgsQuickPrint::setLogo1( QString theFileName )
84 {
85  mLogo1File = theFileName;
86  QgsDebugMsg( QString( "Logo1 set to: %1" ).arg( mLogo1File ) );
87 }
88 void QgsQuickPrint::setLogo2( QString theFileName )
89 {
90  mLogo2File = theFileName;
91  QgsDebugMsg( QString( "Logo2 set to: %1" ).arg( mLogo2File ) );
92 }
93 void QgsQuickPrint::setOutputPdf( QString theFileName )
94 {
95  mOutputFileName = theFileName;
96 }
98 {
99  mpMapRenderer = thepMapCanvas->mapRenderer();
100  mMapBackgroundColor = thepMapCanvas->canvasColor();
101 }
103 {
104  mpMapRenderer = thepMapRenderer;
105 }
107 {
108  mMapBackgroundColor = theColor;
109 }
110 void QgsQuickPrint::setPageSize( QPrinter::PageSize theSize )
111 {
112  mPageSize = theSize;
113 }
114 
116 {
117  if ( mOutputFileName.isEmpty() )
118  {
119  return;
120  }
121  if ( mpMapRenderer == NULL )
122  {
123  return;
124  }
125  //ensure the user never omitted the extension from the file name
126  if ( !mOutputFileName.toUpper().endsWith( ".PDF" ) )
127  {
128  mOutputFileName += ".pdf";
129  }
130 
131  // Initialising the printer this way lets us find out what
132  // the screen resolution is which we store and then
133  // reset the resolution of the printer after that...
134  QPrinter myPrinter( QPrinter::ScreenResolution );
135 
136  // Try to force the printer resolution to 300dpi
137  // to get past platform specific defaults in printer
138  // resolution...
139  //
140  int myPrintResolutionDpi = 300;
141  myPrinter.setResolution( myPrintResolutionDpi );
142  myPrinter.setOutputFormat( QPrinter::PdfFormat );
143  QgsDebugMsg( QString( "Printing to page size %1" ).arg( pageSizeToString( mPageSize ) ) );
144  myPrinter.setPageSize( mPageSize );
145  myPrinter.setOutputFileName( mOutputFileName );
146  myPrinter.setOrientation( QPrinter::Landscape );
147  myPrinter.setDocName( "quickprint Report" );
148  QPainter myPrintPainter( &myPrinter );
149  myPrintPainter.setPen( Qt::gray );
150  myPrintPainter.setBrush( Qt::white );
151  // This is what we are aiming for:
152  // a
153  // +-(1)------ Acme Maps (2) --------------------------------------+
154  // |b 12/01/2007 (3) |
155  // | Earthquakes (4) |
156  // | +--(5)--------------------------------------------------------+ |
157  // | |c | |
158  // | | +-(6)---------------------------------------+ +~(7)~~~~~~+ | |
159  // | | | | | | | |
160  // | | | | | | | |
161  // | | | | | | | |
162  // | | | | | | | |
163  // | | | | | | | |
164  // | | | | | | | |
165  // | | | | | | | |
166  // | | | | | | | |
167  // | | | | | | | |
168  // | | | | | | | |
169  // | | | | | | | |
170  // | | +-------------------------------------------+ +~~~~~~~~~~+ | |
171  // | | | |
172  // | +-------------------------------------------------------------+ |
173  // | |
174  // | +-(8)-----+ +-(9-)----+ +-(10)----+ /|\ |
175  // | | | |Copyright| | | / | \ |
176  // | | | | 2008 | | | |(11) |
177  // | +---------+ +---------+ +---------+ |
178  // | +~(12)~~~~~~+ |
179  // +-----------------------------------------------------------------+
180  //
181  // 1) PageBorder 8) Logo1
182  // 2) PageTitle 9) CopyrightText
183  // 3) MapDate 10) Logo2
184  // 4) MapTitle 11) NorthArrow
185  // 5) MapFrame 12) ScaleBar
186  // 6) MapPixmap
187  // 7) LegendPixmap
188  // a OriginXY
189  // b HorizontalSpacing
190  // c VerticalSpacing
191 
192  //
193  // Note: Different operating systems will use different
194  // page resolutions for QPrinter::HighResolution so I'm
195  // working all coordinates out as percentages of page
196  // size so that we can hopefully get comarable print
197  // results on all platforms.
198  //
199 
200  //
201  // Note #2: Im defining all measurements here as my plan
202  // is to later support templates with different page
203  // layouts and paper sizes etc.
204  //
205 
206 
207  //set the top left origin for the print layout
208  int myOriginX = myPrinter.pageRect().left();
209  int myOriginY = myPrinter.pageRect().top();
210  int myDrawableWidth = myPrinter.pageRect().width() - myOriginX;
211  int myDrawableHeight = myPrinter.pageRect().height() - myOriginY;
212 
213  //define the spacing between layout elements
214  int myHorizontalSpacing = myDrawableWidth / 100; // 1%
215  int myVerticalSpacing = myDrawableHeight / 100; // 1%
216 
217  //define the proportions for the page layout
218  int myMapWidthPercent = 65;
219  int myMapHeightPercent = 71;
220  int myLegendWidthPercent = 25;
221  int myLegendHeightPercent = 65;
222  int myLogoWidthPercent = 23;
223  int myLogoHeightPercent = 17;
224  //
225  // Remember the size and dpi of the maprender
226  // so we can restore it properly
227  //
228  int myOriginalDpi = mpMapRenderer->outputDpi();
229  //sensible default to prevent divide by zero
230  if ( 0 == myOriginalDpi ) myOriginalDpi = 96;
231  QSize myOriginalSize = mpMapRenderer->outputSize();
232 
233  //define the font sizes and family
234  int myMapTitleFontSize = 24;
235  int myMapDateFontSize = 16;
236  int myMapNameFontSize = 32;
237  int myLegendFontSize = 12;
238 #ifdef Q_OS_LINUX//this sucks...
239  myLegendFontSize -= 2;
240 #endif
241 
242 #ifdef WIN32 //this sucks too...
243  myMapTitleFontSize /= 2;
244  myMapDateFontSize /= 2;
245  myMapNameFontSize /= 2;
246  myLegendFontSize /= 2;
247 #endif
248  QString myFontFamily = "Arial";
249 
250  //
251  // Draw the PageBorder
252  //
253  myPrintPainter.drawRect(
254  myOriginX, myOriginY, myDrawableWidth, myDrawableHeight );
255  //
256  // Draw the PageTitle
257  //
258  QFont myTitleFont( myFontFamily, myMapTitleFontSize );
259  myPrintPainter.setFont( myTitleFont );
260  QFontMetrics myTitleMetrics( myTitleFont, &myPrinter );
261  int myPageTitleHeight = myTitleMetrics.height();
262  int myPageTitleWidth = myTitleMetrics.width( mTitleText );
263  myOriginX += myHorizontalSpacing;
264  myOriginY -= ( myPageTitleHeight / 2 );
265  QRect myPageTitleRect( myOriginX,
266  myOriginY,
267  myPageTitleWidth,
268  myPageTitleHeight );
269  // make sure the title goes onto a white background
270  myPrintPainter.setPen( Qt::white );
271  myPrintPainter.drawRect( myPageTitleRect );
272  myPrintPainter.setPen( Qt::black );
273  myPrintPainter.drawText( myPageTitleRect, Qt::AlignCenter, mTitleText );
274 
275  //
276  // Draw the MapDate
277  //
278  QFont myDateFont( myFontFamily, myMapDateFontSize );
279  QString myDateText( QDate::currentDate().toString( Qt::LocalDate ) );
280  myPrintPainter.setFont( myDateFont );
281  QFontMetrics myDateMetrics( myDateFont, &myPrinter );
282  int myDateHeight = myDateMetrics.height();
283  //int myDateWidth = myDateMetrics.width(myDateText);
284  myOriginX += myHorizontalSpacing;
285  myOriginY += myPageTitleHeight + myVerticalSpacing ;
286  QRect myDateRect( myOriginX,
287  myOriginY,
288  myPageTitleWidth, //use same width as page title for centering
289  myDateHeight );
290  // make sure the title goes onto a white background
291  myPrintPainter.setPen( Qt::white );
292  myPrintPainter.drawRect( myDateRect );
293  myPrintPainter.setPen( Qt::black );
294  myPrintPainter.drawText( myDateRect, Qt::AlignCenter, myDateText );
295 
296  //
297  // Draw the MapName
298  //
299  QFont myNameFont( myFontFamily, myMapNameFontSize );
300  myPrintPainter.setFont( myNameFont );
301  QFontMetrics myNameMetrics( myNameFont, &myPrinter );
302  int myNameHeight = myNameMetrics.height();
303  int myNameWidth = myNameMetrics.width( mNameText );
304  myOriginX = myPrinter.pageRect().left() + myDrawableWidth / 2; //page center
305  myOriginX -= myNameWidth / 2;
306  myOriginY = myPrinter.pageRect().top() + ( myPageTitleHeight / 2 ) + myVerticalSpacing ;
307  QRect myNameRect( myOriginX,
308  myOriginY,
309  myNameWidth,
310  myNameHeight );
311  // make sure the title goes onto a white background
312  myPrintPainter.setPen( Qt::white );
313  myPrintPainter.drawRect( myNameRect );
314  myPrintPainter.setPen( Qt::black );
315  myPrintPainter.drawText( myNameRect, Qt::AlignCenter, mNameText );
316 
317  //
318  // Draw the MapFrame (top)
319  //
320  int myMapFrameWidth = myDrawableWidth ;
321  myOriginX = myPrinter.pageRect().left() + myHorizontalSpacing;
322  myOriginY += myNameHeight + myVerticalSpacing;
323  QLine myMapFrameTopLine( myOriginX,
324  myOriginY,
325  myMapFrameWidth,
326  myOriginY );
327  myPrintPainter.setPen( Qt::black );
328  myPrintPainter.drawLine( myMapFrameTopLine );
329 
330 
331  // Draw the map onto a pixmap
332  // @TODO: we need to save teh extent of the screen map and
333  // then set them again for the print map so that the map scales
334  // properly in the print
335  int myMapDimensionX = ( myDrawableWidth / 100 ) * myMapHeightPercent;
336  int myMapDimensionY = ( myDrawableHeight / 100 ) * myMapWidthPercent;
337 
338  QImage myMapImage( QSize( myMapDimensionX, myMapDimensionY ), QImage::Format_ARGB32 );
339  myMapImage.setDotsPerMeterX(( double )( myPrinter.logicalDpiX() ) / 25.4 * 1000.0 );
340  myMapImage.setDotsPerMeterY(( double )( myPrinter.logicalDpiY() ) / 25.4 * 1000.0 );
341  myMapImage.fill( 0 );
342  QPainter myMapPainter;
343  myMapPainter.begin( &myMapImage );
344  // Now resize for print
345  mpMapRenderer->setOutputSize( QSize( myMapDimensionX, myMapDimensionY ), ( myPrinter.logicalDpiX() + myPrinter.logicalDpiY() ) / 2 );
346  mpMapRenderer->render( &myMapPainter );
347 
348  myMapPainter.end();
349  //draw the map pixmap onto our pdf print device
350  myOriginX = myPrinter.pageRect().left() + myHorizontalSpacing;
351  myOriginY += myVerticalSpacing * 2;
352 
353  myPrintPainter.drawImage( myOriginX, myOriginY, myMapImage );
354 
355  //
356  // Draw the legend
357  //
358  QFont myLegendFont( myFontFamily, myLegendFontSize );
359  //myPrintPainter.setFont(myLegendFont);
360  int myLegendDimensionX = ( myDrawableWidth / 100 ) * myLegendWidthPercent;
361  int myLegendDimensionY = ( myDrawableHeight / 100 ) * myLegendHeightPercent;
362 
363 
364  // Create a viewport to make coordinate conversions easier
365  // The viewport has the same dimensions as the page(otherwise items
366  // drawn into it will appear squashed), but a different origin.
367  QRect myOriginalViewport = myPrintPainter.viewport(); //for restoring later
368  myOriginX += myMapDimensionX + myHorizontalSpacing;
369  myPrintPainter.setViewport( myOriginX,
370  myOriginY,
371  myOriginalViewport.width(),
372  myOriginalViewport.height() );
373  //draw a rectangale around the legend frame
374  //@TODO make this user settable
375  if ( 0 == 1 ) //put some real logic here
376  {
377  myPrintPainter.drawRect( 0, 0, myLegendDimensionX, myLegendDimensionY );
378  }
379  //get font metric and other vars needed
380  QFontMetrics myLegendFontMetrics( myLegendFont, &myPrinter );
381  int myLegendFontHeight = myLegendFontMetrics.height();
382  int myLegendXPos = 0;
383  int myLegendYPos = 0;
384  int myLegendSpacer = myLegendFontHeight / 2; //for vertical and horizontal spacing
385  int myLegendVerticalSpacer = myLegendFontHeight / 3; //for vertical between rows
386  int myIconWidth = myLegendFontHeight;
387  myPrintPainter.setFont( myLegendFont );
388  QStringList myLayerSet = mpMapRenderer->layerSet();
389  QStringListIterator myLayerIterator( myLayerSet );
390  //second clause below is to prevent legend spilling out the bottom
391  while ( myLayerIterator.hasNext() &&
392  myLegendYPos < myLegendDimensionY )
393  {
394  QString myLayerId = myLayerIterator.next();
395  QgsMapLayer * mypLayer =
396  QgsMapLayerRegistry::instance()->mapLayer( myLayerId );
397  if ( mypLayer )
398  {
399  QgsVectorLayer *mypVectorLayer =
400  qobject_cast<QgsVectorLayer *>( mypLayer );
401  // TODO: add support for symbology-ng renderers
402  if ( mypVectorLayer && mypVectorLayer->renderer() )
403  {
404  QString myLayerName = mypVectorLayer->name();
405  QIcon myIcon;
406  QPixmap myPixmap( QSize( myIconWidth, myIconWidth ) ); //square
407  //based on code from qgslegendlayer.cpp - see that file for more info
408  const QgsRenderer* mypRenderer = mypVectorLayer->renderer();
409  const QList<QgsSymbol*> mySymbolList = mypRenderer->symbols();
410  //
411  // Single symbol
412  //
413  double widthScale = ( myPrinter.logicalDpiX() + myPrinter.logicalDpiY() ) / 2.0 / 25.4;
414 
415  if ( 1 == mySymbolList.size() )
416  {
417  QgsSymbol * mypSymbol = mySymbolList.at( 0 );
418  myPrintPainter.setPen( mypSymbol->pen() );
419  myPrintPainter.setBrush( mypSymbol->brush() );
420  myLegendXPos = 0 ;
421  if ( mypSymbol->type() == QGis::Point )
422  {
423  QImage myImage;
424  myImage = mypSymbol->getPointSymbolAsImage( widthScale );
425  myPrintPainter.drawImage( myLegendXPos, myLegendYPos, myImage );
426  }
427  else if ( mypSymbol->type() == QGis::Line )
428  {
429  myPrintPainter.drawLine( myLegendXPos, myLegendYPos,
430  myLegendXPos + myIconWidth,
431  myLegendYPos + myIconWidth );
432  }
433  else //polygon
434  {
435  myPrintPainter.drawRect( myLegendXPos, myLegendYPos, myIconWidth, myIconWidth );
436  }
437  myLegendXPos += myIconWidth + myLegendSpacer;
438  myPrintPainter.setPen( Qt::black );
439  QStringList myWrappedLayerNameList = wordWrap( myLayerName,
440  myLegendFontMetrics,
441  myLegendDimensionX - myIconWidth );
442  //
443  // Loop through wrapped legend label lines
444  //
445  QStringListIterator myLineWrapIterator( myWrappedLayerNameList );
446  while ( myLineWrapIterator.hasNext() )
447  {
448  QString myLine = myLineWrapIterator.next();
449  QRect myLegendItemRect( myLegendXPos,
450  myLegendYPos,
451  myLegendDimensionX - myIconWidth,
452  myLegendFontHeight );
453  myPrintPainter.drawText( myLegendItemRect, Qt::AlignLeft, myLine );
454  myLegendYPos += myLegendVerticalSpacer + myLegendFontHeight;
455  }
456  }
457  else //class breaks
458  {
459  // draw in the layer name first, after we loop for the class breaks
460  QStringList myWrappedLayerNameList = wordWrap( myLayerName,
461  myLegendFontMetrics,
462  myLegendDimensionX - myIconWidth );
463  // Check the wrapped layer name wont overrun the space we have
464  // for the legend ...
465  int myLabelHeight = myLegendFontHeight *
466  myWrappedLayerNameList.count();
467  if ( myLegendYPos + myLabelHeight > myLegendDimensionY )
468  {
469  continue;
470  }
471 
472  //
473  // Loop through wrapped legend label lines
474  //
475  QStringListIterator myLineWrapIterator( myWrappedLayerNameList );
476  while ( myLineWrapIterator.hasNext() )
477  {
478  QString myLine = myLineWrapIterator.next();
479  myLegendXPos = myIconWidth;
480  QRect myLegendItemRect( myLegendXPos,
481  myLegendYPos,
482  myLegendFontMetrics.width( myLine ),
483  myLegendFontHeight );
484  myPrintPainter.setPen( Qt::black );
485  myPrintPainter.drawText( myLegendItemRect, Qt::AlignLeft, myLine );
486  myLegendYPos += myLegendVerticalSpacer + myLegendFontHeight;
487  }
488  //
489  // Loop through the class breaks
490  //
491  QListIterator<QgsSymbol *> myIterator( mySymbolList );
492  while ( myIterator.hasNext() && myLegendYPos < myLegendDimensionY )
493  {
494  QgsSymbol * mypSymbol = myIterator.next();
495  myPrintPainter.setPen( mypSymbol->pen() );
496  myPrintPainter.setBrush( mypSymbol->brush() );
497  myLegendXPos = myLegendSpacer * 3; //extra indent for class breaks
498  if ( mypSymbol->type() == QGis::Point )
499  {
500  QImage myImage;
501  myImage = mypSymbol->getPointSymbolAsImage( widthScale );
502  myPrintPainter.drawImage( myLegendXPos, myLegendYPos, myImage );
503  }
504  else if ( mypSymbol->type() == QGis::Line )
505  {
506  myPrintPainter.drawLine( myLegendXPos, myLegendYPos,
507  myLegendXPos + myIconWidth,
508  myLegendYPos + myIconWidth );
509  }
510  else //polygon
511  {
512  myPrintPainter.drawRect(
513  myLegendXPos, myLegendYPos, myIconWidth, myIconWidth );
514  }
515  //
516  // Now work out the class break label
517  //
518  QString myLabel;
519  QString myLower = mypSymbol->lowerValue();
520  if ( !myLower.isEmpty() )
521  {
522  myLabel = myLower;
523  }
524  QString myUpper = mypSymbol->upperValue();
525  if ( !myUpper.isEmpty() )
526  {
527  myLabel += " - ";
528  myLabel += myUpper;
529  }
530  QString myText = mypSymbol->label();
531  if ( !myText.isEmpty() )
532  {
533  myLabel += " ";
534  myLabel += myText;
535  }
536  myLabel = myLabel.trimmed();
537  myLegendXPos += myIconWidth + myLegendSpacer;
538  myPrintPainter.setPen( Qt::black );
539 
540  QStringList myWrappedLayerNameList = wordWrap( myLabel,
541  myLegendFontMetrics,
542  myLegendDimensionX - myLegendXPos );
543  //
544  // Loop through wrapped legend label lines
545  //
546  QStringListIterator myLineWrapIterator( myWrappedLayerNameList );
547  while ( myLineWrapIterator.hasNext() )
548  {
549  QString myLine = myLineWrapIterator.next();
550  // check if the text will overflow the space we have
551  QRect myLegendItemRect( myLegendXPos,
552  myLegendYPos,
553  myLegendDimensionX - myIconWidth,
554  myLegendFontHeight );
555  myPrintPainter.drawText( myLegendItemRect, Qt::AlignLeft, myLine );
556  myLegendYPos += myLegendVerticalSpacer + myLegendFontHeight;
557  } //wordwrap loop
558  } //symbol loop
559  } //class breaks
560  } //if vectorlayer
561  } //if maplayer
562  } //layer iterator
563 
564  //reinstate the viewport
565  myPrintPainter.setViewport( myOriginalViewport );
566 
567 
568  //
569  // Draw the MapFrame (bottom)
570  //
571  myOriginX = myPrinter.pageRect().left() + myHorizontalSpacing;
572  myOriginY += myMapDimensionY + ( myVerticalSpacing * 2 );
573  QLine myMapFrameBottomLine( myOriginX,
574  myOriginY,
575  myMapFrameWidth,
576  myOriginY );
577  myPrintPainter.setPen( Qt::black );
578  myPrintPainter.drawLine( myMapFrameBottomLine );
579 
580 
581  //
582  // Draw logo 1
583  //
584  int myLogoXDim = ( myDrawableWidth / 100 ) * myLogoWidthPercent;
585  int myLogoYDim = ( myDrawableHeight / 100 ) * myLogoHeightPercent;
586  QPixmap myLogo1;
587  QgsDebugMsg( QString( "Logo1: %1" ).arg( mLogo1File ) );
588  myLogo1.fill( Qt::white );
589  myLogo1.load( mLogo1File );
590  myLogo1 = myLogo1.scaled( myLogoXDim, myLogoYDim, Qt::KeepAspectRatio );
591  myOriginX = myPrinter.pageRect().left() + myHorizontalSpacing;
592  myOriginY += myVerticalSpacing ;
593  myPrintPainter.drawPixmap( myOriginX,
594  myOriginY,
595  myLogo1 );
596 
597  //
598  // Draw Copyright Text
599  //
600  myOriginX += myHorizontalSpacing + myLogoXDim;
601  QRect myCopyrightRect( myOriginX, myOriginY, myLogoXDim, myLogoYDim );
602  myPrintPainter.setPen( Qt::black );
603  QFont myCopyrightFont( myFontFamily, myMapDateFontSize );
604  myPrintPainter.setFont( myCopyrightFont );
605  //myPrintPainter.drawRect( myCopyrightRect );
606  myPrintPainter.drawText( myCopyrightRect, Qt::AlignCenter | Qt::TextWordWrap, mCopyrightText );
607 
608  //
609  // Draw logo 2
610  //
611  QPixmap myLogo2;
612  myLogo2.fill( Qt::white );
613  myLogo2.load( mLogo2File );
614  myLogo2 = myLogo2.scaled( myLogoXDim, myLogoYDim, Qt::KeepAspectRatio );
615  myOriginX += myHorizontalSpacing + myLogoXDim;
616  myPrintPainter.drawPixmap( myOriginX,
617  myOriginY,
618  myLogo2 );
619 
620  //
621  // Draw the north arrow
622  //
623  myOriginX += myHorizontalSpacing + myLogoXDim;
624  // use half the available space for the n.arrow
625  // and the rest for the scale bar (see below)
626  QPixmap myNorthArrow( myLogoYDim / 2, myLogoYDim / 2 );
627  myNorthArrow.fill( Qt::white );
628  QPainter myNorthPainter( &myNorthArrow );
629  QSvgRenderer mySvgRenderer( mNorthArrowFile );
630  mySvgRenderer.render( &myNorthPainter );
631  myPrintPainter.drawPixmap( myOriginX + (( myLogoXDim / 2 ) ),
632  myOriginY,
633  myNorthArrow );
634 
635  //
636  // Draw the scale bar
637  //
638  myOriginY += myLogoYDim / 2 + myVerticalSpacing;
639  myPrintPainter.setViewport( myOriginX,
640  myOriginY,
641  myOriginalViewport.width(),
642  myOriginalViewport.height() );
643  renderPrintScaleBar( &myPrintPainter, mpMapRenderer, myLogoXDim );
644  myPrintPainter.setViewport( myOriginalViewport );
645 
646  //
647  // Finish up
648  //
649 
650 
651  myPrintPainter.end();
652 #if 0
653  mProgressDialog.setValue( 0 );
654  mProgressDialog.setLabelText( tr( "Please wait while your report is generated", "COMMENTED OUT" ) );
655  mProgressDialog.show();
656  mProgressDialog.setWindowModality( Qt::WindowModal );
657  mProgressDialog.setAutoClose( true );
658 #endif
659  //
660  // Restore the map render to its former glory
661  //
662  mpMapRenderer->setOutputSize( myOriginalSize, myOriginalDpi );
663 }
664 
665 void QgsQuickPrint::scaleTextLabels( int theScaleFactor, SymbolScalingType theDirection )
666 {
667  if ( 0 >= theScaleFactor )
668  {
669  QgsDebugMsg( "invalid scale factor" );
670  return;
671  }
672  QStringList myLayerSet = mpMapRenderer->layerSet();
673  QStringListIterator myLayerIterator( myLayerSet );
674  while ( myLayerIterator.hasNext() )
675  {
676  QString myLayerId = myLayerIterator.next();
677  QgsDebugMsg( "Scaling text labels for print for " + myLayerId );
678  QgsMapLayer * mypLayer =
679  QgsMapLayerRegistry::instance()->mapLayer( myLayerId );
680  if ( mypLayer )
681  {
682  QgsVectorLayer *mypVectorLayer =
683  qobject_cast<QgsVectorLayer *>( mypLayer );
684  if ( mypVectorLayer )
685  {
686  QgsLabel * mypLabel = mypVectorLayer->label();
687  QgsLabelAttributes * mypLabelAttributes = mypLabel->labelAttributes();
688  if ( theDirection == ScaleUp )
689  {
690  mypLabelAttributes->setSize(
691  mypLabelAttributes->size() * theScaleFactor,
692  mypLabelAttributes->sizeType() );
693  }
694  else //scale down
695  {
696  mypLabelAttributes->setSize(
697  mypLabelAttributes->size() / theScaleFactor,
698  mypLabelAttributes->sizeType() );
699  }
700  } //if vectorlayer
701  } //if maplayer
702  } //layer iterator
703 }
704 
705 void QgsQuickPrint::scalePointSymbols( int theScaleFactor, SymbolScalingType theDirection )
706 {
707  if ( 0 >= theScaleFactor )
708  {
709  QgsDebugMsg( "invalid scale factor" );
710  return;
711  }
712  QStringList myLayerSet = mpMapRenderer->layerSet();
713  QStringListIterator myLayerIterator( myLayerSet );
714  while ( myLayerIterator.hasNext() )
715  {
716  QString myLayerId = myLayerIterator.next();
717  QgsDebugMsg( "Scaling point symbols for print for " + myLayerId );
718  QgsMapLayer * mypLayer =
719  QgsMapLayerRegistry::instance()->mapLayer( myLayerId );
720  if ( mypLayer )
721  {
722  QgsVectorLayer *mypVectorLayer =
723  qobject_cast<QgsVectorLayer *>( mypLayer );
724  if ( mypVectorLayer )
725  {
726  const QgsRenderer* mypRenderer = mypVectorLayer->renderer();
727  const QList<QgsSymbol*> mySymbolList = mypRenderer->symbols();
728  //
729  // Single symbol
730  //
731  if ( 1 == mySymbolList.size() )
732  {
733  QgsSymbol * mypSymbol = mySymbolList.at( 0 );
734  if ( mypSymbol->type() == QGis::Point )
735  {
736  if ( theDirection == ScaleUp )
737  {
738  mypSymbol->setPointSize( mypSymbol->pointSize() * theScaleFactor );
739  }
740  else //Scale Down
741  {
742  mypSymbol->setPointSize( mypSymbol->pointSize() / theScaleFactor );
743  }
744  }
745  }
746  else //class breaks
747  {
748  QListIterator<QgsSymbol *> myIterator( mySymbolList );
749  while ( myIterator.hasNext() )
750  {
751  QgsSymbol * mypSymbol = myIterator.next();
752  if ( mypSymbol->type() == QGis::Point )
753  {
754  if ( theDirection == ScaleUp )
755  {
756  mypSymbol->setPointSize( mypSymbol->pointSize() * theScaleFactor );
757  }
758  else //Scale Down
759  {
760  mypSymbol->setPointSize( mypSymbol->pointSize() / theScaleFactor );
761  }
762  }
763  } //symbol loop
764  } //class breaks
765  } //if vectorlayer
766  } //if maplayer
767  } //layer iterator
768 }
769 
770 
771 
772 void QgsQuickPrint::renderPrintScaleBar( QPainter * thepPainter,
773  QgsMapRenderer * thepMapRenderer,
774  int theMaximumWidth )
775 {
776  //hard coding some options for now
777  bool mySnappingFlag = true;
778  QColor mColor = Qt::black;
779  // Hard coded sizes
780  int myTextOffsetX = 0;
781  int myTextOffsetY = 5;
782  int myXMargin = 20;
783  int myYMargin = 20;
784  int myPreferredSize = theMaximumWidth - ( myXMargin * 2 );
785  double myActualSize = 0;
786  int myBufferSize = 1; //softcode this later
787  QColor myBackColor = Qt::white; //used for text
788  QColor myForeColor = Qt::black; //used for text
789 
790  //Get canvas dimensions
791  //int myCanvasHeight = thepMapCanvas->height();
792 
793  //Get map units per pixel. This can be negative at times (to do with
794  //projections) and that just confuses the rest of the code in this
795  //function, so force to a positive number.
796  double myMapUnitsPerPixelDouble = qAbs( thepMapRenderer->mapUnitsPerPixel() );
797  //
798  // Exit if the canvas width is 0 or layercount is 0 or QGIS will freeze
799  int myLayerCount = thepMapRenderer->layerSet().count();
800  if ( !myLayerCount || !myMapUnitsPerPixelDouble ) return;
801 
802  //Calculate size of scale bar for preferred number of map units
803  double myScaleBarWidth = myPreferredSize;
804  myActualSize = myScaleBarWidth * myMapUnitsPerPixelDouble;
805 
806 
807  // Work out the exponent for the number - e.g, 1234 will give 3,
808  // and .001234 will give -3
809  double myPowerOf10 = floor( log10( myActualSize ) );
810 
811  // snap to integer < 10 times power of 10
812  if ( mySnappingFlag )
813  {
814  double scaler = pow( 10.0, myPowerOf10 );
815  myActualSize = round( myActualSize / scaler ) * scaler;
816  myScaleBarWidth = myActualSize / myMapUnitsPerPixelDouble;
817  }
818 
819  //Get type of map units and set scale bar unit label text
820  QGis::UnitType myMapUnits = thepMapRenderer->mapUnits();
821  QString myScaleBarUnitLabel;
822  switch ( myMapUnits )
823  {
824  case QGis::Meters:
825  if ( myActualSize > 1000.0 )
826  {
827  myScaleBarUnitLabel = tr( " km" );
828  myActualSize = myActualSize / 1000;
829  }
830  else if ( myActualSize < 0.01 )
831  {
832  myScaleBarUnitLabel = tr( " mm" );
833  myActualSize = myActualSize * 1000;
834  }
835  else if ( myActualSize < 0.1 )
836  {
837  myScaleBarUnitLabel = tr( " cm" );
838  myActualSize = myActualSize * 100;
839  }
840  else
841  myScaleBarUnitLabel = tr( " m" );
842  break;
843  case QGis::Feet:
844  if ( myActualSize > 5280.0 ) //5280 feet to the mile
845  {
846  myScaleBarUnitLabel = tr( " miles" );
847  myActualSize = myActualSize / 5280;
848  }
849  else if ( myActualSize == 5280.0 ) //5280 feet to the mile
850  {
851  myScaleBarUnitLabel = tr( " mile" );
852  myActualSize = myActualSize / 5280;
853  }
854  else if ( myActualSize < 1 )
855  {
856  myScaleBarUnitLabel = tr( " inches" );
857  myActualSize = myActualSize * 12;
858  }
859  else if ( myActualSize == 1.0 )
860  {
861  myScaleBarUnitLabel = tr( " foot" );
862  }
863  else
864  {
865  myScaleBarUnitLabel = tr( " feet" );
866  }
867  break;
868  case QGis::Degrees:
869  if ( myActualSize == 1.0 )
870  myScaleBarUnitLabel = tr( " degree" );
871  else
872  myScaleBarUnitLabel = tr( " degrees" );
873  break;
874  case QGis::UnknownUnit:
875  myScaleBarUnitLabel = tr( " unknown" );
876  default:
877  QgsDebugMsg( "Error: not picked up map units - actual value = "
878  + QString::number( myMapUnits ) );
879  };
880 
881  //Set font and calculate width of unit label
882  int myFontSize = 10; //we use this later for buffering
883  QFont myFont( "helvetica", myFontSize );
884  thepPainter->setFont( myFont );
885  QFontMetrics myFontMetrics( myFont );
886  double myFontWidth = myFontMetrics.width( myScaleBarUnitLabel );
887  double myFontHeight = myFontMetrics.height();
888 
889  //Set the maximum label
890  QString myScaleBarMaxLabel = QString::number( myActualSize );
891 
892  //Calculate total width of scale bar and label
893  //we divide by 2 because the max scale label
894  //will be centered over the endpoint of the scale bar
895  double myTotalScaleBarWidth = myScaleBarWidth + ( myFontWidth / 2 );
896 
897  //determine the origin of scale bar (bottom right)
898  //for x origin set things up so the scalebar is centered
899  int myOriginX = ( theMaximumWidth - myTotalScaleBarWidth ) / 2;
900  int myOriginY = myYMargin;
901 
902  //Set pen to draw with
903  QPen myForegroundPen( mColor, 2 );
904  QPen myBackgroundPen( Qt::white, 3 );
905 
906  //Cast myScaleBarWidth to int for drawing
907  int myScaleBarWidthInt = ( int ) myScaleBarWidth;
908 
909  //now draw the bar itself in user selected color
910  thepPainter->setPen( myForegroundPen );
911  //make a glossygradient for the background
912  QGradientStops myStops;
913  myStops << QGradientStop( 0.0, QColor( "#616161" ) );
914  myStops << QGradientStop( 0.5, QColor( "#505050" ) );
915  myStops << QGradientStop( 0.6, QColor( "#434343" ) );
916  myStops << QGradientStop( 1.0, QColor( "#656565" ) );
917  //draw again with the brush in the revers direction to complete teh glossiness
918  QLinearGradient myReverseGlossyBrush(
919  QPointF( myOriginX, myOriginY + myFontHeight*3 ),
920  QPointF( myOriginX, myOriginY ) );
921  thepPainter->setBrush( myReverseGlossyBrush );
922  thepPainter->drawRect(
923  myOriginX,
924  myOriginY,
925  myOriginX + myScaleBarWidthInt,
926  myOriginY + myFontHeight
927  );
928 
929  //
930  //Do drawing of scale bar text
931  //
932 
933 
934  //Draw the minimum label buffer
935  thepPainter->setPen( myBackColor );
936  myFontWidth = myFontMetrics.width( "0" );
937 
938  for ( int i = 0 - myBufferSize; i <= myBufferSize; i++ )
939  {
940  for ( int j = 0 - myBufferSize; j <= myBufferSize; j++ )
941  {
942  thepPainter->drawText( int( i + ( myOriginX - ( myFontWidth / 2 ) ) ),
943  int( j + ( myOriginY - ( myFontHeight / 4 ) ) ) - myTextOffsetY,
944  "0" );
945  }
946  }
947 
948  //Draw minimum label
949  thepPainter->setPen( myForeColor );
950 
951  thepPainter->drawText(
952  int( myOriginX - ( myFontWidth / 2 ) ),
953  int( myOriginY - ( myFontHeight / 4 ) ) - myTextOffsetY,
954  "0"
955  );
956 
957  //
958  //Draw maximum label
959  //
960  thepPainter->setPen( myBackColor );
961  myFontWidth = myFontMetrics.width( myScaleBarMaxLabel );
962  myFontHeight = myFontMetrics.height();
963  //first the buffer
964  for ( int i = 0 - myBufferSize; i <= myBufferSize; i++ )
965  {
966  for ( int j = 0 - myBufferSize; j <= myBufferSize; j++ )
967  {
968  thepPainter->drawText( int( i + ( myOriginX + myScaleBarWidthInt - ( myFontWidth / 2 ) ) ),
969  int( j + ( myOriginY - ( myFontHeight / 4 ) ) ) - myTextOffsetY,
970  myScaleBarMaxLabel );
971  }
972  }
973  //then the text itself
974  thepPainter->setPen( myForeColor );
975  thepPainter->drawText(
976  int( myOriginX + myScaleBarWidthInt - ( myFontWidth / 2 ) ),
977  int( myOriginY - ( myFontHeight / 4 ) ) - myTextOffsetY,
978  myScaleBarMaxLabel
979  );
980 
981  //
982  //Draw unit label
983  //
984  thepPainter->setPen( myBackColor );
985  myFontWidth = myFontMetrics.width( myScaleBarUnitLabel );
986  //first the buffer
987  for ( int i = 0 - myBufferSize; i <= myBufferSize; i++ )
988  {
989  for ( int j = 0 - myBufferSize; j <= myBufferSize; j++ )
990  {
991  thepPainter->drawText( i + ( myOriginX + myScaleBarWidthInt + myTextOffsetX ),
992  j + myOriginY + myFontHeight + ( myFontHeight*2.5 ) + myTextOffsetY,
993  myScaleBarUnitLabel );
994  }
995  }
996  //then the text itself
997  thepPainter->setPen( myForeColor );
998  thepPainter->drawText(
999  myOriginX + myScaleBarWidthInt + myTextOffsetX,
1000  myOriginY + myFontHeight + ( myFontHeight*2.5 ) + myTextOffsetY,
1001  myScaleBarUnitLabel
1002  );
1003 }
1004 
1005 QStringList QgsQuickPrint::wordWrap( QString theString,
1006  QFontMetrics theMetrics,
1007  int theWidth )
1008 {
1009  //iterate the string
1010  QStringList myList;
1011  QString myCumulativeLine = "";
1012  QString myStringToPreviousSpace = "";
1013  int myPreviousSpacePos = 0;
1014  for ( int i = 0; i < theString.count(); ++i )
1015  {
1016  QChar myChar = theString.at( i );
1017  if ( myChar == QChar( ' ' ) )
1018  {
1019  myStringToPreviousSpace = myCumulativeLine;
1020  myPreviousSpacePos = i;
1021  }
1022  myCumulativeLine += myChar;
1023  if ( theMetrics.width( myCumulativeLine ) >= theWidth )
1024  {
1025  //time to wrap
1026  //@todo deal with long strings that have no spaces
1027  //forcing a break at current pos...
1028  myList << myStringToPreviousSpace.trimmed();
1029  i = myPreviousSpacePos;
1030  myStringToPreviousSpace = "";
1031  myCumulativeLine = "";
1032  }
1033  }//end of i loop
1034  //add whatever is left in the string to the list
1035  if ( !myCumulativeLine.trimmed().isEmpty() )
1036  {
1037  myList << myCumulativeLine.trimmed();
1038  }
1039 
1040  //qDebug("Wrapped legend entry: %s\n%s", theString, myList.join("\n").toLocal8Bit().constData() );
1041  return myList;
1042 
1043 }
1044 QString QgsQuickPrint::pageSizeToString( QPrinter::PageSize theSize )
1045 {
1046  if ( theSize == QPrinter::A0 ) return "QPrinter::A0";
1047  if ( theSize == QPrinter::A1 ) return "QPrinter::A1";
1048  if ( theSize == QPrinter::A2 ) return "QPrinter::A2";
1049  if ( theSize == QPrinter::A3 ) return "QPrinter::A3";
1050  if ( theSize == QPrinter::A4 ) return "QPrinter::A4";
1051  if ( theSize == QPrinter::A5 ) return "QPrinter::A5";
1052  if ( theSize == QPrinter::A6 ) return "QPrinter::A6";
1053  if ( theSize == QPrinter::A7 ) return "QPrinter::A7";
1054  if ( theSize == QPrinter::A8 ) return "QPrinter::A8";
1055  if ( theSize == QPrinter::A9 ) return "QPrinter::A9";
1056  if ( theSize == QPrinter::B0 ) return "QPrinter::B0";
1057  if ( theSize == QPrinter::B1 ) return "QPrinter::B1";
1058  if ( theSize == QPrinter::B10 ) return "QPrinter::B10";
1059  if ( theSize == QPrinter::B2 ) return "QPrinter::B2";
1060  if ( theSize == QPrinter::B3 ) return "QPrinter::B3";
1061  if ( theSize == QPrinter::B4 ) return "QPrinter::B4";
1062  if ( theSize == QPrinter::B5 ) return "QPrinter::B5";
1063  if ( theSize == QPrinter::B6 ) return "QPrinter::B6";
1064  if ( theSize == QPrinter::B7 ) return "QPrinter::B7";
1065  if ( theSize == QPrinter::B8 ) return "QPrinter::B8";
1066  if ( theSize == QPrinter::B9 ) return "QPrinter::B9";
1067  if ( theSize == QPrinter::C5E ) return "QPrinter::C5E";
1068  if ( theSize == QPrinter::Comm10E ) return "QPrinter::Comm10E";
1069  if ( theSize == QPrinter::DLE ) return "QPrinter::DLE";
1070  if ( theSize == QPrinter::Executive ) return "QPrinter::Executive";
1071  if ( theSize == QPrinter::Folio ) return "QPrinter::Folio";
1072  if ( theSize == QPrinter::Ledger ) return "QPrinter::Ledger";
1073  if ( theSize == QPrinter::Legal ) return "QPrinter::Legal";
1074  if ( theSize == QPrinter::Letter ) return "QPrinter::Letter";
1075  //falback
1076  return "QPrinter::A4";
1077 
1078 }
1079 
1080 QPrinter::PageSize QgsQuickPrint::stringToPageSize( QString theSize )
1081 {
1082  if ( theSize == "QPrinter::A0" ) return QPrinter::A0;
1083  if ( theSize == "QPrinter::A1" ) return QPrinter::A1;
1084  if ( theSize == "QPrinter::A2" ) return QPrinter::A2;
1085  if ( theSize == "QPrinter::A3" ) return QPrinter::A3;
1086  if ( theSize == "QPrinter::A4" ) return QPrinter::A4;
1087  if ( theSize == "QPrinter::A5" ) return QPrinter::A5;
1088  if ( theSize == "QPrinter::A6" ) return QPrinter::A6;
1089  if ( theSize == "QPrinter::A7" ) return QPrinter::A7;
1090  if ( theSize == "QPrinter::A8" ) return QPrinter::A8;
1091  if ( theSize == "QPrinter::A9" ) return QPrinter::A9;
1092  if ( theSize == "QPrinter::B0" ) return QPrinter::B0;
1093  if ( theSize == "QPrinter::B1" ) return QPrinter::B1;
1094  if ( theSize == "QPrinter::B10" ) return QPrinter::B10;
1095  if ( theSize == "QPrinter::B2" ) return QPrinter::B2;
1096  if ( theSize == "QPrinter::B3" ) return QPrinter::B3;
1097  if ( theSize == "QPrinter::B4" ) return QPrinter::B4;
1098  if ( theSize == "QPrinter::B5" ) return QPrinter::B5;
1099  if ( theSize == "QPrinter::B6" ) return QPrinter::B6;
1100  if ( theSize == "QPrinter::B7" ) return QPrinter::B7;
1101  if ( theSize == "QPrinter::B8" ) return QPrinter::B8;
1102  if ( theSize == "QPrinter::B9" ) return QPrinter::B9;
1103  if ( theSize == "QPrinter::C5E" ) return QPrinter::C5E;
1104  if ( theSize == "QPrinter::Comm10E" ) return QPrinter::Comm10E;
1105  if ( theSize == "QPrinter::DLE" ) return QPrinter::DLE;
1106  if ( theSize == "QPrinter::Executive" ) return QPrinter::Executive;
1107  if ( theSize == "QPrinter::Folio" ) return QPrinter::Folio;
1108  if ( theSize == "QPrinter::Ledger" ) return QPrinter::Ledger;
1109  if ( theSize == "QPrinter::Legal" ) return QPrinter::Legal;
1110  if ( theSize == "QPrinter::Letter" ) return QPrinter::Letter;
1111  //falback
1112  return QPrinter::A4;
1113 
1114 }
1115 
1116 
1117