mirror of
https://github.com/qgis/QGIS.git
synced 2025-04-17 00:04:02 -04:00
Merge pull request #7298 from nyalldawson/layout
[layouts] Save last used export folder in project
This commit is contained in:
commit
2718317e85
@ -75,6 +75,14 @@ for filenames with an '_' character.
|
||||
.. warning::
|
||||
|
||||
This method strips slashes from the filename, so it is safe to call with file names only, not complete paths.
|
||||
%End
|
||||
|
||||
static QString findClosestExistingPath( const QString &path );
|
||||
%Docstring
|
||||
Returns the top-most existing folder from ``path``. E.g. if ``path`` is "/home/user/projects/2018/P4343"
|
||||
and "/home/user/projects" exists but no "2018" subfolder exists, then the function will return "/home/user/projects".
|
||||
|
||||
.. versionadded:: 3.2
|
||||
%End
|
||||
};
|
||||
|
||||
|
@ -57,7 +57,7 @@ Returns the layout view utilized by the designer.
|
||||
Returns the designer's message bar.
|
||||
%End
|
||||
|
||||
virtual void selectItems( QList< QgsLayoutItem * > items ) = 0;
|
||||
virtual void selectItems( const QList< QgsLayoutItem * > &items ) = 0;
|
||||
%Docstring
|
||||
Selects the specified ``items``.
|
||||
%End
|
||||
|
@ -120,7 +120,7 @@ QgsMessageBar *QgsAppLayoutDesignerInterface::messageBar()
|
||||
return mDesigner->messageBar();
|
||||
}
|
||||
|
||||
void QgsAppLayoutDesignerInterface::selectItems( const QList<QgsLayoutItem *> items )
|
||||
void QgsAppLayoutDesignerInterface::selectItems( const QList<QgsLayoutItem *> &items )
|
||||
{
|
||||
mDesigner->selectItems( items );
|
||||
}
|
||||
@ -246,7 +246,7 @@ QgsLayoutDesignerDialog::QgsLayoutDesignerDialog( QWidget *parent, Qt::WindowFla
|
||||
|
||||
connect( mActionOptions, &QAction::triggered, this, [ = ]
|
||||
{
|
||||
QgisApp::instance()->showOptionsDialog( this, QString( "mOptionsPageComposer" ) );
|
||||
QgisApp::instance()->showOptionsDialog( this, QStringLiteral( "mOptionsPageComposer" ) );
|
||||
} );
|
||||
|
||||
mView = new QgsLayoutView();
|
||||
@ -322,7 +322,7 @@ QgsLayoutDesignerDialog::QgsLayoutDesignerDialog( QWidget *parent, Qt::WindowFla
|
||||
mActionsToolbar->addWidget( resizeToolButton );
|
||||
|
||||
QToolButton *atlasExportToolButton = new QToolButton( mAtlasToolbar );
|
||||
atlasExportToolButton->setIcon( QgsApplication::getThemeIcon( "mActionExport.svg" ) );
|
||||
atlasExportToolButton->setIcon( QgsApplication::getThemeIcon( QStringLiteral( "mActionExport.svg" ) ) );
|
||||
atlasExportToolButton->setPopupMode( QToolButton::InstantPopup );
|
||||
atlasExportToolButton->setAutoRaise( true );
|
||||
atlasExportToolButton->setToolButtonStyle( Qt::ToolButtonIconOnly );
|
||||
@ -1462,7 +1462,7 @@ void QgsLayoutDesignerDialog::updateStatusZoom()
|
||||
zoomLevel = mView->transform().m11() * 100 / scale100;
|
||||
}
|
||||
whileBlocking( mStatusZoomCombo )->lineEdit()->setText( tr( "%1%" ).arg( zoomLevel, 0, 'f', 1 ) );
|
||||
whileBlocking( mStatusZoomSlider )->setValue( zoomLevel );
|
||||
whileBlocking( mStatusZoomSlider )->setValue( static_cast< int >( zoomLevel ) );
|
||||
}
|
||||
|
||||
void QgsLayoutDesignerDialog::updateStatusCursorPos( QPointF position )
|
||||
@ -1544,7 +1544,7 @@ void QgsLayoutDesignerDialog::dockVisibilityChanged( bool visible )
|
||||
}
|
||||
}
|
||||
|
||||
void QgsLayoutDesignerDialog::undoRedoOccurredForItems( const QSet<QString> itemUuids )
|
||||
void QgsLayoutDesignerDialog::undoRedoOccurredForItems( const QSet<QString> &itemUuids )
|
||||
{
|
||||
mBlockItemOptions = true;
|
||||
|
||||
@ -1831,14 +1831,17 @@ void QgsLayoutDesignerDialog::exportToRaster()
|
||||
if ( !showFileSizeWarning() )
|
||||
return;
|
||||
|
||||
QgsSettings s;
|
||||
QString outputFileName = QgsFileUtils::stringToSafeFilename( mMasterLayout->name() );
|
||||
QString outputFileName;
|
||||
QgsLayoutAtlas *printAtlas = atlas();
|
||||
QString lastUsedDir = defaultExportPath();
|
||||
if ( printAtlas && printAtlas->enabled() && mActionAtlasPreview->isChecked() )
|
||||
{
|
||||
QString lastUsedDir = s.value( QStringLiteral( "lastSaveAsImageDir" ), QDir::homePath(), QgsSettings::App ).toString();
|
||||
outputFileName = QDir( lastUsedDir ).filePath( QgsFileUtils::stringToSafeFilename( printAtlas->currentFilename() ) );
|
||||
}
|
||||
else
|
||||
{
|
||||
outputFileName = QDir( lastUsedDir ).filePath( QgsFileUtils::stringToSafeFilename( mMasterLayout->name() ) );
|
||||
}
|
||||
|
||||
#ifdef Q_OS_MAC
|
||||
QgisApp::instance()->activateWindow();
|
||||
@ -1852,6 +1855,8 @@ void QgsLayoutDesignerDialog::exportToRaster()
|
||||
return;
|
||||
}
|
||||
|
||||
setLastExportPath( fileNExt.first );
|
||||
|
||||
QgsLayoutExporter::ImageExportSettings settings;
|
||||
QSize imageSize;
|
||||
if ( !getRasterExportSettings( settings, imageSize ) )
|
||||
@ -1921,19 +1926,17 @@ void QgsLayoutDesignerDialog::exportToPdf()
|
||||
showForceVectorWarning();
|
||||
}
|
||||
|
||||
QgsSettings settings;
|
||||
QString lastUsedFile = settings.value( QStringLiteral( "lastSaveAsPdfFile" ), QStringLiteral( "qgis.pdf" ), QgsSettings::App ).toString();
|
||||
QFileInfo file( lastUsedFile );
|
||||
const QString exportPath = defaultExportPath();
|
||||
QString outputFileName;
|
||||
|
||||
QgsLayoutAtlas *printAtlas = atlas();
|
||||
if ( printAtlas && printAtlas->enabled() && mActionAtlasPreview->isChecked() )
|
||||
{
|
||||
outputFileName = QDir( file.path() ).filePath( QgsFileUtils::stringToSafeFilename( printAtlas->currentFilename() ) + QStringLiteral( ".pdf" ) );
|
||||
outputFileName = QDir( exportPath ).filePath( QgsFileUtils::stringToSafeFilename( printAtlas->currentFilename() ) + QStringLiteral( ".pdf" ) );
|
||||
}
|
||||
else
|
||||
{
|
||||
outputFileName = file.path() + '/' + QgsFileUtils::stringToSafeFilename( mMasterLayout->name() ) + QStringLiteral( ".pdf" );
|
||||
outputFileName = exportPath + '/' + QgsFileUtils::stringToSafeFilename( mMasterLayout->name() ) + QStringLiteral( ".pdf" );
|
||||
}
|
||||
|
||||
#ifdef Q_OS_MAC
|
||||
@ -1956,7 +1959,7 @@ void QgsLayoutDesignerDialog::exportToPdf()
|
||||
outputFileName += QLatin1String( ".pdf" );
|
||||
}
|
||||
|
||||
settings.setValue( QStringLiteral( "lastSaveAsPdfFile" ), outputFileName, QgsSettings::App );
|
||||
setLastExportPath( outputFileName );
|
||||
|
||||
mView->setPaintingEnabled( false );
|
||||
QgsTemporaryCursorOverride cursorOverride( Qt::BusyCursor );
|
||||
@ -2025,19 +2028,17 @@ void QgsLayoutDesignerDialog::exportToSvg()
|
||||
|
||||
showSvgExportWarning();
|
||||
|
||||
QgsSettings settings;
|
||||
QString lastUsedFile = settings.value( QStringLiteral( "lastSaveAsSvgFile" ), QStringLiteral( "qgis.svg" ), QgsSettings::App ).toString();
|
||||
QFileInfo file( lastUsedFile );
|
||||
const QString defaultPath = defaultExportPath();
|
||||
QString outputFileName = QgsFileUtils::stringToSafeFilename( mMasterLayout->name() );
|
||||
|
||||
QgsLayoutAtlas *printAtlas = atlas();
|
||||
if ( printAtlas && printAtlas->enabled() && mActionAtlasPreview->isChecked() )
|
||||
{
|
||||
outputFileName = QDir( file.path() ).filePath( QgsFileUtils::stringToSafeFilename( printAtlas->currentFilename() + QStringLiteral( ".svg" ) ) );
|
||||
outputFileName = QDir( defaultPath ).filePath( QgsFileUtils::stringToSafeFilename( printAtlas->currentFilename() + QStringLiteral( ".svg" ) ) );
|
||||
}
|
||||
else
|
||||
{
|
||||
outputFileName = file.path() + '/' + QgsFileUtils::stringToSafeFilename( mMasterLayout->name() ) + QStringLiteral( ".svg" );
|
||||
outputFileName = defaultPath + '/' + QgsFileUtils::stringToSafeFilename( mMasterLayout->name() ) + QStringLiteral( ".svg" );
|
||||
}
|
||||
|
||||
#ifdef Q_OS_MAC
|
||||
@ -2061,7 +2062,7 @@ void QgsLayoutDesignerDialog::exportToSvg()
|
||||
}
|
||||
|
||||
bool prevSettingLabelsAsOutlines = mLayout->project()->readBoolEntry( QStringLiteral( "PAL" ), QStringLiteral( "/DrawOutlineLabels" ), true );
|
||||
settings.setValue( QStringLiteral( "lastSaveAsSvgFile" ), outputFileName, QgsSettings::App );
|
||||
setLastExportPath( outputFileName );
|
||||
|
||||
QgsLayoutExporter::SvgExportSettings svgSettings;
|
||||
bool exportAsText = false;
|
||||
@ -2327,7 +2328,7 @@ void QgsLayoutDesignerDialog::printAtlas()
|
||||
progressDialog->setWindowTitle( tr( "Printing Atlas" ) );
|
||||
connect( feedback.get(), &QgsFeedback::progressChanged, this, [ & ]( double progress )
|
||||
{
|
||||
progressDialog->setValue( progress );
|
||||
progressDialog->setValue( static_cast< int >( progress ) );
|
||||
progressDialog->setLabelText( feedback->property( "progress" ).toString() ) ;
|
||||
|
||||
#ifdef Q_OS_LINUX
|
||||
@ -2437,8 +2438,7 @@ void QgsLayoutDesignerDialog::exportAtlasToRaster()
|
||||
printAtlas->setFilenameExpression( QStringLiteral( "'output_'||@atlas_featurenumber" ), error );
|
||||
}
|
||||
|
||||
QgsSettings s;
|
||||
QString lastUsedDir = s.value( QStringLiteral( "lastSaveAtlasAsImagesDir" ), QDir::homePath(), QgsSettings::App ).toString();
|
||||
QString lastUsedDir = defaultExportPath();
|
||||
|
||||
QFileDialog dlg( this, tr( "Export Atlas to Directory" ) );
|
||||
dlg.setFileMode( QFileDialog::Directory );
|
||||
@ -2461,7 +2461,7 @@ void QgsLayoutDesignerDialog::exportAtlasToRaster()
|
||||
{
|
||||
return;
|
||||
}
|
||||
s.setValue( QStringLiteral( "lastSaveAtlasAsImagesDir" ), dir, QgsSettings::App );
|
||||
setLastExportPath( dir );
|
||||
|
||||
// test directory (if it exists and is writable)
|
||||
if ( !QDir( dir ).exists() || !QFileInfo( dir ).isWritable() )
|
||||
@ -2498,7 +2498,7 @@ void QgsLayoutDesignerDialog::exportAtlasToRaster()
|
||||
progressDialog->setWindowTitle( tr( "Exporting Atlas" ) );
|
||||
connect( feedback.get(), &QgsFeedback::progressChanged, this, [ & ]( double progress )
|
||||
{
|
||||
progressDialog->setValue( progress );
|
||||
progressDialog->setValue( static_cast< int >( progress ) );
|
||||
progressDialog->setLabelText( feedback->property( "progress" ).toString() ) ;
|
||||
|
||||
#ifdef Q_OS_LINUX
|
||||
@ -2592,8 +2592,7 @@ void QgsLayoutDesignerDialog::exportAtlasToSvg()
|
||||
printAtlas->setFilenameExpression( QStringLiteral( "'output_'||@atlas_featurenumber" ), error );
|
||||
}
|
||||
|
||||
QgsSettings s;
|
||||
QString lastUsedDir = s.value( QStringLiteral( "lastSaveAtlasAsSvgDir" ), QDir::homePath(), QgsSettings::App ).toString();
|
||||
QString lastUsedDir = defaultExportPath();
|
||||
|
||||
QFileDialog dlg( this, tr( "Export Atlas to Directory" ) );
|
||||
dlg.setFileMode( QFileDialog::Directory );
|
||||
@ -2619,7 +2618,7 @@ void QgsLayoutDesignerDialog::exportAtlasToSvg()
|
||||
{
|
||||
return;
|
||||
}
|
||||
s.setValue( QStringLiteral( "lastSaveAtlasAsSvgDir" ), dir, QgsSettings::App );
|
||||
setLastExportPath( dir );
|
||||
|
||||
// test directory (if it exists and is writable)
|
||||
if ( !QDir( dir ).exists() || !QFileInfo( dir ).isWritable() )
|
||||
@ -2649,7 +2648,7 @@ void QgsLayoutDesignerDialog::exportAtlasToSvg()
|
||||
progressDialog->setWindowTitle( tr( "Exporting Atlas" ) );
|
||||
connect( feedback.get(), &QgsFeedback::progressChanged, this, [ & ]( double progress )
|
||||
{
|
||||
progressDialog->setValue( progress );
|
||||
progressDialog->setValue( static_cast< int >( progress ) );
|
||||
progressDialog->setLabelText( feedback->property( "progress" ).toString() ) ;
|
||||
|
||||
#ifdef Q_OS_LINUX
|
||||
@ -2754,13 +2753,11 @@ void QgsLayoutDesignerDialog::exportAtlasToPdf()
|
||||
bool singleFile = mLayout->customProperty( QStringLiteral( "singleFile" ), true ).toBool();
|
||||
|
||||
QString outputFileName;
|
||||
QgsSettings settings;
|
||||
QString dir;
|
||||
if ( singleFile )
|
||||
{
|
||||
QString lastUsedFile = settings.value( QStringLiteral( "lastSaveAsPdfFile" ), QStringLiteral( "qgis.pdf" ), QgsSettings::App ).toString();
|
||||
QFileInfo file( lastUsedFile );
|
||||
outputFileName = file.path() + '/' + QgsFileUtils::stringToSafeFilename( mMasterLayout->name() ) + QStringLiteral( ".pdf" );
|
||||
const QString defaultPath = defaultExportPath();
|
||||
outputFileName = defaultPath + '/' + QgsFileUtils::stringToSafeFilename( mMasterLayout->name() ) + QStringLiteral( ".pdf" );
|
||||
|
||||
#ifdef Q_OS_MAC
|
||||
QgisApp::instance()->activateWindow();
|
||||
@ -2781,7 +2778,7 @@ void QgsLayoutDesignerDialog::exportAtlasToPdf()
|
||||
{
|
||||
outputFileName += QLatin1String( ".pdf" );
|
||||
}
|
||||
settings.setValue( QStringLiteral( "lastSaveAsPdfFile" ), outputFileName, QgsSettings::App );
|
||||
setLastExportPath( outputFileName );
|
||||
}
|
||||
else
|
||||
{
|
||||
@ -2800,7 +2797,7 @@ void QgsLayoutDesignerDialog::exportAtlasToPdf()
|
||||
}
|
||||
|
||||
|
||||
QString lastUsedDir = settings.value( QStringLiteral( "lastSaveAtlasAsPdfDir" ), QDir::homePath(), QgsSettings::App ).toString();
|
||||
const QString lastUsedDir = defaultExportPath();
|
||||
|
||||
QFileDialog dlg( this, tr( "Export Atlas to Directory" ) );
|
||||
dlg.setFileMode( QFileDialog::Directory );
|
||||
@ -2826,7 +2823,7 @@ void QgsLayoutDesignerDialog::exportAtlasToPdf()
|
||||
{
|
||||
return;
|
||||
}
|
||||
settings.setValue( QStringLiteral( "lastSaveAtlasAsPdfDir" ), dir, QgsSettings::App );
|
||||
setLastExportPath( dir );
|
||||
|
||||
// test directory (if it exists and is writable)
|
||||
if ( !QDir( dir ).exists() || !QFileInfo( dir ).isWritable() )
|
||||
@ -2856,7 +2853,7 @@ void QgsLayoutDesignerDialog::exportAtlasToPdf()
|
||||
progressDialog->setWindowTitle( tr( "Exporting Atlas" ) );
|
||||
connect( feedback.get(), &QgsFeedback::progressChanged, this, [ & ]( double progress )
|
||||
{
|
||||
progressDialog->setValue( progress );
|
||||
progressDialog->setValue( static_cast< int >( progress ) );
|
||||
progressDialog->setLabelText( feedback->property( "progress" ).toString() ) ;
|
||||
|
||||
#ifdef Q_OS_LINUX
|
||||
@ -2950,7 +2947,6 @@ void QgsLayoutDesignerDialog::exportAtlasToPdf()
|
||||
|
||||
void QgsLayoutDesignerDialog::exportReportToRaster()
|
||||
{
|
||||
QgsSettings s;
|
||||
QString outputFileName = QgsFileUtils::stringToSafeFilename( mMasterLayout->name() );
|
||||
|
||||
QPair<QString, QString> fileNExt = QgsGuiUtils::getSaveAsImageName( this, tr( "Save Report As" ), outputFileName );
|
||||
@ -2961,6 +2957,8 @@ void QgsLayoutDesignerDialog::exportReportToRaster()
|
||||
return;
|
||||
}
|
||||
|
||||
setLastExportPath( fileNExt.first );
|
||||
|
||||
#ifdef Q_OS_MAC
|
||||
QgisApp::instance()->activateWindow();
|
||||
this->raise();
|
||||
@ -3051,10 +3049,8 @@ void QgsLayoutDesignerDialog::exportReportToSvg()
|
||||
{
|
||||
showSvgExportWarning();
|
||||
|
||||
QgsSettings settings;
|
||||
QString lastUsedFile = settings.value( QStringLiteral( "lastSaveAsSvgFile" ), QStringLiteral( "qgis.svg" ), QgsSettings::App ).toString();
|
||||
QFileInfo file( lastUsedFile );
|
||||
QString outputFileName = file.path() + '/' + QgsFileUtils::stringToSafeFilename( mMasterLayout->name() ) + QStringLiteral( ".svg" );
|
||||
const QString defaultPath = defaultExportPath();
|
||||
QString outputFileName = defaultPath + '/' + QgsFileUtils::stringToSafeFilename( mMasterLayout->name() ) + QStringLiteral( ".svg" );
|
||||
|
||||
outputFileName = QFileDialog::getSaveFileName(
|
||||
this,
|
||||
@ -3076,7 +3072,7 @@ void QgsLayoutDesignerDialog::exportReportToSvg()
|
||||
this->raise();
|
||||
#endif
|
||||
bool prevSettingLabelsAsOutlines = mMasterLayout->layoutProject()->readBoolEntry( QStringLiteral( "PAL" ), QStringLiteral( "/DrawOutlineLabels" ), true );
|
||||
settings.setValue( QStringLiteral( "lastSaveAsSvgFile" ), outputFileName, QgsSettings::App );
|
||||
setLastExportPath( outputFileName );
|
||||
|
||||
QgsLayoutExporter::SvgExportSettings svgSettings;
|
||||
bool exportAsText = false;
|
||||
@ -3179,12 +3175,9 @@ void QgsLayoutDesignerDialog::exportReportToSvg()
|
||||
|
||||
void QgsLayoutDesignerDialog::exportReportToPdf()
|
||||
{
|
||||
QgsSettings settings;
|
||||
const QString defaultPath = defaultExportPath();
|
||||
|
||||
QString lastUsedFile = settings.value( QStringLiteral( "lastSaveAsPdfFile" ), QStringLiteral( "qgis.pdf" ), QgsSettings::App ).toString();
|
||||
QFileInfo file( lastUsedFile );
|
||||
|
||||
QString outputFileName = file.path() + '/' + QgsFileUtils::stringToSafeFilename( mMasterLayout->name() ) + QStringLiteral( ".pdf" );
|
||||
QString outputFileName = defaultPath + '/' + QgsFileUtils::stringToSafeFilename( mMasterLayout->name() ) + QStringLiteral( ".pdf" );
|
||||
|
||||
#ifdef Q_OS_MAC
|
||||
QgisApp::instance()->activateWindow();
|
||||
@ -3205,7 +3198,7 @@ void QgsLayoutDesignerDialog::exportReportToPdf()
|
||||
{
|
||||
outputFileName += QLatin1String( ".pdf" );
|
||||
}
|
||||
settings.setValue( QStringLiteral( "lastSaveAsPdfFile" ), outputFileName, QgsSettings::App );
|
||||
setLastExportPath( outputFileName );
|
||||
|
||||
mView->setPaintingEnabled( false );
|
||||
QgsTemporaryCursorOverride cursorOverride( Qt::BusyCursor );
|
||||
@ -3499,12 +3492,12 @@ void QgsLayoutDesignerDialog::restoreWindowState()
|
||||
|
||||
if ( !restoreState( settings.value( QStringLiteral( "LayoutDesigner/state" ), QByteArray::fromRawData( reinterpret_cast< const char * >( defaultLayerDesignerUIstate ), sizeof defaultLayerDesignerUIstate ), QgsSettings::App ).toByteArray() ) )
|
||||
{
|
||||
QgsDebugMsg( "restore of layout UI state failed" );
|
||||
QgsDebugMsg( QStringLiteral( "restore of layout UI state failed" ) );
|
||||
}
|
||||
// restore window geometry
|
||||
if ( !restoreGeometry( settings.value( QStringLiteral( "LayoutDesigner/geometry" ), QgsSettings::App ).toByteArray() ) )
|
||||
{
|
||||
QgsDebugMsg( "restore of layout UI geometry failed" );
|
||||
QgsDebugMsg( QStringLiteral( "restore of layout UI geometry failed" ) );
|
||||
// default to 80% of screen size, at 10% from top left corner
|
||||
resize( QDesktopWidget().availableGeometry( this ).size() * 0.8 );
|
||||
QSize pos = QDesktopWidget().availableGeometry( this ).size() * 0.1;
|
||||
@ -3727,11 +3720,11 @@ bool QgsLayoutDesignerDialog::showFileSizeWarning()
|
||||
// Image size
|
||||
double oneInchInLayoutUnits = mLayout->convertToLayoutUnits( QgsLayoutMeasurement( 1, QgsUnitTypes::LayoutInches ) );
|
||||
QSizeF maxPageSize = mLayout->pageCollection()->maximumPageSize();
|
||||
int width = ( int )( mLayout->renderContext().dpi() * maxPageSize.width() / oneInchInLayoutUnits );
|
||||
int height = ( int )( mLayout->renderContext().dpi() * maxPageSize.height() / oneInchInLayoutUnits );
|
||||
int width = static_cast< int >( mLayout->renderContext().dpi() * maxPageSize.width() / oneInchInLayoutUnits );
|
||||
int height = static_cast< int >( mLayout->renderContext().dpi() * maxPageSize.height() / oneInchInLayoutUnits );
|
||||
int memuse = width * height * 3 / 1000000; // pixmap + image
|
||||
QgsDebugMsg( QString( "Image %1x%2" ).arg( width ).arg( height ) );
|
||||
QgsDebugMsg( QString( "memuse = %1" ).arg( memuse ) );
|
||||
QgsDebugMsg( QStringLiteral( "Image %1x%2" ).arg( width ).arg( height ) );
|
||||
QgsDebugMsg( QStringLiteral( "memuse = %1" ).arg( memuse ) );
|
||||
|
||||
if ( memuse > 400 ) // about 4500x4500
|
||||
{
|
||||
@ -4151,6 +4144,36 @@ void QgsLayoutDesignerDialog::updateActionNames( QgsMasterLayoutInterface::Type
|
||||
}
|
||||
}
|
||||
|
||||
QString QgsLayoutDesignerDialog::defaultExportPath() const
|
||||
{
|
||||
// first priority - last export folder saved in project
|
||||
const QString projectLastExportPath = QgsFileUtils::findClosestExistingPath( QgsProject::instance()->readEntry( QStringLiteral( "Layouts" ), QStringLiteral( "/lastLayoutExportDir" ), QString() ) );
|
||||
if ( !projectLastExportPath.isEmpty() )
|
||||
return projectLastExportPath;
|
||||
|
||||
// second priority - project home path
|
||||
const QString projectHome = QgsFileUtils::findClosestExistingPath( QgsProject::instance()->homePath() );
|
||||
if ( !projectHome.isEmpty() )
|
||||
return projectHome;
|
||||
|
||||
// last priority - app setting last export folder, with homepath as backup
|
||||
QgsSettings s;
|
||||
return QgsFileUtils::findClosestExistingPath( s.value( QStringLiteral( "lastLayoutExportDir" ), QDir::homePath(), QgsSettings::App ).toString() );
|
||||
}
|
||||
|
||||
void QgsLayoutDesignerDialog::setLastExportPath( const QString &path ) const
|
||||
{
|
||||
QFileInfo fi( path );
|
||||
QString savePath;
|
||||
if ( fi.isFile() )
|
||||
savePath = fi.path();
|
||||
else
|
||||
savePath = path;
|
||||
|
||||
QgsProject::instance()->writeEntry( QStringLiteral( "Layouts" ), QStringLiteral( "/lastLayoutExportDir" ), savePath );
|
||||
QgsSettings().setValue( QStringLiteral( "lastLayoutExportDir" ), savePath, QgsSettings::App );
|
||||
}
|
||||
|
||||
void QgsLayoutDesignerDialog::updateWindowTitle()
|
||||
{
|
||||
QString title;
|
||||
@ -4165,7 +4188,7 @@ void QgsLayoutDesignerDialog::updateWindowTitle()
|
||||
setWindowTitle( title );
|
||||
}
|
||||
|
||||
void QgsLayoutDesignerDialog::selectItems( const QList<QgsLayoutItem *> items )
|
||||
void QgsLayoutDesignerDialog::selectItems( const QList<QgsLayoutItem *> &items )
|
||||
{
|
||||
for ( QGraphicsItem *item : items )
|
||||
{
|
||||
|
@ -59,7 +59,7 @@ class QgsAppLayoutDesignerInterface : public QgsLayoutDesignerInterface
|
||||
QgsMasterLayoutInterface *masterLayout() override;
|
||||
QgsLayoutView *view() override;
|
||||
QgsMessageBar *messageBar() override;
|
||||
void selectItems( QList< QgsLayoutItem * > items ) override;
|
||||
void selectItems( const QList< QgsLayoutItem * > &items ) override;
|
||||
|
||||
public slots:
|
||||
|
||||
@ -132,7 +132,7 @@ class QgsLayoutDesignerDialog: public QMainWindow, private Ui::QgsLayoutDesigner
|
||||
/**
|
||||
* Selects the specified \a items.
|
||||
*/
|
||||
void selectItems( QList< QgsLayoutItem * > items );
|
||||
void selectItems( const QList<QgsLayoutItem *> &items );
|
||||
|
||||
/**
|
||||
* Returns the designer's message bar.
|
||||
@ -309,7 +309,7 @@ class QgsLayoutDesignerDialog: public QMainWindow, private Ui::QgsLayoutDesigner
|
||||
void addPages();
|
||||
void statusMessageReceived( const QString &message );
|
||||
void dockVisibilityChanged( bool visible );
|
||||
void undoRedoOccurredForItems( QSet< QString > itemUuids );
|
||||
void undoRedoOccurredForItems( const QSet< QString > &itemUuids );
|
||||
void saveAsTemplate();
|
||||
void addItemsFromTemplate();
|
||||
void duplicate();
|
||||
@ -502,6 +502,9 @@ class QgsLayoutDesignerDialog: public QMainWindow, private Ui::QgsLayoutDesigner
|
||||
QString reportTypeString();
|
||||
void updateActionNames( QgsMasterLayoutInterface::Type type );
|
||||
|
||||
QString defaultExportPath() const;
|
||||
void setLastExportPath( const QString &path ) const;
|
||||
|
||||
};
|
||||
|
||||
#endif // QGSLAYOUTDESIGNERDIALOG_H
|
||||
|
@ -15,6 +15,9 @@
|
||||
#include "qgsfileutils.h"
|
||||
#include <QObject>
|
||||
#include <QRegularExpression>
|
||||
#include <QFileInfo>
|
||||
#include <QDir>
|
||||
#include <QSet>
|
||||
|
||||
QString QgsFileUtils::representFileSize( qint64 bytes )
|
||||
{
|
||||
@ -29,7 +32,7 @@ QString QgsFileUtils::representFileSize( qint64 bytes )
|
||||
unit = i.next();
|
||||
bytes /= 1024.0;
|
||||
}
|
||||
return QString( "%1 %2" ).arg( QString::number( bytes ), unit );
|
||||
return QStringLiteral( "%1 %2" ).arg( QString::number( bytes ), unit );
|
||||
}
|
||||
|
||||
QStringList QgsFileUtils::extensionsFromFilter( const QString &filter )
|
||||
@ -86,8 +89,41 @@ QString QgsFileUtils::addExtensionFromFilter( const QString &fileName, const QSt
|
||||
|
||||
QString QgsFileUtils::stringToSafeFilename( const QString &string )
|
||||
{
|
||||
QRegularExpression rx( "[/\\\\\\?%\\*\\:\\|\"<>]" );
|
||||
QRegularExpression rx( QStringLiteral( "[/\\\\\\?%\\*\\:\\|\"<>]" ) );
|
||||
QString s = string;
|
||||
s.replace( rx, QStringLiteral( "_" ) );
|
||||
return s;
|
||||
}
|
||||
|
||||
QString QgsFileUtils::findClosestExistingPath( const QString &path )
|
||||
{
|
||||
if ( path.isEmpty() )
|
||||
return QString();
|
||||
|
||||
QDir currentPath;
|
||||
QFileInfo fi( path );
|
||||
if ( fi.isFile() )
|
||||
currentPath = fi.dir();
|
||||
else
|
||||
currentPath = QDir( path );
|
||||
|
||||
QSet< QString > visited;
|
||||
while ( !currentPath.exists() )
|
||||
{
|
||||
const QString parentPath = QDir::cleanPath( currentPath.absolutePath() + QStringLiteral( "/.." ) );
|
||||
if ( visited.contains( parentPath ) )
|
||||
return QString(); // break circular links
|
||||
|
||||
if ( parentPath.isEmpty() || parentPath == '.' )
|
||||
return QString();
|
||||
currentPath = QDir( parentPath );
|
||||
visited << parentPath;
|
||||
}
|
||||
|
||||
const QString res = QDir::cleanPath( currentPath.absolutePath() );
|
||||
|
||||
if ( res == QDir::currentPath() )
|
||||
return QString(); // avoid default to binary folder if a filename alone is specified
|
||||
|
||||
return res == '.' ? QString() : res;
|
||||
}
|
||||
|
@ -78,6 +78,14 @@ class CORE_EXPORT QgsFileUtils
|
||||
* \warning This method strips slashes from the filename, so it is safe to call with file names only, not complete paths.
|
||||
*/
|
||||
static QString stringToSafeFilename( const QString &string );
|
||||
|
||||
/**
|
||||
* Returns the top-most existing folder from \a path. E.g. if \a path is "/home/user/projects/2018/P4343"
|
||||
* and "/home/user/projects" exists but no "2018" subfolder exists, then the function will return "/home/user/projects".
|
||||
*
|
||||
* \since QGIS 3.2
|
||||
*/
|
||||
static QString findClosestExistingPath( const QString &path );
|
||||
};
|
||||
|
||||
#endif // QGSFILEUTILS_H
|
||||
|
@ -612,7 +612,7 @@ void QgsProject::clear()
|
||||
// basically a debugging tool to dump property list values
|
||||
void dump_( const QgsProjectPropertyKey &topQgsPropertyKey )
|
||||
{
|
||||
QgsDebugMsg( "current properties:" );
|
||||
QgsDebugMsg( QStringLiteral( "current properties:" ) );
|
||||
topQgsPropertyKey.dump();
|
||||
}
|
||||
|
||||
@ -660,13 +660,13 @@ void _getProperties( const QDomDocument &doc, QgsProjectPropertyKey &project_pro
|
||||
|
||||
if ( scopes.count() < 1 )
|
||||
{
|
||||
QgsDebugMsg( "empty ``properties'' XML tag ... bailing" );
|
||||
QgsDebugMsg( QStringLiteral( "empty ``properties'' XML tag ... bailing" ) );
|
||||
return;
|
||||
}
|
||||
|
||||
if ( ! project_properties.readXml( propertiesElem ) )
|
||||
{
|
||||
QgsDebugMsg( "Project_properties.readXml() failed" );
|
||||
QgsDebugMsg( QStringLiteral( "Project_properties.readXml() failed" ) );
|
||||
}
|
||||
}
|
||||
|
||||
@ -683,7 +683,7 @@ static void _getTitle( const QDomDocument &doc, QString &title )
|
||||
|
||||
if ( !nl.count() )
|
||||
{
|
||||
QgsDebugMsg( "unable to find title element" );
|
||||
QgsDebugMsg( QStringLiteral( "unable to find title element" ) );
|
||||
return;
|
||||
}
|
||||
|
||||
@ -691,7 +691,7 @@ static void _getTitle( const QDomDocument &doc, QString &title )
|
||||
|
||||
if ( !titleNode.hasChildNodes() ) // if not, then there's no actual text
|
||||
{
|
||||
QgsDebugMsg( "unable to find title element" );
|
||||
QgsDebugMsg( QStringLiteral( "unable to find title element" ) );
|
||||
return;
|
||||
}
|
||||
|
||||
@ -699,7 +699,7 @@ static void _getTitle( const QDomDocument &doc, QString &title )
|
||||
|
||||
if ( !titleTextNode.isText() )
|
||||
{
|
||||
QgsDebugMsg( "unable to find title element" );
|
||||
QgsDebugMsg( QStringLiteral( "unable to find title element" ) );
|
||||
return;
|
||||
}
|
||||
|
||||
@ -715,7 +715,7 @@ QgsProjectVersion getVersion( const QDomDocument &doc )
|
||||
|
||||
if ( !nl.count() )
|
||||
{
|
||||
QgsDebugMsg( " unable to find qgis element in project file" );
|
||||
QgsDebugMsg( QStringLiteral( " unable to find qgis element in project file" ) );
|
||||
return QgsProjectVersion( 0, 0, 0, QString() );
|
||||
}
|
||||
|
||||
@ -839,7 +839,7 @@ bool QgsProject::addLayer( const QDomElement &layerElem, QList<QDomNode> &broken
|
||||
|
||||
if ( !mapLayer )
|
||||
{
|
||||
QgsDebugMsg( "Unable to create layer" );
|
||||
QgsDebugMsg( QStringLiteral( "Unable to create layer" ) );
|
||||
|
||||
return false;
|
||||
}
|
||||
@ -976,7 +976,7 @@ bool QgsProject::readProjectFile( const QString &filename )
|
||||
|
||||
// Shows a warning when an old project file is read.
|
||||
emit oldProjectVersionWarning( fileVersion.text() );
|
||||
QgsDebugMsg( "Emitting oldProjectVersionWarning(oldVersion)." );
|
||||
QgsDebugMsg( QStringLiteral( "Emitting oldProjectVersionWarning(oldVersion)." ) );
|
||||
|
||||
projectFile.updateRevision( thisVersion );
|
||||
}
|
||||
@ -1124,7 +1124,7 @@ bool QgsProject::readProjectFile( const QString &filename )
|
||||
// review the integrity of the retrieved map layers
|
||||
if ( !clean )
|
||||
{
|
||||
QgsDebugMsg( "Unable to get map layers from project file." );
|
||||
QgsDebugMsg( QStringLiteral( "Unable to get map layers from project file." ) );
|
||||
|
||||
if ( !brokenNodes.isEmpty() )
|
||||
{
|
||||
@ -1551,15 +1551,15 @@ bool QgsProject::writeProjectFile( const QString &filename )
|
||||
qgisNode.appendChild( titleNode );
|
||||
|
||||
QDomElement transactionNode = doc->createElement( QStringLiteral( "autotransaction" ) );
|
||||
transactionNode.setAttribute( QStringLiteral( "active" ), mAutoTransaction ? "1" : "0" );
|
||||
transactionNode.setAttribute( QStringLiteral( "active" ), mAutoTransaction ? '1' : '0' );
|
||||
qgisNode.appendChild( transactionNode );
|
||||
|
||||
QDomElement evaluateDefaultValuesNode = doc->createElement( QStringLiteral( "evaluateDefaultValues" ) );
|
||||
evaluateDefaultValuesNode.setAttribute( QStringLiteral( "active" ), mEvaluateDefaultValues ? "1" : "0" );
|
||||
evaluateDefaultValuesNode.setAttribute( QStringLiteral( "active" ), mEvaluateDefaultValues ? '1' : '0' );
|
||||
qgisNode.appendChild( evaluateDefaultValuesNode );
|
||||
|
||||
QDomElement trustNode = doc->createElement( QStringLiteral( "trust" ) );
|
||||
trustNode.setAttribute( QStringLiteral( "active" ), mTrustLayerMetadata ? "1" : "0" );
|
||||
trustNode.setAttribute( QStringLiteral( "active" ), mTrustLayerMetadata ? '1' : '0' );
|
||||
qgisNode.appendChild( trustNode );
|
||||
|
||||
QDomText titleText = doc->createTextNode( title() ); // XXX why have title TWICE?
|
||||
@ -1643,7 +1643,7 @@ bool QgsProject::writeProjectFile( const QString &filename )
|
||||
|
||||
dump_( mProperties );
|
||||
|
||||
QgsDebugMsg( QString( "there are %1 property scopes" ).arg( static_cast<int>( mProperties.count() ) ) );
|
||||
QgsDebugMsg( QStringLiteral( "there are %1 property scopes" ).arg( static_cast<int>( mProperties.count() ) ) );
|
||||
|
||||
if ( !mProperties.isEmpty() ) // only worry about properties if we
|
||||
// actually have any properties
|
||||
@ -2691,6 +2691,7 @@ QSet<QgsMapLayer *> QgsProject::requiredLayers() const
|
||||
void QgsProject::setRequiredLayers( const QSet<QgsMapLayer *> &layers )
|
||||
{
|
||||
QStringList layerIds;
|
||||
layerIds.reserve( layers.count() );
|
||||
for ( QgsMapLayer *layer : layers )
|
||||
{
|
||||
layerIds << layer->id();
|
||||
|
@ -76,7 +76,7 @@ class GUI_EXPORT QgsLayoutDesignerInterface: public QObject
|
||||
/**
|
||||
* Selects the specified \a items.
|
||||
*/
|
||||
virtual void selectItems( QList< QgsLayoutItem * > items ) = 0;
|
||||
virtual void selectItems( const QList< QgsLayoutItem * > &items ) = 0;
|
||||
|
||||
public slots:
|
||||
|
||||
|
@ -14,6 +14,8 @@ __revision__ = '$Format:%H$'
|
||||
|
||||
import qgis # NOQA
|
||||
|
||||
import tempfile
|
||||
import os
|
||||
from qgis.core import QgsFileUtils
|
||||
from qgis.testing import unittest
|
||||
|
||||
@ -61,6 +63,37 @@ class TestQgsFileUtils(unittest.TestCase):
|
||||
QgsFileUtils.stringToSafeFilename('rendered map_final? rev (12-03-1017)_real/\\?%*:|"<>.tif'),
|
||||
'rendered map_final_ rev (12-03-1017)_real__________.tif')
|
||||
|
||||
def testFindClosestExistingPath(self):
|
||||
self.assertEqual(QgsFileUtils.findClosestExistingPath(''), '')
|
||||
self.assertEqual(QgsFileUtils.findClosestExistingPath('.'), '')
|
||||
self.assertEqual(QgsFileUtils.findClosestExistingPath('just_a_filename'), '')
|
||||
self.assertEqual(QgsFileUtils.findClosestExistingPath('just_a_filename.txt'), '')
|
||||
self.assertEqual(QgsFileUtils.findClosestExistingPath('a_very_unlikely_path_to_really_exist/because/no_one_would_have_a_folder_called/MapInfo is the bestest/'), '')
|
||||
# sorry anyone not on linux!
|
||||
self.assertEqual(QgsFileUtils.findClosestExistingPath('/usr/youve_been_hacked/by_the_l77t_krew'), '/usr')
|
||||
|
||||
base_path = tempfile.mkdtemp()
|
||||
file = os.path.join(base_path, 'test.csv')
|
||||
with open(file, 'wt') as f:
|
||||
f.write('\n')
|
||||
|
||||
self.assertEqual(QgsFileUtils.findClosestExistingPath(os.path.join(base_path, 'a file name.bmp')), base_path) # non-existent file
|
||||
self.assertEqual(QgsFileUtils.findClosestExistingPath(file), base_path) # real file!
|
||||
self.assertEqual(QgsFileUtils.findClosestExistingPath(os.path.join(base_path, 'non/existent/subfolder')), base_path)
|
||||
|
||||
sub_folder1 = os.path.join(base_path, 'subfolder1')
|
||||
os.mkdir(sub_folder1)
|
||||
sub_folder2 = os.path.join(sub_folder1, 'subfolder2')
|
||||
os.mkdir(sub_folder2)
|
||||
bad_sub_folder = os.path.join(sub_folder2, 'nooo')
|
||||
self.assertEqual(QgsFileUtils.findClosestExistingPath(bad_sub_folder), sub_folder2)
|
||||
self.assertEqual(QgsFileUtils.findClosestExistingPath(sub_folder2), sub_folder2)
|
||||
self.assertEqual(QgsFileUtils.findClosestExistingPath(sub_folder2 + '/.'), sub_folder2)
|
||||
self.assertEqual(QgsFileUtils.findClosestExistingPath(sub_folder2 + '/..'), sub_folder1)
|
||||
self.assertEqual(QgsFileUtils.findClosestExistingPath(sub_folder2 + '/../ddddddd'), sub_folder1)
|
||||
self.assertEqual(QgsFileUtils.findClosestExistingPath(sub_folder2 + '/../subfolder2'), sub_folder2)
|
||||
self.assertEqual(QgsFileUtils.findClosestExistingPath(sub_folder2 + '/../subfolder2/zxcv/asfdasd'), sub_folder2)
|
||||
|
||||
|
||||
if __name__ == '__main__':
|
||||
unittest.main()
|
||||
|
Loading…
x
Reference in New Issue
Block a user