|
19 | 19 | #include "qgslayoutitemregistry.h"
|
20 | 20 | #include "qgssettings.h"
|
21 | 21 | #include "qgisapp.h"
|
| 22 | +#include "qgsfileutils.h" |
22 | 23 | #include "qgslogger.h"
|
23 | 24 | #include "qgslayout.h"
|
24 | 25 | #include "qgslayoutappmenuprovider.h"
|
|
53 | 54 | #include "qgsbusyindicatordialog.h"
|
54 | 55 | #include "qgslayoutundostack.h"
|
55 | 56 | #include "qgslayoutpagecollection.h"
|
| 57 | +#include "ui_qgssvgexportoptions.h" |
56 | 58 | #include <QShortcut>
|
57 | 59 | #include <QComboBox>
|
58 | 60 | #include <QLineEdit>
|
@@ -182,6 +184,7 @@ QgsLayoutDesignerDialog::QgsLayoutDesignerDialog( QWidget *parent, Qt::WindowFla
|
182 | 184 |
|
183 | 185 | connect( mActionExportAsImage, &QAction::triggered, this, &QgsLayoutDesignerDialog::exportToRaster );
|
184 | 186 | connect( mActionExportAsPDF, &QAction::triggered, this, &QgsLayoutDesignerDialog::exportToPdf );
|
| 187 | + connect( mActionExportAsSVG, &QAction::triggered, this, &QgsLayoutDesignerDialog::exportToSvg ); |
185 | 188 |
|
186 | 189 | connect( mActionShowGrid, &QAction::triggered, this, &QgsLayoutDesignerDialog::showGrid );
|
187 | 190 | connect( mActionSnapGrid, &QAction::triggered, this, &QgsLayoutDesignerDialog::snapToGrid );
|
@@ -1474,7 +1477,7 @@ void QgsLayoutDesignerDialog::exportToRaster()
|
1474 | 1477 | QgsAtlasComposition *atlasMap = &mComposition->atlasComposition();
|
1475 | 1478 | #endif
|
1476 | 1479 |
|
1477 |
| - QString outputFileName; |
| 1480 | + QString outputFileName = QgsFileUtils::stringToSafeFilename( mLayout->name() ); |
1478 | 1481 | #if 0 //TODO
|
1479 | 1482 | if ( atlasMap->enabled() && mComposition->atlasMode() == QgsComposition::PreviewAtlas )
|
1480 | 1483 | {
|
@@ -1539,6 +1542,8 @@ void QgsLayoutDesignerDialog::exportToRaster()
|
1539 | 1542 | break;
|
1540 | 1543 |
|
1541 | 1544 | case QgsLayoutExporter::PrintError:
|
| 1545 | + case QgsLayoutExporter::SvgLayerError: |
| 1546 | + // no meaning for raster exports, will not be encountered |
1542 | 1547 | break;
|
1543 | 1548 |
|
1544 | 1549 | case QgsLayoutExporter::FileError:
|
@@ -1594,7 +1599,7 @@ void QgsLayoutDesignerDialog::exportToPdf()
|
1594 | 1599 | else
|
1595 | 1600 | {
|
1596 | 1601 | #endif
|
1597 |
| - outputFileName = file.path(); |
| 1602 | + outputFileName = file.path() + '/' + QgsFileUtils::stringToSafeFilename( mLayout->name() ) + QStringLiteral( ".pdf" ); |
1598 | 1603 | #if 0 //TODO
|
1599 | 1604 | }
|
1600 | 1605 | #endif
|
@@ -1665,12 +1670,170 @@ void QgsLayoutDesignerDialog::exportToPdf()
|
1665 | 1670 | "Please try a lower resolution or a smaller paper size." ),
|
1666 | 1671 | QMessageBox::Ok, QMessageBox::Ok );
|
1667 | 1672 | break;
|
| 1673 | + |
| 1674 | + case QgsLayoutExporter::SvgLayerError: |
| 1675 | + // no meaning for PDF exports, will not be encountered |
| 1676 | + break; |
1668 | 1677 | }
|
1669 | 1678 |
|
1670 | 1679 | mView->setPaintingEnabled( true );
|
1671 | 1680 | QApplication::restoreOverrideCursor();
|
1672 | 1681 | }
|
1673 | 1682 |
|
| 1683 | +void QgsLayoutDesignerDialog::exportToSvg() |
| 1684 | +{ |
| 1685 | + if ( containsWmsLayers() ) |
| 1686 | + { |
| 1687 | + showWmsPrintingWarning(); |
| 1688 | + } |
| 1689 | + |
| 1690 | + showSvgExportWarning(); |
| 1691 | + |
| 1692 | + QgsSettings settings; |
| 1693 | + QString lastUsedFile = settings.value( QStringLiteral( "UI/lastSaveAsSvgFile" ), QStringLiteral( "qgis.svg" ) ).toString(); |
| 1694 | + QFileInfo file( lastUsedFile ); |
| 1695 | + QString outputFileName = QgsFileUtils::stringToSafeFilename( mLayout->name() ); |
| 1696 | + |
| 1697 | +#if 0// TODO |
| 1698 | + if ( hasAnAtlas && !atlasOnASingleFile && |
| 1699 | + ( mode == QgsComposer::Atlas || mComposition->atlasMode() == QgsComposition::PreviewAtlas ) ) |
| 1700 | + { |
| 1701 | + outputFileName = QDir( file.path() ).filePath( atlasMap->currentFilename() ) + ".pdf"; |
| 1702 | + } |
| 1703 | + else |
| 1704 | + { |
| 1705 | +#endif |
| 1706 | + outputFileName = file.path() + '/' + QgsFileUtils::stringToSafeFilename( mLayout->name() ) + QStringLiteral( ".svg" ); |
| 1707 | +#if 0 //TODO |
| 1708 | + } |
| 1709 | +#endif |
| 1710 | + |
| 1711 | +#ifdef Q_OS_MAC |
| 1712 | + QgisApp::instance()->activateWindow(); |
| 1713 | + this->raise(); |
| 1714 | +#endif |
| 1715 | + outputFileName = QFileDialog::getSaveFileName( |
| 1716 | + this, |
| 1717 | + tr( "Export to SVG" ), |
| 1718 | + outputFileName, |
| 1719 | + tr( "SVG Format" ) + " (*.svg *.SVG)" ); |
| 1720 | + this->activateWindow(); |
| 1721 | + if ( outputFileName.isEmpty() ) |
| 1722 | + { |
| 1723 | + return; |
| 1724 | + } |
| 1725 | + |
| 1726 | + if ( !outputFileName.endsWith( QLatin1String( ".svg" ), Qt::CaseInsensitive ) ) |
| 1727 | + { |
| 1728 | + outputFileName += QLatin1String( ".svg" ); |
| 1729 | + } |
| 1730 | + |
| 1731 | + settings.setValue( QStringLiteral( "UI/lastSaveAsSvgFile" ), outputFileName ); |
| 1732 | + |
| 1733 | + bool groupLayers = false; |
| 1734 | + bool prevSettingLabelsAsOutlines = mLayout->project()->readBoolEntry( QStringLiteral( "PAL" ), QStringLiteral( "/DrawOutlineLabels" ), true ); |
| 1735 | + bool clipToContent = false; |
| 1736 | + double marginTop = 0.0; |
| 1737 | + double marginRight = 0.0; |
| 1738 | + double marginBottom = 0.0; |
| 1739 | + double marginLeft = 0.0; |
| 1740 | + bool previousForceVector = mLayout->customProperty( QStringLiteral( "forceVector" ), false ).toBool(); |
| 1741 | + |
| 1742 | + // open options dialog |
| 1743 | + QDialog dialog; |
| 1744 | + Ui::QgsSvgExportOptionsDialog options; |
| 1745 | + options.setupUi( &dialog ); |
| 1746 | + options.chkTextAsOutline->setChecked( prevSettingLabelsAsOutlines ); |
| 1747 | + options.chkMapLayersAsGroup->setChecked( mLayout->customProperty( QStringLiteral( "svgGroupLayers" ), false ).toBool() ); |
| 1748 | + options.mClipToContentGroupBox->setChecked( mLayout->customProperty( QStringLiteral( "svgCropToContents" ), false ).toBool() ); |
| 1749 | + options.mForceVectorCheckBox->setChecked( previousForceVector ); |
| 1750 | + options.mTopMarginSpinBox->setValue( mLayout->customProperty( QStringLiteral( "svgCropMarginTop" ), 0 ).toInt() ); |
| 1751 | + options.mRightMarginSpinBox->setValue( mLayout->customProperty( QStringLiteral( "svgCropMarginRight" ), 0 ).toInt() ); |
| 1752 | + options.mBottomMarginSpinBox->setValue( mLayout->customProperty( QStringLiteral( "svgCropMarginBottom" ), 0 ).toInt() ); |
| 1753 | + options.mLeftMarginSpinBox->setValue( mLayout->customProperty( QStringLiteral( "svgCropMarginLeft" ), 0 ).toInt() ); |
| 1754 | + |
| 1755 | + if ( dialog.exec() != QDialog::Accepted ) |
| 1756 | + return; |
| 1757 | + |
| 1758 | + groupLayers = options.chkMapLayersAsGroup->isChecked(); |
| 1759 | + clipToContent = options.mClipToContentGroupBox->isChecked(); |
| 1760 | + marginTop = options.mTopMarginSpinBox->value(); |
| 1761 | + marginRight = options.mRightMarginSpinBox->value(); |
| 1762 | + marginBottom = options.mBottomMarginSpinBox->value(); |
| 1763 | + marginLeft = options.mLeftMarginSpinBox->value(); |
| 1764 | + |
| 1765 | + //save dialog settings |
| 1766 | + mLayout->setCustomProperty( QStringLiteral( "svgGroupLayers" ), groupLayers ); |
| 1767 | + mLayout->setCustomProperty( QStringLiteral( "svgCropToContents" ), clipToContent ); |
| 1768 | + mLayout->setCustomProperty( QStringLiteral( "svgCropMarginTop" ), marginTop ); |
| 1769 | + mLayout->setCustomProperty( QStringLiteral( "svgCropMarginRight" ), marginRight ); |
| 1770 | + mLayout->setCustomProperty( QStringLiteral( "svgCropMarginBottom" ), marginBottom ); |
| 1771 | + mLayout->setCustomProperty( QStringLiteral( "svgCropMarginLeft" ), marginLeft ); |
| 1772 | + |
| 1773 | + //temporarily override label draw outlines setting |
| 1774 | + mLayout->project()->writeEntry( QStringLiteral( "PAL" ), QStringLiteral( "/DrawOutlineLabels" ), options.chkTextAsOutline->isChecked() ); |
| 1775 | + |
| 1776 | + mView->setPaintingEnabled( false ); |
| 1777 | + QApplication::setOverrideCursor( Qt::BusyCursor ); |
| 1778 | + |
| 1779 | + QgsLayoutExporter::SvgExportSettings svgSettings; |
| 1780 | + svgSettings.forceVectorOutput = mLayout->customProperty( QStringLiteral( "forceVector" ), false ).toBool(); |
| 1781 | + svgSettings.cropToContents = clipToContent; |
| 1782 | + svgSettings.cropMargins = QgsMargins( marginLeft, marginTop, marginRight, marginBottom ); |
| 1783 | + svgSettings.forceVectorOutput = options.mForceVectorCheckBox->isChecked(); |
| 1784 | + svgSettings.exportAsLayers = groupLayers; |
| 1785 | + |
| 1786 | + // force a refresh, to e.g. update data defined properties, tables, etc |
| 1787 | + mLayout->refresh(); |
| 1788 | + |
| 1789 | + QFileInfo fi( outputFileName ); |
| 1790 | + QgsLayoutExporter exporter( mLayout ); |
| 1791 | + switch ( exporter.exportToSvg( outputFileName, svgSettings ) ) |
| 1792 | + { |
| 1793 | + case QgsLayoutExporter::Success: |
| 1794 | + { |
| 1795 | + mMessageBar->pushMessage( tr( "Export layout" ), |
| 1796 | + tr( "Successfully exported layout to <a href=\"%1\">%2</a>" ).arg( QUrl::fromLocalFile( fi.path() ).toString(), outputFileName ), |
| 1797 | + QgsMessageBar::INFO, 0 ); |
| 1798 | + break; |
| 1799 | + } |
| 1800 | + |
| 1801 | + case QgsLayoutExporter::FileError: |
| 1802 | + QMessageBox::warning( this, tr( "Export to SVG" ), |
| 1803 | + tr( "Cannot write to %1.\n\nThis file may be open in another application." ).arg( outputFileName ), |
| 1804 | + QMessageBox::Ok, |
| 1805 | + QMessageBox::Ok ); |
| 1806 | + break; |
| 1807 | + |
| 1808 | + case QgsLayoutExporter::SvgLayerError: |
| 1809 | + QMessageBox::warning( this, tr( "Export to SVG" ), |
| 1810 | + tr( "Cannot create layered SVG file %1." ).arg( outputFileName ), |
| 1811 | + QMessageBox::Ok, |
| 1812 | + QMessageBox::Ok ); |
| 1813 | + break; |
| 1814 | + |
| 1815 | + case QgsLayoutExporter::PrintError: |
| 1816 | + QMessageBox::warning( this, tr( "Export to SVG" ), |
| 1817 | + tr( "Could not create print device." ), |
| 1818 | + QMessageBox::Ok, |
| 1819 | + QMessageBox::Ok ); |
| 1820 | + break; |
| 1821 | + |
| 1822 | + |
| 1823 | + case QgsLayoutExporter::MemoryError: |
| 1824 | + QMessageBox::warning( this, tr( "Memory Allocation Error" ), |
| 1825 | + tr( "Exporting the SVG " |
| 1826 | + "resulted in a memory overflow.\n\n" |
| 1827 | + "Please try a lower resolution or a smaller paper size." ), |
| 1828 | + QMessageBox::Ok, QMessageBox::Ok ); |
| 1829 | + break; |
| 1830 | + } |
| 1831 | + |
| 1832 | + mView->setPaintingEnabled( true ); |
| 1833 | + mLayout->project()->writeEntry( QStringLiteral( "PAL" ), QStringLiteral( "/DrawOutlineLabels" ), prevSettingLabelsAsOutlines ); |
| 1834 | + QApplication::restoreOverrideCursor(); |
| 1835 | +} |
| 1836 | + |
1674 | 1837 | void QgsLayoutDesignerDialog::paste()
|
1675 | 1838 | {
|
1676 | 1839 | QPointF pt = mView->mapFromGlobal( QCursor::pos() );
|
@@ -1816,6 +1979,34 @@ void QgsLayoutDesignerDialog::showWmsPrintingWarning()
|
1816 | 1979 | }
|
1817 | 1980 | }
|
1818 | 1981 |
|
| 1982 | +void QgsLayoutDesignerDialog::showSvgExportWarning() |
| 1983 | +{ |
| 1984 | + QgsSettings settings; |
| 1985 | + |
| 1986 | + bool displaySVGWarning = settings.value( QStringLiteral( "/UI/displaySVGWarning" ), true ).toBool(); |
| 1987 | + |
| 1988 | + if ( displaySVGWarning ) |
| 1989 | + { |
| 1990 | + QgsMessageViewer m( this ); |
| 1991 | + m.setWindowTitle( tr( "Export as SVG" ) ); |
| 1992 | + m.setCheckBoxText( tr( "Don't show this message again" ) ); |
| 1993 | + m.setCheckBoxState( Qt::Unchecked ); |
| 1994 | + m.setCheckBoxVisible( true ); |
| 1995 | + m.setCheckBoxQgsSettingsLabel( QStringLiteral( "/UI/displaySVGWarning" ) ); |
| 1996 | + m.setMessageAsHtml( tr( "<p>The SVG export function in QGIS has several " |
| 1997 | + "problems due to bugs and deficiencies in the " ) |
| 1998 | + + tr( "underlying Qt SVG library. In particular, there are problems " |
| 1999 | + "with layers not being clipped to the map " |
| 2000 | + "bounding box.</p>" ) |
| 2001 | + + tr( "If you require a vector-based output file from " |
| 2002 | + "QGIS it is suggested that you try exporting " |
| 2003 | + "to PDF if the SVG output is not " |
| 2004 | + "satisfactory." |
| 2005 | + "</p>" ) ); |
| 2006 | + m.exec(); |
| 2007 | + } |
| 2008 | +} |
| 2009 | + |
1819 | 2010 | bool QgsLayoutDesignerDialog::requiresRasterization() const
|
1820 | 2011 | {
|
1821 | 2012 | QList< QgsLayoutItem *> items;
|
|
0 commit comments