44
47
#include "qgscursors.h"
46
49
#include <QCloseEvent>
47
51
#include <QDesktopWidget>
48
52
#include <QFileDialog>
49
53
#include <QFileInfo>
55
#include <QImageWriter>
51
57
#include <QMenuBar>
52
58
#include <QMessageBox>
59
#include <QPageSetupDialog>
53
60
#include <QPainter>
56
62
#include <QPrintDialog>
57
63
#include <QSettings>
60
#if QT_VERSION < 0x040300
63
65
#include <QSvgGenerator>
65
66
#include <QToolBar>
66
67
#include <QToolButton>
67
#include <QImageWriter>
70
#include "qgslogger.h"
72
QgsComposer::QgsComposer( QgisApp *qgis, const QString& title ): QMainWindow(), mTitle( title )
69
#include <QPaintEngine>
72
QgsComposer::QgsComposer( QgisApp *qgis, const QString& title ): QMainWindow(), mTitle( title ), mUndoView( 0 )
75
75
setWindowTitle( mTitle );
77
77
QObject::connect( mButtonBox, SIGNAL( rejected() ), this, SLOT( close() ) );
80
int size = settings.value( "/IconSize", 24 ).toInt();
81
setIconSize( QSize( size, size ) );
79
83
QToolButton* orderingToolButton = new QToolButton( this );
80
84
orderingToolButton->setPopupMode( QToolButton::InstantPopup );
81
85
orderingToolButton->setAutoRaise( true );
271
298
mActionAlignBottom->setIcon( QgisApp::getThemeIcon( "/mActionAlignBottom.png" ) );
301
void QgsComposer::setIconSizes( int size )
303
//Set the icon size of for all the toolbars created in the future.
304
setIconSize( QSize( size, size ) );
306
//Change all current icon sizes.
307
QList<QToolBar *> toolbars = findChildren<QToolBar *>();
308
foreach( QToolBar * toolbar, toolbars )
310
toolbar->setIconSize( QSize( size, size ) );
274
314
void QgsComposer::connectSlots()
276
connect( mView, SIGNAL( selectedItemChanged( const QgsComposerItem* ) ), this, SLOT( showItemOptions( const QgsComposerItem* ) ) );
316
connect( mView, SIGNAL( selectedItemChanged( QgsComposerItem* ) ), this, SLOT( showItemOptions( QgsComposerItem* ) ) );
277
317
connect( mView, SIGNAL( composerLabelAdded( QgsComposerLabel* ) ), this, SLOT( addComposerLabel( QgsComposerLabel* ) ) );
278
318
connect( mView, SIGNAL( composerMapAdded( QgsComposerMap* ) ), this, SLOT( addComposerMap( QgsComposerMap* ) ) );
279
319
connect( mView, SIGNAL( itemRemoved( QgsComposerItem* ) ), this, SLOT( deleteItem( QgsComposerItem* ) ) );
453
494
mComposition->update();
497
// Hack to workaround Qt #5114 by disabling PatternTransform
498
class QgsPaintEngineHack : public QPaintEngine
504
gccaps |= ( QPaintEngine::PrimitiveTransform
505
// | QPaintEngine::PatternTransform
506
| QPaintEngine::PixmapTransform
507
| QPaintEngine::PatternBrush
508
// | QPaintEngine::LinearGradientFill
509
// | QPaintEngine::RadialGradientFill
510
// | QPaintEngine::ConicalGradientFill
511
| QPaintEngine::AlphaBlend
512
// | QPaintEngine::PorterDuff
513
| QPaintEngine::PainterPaths
514
| QPaintEngine::Antialiasing
515
| QPaintEngine::BrushStroke
516
| QPaintEngine::ConstantOpacity
517
| QPaintEngine::MaskedBrush
518
// | QPaintEngine::PerspectiveTransform
519
| QPaintEngine::BlendModes
520
// | QPaintEngine::ObjectBoundingModeGradients
521
#if QT_VERSION >= 0x040500
522
| QPaintEngine::RasterOpModes
524
| QPaintEngine::PaintOutsidePaintEvent
456
529
void QgsComposer::on_mActionExportAsPDF_triggered()
458
531
QSettings myQSettings; // where we keep last used filter in persistent state
459
QString myLastUsedFile = myQSettings.value( "/UI/lastSaveAsPdfFile", "qgis.pdf" ).toString();
460
QFileInfo file( myLastUsedFile );
461
QFileDialog *myQFileDialog = new QFileDialog( this, tr( "Choose a file name to save the map as" ),
462
file.path(), tr( "PDF Format" ) + " (*.pdf *PDF)" );
463
myQFileDialog->selectFile( file.fileName() );
464
myQFileDialog->setFileMode( QFileDialog::AnyFile );
465
myQFileDialog->setAcceptMode( QFileDialog::AcceptSave );
467
int result = myQFileDialog->exec();
469
if ( result != QDialog::Accepted ) return;
471
QString myOutputFileNameQString = myQFileDialog->selectedFiles().first();
472
if ( myOutputFileNameQString == "" ) return;
474
myQSettings.setValue( "/UI/lastSaveAsPdfFile", myOutputFileNameQString );
532
QString lastUsedFile = myQSettings.value( "/UI/lastSaveAsPdfFile", "qgis.pdf" ).toString();
533
QFileInfo file( lastUsedFile );
535
QString outputFileName = QFileDialog::getSaveFileName(
537
tr( "Choose a file name to save the map as" ),
539
tr( "PDF Format" ) + " (*.pdf *.PDF)" );
541
if ( !outputFileName.endsWith( ".pdf", Qt::CaseInsensitive ) )
543
outputFileName += ".pdf";
546
myQSettings.setValue( "/UI/lastSaveAsPdfFile", outputFileName );
476
548
QPrinter printer;
478
550
printer.setOutputFormat( QPrinter::PdfFormat );
479
printer.setOutputFileName( myOutputFileNameQString );
551
printer.setOutputFileName( outputFileName );
480
552
printer.setPaperSize( QSizeF( mComposition->paperWidth(), mComposition->paperHeight() ), QPrinter::Millimeter );
554
QPaintEngine *engine = printer.paintEngine();
557
QgsPaintEngineHack *hack = static_cast<QgsPaintEngineHack*>( engine );
482
561
print( printer );
485
564
void QgsComposer::on_mActionPrint_triggered()
490
if ( mComposition->paperWidth() >= mComposition->paperHeight() )
492
printer.setOrientation( QPrinter::Landscape );
496
printer.setOrientation( QPrinter::Portrait );
499
printer.setPaperSize( QSizeF( mComposition->paperWidth(), mComposition->paperHeight() ), QPrinter::Millimeter );
500
QPrintDialog printDialog( &printer, 0 );
566
//orientation and page size are already set to QPrinter in the page setup dialog
567
QPrintDialog printDialog( &mPrinter, 0 );
501
568
if ( printDialog.exec() != QDialog::Accepted )
509
576
void QgsComposer::print( QPrinter &printer )
578
if ( !mComposition || !mView )
514
581
if ( containsWMSLayer() )
531
598
QApplication::setOverrideCursor( Qt::BusyCursor );
533
if ( mComposition->printAsRaster() )
600
bool printAsRaster = mComposition->printAsRaster();
601
//mView->setScene( 0 );
535
605
//print out via QImage, code copied from on_mActionExportAsImage_activated
536
606
int width = ( int )( mComposition->printResolution() * mComposition->paperWidth() / 25.4 );
537
607
int height = ( int )( mComposition-> printResolution() * mComposition->paperHeight() / 25.4 );
538
608
QImage image( QSize( width, height ), QImage::Format_ARGB32 );
539
image.setDotsPerMeterX( mComposition->printResolution() / 25.4 * 1000 );
540
image.setDotsPerMeterY( mComposition->printResolution() / 25.4 * 1000 );
542
QPainter imagePainter( &image );
543
QRectF sourceArea( 0, 0, mComposition->paperWidth(), mComposition->paperHeight() );
544
QRectF targetArea( 0, 0, width, height );
545
mComposition->render( &imagePainter, targetArea, sourceArea );
547
p.drawImage( targetArea, image, targetArea );
609
if ( !image.isNull() )
611
image.setDotsPerMeterX( mComposition->printResolution() / 25.4 * 1000 );
612
image.setDotsPerMeterY( mComposition->printResolution() / 25.4 * 1000 );
614
QPainter imagePainter( &image );
615
QRectF sourceArea( 0, 0, mComposition->paperWidth(), mComposition->paperHeight() );
616
QRectF targetArea( 0, 0, width, height );
617
mView->setPaintingEnabled( false );
618
mComposition->render( &imagePainter, targetArea, sourceArea );
619
mView->setPaintingEnabled( true );
620
p.drawImage( targetArea, image, targetArea );
624
QApplication::restoreOverrideCursor();
625
int answer = QMessageBox::warning( 0,
626
tr( "Image too large" ),
627
tr( "Creation of image with %1x%2 pixels failed. Retry without 'Print As Raster'?" )
628
.arg( width ).arg( height ),
629
QMessageBox::Ok | QMessageBox::Cancel,
631
if ( answer == QMessageBox::Cancel )
633
mComposition->setPlotStyle( savedPlotStyle );
637
QApplication::setOverrideCursor( Qt::BusyCursor );
638
printAsRaster = false;
642
if ( !printAsRaster )
551
#if QT_VERSION < 0x040400
552
QRectF paperRect( 0, 0, mComposition->paperWidth(), mComposition->paperHeight() );
553
QRect pageRect = printer.pageRect();
554
mComposition->render( &p, pageRect, paperRect );
556
644
//better in case of custom page size, but only possible with Qt>=4.4.0
557
645
QRectF paperRectMM = printer.pageRect( QPrinter::Millimeter );
558
646
QRectF paperRectPixel = printer.pageRect( QPrinter::DevicePixel );
648
mView->setPaintingEnabled( false );
559
649
mComposition->render( &p, paperRectPixel, paperRectMM );
650
mView->setPaintingEnabled( true );
562
653
mComposition->setPlotStyle( savedPlotStyle );
563
654
QApplication::restoreOverrideCursor();
575
666
int height = ( int )( mComposition-> printResolution() * mComposition->paperHeight() / 25.4 );
577
668
int memuse = width * height * 3 / 1000000; // pixmap + image
578
QgsDebugMsg( QString( "Image %1 x %2" ).arg( width ).arg( height ) );
669
QgsDebugMsg( QString( "Image %1x%2" ).arg( width ).arg( height ) );
579
670
QgsDebugMsg( QString( "memuse = %1" ).arg( memuse ) );
581
if ( memuse > 200 ) // cca 4500 x 4500
672
if ( memuse > 200 ) // about 4500x4500
583
674
int answer = QMessageBox::warning( 0, tr( "Big image" ),
584
tr( "To create image %1 x %2 requires circa %3 MB of memory" )
675
tr( "To create image %1x%2 requires about %3 MB of memory. Proceed?" )
585
676
.arg( width ).arg( height ).arg( memuse ),
586
QMessageBox::Ok, QMessageBox::Abort );
677
QMessageBox::Ok | QMessageBox::Cancel, QMessageBox::Ok );
589
if ( answer == QMessageBox::Abort ) return;
592
// Get file and format (stolen from qgisapp.cpp but modified significantely)
594
//create a map to hold the QImageIO names and the filter names
595
//the QImageIO name must be passed to the mapcanvas saveas image function
596
typedef QMap<QString, QString> FilterMap;
597
FilterMap myFilterMap;
599
//find out the last used filter
600
QSettings myQSettings; // where we keep last used filter in persistent state
601
QString myLastUsedFormat = myQSettings.value( "/UI/lastSaveAsImageFormat", "png" ).toString();
602
QString myLastUsedFile = myQSettings.value( "/UI/lastSaveAsImageFile", "qgis.png" ).toString();
603
QFileInfo file( myLastUsedFile );
605
// get a list of supported output image types
606
int myCounterInt = 0;
608
QString myLastUsedFilter;
609
for ( ; myCounterInt < QImageWriter::supportedImageFormats().count(); myCounterInt++ )
611
QString myFormat = QString( QImageWriter::supportedImageFormats().at( myCounterInt ) );
612
QString myFilter = tr( "%1 format (*.%2 *.%3)" )
613
.arg( myFormat ).arg( myFormat.toLower() ).arg( myFormat.toUpper() );
615
if ( myCounterInt > 0 ) myFilters += ";;";
616
myFilters += myFilter;
617
myFilterMap[myFilter] = myFormat;
618
if ( myFormat == myLastUsedFormat )
620
myLastUsedFilter = myFilter;
624
QgsDebugMsg( "Available Filters Map: " );
625
FilterMap::Iterator myIterator;
626
for ( myIterator = myFilterMap.begin(); myIterator != myFilterMap.end(); ++myIterator )
628
QgsDebugMsg( QString( "%1 : %2" ).arg( myIterator.key() ).arg( myIterator.value() ) );
632
//create a file dialog using the the filter list generated above
633
std::auto_ptr < QFileDialog > myQFileDialog(
636
tr( "Choose a file name to save the map image as" ),
642
myQFileDialog->setFileMode( QFileDialog::AnyFile );
644
// set the filter to the last one used
645
myQFileDialog->selectFilter( myLastUsedFilter );
647
// set the 'Open' button to something that makes more sense
648
myQFileDialog->setAcceptMode( QFileDialog::AcceptSave );
650
//prompt the user for a file name
651
QString myOutputFileNameQString;
653
int result = myQFileDialog->exec();
656
if ( result != QDialog::Accepted )
680
if ( answer == QMessageBox::Cancel )
684
QPair<QString, QString> fileNExt = QgisGui::getSaveAsImageName( this, tr( "Choose a file name to save the map image as" ) );
686
QgsDebugMsg( QString( "Selected filter: %1" ).arg( fileNExt.first ) );
687
QgsDebugMsg( QString( "Image type: %1" ).arg( fileNExt.second ) );
689
if ( fileNExt.first.isEmpty() )
661
myOutputFileNameQString = myQFileDialog->selectedFiles().last();
662
QgsDebugMsg( myOutputFileNameQString );
663
QString myFilterString = myQFileDialog->selectedFilter();
664
QgsDebugMsg( QString( "Selected filter: %1" ).arg( myFilterString ) );
665
QgsDebugMsg( QString( "Image type: %1" ).arg( myFilterMap[myFilterString] ) );
667
// Add the file type suffix to the fileName if required
668
if ( !myOutputFileNameQString.endsWith( myFilterMap[myFilterString] ) )
670
myOutputFileNameQString += "." + myFilterMap[myFilterString];
673
myQSettings.setValue( "/UI/lastSaveAsImageFormat", myFilterMap[myFilterString] );
674
myQSettings.setValue( "/UI/lastSaveAsImageFile", myOutputFileNameQString );
676
if ( myOutputFileNameQString == "" ) return;
678
mComposition->setPlotStyle( QgsComposition::Print );
679
mView->setScene( 0 );
681
694
QImage image( QSize( width, height ), QImage::Format_ARGB32 );
695
if ( image.isNull() )
697
QMessageBox::warning( 0,
698
tr( "Image too big" ),
699
tr( "Creation of image with %1x%2 pixels failed. Export aborted." )
700
.arg( width ).arg( height ),
705
mComposition->setPlotStyle( QgsComposition::Print );
682
706
image.setDotsPerMeterX( mComposition->printResolution() / 25.4 * 1000 );
683
707
image.setDotsPerMeterY( mComposition->printResolution() / 25.4 * 1000 );
685
709
QPainter p( &image );
686
710
QRectF sourceArea( 0, 0, mComposition->paperWidth(), mComposition->paperHeight() );
687
711
QRectF targetArea( 0, 0, width, height );
712
mView->setPaintingEnabled( false );
688
713
mComposition->render( &p, targetArea, sourceArea );
691
715
mComposition->setPlotStyle( QgsComposition::Preview );
692
image.save( myOutputFileNameQString, myFilterMap[myFilterString].toLocal8Bit().data() );
693
mView->setScene( mComposition );
716
mView->setPaintingEnabled( true );
717
image.save( fileNExt.first, fileNExt.second.toLocal8Bit().constData() );
729
QString myLastUsedFile = myQSettings.value( "/UI/lastSaveAsSvgFile", "qgis.svg" ).toString();
730
QFileInfo file( myLastUsedFile );
731
QFileDialog *myQFileDialog = new QFileDialog( this, tr( "Choose a file name to save the map as" ),
732
file.path(), tr( "SVG Format" ) + " (*.svg *SVG)" );
733
myQFileDialog->selectFile( file.fileName() );
734
myQFileDialog->setFileMode( QFileDialog::AnyFile );
735
myQFileDialog->setAcceptMode( QFileDialog::AcceptSave );
737
int result = myQFileDialog->exec();
739
if ( result != QDialog::Accepted ) return;
741
QString myOutputFileNameQString = myQFileDialog->selectedFiles().first();
742
if ( myOutputFileNameQString == "" ) return;
744
myQSettings.setValue( "/UI/lastSaveAsSvgFile", myOutputFileNameQString );
746
//mView->setScene(0);//don't redraw the scene on the display while we render
754
QString lastUsedFile = settings.value( "/UI/lastSaveAsSvgFile", "qgis.svg" ).toString();
755
QFileInfo file( lastUsedFile );
757
QString outputFileName = QFileDialog::getSaveFileName(
759
tr( "Choose a file name to save the map as" ),
761
tr( "SVG Format" ) + " (*.svg *.SVG)" );
763
if ( outputFileName.isEmpty() )
769
if ( !outputFileName.endsWith( ".svg", Qt::CaseInsensitive ) )
771
outputFileName += ".svg" ;
774
settings.setValue( "/UI/lastSaveAsSvgFile", outputFileName );
747
775
mComposition->setPlotStyle( QgsComposition::Print );
749
777
QSvgGenerator generator;
750
778
#if QT_VERSION >= 0x040500
751
779
generator.setTitle( QgsProject::instance()->title() );
753
generator.setFileName( myOutputFileNameQString );
781
generator.setFileName( outputFileName );
755
783
int width = ( int )( mComposition->paperWidth() * mComposition->printResolution() / 25.4 );
756
784
//height in pixel
757
785
int height = ( int )( mComposition->paperHeight() * mComposition->printResolution() / 25.4 );
758
786
generator.setSize( QSize( width, height ) );
787
#if QT_VERSION >= 0x040500
788
generator.setViewBox( QRect( 0, 0, width, height ) );
759
790
generator.setResolution( mComposition->printResolution() ); //because the rendering is done in mm, convert the dpi
761
792
QPainter p( &generator );
763
794
QRectF sourceArea( 0, 0, mComposition->paperWidth(), mComposition->paperHeight() );
764
795
QRectF targetArea( 0, 0, width, height );
796
mView->setPaintingEnabled( false );
765
797
mComposition->render( &p, targetArea, sourceArea );
769
799
mComposition->setPlotStyle( QgsComposition::Preview );
770
//mView->setScene(mComposition->canvas()); //now that we're done, set the view to show the scene again
800
mView->setPaintingEnabled( true );
773
803
void QgsComposer::on_mActionSelectMoveItem_triggered()
1260
1320
showItemOptions( newArrow );
1324
QDomNodeList composerTableList = composerElem.elementsByTagName( "ComposerAttributeTable" );
1325
for ( int i = 0; i < composerTableList.size(); ++i )
1327
QDomElement currentTableElem = composerTableList.at( i ).toElement();
1328
QgsComposerAttributeTable* newTable = new QgsComposerAttributeTable( mComposition );
1329
newTable->readXML( currentTableElem, doc );
1330
addComposerTable( newTable );
1331
mComposition->addItem( newTable );
1332
mComposition->update();
1333
mComposition->clearSelection();
1334
newTable->setSelected( true );
1335
showItemOptions( newTable );
1263
1338
mComposition->sortZList();
1264
1339
mView->setComposition( mComposition );
1343
//init undo/redo buttons
1344
mActionUndo->setEnabled( false );
1345
mActionRedo->setEnabled( false );
1346
if ( mComposition->undoStack() )
1348
mUndoView->setStack( mComposition->undoStack() );
1349
connect( mComposition->undoStack(), SIGNAL( canUndoChanged( bool ) ), mActionUndo, SLOT( setEnabled( bool ) ) );
1350
connect( mComposition->undoStack(), SIGNAL( canRedoChanged( bool ) ), mActionRedo, SLOT( setEnabled( bool ) ) );
1266
1356
setSelectionTool();