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