|
Quantum GIS API Documentation
master-2bfffaa
|
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 }