|
33 | 33 | #include "qgslayoutviewtoolselect.h" |
34 | 34 | #include "qgslayoutviewtooleditnodes.h" |
35 | 35 | #include "qgslayoutitemwidget.h" |
| 36 | +#include "qgslayoutimageexportoptionsdialog.h" |
| 37 | +#include "qgslayoutitemmap.h" |
| 38 | +#include "qgsmessageviewer.h" |
36 | 39 | #include "qgsgui.h" |
37 | 40 | #include "qgslayoutitemguiregistry.h" |
38 | 41 | #include "qgslayoutpropertieswidget.h" |
@@ -168,6 +171,8 @@ QgsLayoutDesignerDialog::QgsLayoutDesignerDialog( QWidget *parent, Qt::WindowFla |
168 | 171 | connect( mActionLayoutManager, &QAction::triggered, this, &QgsLayoutDesignerDialog::showManager ); |
169 | 172 | connect( mActionRemoveLayout, &QAction::triggered, this, &QgsLayoutDesignerDialog::deleteLayout ); |
170 | 173 |
|
| 174 | + connect( mActionExportAsImage, &QAction::triggered, this, &QgsLayoutDesignerDialog::exportToRaster ); |
| 175 | + |
171 | 176 | connect( mActionShowGrid, &QAction::triggered, this, &QgsLayoutDesignerDialog::showGrid ); |
172 | 177 | connect( mActionSnapGrid, &QAction::triggered, this, &QgsLayoutDesignerDialog::snapToGrid ); |
173 | 178 |
|
@@ -1410,6 +1415,123 @@ void QgsLayoutDesignerDialog::deleteLayout() |
1410 | 1415 | close(); |
1411 | 1416 | } |
1412 | 1417 |
|
| 1418 | +void QgsLayoutDesignerDialog::exportToRaster() |
| 1419 | +{ |
| 1420 | + if ( containsWmsLayers() ) |
| 1421 | + showWmsPrintingWarning(); |
| 1422 | + |
| 1423 | + // Image size |
| 1424 | + double oneInchInLayoutUnits = mLayout->convertToLayoutUnits( QgsLayoutMeasurement( 1, QgsUnitTypes::LayoutInches ) ); |
| 1425 | + QSizeF maxPageSize = mLayout->pageCollection()->maximumPageSize(); |
| 1426 | + bool hasUniformPageSizes = mLayout->pageCollection()->hasUniformPageSizes(); |
| 1427 | + int width = ( int )( mLayout->context().dpi() * maxPageSize.width() / oneInchInLayoutUnits ); |
| 1428 | + int height = ( int )( mLayout->context().dpi() * maxPageSize.height() / oneInchInLayoutUnits ); |
| 1429 | + double dpi = mLayout->context().dpi(); |
| 1430 | + |
| 1431 | + int memuse = width * height * 3 / 1000000; // pixmap + image |
| 1432 | + QgsDebugMsg( QString( "Image %1x%2" ).arg( width ).arg( height ) ); |
| 1433 | + QgsDebugMsg( QString( "memuse = %1" ).arg( memuse ) ); |
| 1434 | + |
| 1435 | + if ( memuse > 400 ) // about 4500x4500 |
| 1436 | + { |
| 1437 | + int answer = QMessageBox::warning( nullptr, tr( "Export layout" ), |
| 1438 | + tr( "To create an image of %1x%2 requires about %3 MB of memory. Proceed?" ) |
| 1439 | + .arg( width ).arg( height ).arg( memuse ), |
| 1440 | + QMessageBox::Ok | QMessageBox::Cancel, QMessageBox::Ok ); |
| 1441 | + |
| 1442 | + raise(); |
| 1443 | + if ( answer == QMessageBox::Cancel ) |
| 1444 | + return; |
| 1445 | + } |
| 1446 | + |
| 1447 | + //get some defaults from the composition |
| 1448 | + bool cropToContents = mLayout->customProperty( QStringLiteral( "imageCropToContents" ), false ).toBool(); |
| 1449 | + int marginTop = mLayout->customProperty( QStringLiteral( "imageCropMarginTop" ), 0 ).toInt(); |
| 1450 | + int marginRight = mLayout->customProperty( QStringLiteral( "imageCropMarginRight" ), 0 ).toInt(); |
| 1451 | + int marginBottom = mLayout->customProperty( QStringLiteral( "imageCropMarginBottom" ), 0 ).toInt(); |
| 1452 | + int marginLeft = mLayout->customProperty( QStringLiteral( "imageCropMarginLeft" ), 0 ).toInt(); |
| 1453 | + |
| 1454 | + QgsLayoutImageExportOptionsDialog imageDlg( this ); |
| 1455 | + imageDlg.setImageSize( maxPageSize ); |
| 1456 | + imageDlg.setResolution( dpi ); |
| 1457 | + imageDlg.setCropToContents( cropToContents ); |
| 1458 | + imageDlg.setCropMargins( marginTop, marginRight, marginBottom, marginLeft ); |
| 1459 | + |
| 1460 | +#if 0 //TODO |
| 1461 | + QgsAtlasComposition *atlasMap = &mComposition->atlasComposition(); |
| 1462 | +#endif |
| 1463 | + |
| 1464 | + QString outputFileName; |
| 1465 | +#if 0 //TODO |
| 1466 | + if ( atlasMap->enabled() && mComposition->atlasMode() == QgsComposition::PreviewAtlas ) |
| 1467 | + { |
| 1468 | + QString lastUsedDir = settings.value( QStringLiteral( "UI/lastSaveAsImageDir" ), QDir::homePath() ).toString(); |
| 1469 | + outputFileName = QDir( lastUsedDir ).filePath( atlasMap->currentFilename() ); |
| 1470 | + } |
| 1471 | +#endif |
| 1472 | + |
| 1473 | +#ifdef Q_OS_MAC |
| 1474 | + mQgis->activateWindow(); |
| 1475 | + this->raise(); |
| 1476 | +#endif |
| 1477 | + QPair<QString, QString> fileNExt = QgsGuiUtils::getSaveAsImageName( this, tr( "Save layout as" ), outputFileName ); |
| 1478 | + this->activateWindow(); |
| 1479 | + |
| 1480 | + if ( fileNExt.first.isEmpty() ) |
| 1481 | + { |
| 1482 | + return; |
| 1483 | + } |
| 1484 | + |
| 1485 | + if ( !imageDlg.exec() ) |
| 1486 | + return; |
| 1487 | + |
| 1488 | + cropToContents = imageDlg.cropToContents(); |
| 1489 | + imageDlg.getCropMargins( marginTop, marginRight, marginBottom, marginLeft ); |
| 1490 | + mLayout->setCustomProperty( QStringLiteral( "imageCropToContents" ), cropToContents ); |
| 1491 | + mLayout->setCustomProperty( QStringLiteral( "imageCropMarginTop" ), marginTop ); |
| 1492 | + mLayout->setCustomProperty( QStringLiteral( "imageCropMarginRight" ), marginRight ); |
| 1493 | + mLayout->setCustomProperty( QStringLiteral( "imageCropMarginBottom" ), marginBottom ); |
| 1494 | + mLayout->setCustomProperty( QStringLiteral( "imageCropMarginLeft" ), marginLeft ); |
| 1495 | + |
| 1496 | + mView->setPaintingEnabled( false ); |
| 1497 | + |
| 1498 | + QgsLayoutExporter exporter( mLayout ); |
| 1499 | + |
| 1500 | + QgsLayoutExporter::ImageExportSettings settings; |
| 1501 | + settings.cropToContents = cropToContents; |
| 1502 | + settings.cropMargins = QgsMargins( marginLeft, marginTop, marginRight, marginBottom ); |
| 1503 | + settings.dpi = imageDlg.resolution(); |
| 1504 | + if ( hasUniformPageSizes ) |
| 1505 | + { |
| 1506 | + settings.imageSize = QSize( imageDlg.imageWidth(), imageDlg.imageHeight() ); |
| 1507 | + } |
| 1508 | + settings.generateWorldFile = mLayout->customProperty( QStringLiteral( "exportWorldFile" ), false ).toBool(); |
| 1509 | + |
| 1510 | + switch ( exporter.exportToImage( fileNExt.first, settings ) ) |
| 1511 | + { |
| 1512 | + case QgsLayoutExporter::Success: |
| 1513 | + break; |
| 1514 | + |
| 1515 | + case QgsLayoutExporter::FileError: |
| 1516 | + QMessageBox::warning( this, tr( "Image Export Error" ), |
| 1517 | + QString( tr( "Cannot write to %1.\n\nThis file may be open in another application." ) ).arg( exporter.errorFile() ), |
| 1518 | + QMessageBox::Ok, |
| 1519 | + QMessageBox::Ok ); |
| 1520 | + break; |
| 1521 | + |
| 1522 | + case QgsLayoutExporter::MemoryError: |
| 1523 | + QMessageBox::warning( nullptr, tr( "Memory Allocation Error" ), |
| 1524 | + tr( "Trying to create image %1 (%2×%3 @ %4dpi ) " |
| 1525 | + "resulted in a memory overflow.\n\n" |
| 1526 | + "Please try a lower resolution or a smaller paper size." ) |
| 1527 | + .arg( exporter.errorFile() ).arg( imageDlg.imageWidth() ).arg( imageDlg.imageHeight() ).arg( settings.dpi ), |
| 1528 | + QMessageBox::Ok, QMessageBox::Ok ); |
| 1529 | + break; |
| 1530 | + |
| 1531 | + } |
| 1532 | + mView->setPaintingEnabled( true ); |
| 1533 | +} |
| 1534 | + |
1413 | 1535 | void QgsLayoutDesignerDialog::paste() |
1414 | 1536 | { |
1415 | 1537 | QPointF pt = mView->mapFromGlobal( QCursor::pos() ); |
@@ -1525,6 +1647,36 @@ void QgsLayoutDesignerDialog::initializeRegistry() |
1525 | 1647 |
|
1526 | 1648 | } |
1527 | 1649 |
|
| 1650 | +bool QgsLayoutDesignerDialog::containsWmsLayers() const |
| 1651 | +{ |
| 1652 | + QList< QgsLayoutItemMap *> maps; |
| 1653 | + mLayout->layoutItems( maps ); |
| 1654 | + |
| 1655 | + for ( QgsLayoutItemMap *map : qgis::as_const( maps ) ) |
| 1656 | + { |
| 1657 | + if ( map->containsWmsLayer() ) |
| 1658 | + return true; |
| 1659 | + } |
| 1660 | + return false; |
| 1661 | +} |
| 1662 | + |
| 1663 | +void QgsLayoutDesignerDialog::showWmsPrintingWarning() |
| 1664 | +{ |
| 1665 | + QgsSettings settings; |
| 1666 | + bool displayWMSWarning = settings.value( QStringLiteral( "/UI/displayComposerWMSWarning" ), true ).toBool(); |
| 1667 | + if ( displayWMSWarning ) |
| 1668 | + { |
| 1669 | + QgsMessageViewer *m = new QgsMessageViewer( this ); |
| 1670 | + m->setWindowTitle( tr( "Project Contains WMS Layers" ) ); |
| 1671 | + m->setMessage( tr( "Some WMS servers (e.g. UMN mapserver) have a limit for the WIDTH and HEIGHT parameter. Printing layers from such servers may exceed this limit. If this is the case, the WMS layer will not be printed" ), QgsMessageOutput::MessageText ); |
| 1672 | + m->setCheckBoxText( tr( "Don't show this message again" ) ); |
| 1673 | + m->setCheckBoxState( Qt::Unchecked ); |
| 1674 | + m->setCheckBoxVisible( true ); |
| 1675 | + m->setCheckBoxQgsSettingsLabel( QStringLiteral( "/UI/displayComposerWMSWarning" ) ); |
| 1676 | + m->exec(); //deleted on close |
| 1677 | + } |
| 1678 | +} |
| 1679 | + |
1528 | 1680 | void QgsLayoutDesignerDialog::selectItems( const QList<QgsLayoutItem *> items ) |
1529 | 1681 | { |
1530 | 1682 | for ( QGraphicsItem *item : items ) |
|
0 commit comments