KiCad PCB EDA Suite
Loading...
Searching...
No Matches
project_template.cpp
Go to the documentation of this file.
1/*
2 * This program source code file is part of KiCad, a free EDA CAD application.
3 *
4 * Copyright (C) 2012 Brian Sidebotham <[email protected]>
5 * Copyright (C) 1992-2024 KiCad Developers, see AUTHORS.txt for contributors.
6 *
7 * This program is free software; you can redistribute it and/or
8 * modify it under the terms of the GNU General Public License
9 * as published by the Free Software Foundation; either version 2
10 * of the License, or (at your option) any later version.
11 *
12 * This program is distributed in the hope that it will be useful,
13 * but WITHOUT ANY WARRANTY; without even the implied warranty of
14 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
15 * GNU General Public License for more details.
16 *
17 * You should have received a copy of the GNU General Public License
18 * along with this program; if not, you may find one here:
19 * http://www.gnu.org/licenses/old-licenses/gpl-2.0.html
20 * or you may search the http://www.gnu.org website for the version 2 license,
21 * or you may write to the Free Software Foundation, Inc.,
22 * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA
23 */
24
25
26#include <wx/bitmap.h>
27#include <wx/dir.h>
28#include <wx/txtstrm.h>
29#include <wx/wfstream.h>
30#include <wx/log.h>
31
33#include "project_template.h"
34
35
36#define SEP wxFileName::GetPathSeparator()
37
38
39PROJECT_TEMPLATE::PROJECT_TEMPLATE( const wxString& aPath )
40{
41 m_basePath = wxFileName::DirName( aPath );
42 m_metaPath = wxFileName::DirName( aPath + SEP + METADIR );
43 m_metaHtmlFile = wxFileName::FileName( aPath + SEP + METADIR + SEP + METAFILE_INFO_HTML );
44 m_metaIconFile = wxFileName::FileName( aPath + SEP + METADIR + SEP + METAFILE_ICON );
45
46 m_title = wxEmptyString;
47
48 // Test the project template requirements to make sure aPath is a valid template structure.
49 if( !wxFileName::DirExists( m_basePath.GetPath() ) )
50 {
51 // Error, the path doesn't exist!
52 m_title = _( "Could open the template path!" ) + wxS( " " ) + aPath;
53 }
54 else if( !wxFileName::DirExists( m_metaPath.GetPath() ) )
55 {
56 // Error, the meta information directory doesn't exist!
57 m_title = _( "Couldn't open the meta information directory for this template!" ) +
58 wxS( " " ) + m_metaPath.GetPath();
59 }
60 else if( !wxFileName::FileExists( m_metaHtmlFile.GetFullPath() ) )
61 {
62 // Error, the meta information directory doesn't contain the informational html file!
63 m_title = _( "Couldn't find the meta HTML information file for this template!" );
64 }
65
66 // Try to load an icon
67 if( !wxFileName::FileExists( m_metaIconFile.GetFullPath() ) )
68 m_metaIcon = &wxNullBitmap;
69 else
70 m_metaIcon = new wxBitmap( m_metaIconFile.GetFullPath(), wxBITMAP_TYPE_PNG );
71}
72
73
74class FILE_TRAVERSER : public wxDirTraverser
75{
76public:
77 FILE_TRAVERSER( std::vector<wxFileName>& files, const wxString exclude ) :
78 m_files( files ),
79 m_exclude( exclude )
80 { }
81
82 virtual wxDirTraverseResult OnFile( const wxString& filename ) override
83 {
84 wxFileName fn( filename );
85 wxString path( fn.GetPathWithSep() );
86
87 bool exclude = fn.GetName().Contains( "fp-info-cache" )
88 || fn.GetName().StartsWith( FILEEXT::AutoSaveFilePrefix )
89 || fn.GetExt().Contains( "lck" );
90
91 if( !exclude )
92 m_files.emplace_back( wxFileName( filename ) );
93
94 if( path != m_oldPath )
95 {
96 const wxString gitfiles[] = { wxT( ".gitignore" ), wxT( ".gitattributes" ) };
97
98 for( const wxString& file : gitfiles )
99 {
100 if( wxFileExists( path + file ) )
101 m_files.emplace_back( wxFileName( path + file ) );
102 }
103
104 m_oldPath = path;
105 }
106
107 return wxDIR_CONTINUE;
108 }
109
110 virtual wxDirTraverseResult OnDir( const wxString& dirname ) override
111 {
112 wxDirTraverseResult result = wxDIR_IGNORE;
113
114 bool exclude = dirname.StartsWith( m_exclude ) || dirname.EndsWith( "-backups" );
115
116 if( !exclude )
117 {
118 m_files.emplace_back( wxFileName::DirName( dirname ) );
119 result = wxDIR_CONTINUE;
120 }
121
122 return result;
123 }
124
125private:
126 std::vector<wxFileName>& m_files;
127 wxString m_exclude;
128 wxString m_oldPath;
129};
130
131
132std::vector<wxFileName> PROJECT_TEMPLATE::GetFileList()
133{
134 std::vector<wxFileName> files;
135 FILE_TRAVERSER sink( files, m_metaPath.GetPath() );
136 wxDir dir( m_basePath.GetPath() );
137
138 dir.Traverse( sink, wxEmptyString, ( wxDIR_FILES | wxDIR_DIRS ) );
139 return files;
140}
141
142
144{
145 return m_basePath.GetDirs()[ m_basePath.GetDirCount() - 1 ];
146}
147
148
150{
151
152}
153
154
156{
157 return m_metaHtmlFile;
158}
159
160
162{
163 return m_metaIcon;
164}
165
166
167size_t PROJECT_TEMPLATE::GetDestinationFiles( const wxFileName& aNewProjectPath,
168 std::vector< wxFileName >& aDestFiles )
169{
170 std::vector< wxFileName > srcFiles = GetFileList();
171
172 // Find the template file name base. this is the name of the .pro template file
173 wxString basename;
174 bool multipleProjectFilesFound = false;
175
176 for( wxFileName& file : srcFiles )
177 {
178 if( file.GetExt() == FILEEXT::ProjectFileExtension
179 || file.GetExt() == FILEEXT::LegacyProjectFileExtension )
180 {
181 if( !basename.IsEmpty() && basename != file.GetName() )
182 multipleProjectFilesFound = true;
183
184 basename = file.GetName();
185 }
186 }
187
188 if( multipleProjectFilesFound )
189 basename = GetPrjDirName();
190
191 for( wxFileName& srcFile : srcFiles )
192 {
193 // Replace the template path
194 wxFileName destFile = srcFile;
195
196 // Replace the template filename with the project filename for the new project creation
197 wxString name = destFile.GetName();
198 name.Replace( basename, aNewProjectPath.GetName() );
199 destFile.SetName( name );
200
201 // Replace the template path with the project path.
202 wxString path = destFile.GetPathWithSep();
203 path.Replace( m_basePath.GetPathWithSep(), aNewProjectPath.GetPathWithSep() );
204 destFile.SetPath( path );
205
206 aDestFiles.push_back( destFile );
207 }
208
209 return aDestFiles.size();
210}
211
212
213bool PROJECT_TEMPLATE::CreateProject( wxFileName& aNewProjectPath, wxString* aErrorMsg )
214{
215 // CreateProject copy the files from template to the new project folder and renames files
216 // which have the same name as the template .kicad_pro file
217 bool result = true;
218
219 std::vector<wxFileName> srcFiles = GetFileList();
220
221 // Find the template file name base. this is the name of the .kicad_pro (or .pro) template
222 // file
223 wxString basename;
224 bool multipleProjectFilesFound = false;
225
226 for( wxFileName& file : srcFiles )
227 {
228 if( file.GetExt() == FILEEXT::ProjectFileExtension
229 || file.GetExt() == FILEEXT::LegacyProjectFileExtension )
230 {
231 if( !basename.IsEmpty() && basename != file.GetName() )
232 multipleProjectFilesFound = true;
233
234 basename = file.GetName();
235 }
236 }
237
238 if( multipleProjectFilesFound )
239 basename = GetPrjDirName();
240
241 for( wxFileName& srcFile : srcFiles )
242 {
243 // Replace the template path
244 wxFileName destFile = srcFile;
245
246 // Replace the template filename with the project filename for the new project creation
247 wxString currname = destFile.GetName();
248
249 if( destFile.GetExt() == FILEEXT::DrawingSheetFileExtension )
250 {
251 // Don't rename drawing sheet definitions; they're often shared
252 }
253 else if( destFile.GetName().EndsWith( "-cache" )
254 || destFile.GetName().EndsWith( "-rescue" ) )
255 {
256 currname.Replace( basename, aNewProjectPath.GetName() );
257 }
258 else if( destFile.GetExt() == "dcm"
259 || destFile.GetExt() == "lib"
260 // Footprint libraries are directories not files, so GetExt() won't work
261 || destFile.GetPath().EndsWith( ".pretty" ) )
262 {
263 // Don't rename project-specific libraries. This will break the library tables and
264 // cause broken links in the schematic/pcb.
265 }
266 else
267 {
268 currname.Replace( basename, aNewProjectPath.GetName() );
269 }
270
271 destFile.SetName( currname );
272
273 // Replace the template path with the project path for the new project creation
274 // but keep the sub directory name, if exists
275 wxString destpath = destFile.GetPathWithSep();
276 destpath.Replace( m_basePath.GetPathWithSep(), aNewProjectPath.GetPathWithSep() );
277
278 // Check to see if the path already exists, if not attempt to create it here.
279 if( !wxFileName::DirExists( destpath ) )
280 {
281 if( !wxFileName::Mkdir( destpath, 0777, wxPATH_MKDIR_FULL ) )
282 {
283 if( aErrorMsg )
284 {
285 if( !aErrorMsg->empty() )
286 *aErrorMsg += "\n";
287
288 wxString msg;
289
290 msg.Printf( _( "Cannot create folder '%s'." ), destpath );
291 *aErrorMsg += msg;
292 }
293
294 continue;
295 }
296 }
297
298 destFile.SetPath( destpath );
299
300 if( srcFile.FileExists() && !wxCopyFile( srcFile.GetFullPath(), destFile.GetFullPath() ) )
301 {
302 if( aErrorMsg )
303 {
304 if( !aErrorMsg->empty() )
305 *aErrorMsg += "\n";
306
307 wxString msg;
308
309 msg.Printf( _( "Cannot copy file '%s'." ), destFile.GetFullPath() );
310 *aErrorMsg += msg;
311 }
312
313 result = false;
314 }
315 }
316
317 return result;
318}
319
320
322{
323 wxFFileInputStream input( GetHtmlFile().GetFullPath() );
324 wxString separator( wxT( "\x9" ) );
325 wxTextInputStream text( input, separator, wxConvUTF8 );
326
327 /* Open HTML file and get the text between the title tags */
328 if( m_title == wxEmptyString )
329 {
330 int start = 0;
331 int finish = 0;
332 bool done = false;
333
334 while( input.IsOk() && !input.Eof() && !done )
335 {
336 wxString line = text.ReadLine();
337 wxString upperline = line.Clone().Upper();
338
339 start = upperline.Find( wxT( "<TITLE>" ) );
340 finish = upperline.Find( wxT( "</TITLE>" ) );
341 int length = finish - start - 7;
342
343 // find the opening tag
344 if( start != wxNOT_FOUND )
345 {
346 if( finish != wxNOT_FOUND )
347 {
348 m_title = line( start + 7, length );
349 }
350 else
351 {
352 m_title = line.Mid( start + 7 );
353 }
354
355 done = true;
356 }
357 else
358 {
359 if( finish != wxNOT_FOUND )
360 {
361 m_title += line.SubString( 0, finish );
362 done = true;
363 }
364 }
365
366 // Remove line endings
367 m_title.Replace( wxT( "\r" ), wxT( " " ) );
368 m_title.Replace( wxT( "\n" ), wxT( " " ) );
369 }
370 }
371
372 return &m_title;
373}
const char * name
Definition: DXF_plotter.cpp:57
virtual wxDirTraverseResult OnDir(const wxString &dirname) override
FILE_TRAVERSER(std::vector< wxFileName > &files, const wxString exclude)
virtual wxDirTraverseResult OnFile(const wxString &filename) override
std::vector< wxFileName > & m_files
wxBitmap * GetIcon()
Get the 64px^2 icon for the project template.
size_t GetDestinationFiles(const wxFileName &aNewProjectPath, std::vector< wxFileName > &aDestFiles)
Fetch the list of destination files to be copied when the new project is created.
wxFileName m_metaHtmlFile
PROJECT_TEMPLATE(const wxString &aPath)
Create a new project instance from aPath.
std::vector< wxFileName > GetFileList()
Get a vector list of filenames for the template.
~PROJECT_TEMPLATE()
Non-virtual destructor (so no derived classes)
wxFileName GetHtmlFile()
Get the full Html filename for the project template.
wxString * GetTitle()
Get the title of the project (extracted from the html title tag)
bool CreateProject(wxFileName &aNewProjectPath, wxString *aErrorMsg=nullptr)
Copies and renames all template files to create a new project.
wxFileName m_metaIconFile
wxString GetPrjDirName()
Get the dir name of the project template (i.e.
#define _(s)
static const std::string ProjectFileExtension
static const std::string LegacyProjectFileExtension
static const std::string DrawingSheetFileExtension
static const std::string AutoSaveFilePrefix
#define SEP()
#define METAFILE_ICON
An optional png icon, exactly 64px x 64px which is used in the template selector if present.
#define METADIR
A directory which contains information about the project template and does not get copied.
#define METAFILE_INFO_HTML
A required html formatted file which contains information about the project template.
Definition of file extensions used in Kicad.