31#include <wx/mimetype.h>
40#include "wx/tokenzr.h"
44#include <wx/wfstream.h>
46#include <wx/zipstrm.h>
52 if( !
string.StartsWith( wxT(
"\"" ) ) )
54 string.Prepend ( wxT(
"\"" ) );
55 string.Append ( wxT(
"\"" ) );
69 if( wxFileExists( fullFileName ) )
72 if( wxGetEnv( wxT(
"KICAD_RUN_FROM_BUILD_DIR" ),
nullptr ) )
74 wxFileName buildDir(
Pgm().GetExecutablePath(), shortname );
75 buildDir.RemoveLastDir();
77 buildDir.AppendDir( shortname );
79 buildDir.AppendDir( shortname.BeforeLast(
'.' ) );
82 if( buildDir.GetDirs().Last() ==
"pl_editor" )
84 buildDir.RemoveLastDir();
85 buildDir.AppendDir(
"pagelayout_editor" );
88 if( wxFileExists( buildDir.GetFullPath() ) )
89 return buildDir.GetFullPath();
94 if(
Pgm().IsKicadEnvVariableDefined() )
98 if( wxFileExists( fullFileName ) )
102#if defined( __WINDOWS__ )
109 const static wxChar* possibilities[] = {
110#if defined( __WXMAC__ )
112 wxT(
"Contents/Applications/pcbnew.app/Contents/MacOS/" ),
113 wxT(
"Contents/Applications/eeschema.app/Contents/MacOS/" ),
114 wxT(
"Contents/Applications/gerbview.app/Contents/MacOS/" ),
115 wxT(
"Contents/Applications/bitmap2component.app/Contents/MacOS/" ),
116 wxT(
"Contents/Applications/pcb_calculator.app/Contents/MacOS/" ),
117 wxT(
"Contents/Applications/pl_editor.app/Contents/MacOS/" ),
120 wxT(
"/usr/local/bin/" ),
121 wxT(
"/usr/local/kicad/bin/" ),
126 for(
unsigned i=0; i<
arrayDim(possibilities); ++i )
129 fullFileName = possibilities[i] + shortname;
135 if( wxFileExists( fullFileName ) )
145int ExecuteFile(
const wxString& aEditorName,
const wxString& aFileName, wxProcess* aCallback,
148 wxString fullEditorName;
149 std::vector<wxString> params;
153 bool inSingleQuotes =
false;
154 bool inDoubleQuotes =
false;
159 if( !param.IsEmpty() )
161 params.push_back( param );
166 for( wxUniChar ch : aEditorName )
173 inSingleQuotes =
false;
181 else if( inDoubleQuotes )
186 inDoubleQuotes =
false;
193 else if( ch ==
'\'' )
196 inSingleQuotes =
true;
201 inDoubleQuotes =
true;
218 fullEditorName = params[0];
220 params.erase( params.begin() );
226 fullEditorName = aEditorName;
229 if( wxFileExists( fullEditorName ) )
231 std::vector<const wchar_t*> args;
233 args.emplace_back( fullEditorName.wc_str() );
235 if( !params.empty() )
237 for(
const wxString& p : params )
238 args.emplace_back( p.wc_str() );
241 if( !aFileName.IsEmpty() )
242 args.emplace_back( aFileName.wc_str() );
244 args.emplace_back(
nullptr );
246 return wxExecute(
const_cast<wchar_t**
>( args.data() ), wxEXEC_ASYNC, aCallback );
250 msg.Printf(
_(
"Command '%s' could not be found." ), fullEditorName );
259 wxString filename = file;
263 if(
Pgm().UseSystemPdfBrowser() )
267 msg.Printf(
_(
"Unable to find a PDF viewer for '%s'." ), filename );
274 const wchar_t* args[3];
277 args[1] = filename.wc_str();
280 if( wxExecute(
const_cast<wchar_t**
>( args ) ) == -1 )
282 msg.Printf(
_(
"Problem while running the PDF viewer '%s'." ), args[0] );
292void KiCopyFile(
const wxString& aSrcPath,
const wxString& aDestPath, wxString& aErrors )
294 if( !wxCopyFile( aSrcPath, aDestPath ) )
298 if( !aErrors.IsEmpty() )
301 msg.Printf(
_(
"Cannot copy file '%s'." ), aDestPath );
320 std::function<
bool(
const std::string& token, wxString& value )> aCallback,
323 bool success =
false;
333 if( node->IsList() && node->GetNumberOfChildren() > 1 && node->GetChild( 0 )->IsSymbol() )
335 std::string token = node->GetChild( 0 )->GetSymbol();
336 SEXPR::SEXPR_STRING* pathNode = dynamic_cast<SEXPR::SEXPR_STRING*>( node->GetChild( 1 ) );
337 SEXPR::SEXPR_SYMBOL* symNode = dynamic_cast<SEXPR::SEXPR_SYMBOL*>( node->GetChild( 1 ) );
341 path = pathNode->m_value;
343 path = symNode->m_value;
345 if( aCallback( token, path ) )
348 pathNode->m_value = path;
350 symNode->m_value = path;
355 wxFFile destFile( aDestPath,
"wb" );
357 if( destFile.IsOpened() )
358 success = destFile.Write( sexpr->AsString( 0 ) );
371 if( !aErrors.empty() )
372 aErrors += wxS(
"\n" );
374 msg.Printf(
_(
"Cannot copy file '%s'." ), aDestPath );
382 return wxT(
"\"" ) + fn.GetFullPath( format ) + wxT(
"\"" );
388 namespace fs = std::filesystem;
390 std::string rmDir = aFileName.ToStdString();
392 if( rmDir.length() < 3 )
395 *aErrors =
_(
"Invalid directory name, cannot remove root" );
400 if( !fs::exists( rmDir ) )
403 *aErrors = wxString::Format(
_(
"Directory '%s' does not exist" ), aFileName );
408 fs::path
path( rmDir );
410 if( !fs::is_directory(
path ) )
413 *aErrors = wxString::Format(
_(
"'%s' is not a directory" ), aFileName );
420 fs::remove_all(
path );
422 catch(
const fs::filesystem_error& e )
425 *aErrors = wxString::Format(
_(
"Error removing directory '%s': %s" ),
426 aFileName, e.what() );
435bool CopyDirectory(
const wxString& aSourceDir,
const wxString& aDestDir, wxString& aErrors )
437 wxDir dir( aSourceDir );
439 if( !dir.IsOpened() )
441 aErrors += wxString::Format(
_(
"Could not open source directory: %s" ), aSourceDir );
442 aErrors += wxT(
"\n" );
446 if( !wxFileName::Mkdir( aDestDir, wxS_DIR_DEFAULT, wxPATH_MKDIR_FULL ) )
448 aErrors += wxString::Format(
_(
"Could not create destination directory: %s" ), aDestDir );
449 aErrors += wxT(
"\n" );
454 bool cont = dir.GetFirst( &filename );
458 wxString sourcePath = aSourceDir + wxFileName::GetPathSeparator() + filename;
459 wxString destPath = aDestDir + wxFileName::GetPathSeparator() + filename;
461 if( wxFileName::DirExists( sourcePath ) )
470 if( !wxCopyFile( sourcePath, destPath ) )
472 aErrors += wxString::Format(
_(
"Could not copy file: %s to %s" ),
479 cont = dir.GetNext( &filename );
487 int& aFileCopiedCount,
const std::vector<wxString>& aExclusions )
490 wxFileName sourceFn( aSourcePath );
491 wxString sourcePath = sourceFn.GetFullPath();
492 bool isSourceDirectory = wxFileName::DirExists( sourcePath );
493 wxString baseDestDir = aDestDir;
495 auto performCopy = [&](
const wxString& src,
const wxString& dest ) ->
bool
497 if( wxCopyFile( src, dest ) )
503 aErrors += wxString::Format(
_(
"Could not copy file: %s to %s" ), src, dest );
504 aErrors += wxT(
"\n" );
508 auto processEntries = [&](
const wxString& srcDir,
const wxString& pattern,
509 const wxString& destDir ) ->
bool
513 if( !dir.IsOpened() )
515 aErrors += wxString::Format(
_(
"Could not open source directory: %s" ), srcDir );
516 aErrors += wxT(
"\n" );
524 bool cont = dir.GetFirst( &filename, pattern, wxDIR_FILES | wxDIR_DIRS | wxDIR_HIDDEN );
528 const wxString entrySrc = srcDir + wxFileName::GetPathSeparator() + filename;
529 const wxString entryDest = destDir + wxFileName::GetPathSeparator() + filename;
533 filename.Matches( wxT(
"~*.lck" ) ) || filename.Matches( wxT(
"*.lck" ) );
535 for(
const auto& exclusion : aExclusions )
537 if( entrySrc.Matches( exclusion ) )
546 if( wxFileName::DirExists( entrySrc ) )
552 aErrors += wxString::Format(
_(
"Could not copy directory: %s to %s" ),
553 entrySrc, entryDest );
554 aErrors += wxT(
"\n" );
562 if( !performCopy( entrySrc, entryDest ) )
569 cont = dir.GetNext( &filename );
576 if( isSourceDirectory )
578 wxString sourceDirName = sourceFn.GetFullName();
579 baseDestDir = wxFileName( aDestDir, sourceDirName ).GetFullPath();
583 if( !wxFileName::Mkdir( baseDestDir, wxS_DIR_DEFAULT, wxPATH_MKDIR_FULL ) )
586 wxString::Format(
_(
"Could not create destination directory: %s" ), baseDestDir );
587 aErrors += wxT(
"\n" );
593 if( !isSourceDirectory )
595 const wxString fileName = sourceFn.GetFullName();
598 if( fileName.Contains(
'*' ) || fileName.Contains(
'?' ) )
600 const wxString dirPath = sourceFn.GetPath();
602 if( !wxFileName::DirExists( dirPath ) )
604 aErrors += wxString::Format(
_(
"Source directory does not exist: %s" ), dirPath );
605 aErrors += wxT(
"\n" );
610 return processEntries( dirPath, fileName, baseDestDir );
614 return performCopy( sourcePath, wxFileName( baseDestDir, fileName ).GetFullPath() );
618 return processEntries( sourcePath, wxEmptyString, baseDestDir );
623 const wxString& aParentDir )
625 wxDir dir( aSourceDir );
627 if( !dir.IsOpened() )
629 aErrors += wxString::Format(
_(
"Could not open source directory: %s" ), aSourceDir );
635 bool cont = dir.GetFirst( &filename );
639 wxString sourcePath = aSourceDir + wxFileName::GetPathSeparator() + filename;
640 wxString zipPath = aParentDir + filename;
642 if( wxFileName::DirExists( sourcePath ) )
645 aZip.PutNextDirEntry( zipPath +
"/" );
654 aZip.PutNextEntry( zipPath );
655 wxFFileInputStream fileStream( sourcePath );
657 if( !fileStream.IsOk() )
659 aErrors += wxString::Format(
_(
"Could not read file: %s" ), sourcePath );
663 aZip.Write( fileStream );
666 cont = dir.GetNext( &filename );
constexpr std::size_t arrayDim(T const (&)[N]) noexcept
Returns # of elements in an array.
virtual const wxString & GetKicadEnvVariable() const
virtual void ReadPdfBrowserInfos()
Read the PDF browser choice from the common configuration.
virtual const wxString & GetPdfBrowserName() const
virtual const wxString & GetExecutablePath() const
std::unique_ptr< SEXPR > ParseFromFile(const std::string &aFilename)
size_t GetNumberOfChildren() const
SEXPR * GetChild(size_t aIndex) const
void DisplayErrorMessage(wxWindow *aParent, const wxString &aText, const wxString &aExtraInfo)
Display an error message with aMessage.
This file is part of the common library.
wxString FindKicadFile(const wxString &shortname)
Search the executable file shortname in KiCad binary path and return full file name if found or short...
wxString QuoteFullPath(wxFileName &fn, wxPathFormat format)
Quote return value of wxFileName::GetFullPath().
void CopySexprFile(const wxString &aSrcPath, const wxString &aDestPath, std::function< bool(const std::string &token, wxString &value)> aCallback, wxString &aErrors)
bool OpenPDF(const wxString &file)
Run the PDF viewer and display a PDF file.
void KiCopyFile(const wxString &aSrcPath, const wxString &aDestPath, wxString &aErrors)
int ExecuteFile(const wxString &aEditorName, const wxString &aFileName, wxProcess *aCallback, bool aFileForKicad)
Call the executable file aEditorName with the parameter aFileName.
bool CopyFilesOrDirectory(const wxString &aSourcePath, const wxString &aDestDir, wxString &aErrors, int &aFileCopiedCount, const std::vector< wxString > &aExclusions)
bool RmDirRecursive(const wxString &aFileName, wxString *aErrors)
Remove the directory aDirName and all its contents including subdirectories and their files.
void QuoteString(wxString &string)
Add un " to the start and the end of string (if not already done).
static void traverseSEXPR(SEXPR::SEXPR *aNode, const std::function< void(SEXPR::SEXPR *)> &aVisitor)
bool CopyDirectory(const wxString &aSourceDir, const wxString &aDestDir, wxString &aErrors)
Copy a directory and its contents to another directory.
bool AddDirectoryToZip(wxZipOutputStream &aZip, const wxString &aSourceDir, wxString &aErrors, const wxString &aParentDir)
Add a directory and its contents to a zip file.
bool LaunchExternal(const wxString &aPath)
Launches the given file or folder in the host OS.
PGM_BASE & Pgm()
The global program "get" accessor.
#define TO_UTF8(wxstring)
Convert a wxString to a UTF8 encoded C string for all wxWidgets build modes.