/* * This program source code file is part of KiCad, a free EDA CAD application. * * Copyright (C) 2012 Brian Sidebotham * Copyright The KiCad Developers, see AUTHORS.txt for contributors. * * This program is free software; you can redistribute it and/or * modify it under the terms of the GNU General Public License * as published by the Free Software Foundation; either version 2 * of the License, or (at your option) any later version. * * This program is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. * * You should have received a copy of the GNU General Public License * along with this program; if not, you may find one here: * http://www.gnu.org/licenses/old-licenses/gpl-2.0.html * or you may search the http://www.gnu.org website for the version 2 license, * or you may write to the Free Software Foundation, Inc., * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA */ #include #include #include #include #include #include #include "project_template.h" #define SEP wxFileName::GetPathSeparator() PROJECT_TEMPLATE::PROJECT_TEMPLATE( const wxString& aPath ) { m_basePath = wxFileName::DirName( aPath ); m_metaPath = wxFileName::DirName( aPath + SEP + METADIR ); m_metaHtmlFile = wxFileName::FileName( aPath + SEP + METADIR + SEP + METAFILE_INFO_HTML ); m_metaIconFile = wxFileName::FileName( aPath + SEP + METADIR + SEP + METAFILE_ICON ); m_title = wxEmptyString; // Test the project template requirements to make sure aPath is a valid template structure. if( !wxFileName::DirExists( m_basePath.GetPath() ) ) { // Error, the path doesn't exist! m_title = _( "Could not open the template path" ) + wxS( " " ) + aPath; } else if( !wxFileName::DirExists( m_metaPath.GetPath() ) ) { // Error, the meta information directory doesn't exist! m_title = _( "Could not find the expected 'meta' directory at" ) + wxS( " " ) + m_metaPath.GetPath(); } else if( !wxFileName::FileExists( m_metaHtmlFile.GetFullPath() ) ) { // Error, the meta information directory doesn't contain the informational html file! m_title = _( "Could not find the expected meta HTML file at" ) + wxS( " " ) + m_metaHtmlFile.GetFullPath(); } // Try to load an icon if( !wxFileName::FileExists( m_metaIconFile.GetFullPath() ) ) m_metaIcon = &wxNullBitmap; else m_metaIcon = new wxBitmap( m_metaIconFile.GetFullPath(), wxBITMAP_TYPE_PNG ); } class FILE_TRAVERSER : public wxDirTraverser { public: FILE_TRAVERSER( std::vector& files, const wxString& exclude ) : m_files( files ), m_exclude( exclude ) { } virtual wxDirTraverseResult OnFile( const wxString& filename ) override { wxFileName fn( filename ); wxString path( fn.GetPathWithSep() ); bool exclude = fn.GetName().Contains( "fp-info-cache" ) || fn.GetName().StartsWith( FILEEXT::AutoSaveFilePrefix ) || fn.GetName().StartsWith( FILEEXT::LockFilePrefix ); if( !exclude ) m_files.emplace_back( wxFileName( filename ) ); if( path != m_oldPath ) { const wxString gitfiles[] = { wxT( ".gitignore" ), wxT( ".gitattributes" ) }; for( const wxString& file : gitfiles ) { if( wxFileExists( path + file ) ) m_files.emplace_back( wxFileName( path + file ) ); } m_oldPath = path; } return wxDIR_CONTINUE; } virtual wxDirTraverseResult OnDir( const wxString& dirname ) override { wxDirTraverseResult result = wxDIR_IGNORE; bool exclude = dirname.StartsWith( m_exclude ) || dirname.EndsWith( "-backups" ); if( !exclude ) { m_files.emplace_back( wxFileName::DirName( dirname ) ); result = wxDIR_CONTINUE; } return result; } private: std::vector& m_files; wxString m_exclude; wxString m_oldPath; }; std::vector PROJECT_TEMPLATE::GetFileList() { std::vector files; FILE_TRAVERSER sink( files, m_metaPath.GetPath() ); wxDir dir( m_basePath.GetPath() ); dir.Traverse( sink, wxEmptyString, ( wxDIR_FILES | wxDIR_DIRS ) ); return files; } wxString PROJECT_TEMPLATE::GetPrjDirName() { return m_basePath.GetDirs()[ m_basePath.GetDirCount() - 1 ]; } PROJECT_TEMPLATE::~PROJECT_TEMPLATE() { } wxFileName PROJECT_TEMPLATE::GetHtmlFile() { return m_metaHtmlFile; } wxBitmap* PROJECT_TEMPLATE::GetIcon() { return m_metaIcon; } size_t PROJECT_TEMPLATE::GetDestinationFiles( const wxFileName& aNewProjectPath, std::vector< wxFileName >& aDestFiles ) { std::vector< wxFileName > srcFiles = GetFileList(); // Find the template file name base. this is the name of the .pro template file wxString basename; bool multipleProjectFilesFound = false; for( wxFileName& file : srcFiles ) { if( file.GetExt() == FILEEXT::ProjectFileExtension || file.GetExt() == FILEEXT::LegacyProjectFileExtension ) { if( !basename.IsEmpty() && basename != file.GetName() ) multipleProjectFilesFound = true; basename = file.GetName(); } } if( multipleProjectFilesFound ) basename = GetPrjDirName(); for( wxFileName& srcFile : srcFiles ) { // Replace the template path wxFileName destFile = srcFile; // Replace the template filename with the project filename for the new project creation wxString name = destFile.GetName(); name.Replace( basename, aNewProjectPath.GetName() ); destFile.SetName( name ); // Replace the template path with the project path. wxString path = destFile.GetPathWithSep(); path.Replace( m_basePath.GetPathWithSep(), aNewProjectPath.GetPathWithSep() ); destFile.SetPath( path ); aDestFiles.push_back( destFile ); } return aDestFiles.size(); } bool PROJECT_TEMPLATE::CreateProject( wxFileName& aNewProjectPath, wxString* aErrorMsg ) { // CreateProject copy the files from template to the new project folder and renames files // which have the same name as the template .kicad_pro file bool result = true; std::vector srcFiles = GetFileList(); // Find the template file name base. this is the name of the .kicad_pro (or .pro) template // file wxString basename; bool multipleProjectFilesFound = false; for( wxFileName& file : srcFiles ) { if( file.GetExt() == FILEEXT::ProjectFileExtension || file.GetExt() == FILEEXT::LegacyProjectFileExtension ) { if( !basename.IsEmpty() && basename != file.GetName() ) multipleProjectFilesFound = true; basename = file.GetName(); } } if( multipleProjectFilesFound ) basename = GetPrjDirName(); for( wxFileName& srcFile : srcFiles ) { // Replace the template path wxFileName destFile = srcFile; // Replace the template filename with the project filename for the new project creation wxString currname = destFile.GetName(); if( destFile.GetExt() == FILEEXT::DrawingSheetFileExtension ) { // Don't rename drawing sheet definitions; they're often shared } else if( destFile.GetName().EndsWith( "-cache" ) || destFile.GetName().EndsWith( "-rescue" ) ) { currname.Replace( basename, aNewProjectPath.GetName() ); } else if( destFile.GetExt() == FILEEXT::LegacySymbolDocumentFileExtension || destFile.GetExt() == FILEEXT::LegacySymbolLibFileExtension // Footprint libraries are directories not files, so GetExt() won't work || destFile.GetPath().EndsWith( '.' + FILEEXT::KiCadFootprintLibPathExtension ) ) { // Don't rename project-specific libraries. This will break the library tables and // cause broken links in the schematic/pcb. } else { currname.Replace( basename, aNewProjectPath.GetName() ); } destFile.SetName( currname ); // Replace the template path with the project path for the new project creation // but keep the sub directory name, if exists wxString destpath = destFile.GetPathWithSep(); destpath.Replace( m_basePath.GetPathWithSep(), aNewProjectPath.GetPathWithSep() ); // Check to see if the path already exists, if not attempt to create it here. if( !wxFileName::DirExists( destpath ) ) { if( !wxFileName::Mkdir( destpath, 0777, wxPATH_MKDIR_FULL ) ) { if( aErrorMsg ) { if( !aErrorMsg->empty() ) *aErrorMsg += "\n"; wxString msg; msg.Printf( _( "Cannot create folder '%s'." ), destpath ); *aErrorMsg += msg; } continue; } } destFile.SetPath( destpath ); if( srcFile.FileExists() && !wxCopyFile( srcFile.GetFullPath(), destFile.GetFullPath() ) ) { if( aErrorMsg ) { if( !aErrorMsg->empty() ) *aErrorMsg += "\n"; wxString msg; msg.Printf( _( "Cannot copy file '%s'." ), destFile.GetFullPath() ); *aErrorMsg += msg; } result = false; } } return result; } wxString* PROJECT_TEMPLATE::GetTitle() { wxFFileInputStream input( GetHtmlFile().GetFullPath() ); wxString separator( wxT( "\x9" ) ); wxTextInputStream text( input, separator, wxConvUTF8 ); /* Open HTML file and get the text between the title tags */ if( m_title == wxEmptyString ) { int start = 0; int finish = 0; bool done = false; bool hasStart = false; while( input.IsOk() && !input.Eof() && !done ) { wxString line = text.ReadLine(); wxString upperline = line.Clone().Upper(); start = upperline.Find( wxT( "" ) ); finish = upperline.Find( wxT( "" ) ); int length = finish - start - 7; // find the opening tag if( start != wxNOT_FOUND ) { if( finish != wxNOT_FOUND ) { m_title = line( start + 7, length ); done = true; } else { m_title = line.Mid( start + 7 ); hasStart = true; } } else { if( finish != wxNOT_FOUND ) { m_title += line.SubString( 0, finish - 1 ); done = true; } else if( hasStart ) m_title += line; } } // Remove line endings m_title.Replace( wxT( "\r" ), wxT( "" ) ); m_title.Replace( wxT( "\n" ), wxT( "" ) ); m_title.Trim( false ); // Trim from left m_title.Trim(); // Trim from right } return &m_title; }