KiCad PCB EDA Suite
Loading...
Searching...
No Matches
import_proj.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) 2019 CERN
5 * Copyright The KiCad Developers, see AUTHORS.txt for contributors.
6 *
7 * This program is free software: you can redistribute it and/or modify it
8 * under the terms of the GNU General Public License as published by the
9 * Free Software Foundation, either version 3 of the License, or (at your
10 * option) any later version.
11 *
12 * This program is distributed in the hope that it will be useful, but
13 * WITHOUT ANY WARRANTY; without even the implied warranty of
14 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
15 * General Public License for more details.
16 *
17 * You should have received a copy of the GNU General Public License along
18 * with this program. If not, see <http://www.gnu.org/licenses/>.
19 */
20
21#include "import_proj.h"
23#include <macros.h>
24#include <string_utils.h>
25#include <richio.h>
26
27#include <wx/fileconf.h>
28#include <wx/filedlg.h>
29#include <wx/msgdlg.h>
30#include <wx/tokenzr.h>
31#include <wx/dir.h>
32#include <wx/textfile.h>
33#include <wx/wfstream.h>
34
35#include <kiway.h>
36#include <kiway_player.h>
37#include <kicad_manager_frame.h>
38#include <pcb_edit_frame.h>
39#include <sch_edit_frame.h>
40
41#include <sch_io/sch_io_mgr.h>
42#include <pcb_io/pcb_io_mgr.h>
43#include <project_sch.h>
44#include <project_pcb.h>
45
49#include <io/pads/pads_common.h>
51
52#include <wx/log.h>
53
54
56 const std::vector<wxString>& aSchFileExtensions,
57 const std::vector<wxString>& aPcbFileExtensions ) :
58 m_frame( aFrame ),
59 m_schExtenstions( aSchFileExtensions ), m_pcbExtenstions( aPcbFileExtensions )
60{
61}
62
63
65{
66 // Append a new directory with the same name of the project file
67 // Keep iterating until we find an empty directory
68 wxString newDir = m_TargetProj.GetName();
69 int attempt = 0;
70
71 m_TargetProj.AppendDir( newDir );
72
73 while( m_TargetProj.DirExists() )
74 {
75 m_TargetProj.RemoveLastDir();
76 wxString suffix = wxString::Format( "_%d", ++attempt );
77 m_TargetProj.AppendDir( newDir + suffix );
78 }
79}
80
81
83{
84 wxString m_file;
85
86public:
87 SCOPED_FILE_REMOVER( const wxString& aFile ) : m_file( aFile ) {}
88 ~SCOPED_FILE_REMOVER() { wxRemoveFile( m_file ); }
89};
90
91
92void IMPORT_PROJ_HELPER::ImportIndividualFile( KICAD_T aFT, int aImportedFileType )
93{
94 FRAME_T frame_type;
95 wxString appImportFile;
96 std::vector<wxString> neededExts;
97
98 switch( aFT )
99 {
100 case SCHEMATIC_T:
101 neededExts = m_schExtenstions;
102 frame_type = FRAME_SCH;
103 break;
104
105 case PCB_T:
106 neededExts = m_pcbExtenstions;
107 frame_type = FRAME_PCB_EDITOR;
108 break;
109
110 default: return;
111 }
112
113 std::vector<SCOPED_FILE_REMOVER> copiedFiles;
114
115 for( wxString ext : neededExts )
116 {
117 if( ext == wxS( "INPUT" ) )
118 ext = m_InputFile.GetExt();
119
120 wxFileName candidate = m_InputFile;
121 candidate.SetExt( ext );
122
123 if( !candidate.FileExists() )
124 continue;
125
126 wxFileName targetFile( m_TargetProj.GetPath(), candidate.GetName(), candidate.GetExt() );
127
128 if( !targetFile.FileExists() )
129 {
130 bool copied = wxCopyFile( candidate.GetFullPath(), targetFile.GetFullPath(), false );
131
132 if( copied )
133 {
134 // Will be auto-removed
135 copiedFiles.emplace_back( targetFile.GetFullPath() );
136 }
137 }
138
139 // Pick the first file to pass to application
140 if( appImportFile.empty() && targetFile.FileExists() )
141 appImportFile = targetFile.GetFullPath();
142 }
143
144 if( appImportFile.empty() )
145 return;
146
147 doImport( appImportFile, frame_type, aImportedFileType );
148}
149
150
151void IMPORT_PROJ_HELPER::doImport( const wxString& aFile, FRAME_T aFrameType, int aImportedFileType )
152{
153 if( KIWAY_PLAYER* frame = m_frame->Kiway().Player( aFrameType, true ) )
154 {
155 std::stringstream ss;
156 ss << aImportedFileType << '\n' << TO_UTF8( aFile );
157
158 for( const auto& [key, value] : m_properties )
159 ss << '\n' << key << '\n' << value.wx_str();
160
161 std::string packet = ss.str();
162 frame->Kiway().ExpressMail( aFrameType, MAIL_IMPORT_FILE, packet, m_frame );
163
164 if( !frame->IsShownOnScreen() )
165 frame->Show( true );
166
167 // On Windows, Raise() does not bring the window on screen, when iconized
168 if( frame->IsIconized() )
169 frame->Iconize( false );
170
171 frame->Raise();
172 }
173}
174
175
177{
178 wxFileName fname = m_InputFile;
179
180 if( fname.GetExt() == wxS( "epro" ) || fname.GetExt() == wxS( "zip" ) )
181 {
182 nlohmann::json project = EASYEDAPRO::ReadProjectOrDeviceFile( fname.GetFullPath() );
183
184 std::map<wxString, EASYEDAPRO::PRJ_SCHEMATIC> prjSchematics = project.at( "schematics" );
185 std::map<wxString, EASYEDAPRO::PRJ_BOARD> prjBoards = project.at( "boards" );
186 std::map<wxString, wxString> prjPcbNames = project.at( "pcbs" );
187
188 std::vector<IMPORT_PROJECT_DESC> toImport =
190
191 if( toImport.size() > 1 )
192 toImport = DIALOG_IMPORT_CHOOSE_PROJECT::RunModal( m_frame, toImport );
193
194 if( toImport.size() == 1 )
195 {
196 const IMPORT_PROJECT_DESC& desc = toImport[0];
197
198 m_properties["pcb_id"] = desc.PCBId;
199 m_properties["sch_id"] = desc.SchematicId;
200 }
201 else
202 {
203 m_properties["pcb_id"] = "";
204 m_properties["sch_id"] = "";
205 }
206 }
207}
208
209
210void IMPORT_PROJ_HELPER::addLocalLibraries( const std::set<wxString>& aNames, FRAME_T aFrameType )
211{
212 KIWAY_PLAYER* frame = m_frame->Kiway().Player( aFrameType, true );
213
214 std::stringstream ss;
215
216 // First line is the source project directory so the handler can distinguish
217 // project-local libraries from external fixed-path references.
218 ss << TO_UTF8( m_InputFile.GetPath() ) << '\n';
219
220 for( const wxString& name : aNames )
221 {
222 wxFileName fname( name );
223 fname.MakeAbsolute( m_InputFile.GetPath() );
224 ss << TO_UTF8( fname.GetFullPath() ) << '\n';
225 }
226
227 std::string packet = ss.str();
228 frame->Kiway().ExpressMail( aFrameType, MAIL_ADD_LOCAL_LIB, packet, m_frame );
229}
230
231
233{
234 wxFileConfig config( wxEmptyString, wxEmptyString, wxEmptyString, m_InputFile.GetFullPath(),
235 wxCONFIG_USE_NO_ESCAPE_CHARACTERS );
236
237 wxString groupname;
238 long groupid;
239
240 std::set<wxString> sch_file;
241 std::set<wxString> pcb_file;
242 std::set<wxString> sch_libs;
243 std::set<wxString> pcb_libs;
244
245 for( bool more = config.GetFirstGroup( groupname, groupid ); more;
246 more = config.GetNextGroup( groupname, groupid ) )
247 {
248 if( !groupname.StartsWith( wxS( "Document" ) ) )
249 continue;
250
251 wxString number = groupname.Mid( 8 );
252 long docNumber;
253
254 if( !number.ToLong( &docNumber ) )
255 continue;
256
257 wxString path = config.Read( groupname + wxS( "/DocumentPath" ), wxEmptyString );
258
259 if( path.empty() )
260 continue;
261
262 wxFileName fname( path, wxPATH_WIN );
263
264 if( !fname.IsAbsolute() )
265 fname.MakeAbsolute( m_InputFile.GetPath() );
266
267 if( !fname.GetExt().CmpNoCase( "PCBDOC" ) )
268 pcb_file.insert( fname.GetFullPath() );
269
270 if( !fname.GetExt().CmpNoCase( "SCHDOC" ) )
271 sch_file.insert( fname.GetFullPath() );
272
273 if( !fname.GetExt().CmpNoCase( "PCBLIB" ) )
274 pcb_libs.insert( fname.GetFullPath() );
275
276 if( !fname.GetExt().CmpNoCase( "SCHLIB" ) )
277 sch_libs.insert( fname.GetFullPath() );
278 }
279
280 addLocalLibraries( sch_libs, FRAME_SCH );
282
283 m_properties["project_file"] = m_InputFile.GetFullPath();
284
285 int ii = 0;
286
287 for( auto& path : sch_file )
288 {
289 std::string key = "sch" + std::to_string( ii++ );
290 m_properties[key] = path.ToStdString();
291 }
292
293 if( !sch_file.empty() )
294 doImport( "", FRAME_SCH, SCH_IO_MGR::SCH_ALTIUM );
295
296 if( !pcb_file.empty() )
298}
299
300
302{
303 m_properties.clear();
304
306
307 if( !related.HasPcb() && !related.HasSchematic() )
308 return;
309
310 std::vector<SCOPED_FILE_REMOVER> copiedFiles;
311
312 auto copyAndImport = [&]( const wxString& sourceFile, FRAME_T frameType, int fileType )
313 {
314 if( sourceFile.IsEmpty() )
315 return;
316
317 wxFileName srcFn( sourceFile );
318 wxFileName targetFile( m_TargetProj.GetPath(), srcFn.GetName(), srcFn.GetExt() );
319
320 if( !targetFile.FileExists() )
321 {
322 bool copied = wxCopyFile( srcFn.GetFullPath(), targetFile.GetFullPath(), false );
323
324 if( copied )
325 copiedFiles.emplace_back( targetFile.GetFullPath() );
326 }
327
328 if( targetFile.FileExists() )
329 doImport( targetFile.GetFullPath(), frameType, fileType );
330 };
331
332 copyAndImport( related.schematicFile, FRAME_SCH, SCH_IO_MGR::SCH_PADS );
333 copyAndImport( related.pcbFile, FRAME_PCB_EDITOR, PCB_IO_MGR::PADS );
334}
335
336
338{
339 wxFileName prjFile = m_InputFile;
340
341 if( prjFile.GetExt().CmpNoCase( "prj" ) != 0 )
342 return;
343
344 wxTextFile file;
345
346 if( !file.Open( prjFile.GetFullPath() ) )
347 {
348 wxLogWarning( _( "Could not open gEDA / Lepton EDA project file '%s'." ), prjFile.GetFullPath() );
349 return;
350 }
351
352 std::vector<wxFileName> schFiles;
353 wxString outputName;
354 wxString elementsDir;
355
356 for( size_t i = 0; i < file.GetLineCount(); ++i )
357 {
358 wxString line = file.GetLine( i );
359
360 line.Trim( true );
361 line.Trim( false );
362
363 if( line.IsEmpty() )
364 continue;
365
366 if( line.StartsWith( wxT( "#" ) ) || line.StartsWith( wxT( ";" ) ) )
367 continue;
368
369 int commentPos = line.Find( wxT( "#" ) );
370
371 if( commentPos != wxNOT_FOUND )
372 {
373 line = line.Left( commentPos );
374 line.Trim( true );
375 line.Trim( false );
376 }
377
378 if( line.IsEmpty() )
379 continue;
380
381 wxStringTokenizer tok( line );
382
383 if( !tok.HasMoreTokens() )
384 continue;
385
386 wxString keyword = tok.GetNextToken();
387
388 if( keyword.CmpNoCase( "schematics" ) == 0 )
389 {
390 while( tok.HasMoreTokens() )
391 {
392 wxString schToken = tok.GetNextToken();
393 wxFileName schFile( schToken );
394
395 if( !schFile.IsAbsolute() )
396 schFile.MakeAbsolute( prjFile.GetPath() );
397
398 schFiles.push_back( schFile );
399 }
400 }
401 else if( keyword.CmpNoCase( "output-name" ) == 0 )
402 {
403 wxString rest = line.Mid( keyword.length() );
404 rest.Trim( true );
405 rest.Trim( false );
406 outputName = rest;
407 }
408 else if( keyword.CmpNoCase( "elements-dir" ) == 0 )
409 {
410 wxString rest = line.Mid( keyword.length() );
411 rest.Trim( true );
412 rest.Trim( false );
413 elementsDir = rest;
414 }
415 }
416
417 if( !elementsDir.IsEmpty() )
418 {
419 wxFileName elementsPath( elementsDir );
420
421 if( !elementsPath.IsAbsolute() )
422 elementsPath.MakeAbsolute( prjFile.GetPath() );
423
424 m_properties["elements_dir"] = elementsPath.GetFullPath().ToStdString();
425 }
426
427 if( schFiles.empty() )
428 {
429 wxFileName candidate = prjFile;
430 candidate.SetExt( wxS( "sch" ) );
431
432 if( candidate.FileExists() )
433 schFiles.push_back( candidate );
434 }
435
436 auto promptForMissingFile =
437 [&]( const wxString& aTitle, const wxString& aWildcard, wxFileName& aFile ) -> bool
438 {
439 wxString defaultDir = aFile.GetPath();
440
441 if( defaultDir.IsEmpty() )
442 defaultDir = prjFile.GetPath();
443
444 wxFileDialog dlg( m_frame, aTitle, defaultDir, wxEmptyString, aWildcard,
445 wxFD_OPEN | wxFD_FILE_MUST_EXIST );
446
447 if( dlg.ShowModal() == wxID_OK )
448 {
449 aFile.Assign( dlg.GetPath() );
450 return true;
451 }
452
453 aFile.Clear();
454 return false;
455 };
456
457 std::vector<wxFileName> resolvedSchFiles;
458 const wxString schWildcard = _( "gEDA / Lepton EDA schematic files" ) + wxS( " (*.sch)|*.sch" );
459
460 for( wxFileName schFile : schFiles )
461 {
462 if( !schFile.FileExists() )
463 {
464 if( !promptForMissingFile( _( "Locate gEDA / Lepton EDA Schematic" ), schWildcard, schFile ) )
465 continue;
466 }
467
468 resolvedSchFiles.push_back( schFile );
469 }
470
471 if( schFiles.empty() && resolvedSchFiles.empty() )
472 {
473 wxFileName schFile;
474
475 if( promptForMissingFile( _( "Locate gEDA / Lepton EDA Schematic" ), schWildcard, schFile ) )
476 resolvedSchFiles.push_back( schFile );
477 }
478
479 if( resolvedSchFiles.size() > 1 )
480 {
481 // Pass additional schematic files as a semicolon-delimited property so the
482 // importer can create sub-sheets for each additional page within a single
483 // KiCad project hierarchy.
484 wxString additionalFiles;
485
486 for( size_t i = 1; i < resolvedSchFiles.size(); i++ )
487 {
488 if( !additionalFiles.IsEmpty() )
489 additionalFiles += wxT( ";" );
490
491 additionalFiles += resolvedSchFiles[i].GetFullPath();
492 }
493
494 m_properties["additional_schematics"] = additionalFiles.ToStdString();
495 }
496
497 // Auto-discover subdirectories containing .sym files and pass them as
498 // additional search paths for the importer's symbol resolution.
499 auto discoverSymDirs = [&]( const wxString& aBaseDir, wxString& aSymPaths )
500 {
501 wxDir dir( aBaseDir );
502
503 if( !dir.IsOpened() )
504 return;
505
506 wxString subdir;
507 bool cont = dir.GetFirst( &subdir, wxEmptyString, wxDIR_DIRS );
508
509 while( cont )
510 {
511 wxString subdirPath = aBaseDir + wxFileName::GetPathSeparator() + subdir;
512 wxDir childDir( subdirPath );
513
514 if( childDir.IsOpened() && childDir.HasFiles( wxT( "*.sym" ) ) )
515 {
516 if( !aSymPaths.IsEmpty() )
517 aSymPaths += wxT( "\n" );
518
519 aSymPaths += subdirPath;
520 }
521
522 cont = dir.GetNext( &subdir );
523 }
524 };
525
526 wxString symPaths;
527 discoverSymDirs( prjFile.GetPath(), symPaths );
528
529 if( !resolvedSchFiles.empty() )
530 {
531 wxString schDir = resolvedSchFiles[0].GetPath();
532
533 if( schDir != prjFile.GetPath() )
534 discoverSymDirs( schDir, symPaths );
535 }
536
537 if( !symPaths.IsEmpty() )
538 m_properties["sym_search_paths"] = symPaths.ToStdString();
539
540 if( !resolvedSchFiles.empty() )
541 doImport( resolvedSchFiles[0].GetFullPath(), FRAME_SCH, SCH_IO_MGR::SCH_GEDA );
542
543 wxFileName layoutDir( prjFile.GetPath(), wxEmptyString );
544 layoutDir.RemoveLastDir();
545 layoutDir.AppendDir( wxS( "layout" ) );
546
547 wxFileName pcbFile;
548
549 if( !outputName.IsEmpty() )
550 {
551 wxFileName candidate( layoutDir.GetPath(), outputName, wxS( "pcb" ) );
552
553 if( candidate.FileExists() )
554 pcbFile = candidate;
555 }
556
557 if( !pcbFile.FileExists() )
558 {
559 wxFileName candidate( prjFile.GetPath(), prjFile.GetName(), wxS( "pcb" ) );
560
561 if( candidate.FileExists() )
562 pcbFile = candidate;
563 }
564
565 if( !pcbFile.FileExists() )
566 {
567 wxFileName candidate( layoutDir.GetPath(), prjFile.GetName(), wxS( "pcb" ) );
568
569 if( candidate.FileExists() )
570 pcbFile = candidate;
571 }
572
573 const wxString pcbWildcard = _( "gEDA / Lepton EDA PCB files" ) + wxS( " (*.pcb)|*.pcb" );
574
575 if( !pcbFile.FileExists() )
576 promptForMissingFile( _( "Locate gEDA / Lepton EDA PCB" ), pcbWildcard, pcbFile );
577
578 if( pcbFile.FileExists() )
579 doImport( pcbFile.GetFullPath(), FRAME_PCB_EDITOR, PCB_IO_MGR::GEDA_PCB );
580}
581
582
583void IMPORT_PROJ_HELPER::ImportFiles( int aImportedSchFileType, int aImportedPcbFileType )
584{
585 m_properties.clear();
586
587 if( aImportedSchFileType == SCH_IO_MGR::SCH_EASYEDAPRO
588 || aImportedPcbFileType == PCB_IO_MGR::EASYEDAPRO )
589 {
591 }
592 else if( aImportedSchFileType == SCH_IO_MGR::SCH_ALTIUM
593 || aImportedPcbFileType == PCB_IO_MGR::ALTIUM_DESIGNER )
594 {
596 return;
597 }
598 else if( aImportedSchFileType == SCH_IO_MGR::SCH_GEDA )
599 {
600 if( m_InputFile.GetExt().CmpNoCase( "prj" ) == 0 )
601 {
603 }
604 else if( m_InputFile.GetExt().CmpNoCase( "pcb" ) == 0 )
605 {
606 ImportIndividualFile( PCB_T, aImportedPcbFileType );
607 }
608 else
609 {
610 // When importing a bare .sch file, pass the original source directory
611 // so the importer can find symbols in subdirectories relative to the
612 // gEDA / Lepton EDA schematic, even though the file may be copied to a new location
613 // for the KiCad project.
614 wxString sourceDir = m_InputFile.GetPath();
615 wxString symPaths = sourceDir;
616
617 auto discoverSymDirs = [&]( const wxString& aBaseDir )
618 {
619 wxDir dir( aBaseDir );
620
621 if( !dir.IsOpened() )
622 return;
623
624 wxString subdir;
625 bool cont = dir.GetFirst( &subdir, wxEmptyString, wxDIR_DIRS );
626
627 while( cont )
628 {
629 wxString subdirPath =
630 aBaseDir + wxFileName::GetPathSeparator() + subdir;
631 wxDir childDir( subdirPath );
632
633 if( childDir.IsOpened() && childDir.HasFiles( wxT( "*.sym" ) ) )
634 symPaths += wxT( "\n" ) + subdirPath;
635
636 cont = dir.GetNext( &subdir );
637 }
638 };
639
640 discoverSymDirs( sourceDir );
641 m_properties["sym_search_paths"] = symPaths.ToStdString();
642
643 doImport( m_InputFile.GetFullPath(), FRAME_SCH, SCH_IO_MGR::SCH_GEDA );
644 ImportIndividualFile( PCB_T, aImportedPcbFileType );
645 }
646
647 return;
648 }
649
650 ImportIndividualFile( SCHEMATIC_T, aImportedSchFileType );
651 ImportIndividualFile( PCB_T, aImportedPcbFileType );
652}
const char * name
static std::vector< IMPORT_PROJECT_DESC > RunModal(wxWindow *aParent, const std::vector< IMPORT_PROJECT_DESC > &aProjectDesc)
Create and show a dialog (modal) and returns the data from it after completion.
wxFileName m_TargetProj
Definition import_proj.h:63
void EasyEDAProProjectHandler()
IMPORT_PROJ_HELPER(KICAD_MANAGER_FRAME *aframe, const std::vector< wxString > &aSchFileExtensions, const std::vector< wxString > &aPcbFileExtensions)
std::map< std::string, UTF8 > m_properties
Definition import_proj.h:68
void FindEmptyTargetDir()
Appends a new directory with the name of the project file Keep iterating until an empty directory is ...
std::vector< wxString > m_pcbExtenstions
Definition import_proj.h:74
KICAD_MANAGER_FRAME * m_frame
Definition import_proj.h:66
void ImportFiles(int aImportedSchFileType, int aImportedPcbFileType)
Converts imported files to kicad type files.
void addLocalLibraries(const std::set< wxString > &aLibName, FRAME_T aFrameType)
void ImportIndividualFile(KICAD_T aKicad_T, int aImportedFileType)
wxFileName m_InputFile
Definition import_proj.h:62
std::vector< wxString > m_schExtenstions
Definition import_proj.h:73
void ImportPadsFiles()
Converts PADS ASCII schematic and PCB files to KiCad type files.
void doImport(const wxString &aFile, FRAME_T aFrameType, int aImportedFileType)
The main KiCad project manager frame.
KIWAY & Kiway() const
Return a reference to the KIWAY that this object has an opportunity to participate in.
A wxFrame capable of the OpenProjectFiles function, meaning it can load a portion of a KiCad project.
virtual void ExpressMail(FRAME_T aDestination, MAIL_T aCommand, std::string &aPayload, wxWindow *aSource=nullptr, bool aFromOtherThread=false)
Send aPayload to aDestination from aSource.
Definition kiway.cpp:505
@ GEDA_PCB
Geda PCB file formats.
Definition pcb_io_mgr.h:69
@ ALTIUM_DESIGNER
Definition pcb_io_mgr.h:63
SCOPED_FILE_REMOVER(const wxString &aFile)
#define _(s)
FRAME_T
The set of EDA_BASE_FRAME derivatives, typically stored in EDA_BASE_FRAME::m_Ident.
Definition frame_type.h:33
@ FRAME_PCB_EDITOR
Definition frame_type.h:42
@ FRAME_SCH
Definition frame_type.h:34
This file contains miscellaneous commonly used macros and functions.
@ MAIL_IMPORT_FILE
Definition mail_type.h:48
@ MAIL_ADD_LOCAL_LIB
Definition mail_type.h:54
std::vector< IMPORT_PROJECT_DESC > ProjectToSelectorDialog(const nlohmann::json &aProject, bool aPcbOnly=false, bool aSchOnly=false)
nlohmann::json ReadProjectOrDeviceFile(const wxString &aZipFileName)
RELATED_FILES FindRelatedPadsFiles(const wxString &aFilePath)
Find related PADS project files from a given source file.
Common utilities and types for parsing PADS file formats.
MODEL3D_FORMAT_TYPE fileType(const char *aFileName)
#define TO_UTF8(wxstring)
Convert a wxString to a UTF8 encoded C string for all wxWidgets build modes.
Describes how non-KiCad boards and schematics should be imported as KiCad projects.
Result of detecting related PADS project files.
Definition pads_common.h:73
wxString schematicFile
Path to schematic file if found.
Definition pads_common.h:75
wxString pcbFile
Path to PCB file if found.
Definition pads_common.h:74
bool copied
std::string path
KICAD_T
The set of class identification values stored in EDA_ITEM::m_structType.
Definition typeinfo.h:78
@ PCB_T
Definition typeinfo.h:82
@ SCHEMATIC_T
Definition typeinfo.h:208
Definition of file extensions used in Kicad.