Eeschema: fix plot path in stand alone mode with no project loaded.

Fixes https://gitlab.com/kicad/code/kicad/8308
This commit is contained in:
Wayne Stambaugh 2021-05-18 13:59:03 -04:00
parent 1bf5642228
commit 11785b08fe
2 changed files with 176 additions and 18 deletions

View File

@ -34,6 +34,7 @@
#include <pgm_base.h> #include <pgm_base.h>
#include <plotters_specific.h> #include <plotters_specific.h>
#include <reporter.h> #include <reporter.h>
#include <trace_helpers.h>
#include <settings/settings_manager.h> #include <settings/settings_manager.h>
#include <drawing_sheet/ds_painter.h> #include <drawing_sheet/ds_painter.h>
@ -44,6 +45,8 @@
#include <wx/dirdlg.h> #include <wx/dirdlg.h>
#include <wx/msgdlg.h> #include <wx/msgdlg.h>
#include <wx/stdpaths.h>
// static members (static to remember last state): // static members (static to remember last state):
int DIALOG_PLOT_SCHEMATIC::m_pageSizeSelect = PAGE_SIZE_AUTO; int DIALOG_PLOT_SCHEMATIC::m_pageSizeSelect = PAGE_SIZE_AUTO;
@ -194,14 +197,26 @@ void DIALOG_PLOT_SCHEMATIC::OnOutputDirectoryBrowseClicked( wxCommandEvent& even
{ {
// Build the absolute path of current output directory to preselect it in the file browser. // Build the absolute path of current output directory to preselect it in the file browser.
wxString path = ExpandEnvVarSubstitutions( m_outputDirectoryName->GetValue(), &Prj() ); wxString path = ExpandEnvVarSubstitutions( m_outputDirectoryName->GetValue(), &Prj() );
path = Prj().AbsolutePath( path );
// When editing a schematic that is not part of a project in the stand alone mode, the
// project path is not defined so point to the users document path to save the plot files.
if( Prj().IsNullProject() )
{
path = wxStandardPaths::Get().GetDocumentsDir();
}
else
{
// Build the absolute path of current output directory to preselect it in the file browser.
path = ExpandEnvVarSubstitutions( m_outputDirectoryName->GetValue(), &Prj() );
path = Prj().AbsolutePath( path );
}
wxDirDialog dirDialog( this, _( "Select Output Directory" ), path ); wxDirDialog dirDialog( this, _( "Select Output Directory" ), path );
if( dirDialog.ShowModal() == wxID_CANCEL ) if( dirDialog.ShowModal() == wxID_CANCEL )
return; return;
wxFileName dirName = wxFileName::DirName( dirDialog.GetPath() ); wxFileName dirName = wxFileName::DirName( dirDialog.GetPath() );
wxFileName fn( Prj().AbsolutePath( m_parent->Schematic().Root().GetFileName() ) ); wxFileName fn( Prj().AbsolutePath( m_parent->Schematic().Root().GetFileName() ) );
wxString defaultPath = fn.GetPathWithSep(); wxString defaultPath = fn.GetPathWithSep();
@ -409,25 +424,40 @@ wxFileName DIALOG_PLOT_SCHEMATIC::createPlotFileName( const wxString& aPlotFileN
const wxString& aExtension, const wxString& aExtension,
REPORTER* aReporter ) REPORTER* aReporter )
{ {
wxString path = ExpandEnvVarSubstitutions( m_outputDirectoryName->GetValue(), &Prj() ); wxFileName retv;
wxFileName outputDir = wxFileName::DirName( path ); wxFileName tmp;
wxString plotFileName;
tmp.SetPath( getOutputPath() );
retv.SetPath( tmp.GetPath() );
if( !aPlotFileName.IsEmpty() ) if( !aPlotFileName.IsEmpty() )
plotFileName = Prj().AbsolutePath( aPlotFileName + wxT( "." ) + aExtension ); retv.SetName( aPlotFileName );
else else
plotFileName = Prj().AbsolutePath( _( "Schematic" ) + wxT( "." ) + aExtension ); retv.SetName( _( "Schematic" ) );
if( !EnsureFileDirectoryExists( &outputDir, plotFileName, aReporter ) ) retv.SetExt( aExtension );
if( !EnsureFileDirectoryExists( &tmp, retv.GetFullName(), aReporter )
|| !tmp.IsDirWritable() )
{ {
wxString msg = wxString::Format( _( "Could not write plot files to folder \"%s\"." ), wxString msg = wxString::Format( _( "Could not write plot files to folder \"%s\"." ),
outputDir.GetPath() ); tmp.GetPath() );
aReporter->Report( msg, RPT_SEVERITY_ERROR ); aReporter->Report( msg, RPT_SEVERITY_ERROR );
retv.Clear();
SCHEMATIC_SETTINGS& settings = m_parent->Schematic().Settings();
settings.m_PlotDirectoryName.Clear();
m_configChanged = true;
}
else
{
retv.SetPath( tmp.GetPath() );
} }
wxFileName fn( plotFileName ); wxLogTrace( tracePathsAndFiles, "Writing plot file '%s'.", retv.GetFullPath() );
fn.SetPath( outputDir.GetFullPath() );
return fn; return retv;
} }
@ -479,6 +509,9 @@ void DIALOG_PLOT_SCHEMATIC::createDxfFile( bool aPlotAll, bool aPlotDrawingSheet
wxString ext = DXF_PLOTTER::GetDefaultFileExtension(); wxString ext = DXF_PLOTTER::GetDefaultFileExtension();
wxFileName plotFileName = createPlotFileName( fname, ext, &reporter ); wxFileName plotFileName = createPlotFileName( fname, ext, &reporter );
if( !plotFileName.IsOk() )
return;
if( plotOneSheetDxf( plotFileName.GetFullPath(), screen, aRenderSettings, if( plotOneSheetDxf( plotFileName.GetFullPath(), screen, aRenderSettings,
plot_offset, 1.0, aPlotDrawingSheet ) ) plot_offset, 1.0, aPlotDrawingSheet ) )
{ {
@ -644,6 +677,9 @@ void DIALOG_PLOT_SCHEMATIC::createHPGLFile( bool aPlotAll, bool aPlotFrameRef,
wxString ext = HPGL_PLOTTER::GetDefaultFileExtension(); wxString ext = HPGL_PLOTTER::GetDefaultFileExtension();
wxFileName plotFileName = createPlotFileName( fname, ext, &reporter ); wxFileName plotFileName = createPlotFileName( fname, ext, &reporter );
if( !plotFileName.IsOk() )
return;
LOCALE_IO toggle; LOCALE_IO toggle;
if( plotOneSheetHpgl( plotFileName.GetFullPath(), screen, plotPage, aRenderSettings, if( plotOneSheetHpgl( plotFileName.GetFullPath(), screen, plotPage, aRenderSettings,
@ -713,7 +749,7 @@ bool DIALOG_PLOT_SCHEMATIC::plotOneSheetHpgl( const wxString& aFileName,
// Init : // Init :
plotter->SetCreator( wxT( "Eeschema-HPGL" ) ); plotter->SetCreator( wxT( "Eeschema-HPGL" ) );
if( ! plotter->OpenFile( aFileName ) ) if( !plotter->OpenFile( aFileName ) )
{ {
delete plotter; delete plotter;
return false; return false;
@ -801,6 +837,9 @@ void DIALOG_PLOT_SCHEMATIC::createPDFFile( bool aPlotAll, bool aPlotDrawingSheet
wxString ext = PDF_PLOTTER::GetDefaultFileExtension(); wxString ext = PDF_PLOTTER::GetDefaultFileExtension();
plotFileName = createPlotFileName( fname, ext, &reporter ); plotFileName = createPlotFileName( fname, ext, &reporter );
if( !plotFileName.IsOk() )
return;
if( !plotter->OpenFile( plotFileName.GetFullPath() ) ) if( !plotter->OpenFile( plotFileName.GetFullPath() ) )
{ {
msg.Printf( _( "Unable to create file \"%s\".\n" ), msg.Printf( _( "Unable to create file \"%s\".\n" ),
@ -985,6 +1024,7 @@ void DIALOG_PLOT_SCHEMATIC::createPSFile( bool aPlotAll, bool aPlotFrameRef,
try try
{ {
wxString fname = m_parent->GetUniqueFilenameForCurrentSheet(); wxString fname = m_parent->GetUniqueFilenameForCurrentSheet();
// The sub sheet can be in a sub_hierarchy, but we plot the file in the // The sub sheet can be in a sub_hierarchy, but we plot the file in the
// main project folder (or the folder specified by the caller), // main project folder (or the folder specified by the caller),
// so replace separators to create a unique filename: // so replace separators to create a unique filename:
@ -993,6 +1033,9 @@ void DIALOG_PLOT_SCHEMATIC::createPSFile( bool aPlotAll, bool aPlotFrameRef,
wxString ext = PS_PLOTTER::GetDefaultFileExtension(); wxString ext = PS_PLOTTER::GetDefaultFileExtension();
wxFileName plotFileName = createPlotFileName( fname, ext, &reporter ); wxFileName plotFileName = createPlotFileName( fname, ext, &reporter );
if( !plotFileName.IsOk() )
return;
if( plotOneSheetPS( plotFileName.GetFullPath(), screen, aRenderSettings, plotPage, if( plotOneSheetPS( plotFileName.GetFullPath(), screen, aRenderSettings, plotPage,
plot_offset, scale, aPlotFrameRef ) ) plot_offset, scale, aPlotFrameRef ) )
{ {
@ -1114,6 +1157,9 @@ void DIALOG_PLOT_SCHEMATIC::createSVGFile( bool aPrintAll, bool aPrintFrameRef,
wxString ext = SVG_PLOTTER::GetDefaultFileExtension(); wxString ext = SVG_PLOTTER::GetDefaultFileExtension();
wxFileName plotFileName = createPlotFileName( fname, ext, &reporter ); wxFileName plotFileName = createPlotFileName( fname, ext, &reporter );
if( !plotFileName.IsOk() )
return;
bool success = plotOneSheetSVG( plotFileName.GetFullPath(), screen, aRenderSettings, bool success = plotOneSheetSVG( plotFileName.GetFullPath(), screen, aRenderSettings,
getModeColor() ? false : true, aPrintFrameRef ); getModeColor() ? false : true, aPrintFrameRef );
@ -1199,3 +1245,96 @@ bool DIALOG_PLOT_SCHEMATIC::plotOneSheetSVG( const wxString& aFileName,
return true; return true;
} }
wxString DIALOG_PLOT_SCHEMATIC::getOutputPath()
{
wxString msg;
wxString extMsg;
wxFileName fn;
extMsg.Printf( _( "Falling back to user path '%s'." ),
wxStandardPaths::Get().GetDocumentsDir() );
// Build the absolute path of current output directory to preselect it in the file browser.
wxString path = ExpandEnvVarSubstitutions( m_outputDirectoryName->GetValue(), &Prj() );
fn.SetPath( path );
// If the contents of the path edit control results in an absolute path, return it as is.
if( fn.IsAbsolute() )
return path;
// When editing a schematic that is not part of a project in the stand alone mode, the
// project path is not defined.
if( Prj().IsNullProject() )
{
SCH_SCREEN* screen = m_parent->Schematic().RootScreen();
if( screen && !screen->GetFileName().IsEmpty() )
{
fn = screen->GetFileName();
msg.Printf( _( "Cannot normalize path '%s%s'." ), fn.GetPathWithSep(), path );
fn.SetPath( fn.GetPathWithSep() + path );
// Normalize always returns true for a non-empty file name so clear the file name
// and extension so that only the path is normalized.
fn.SetName( wxEmptyString );
fn.SetExt( wxEmptyString );
if( fn.Normalize() )
{
path = fn.GetPath();
}
else
{
wxMessageDialog dlg( this, msg, _( "Warning" ),
wxOK | wxCENTER | wxRESIZE_BORDER | wxICON_EXCLAMATION |
wxSTAY_ON_TOP );
dlg.SetExtendedMessage( extMsg );
dlg.ShowModal();
path = wxStandardPaths::Get().GetDocumentsDir();
}
}
else
{
msg = _( "No project or path defined for the current schematic." );
wxMessageDialog dlg( this, msg, _( "Warning" ),
wxOK | wxCENTER | wxRESIZE_BORDER | wxICON_EXCLAMATION |
wxSTAY_ON_TOP );
dlg.SetExtendedMessage( extMsg );
dlg.ShowModal();
// Always fall back to user's document path if no other absolute path can be normalized.
path = wxStandardPaths::Get().GetDocumentsDir();
}
}
else
{
msg.Printf( _( "Cannot normalize path '%s%s'." ), Prj().GetProjectPath(), path );
// Build the absolute path of current output directory and the project path.
fn.SetPath( Prj().GetProjectPath() + path );
if( fn.Normalize() )
{
path = fn.GetPath();
}
else
{
wxMessageDialog dlg( this, msg, _( "Warning" ),
wxOK | wxCENTER | wxRESIZE_BORDER | wxICON_EXCLAMATION |
wxSTAY_ON_TOP );
dlg.SetExtendedMessage( extMsg );
dlg.ShowModal();
path = wxStandardPaths::Get().GetDocumentsDir();
}
}
return path;
}

View File

@ -63,7 +63,7 @@ public:
DIALOG_PLOT_SCHEMATIC( SCH_EDIT_FRAME* parent ); DIALOG_PLOT_SCHEMATIC( SCH_EDIT_FRAME* parent );
/** /**
* Return true if the project configutation was modified. * Return true if the project configuration was modified.
*/ */
bool PrjConfigChanged() { return m_configChanged; } bool PrjConfigChanged() { return m_configChanged; }
@ -102,10 +102,11 @@ private:
void setupPlotPagePDF( PLOTTER* aPlotter, SCH_SCREEN* aScreen ); void setupPlotPagePDF( PLOTTER* aPlotter, SCH_SCREEN* aScreen );
/** /**
* Everything done, close the plot and restore the environment * Everything done, close the plot and restore the environment.
* @param aPlotter the plotter to close and destroy *
* @param aOldsheetpath the stored old sheet path for the current sheet before the plot started * @param aPlotter the plotter to close and destroy
*/ * @param aOldsheetpath the stored old sheet path for the current sheet before the plot started
*/
void restoreEnvironment( PDF_PLOTTER* aPlotter, SCH_SHEET_PATH& aOldsheetpath ); void restoreEnvironment( PDF_PLOTTER* aPlotter, SCH_SHEET_PATH& aOldsheetpath );
// DXF // DXF
@ -181,6 +182,24 @@ private:
wxFileName createPlotFileName( const wxString& aPlotFileName, const wxString& aExtension, wxFileName createPlotFileName( const wxString& aPlotFileName, const wxString& aExtension,
REPORTER* aReporter = nullptr ); REPORTER* aReporter = nullptr );
/**
* Determine the best absolute path to plot files given the contents of the path
* edit control.
*
* - If the path edit control results in an absolute path, use it as is.
* - If the path edit control is not an absolute path and the project file is valid, use
the project root path to normalize the contents of the path edit control.
* - If the path edit control is not an absolute path and the project file does not exist
* and the screen file name is valid, use the screen file name path.
* - If the path edit control is not an absolute path and the project file does not exist
* and the screen file name is empty, user the user's documents folder.
* - Fall back to the user's document path if any of the above conditions do not result
* in a valid absolute path.
*
* @return a valid path to write the plot files.
*/
wxString getOutputPath();
SCH_EDIT_FRAME* m_parent; SCH_EDIT_FRAME* m_parent;
bool m_configChanged; // true if a project config param has changed bool m_configChanged; // true if a project config param has changed
PLOT_FORMAT m_plotFormat; PLOT_FORMAT m_plotFormat;