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( "_autosave-" ) || fn.GetExt().Contains( "lck" );
89
90 if( !exclude )
91 m_files.emplace_back( wxFileName( filename ) );
92
93 if( path != m_oldPath )
94 {
95 const wxString gitfiles[] = { wxT( ".gitignore" ), wxT( ".gitattributes" ) };
96
97 for( const wxString& file : gitfiles )
98 {
99 if( wxFileExists( path + file ) )
100 m_files.emplace_back( wxFileName( path + file ) );
101 }
102
103 m_oldPath = path;
104 }
105
106 return wxDIR_CONTINUE;
107 }
108
109 virtual wxDirTraverseResult OnDir( const wxString& dirname ) override
110 {
111 wxDirTraverseResult result = wxDIR_IGNORE;
112
113 bool exclude = dirname.StartsWith( m_exclude ) || dirname.EndsWith( "-backups" );
114
115 if( !exclude )
116 {
117 m_files.emplace_back( wxFileName::DirName( dirname ) );
118 result = wxDIR_CONTINUE;
119 }
120
121 return result;
122 }
123
124private:
125 std::vector<wxFileName>& m_files;
126 wxString m_exclude;
127 wxString m_oldPath;
128};
129
130
131std::vector<wxFileName> PROJECT_TEMPLATE::GetFileList()
132{
133 std::vector<wxFileName> files;
134 FILE_TRAVERSER sink( files, m_metaPath.GetPath() );
135 wxDir dir( m_basePath.GetPath() );
136
137 dir.Traverse( sink, wxEmptyString, ( wxDIR_FILES | wxDIR_DIRS ) );
138 return files;
139}
140
141
143{
144 return m_basePath.GetDirs()[ m_basePath.GetDirCount() - 1 ];
145}
146
147
149{
150
151}
152
153
155{
156 return m_metaHtmlFile;
157}
158
159
161{
162 return m_metaIcon;
163}
164
165
166size_t PROJECT_TEMPLATE::GetDestinationFiles( const wxFileName& aNewProjectPath,
167 std::vector< wxFileName >& aDestFiles )
168{
169 std::vector< wxFileName > srcFiles = GetFileList();
170
171 // Find the template file name base. this is the name of the .pro template file
172 wxString basename;
173 bool multipleProjectFilesFound = false;
174
175 for( wxFileName& file : srcFiles )
176 {
177 if( file.GetExt() == FILEEXT::ProjectFileExtension
178 || file.GetExt() == FILEEXT::LegacyProjectFileExtension )
179 {
180 if( !basename.IsEmpty() && basename != file.GetName() )
181 multipleProjectFilesFound = true;
182
183 basename = file.GetName();
184 }
185 }
186
187 if( multipleProjectFilesFound )
188 basename = GetPrjDirName();
189
190 for( wxFileName& srcFile : srcFiles )
191 {
192 // Replace the template path
193 wxFileName destFile = srcFile;
194
195 // Replace the template filename with the project filename for the new project creation
196 wxString name = destFile.GetName();
197 name.Replace( basename, aNewProjectPath.GetName() );
198 destFile.SetName( name );
199
200 // Replace the template path with the project path.
201 wxString path = destFile.GetPathWithSep();
202 path.Replace( m_basePath.GetPathWithSep(), aNewProjectPath.GetPathWithSep() );
203 destFile.SetPath( path );
204
205 aDestFiles.push_back( destFile );
206 }
207
208 return aDestFiles.size();
209}
210
211
212bool PROJECT_TEMPLATE::CreateProject( wxFileName& aNewProjectPath, wxString* aErrorMsg )
213{
214 // CreateProject copy the files from template to the new project folder and renames files
215 // which have the same name as the template .kicad_pro file
216 bool result = true;
217
218 std::vector<wxFileName> srcFiles = GetFileList();
219
220 // Find the template file name base. this is the name of the .kicad_pro (or .pro) template
221 // file
222 wxString basename;
223 bool multipleProjectFilesFound = false;
224
225 for( wxFileName& file : srcFiles )
226 {
227 if( file.GetExt() == FILEEXT::ProjectFileExtension
228 || file.GetExt() == FILEEXT::LegacyProjectFileExtension )
229 {
230 if( !basename.IsEmpty() && basename != file.GetName() )
231 multipleProjectFilesFound = true;
232
233 basename = file.GetName();
234 }
235 }
236
237 if( multipleProjectFilesFound )
238 basename = GetPrjDirName();
239
240 for( wxFileName& srcFile : srcFiles )
241 {
242 // Replace the template path
243 wxFileName destFile = srcFile;
244
245 // Replace the template filename with the project filename for the new project creation
246 wxString currname = destFile.GetName();
247
248 if( destFile.GetExt() == FILEEXT::DrawingSheetFileExtension )
249 {
250 // Don't rename drawing sheet definitions; they're often shared
251 }
252 else if( destFile.GetName().EndsWith( "-cache" )
253 || destFile.GetName().EndsWith( "-rescue" ) )
254 {
255 currname.Replace( basename, aNewProjectPath.GetName() );
256 }
257 else if( destFile.GetExt() == "dcm"
258 || destFile.GetExt() == "lib"
259 // Footprint libraries are directories not files, so GetExt() won't work
260 || destFile.GetPath().EndsWith( ".pretty" ) )
261 {
262 // Don't rename project-specific libraries. This will break the library tables and
263 // cause broken links in the schematic/pcb.
264 }
265 else
266 {
267 currname.Replace( basename, aNewProjectPath.GetName() );
268 }
269
270 destFile.SetName( currname );
271
272 // Replace the template path with the project path for the new project creation
273 // but keep the sub directory name, if exists
274 wxString destpath = destFile.GetPathWithSep();
275 destpath.Replace( m_basePath.GetPathWithSep(), aNewProjectPath.GetPathWithSep() );
276
277 // Check to see if the path already exists, if not attempt to create it here.
278 if( !wxFileName::DirExists( destpath ) )
279 {
280 if( !wxFileName::Mkdir( destpath, 0777, wxPATH_MKDIR_FULL ) )
281 {
282 if( aErrorMsg )
283 {
284 if( !aErrorMsg->empty() )
285 *aErrorMsg += "\n";
286
287 wxString msg;
288
289 msg.Printf( _( "Cannot create folder '%s'." ), destpath );
290 *aErrorMsg += msg;
291 }
292
293 continue;
294 }
295 }
296
297 destFile.SetPath( destpath );
298
299 if( srcFile.FileExists() && !wxCopyFile( srcFile.GetFullPath(), destFile.GetFullPath() ) )
300 {
301 if( aErrorMsg )
302 {
303 if( !aErrorMsg->empty() )
304 *aErrorMsg += "\n";
305
306 wxString msg;
307
308 msg.Printf( _( "Cannot copy file '%s'." ), destFile.GetFullPath() );
309 *aErrorMsg += msg;
310 }
311
312 result = false;
313 }
314 }
315
316 return result;
317}
318
319
321{
322 wxFFileInputStream input( GetHtmlFile().GetFullPath() );
323 wxString separator( wxT( "\x9" ) );
324 wxTextInputStream text( input, separator, wxConvUTF8 );
325
326 /* Open HTML file and get the text between the title tags */
327 if( m_title == wxEmptyString )
328 {
329 int start = 0;
330 int finish = 0;
331 bool done = false;
332
333 while( input.IsOk() && !input.Eof() && !done )
334 {
335 wxString line = text.ReadLine();
336 wxString upperline = line.Clone().Upper();
337
338 start = upperline.Find( wxT( "<TITLE>" ) );
339 finish = upperline.Find( wxT( "</TITLE>" ) );
340 int length = finish - start - 7;
341
342 // find the opening tag
343 if( start != wxNOT_FOUND )
344 {
345 if( finish != wxNOT_FOUND )
346 {
347 m_title = line( start + 7, length );
348 }
349 else
350 {
351 m_title = line.Mid( start + 7 );
352 }
353
354 done = true;
355 }
356 else
357 {
358 if( finish != wxNOT_FOUND )
359 {
360 m_title += line.SubString( 0, finish );
361 done = true;
362 }
363 }
364
365 // Remove line endings
366 m_title.Replace( wxT( "\r" ), wxT( " " ) );
367 m_title.Replace( wxT( "\n" ), wxT( " " ) );
368 }
369 }
370
371 return &m_title;
372}
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
#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.