KiCad PCB EDA Suite
Loading...
Searching...
No Matches
pcb_io_mgr.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) 2011-2012 SoftPLC Corporation, Dick Hollenbeck <[email protected]>
5 * Copyright The 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, see <https://www.gnu.org/licenses/>.
19 */
20
21#include <wx/filename.h>
22#include <wx/uri.h>
23
24#include <config.h>
25#include <board.h>
26#include <footprint.h>
27#include <kiway_player.h>
30#include <pcb_io/pcb_io_mgr.h>
31
55#include <reporter.h>
57
58
59#define FMT_UNIMPLEMENTED _( "Plugin '%s' does not implement the '%s' function." )
60#define FMT_NOTFOUND _( "Plugin type '%s' is not found." )
61
62
63// Some day plugins might be in separate DLL/DSOs, simply because of numbers of them
64// and code size. Until then, use the simplest method:
65
66// This implementation is one of two which could be done.
67// The other one would cater to DLL/DSO's. But since it would be nearly
68// impossible to link a KICAD type DLL/DSO right now without pulling in all
69// ::Draw() functions, I forgo that option temporarily.
70
71// Some day it may be possible to have some built in AND some DLL/DSO
72// plugins coexisting.
73
74
76{
77 // This implementation is subject to change, any magic is allowed here.
78 // The public IO_MGR API is the only pertinent public information.
79
80 return PLUGIN_REGISTRY::Instance()->Create( aFileType );
81}
82
83
84const wxString PCB_IO_MGR::ShowType( PCB_FILE_T aType )
85{
86 if( aType == PCB_IO_MGR::NESTED_TABLE )
88
89 const auto& plugins = PLUGIN_REGISTRY::Instance()->AllPlugins();
90
91 for( const auto& plugin : plugins )
92 {
93 if ( plugin.m_type == aType )
94 return plugin.m_name;
95 }
96
97 return wxString::Format( _( "UNKNOWN (%d)" ), aType );
98}
99
100
102{
105
106 const auto& plugins = PLUGIN_REGISTRY::Instance()->AllPlugins();
107
108 for( const auto& plugin : plugins )
109 {
110 if( plugin.m_name.CmpNoCase( aType ) == 0 )
111 return plugin.m_type;
112 }
113
115}
116
117
119{
120 switch( aFileType )
121 {
122 case ALLEGRO:
123 return true;
124
125 default:
126 return false;
127 }
128}
129
130
132{
133 switch( aFileType )
134 {
136 case EAGLE:
137 case EASYEDA:
138 case EASYEDAPRO:
139 case EASYEDAPRO_V3:
140 case GEDA_PCB:
141 case ALTIUM_DESIGNER:
144 case ALLEGRO:
145 return true;
146
147 default:
148 return false;
149 }
150}
151
152
153// The KIWAY_PLAYER::OpenProjectFiles() API knows nothing about plugins, so
154// determine how to load the BOARD here
156{
157 const auto& plugins = PCB_IO_MGR::PLUGIN_REGISTRY::Instance()->AllPlugins();
158
159 for( const auto& plugin : plugins )
160 {
161 bool isKiCad = plugin.m_type == PCB_IO_MGR::KICAD_SEXP || plugin.m_type == PCB_IO_MGR::LEGACY;
162
163 if( ( aCtl & KICTL_KICAD_ONLY ) && !isKiCad )
164 continue;
165
166 if( ( aCtl & KICTL_NONKICAD_ONLY ) && isKiCad )
167 continue;
168
169 IO_RELEASER<PCB_IO> pi( plugin.m_createFunc() );
170
171 if( pi->CanReadBoard( aFileName ) )
172 return plugin.m_type;
173 }
174
176}
177
178
180{
182
183 if( parser.Parse( aLibPath.ToStdString() ).has_value() )
184 return NESTED_TABLE;
185
186 const auto& plugins = PCB_IO_MGR::PLUGIN_REGISTRY::Instance()->AllPlugins();
187
188 for( const auto& plugin : plugins )
189 {
190 bool isKiCad = plugin.m_type == PCB_IO_MGR::KICAD_SEXP || plugin.m_type == PCB_IO_MGR::LEGACY;
191
192 if( ( aCtl & KICTL_KICAD_ONLY ) && !isKiCad )
193 continue;
194
195 if( ( aCtl & KICTL_NONKICAD_ONLY ) && isKiCad )
196 continue;
197
198 IO_RELEASER<PCB_IO> pi( plugin.m_createFunc() );
199
200 if( pi->CanReadLibrary( aLibPath ) )
201 return plugin.m_type;
202 }
203
205}
206
207
208std::unique_ptr<BOARD> PCB_IO_MGR::Load( PCB_FILE_T aFileType, const wxString& aFileName,
209 const std::map<std::string, UTF8>* aProperties, PROJECT* aProject,
210 PROGRESS_REPORTER* aProgressReporter )
211{
212 IO_RELEASER<PCB_IO> pi( FindPlugin( aFileType ) );
213
214 if( pi ) // test pi->plugin
215 {
216 pi->SetProgressReporter( aProgressReporter );
217 return pi->LoadBoard( aFileName, aProperties, aProject );
218 }
219
220 THROW_IO_ERROR( wxString::Format( FMT_NOTFOUND, ShowType( aFileType ).GetData() ) );
221}
222
223
224void PCB_IO_MGR::Save( PCB_FILE_T aFileType, const wxString& aFileName, BOARD& aBoard,
225 const std::map<std::string, UTF8>* aProperties )
226{
227 IO_RELEASER<PCB_IO> pi( FindPlugin( aFileType ) );
228
229 if( pi )
230 {
231 pi->SaveBoard( aFileName, aBoard, aProperties ); // virtual
232 return;
233 }
234
235 THROW_IO_ERROR( wxString::Format( FMT_NOTFOUND, ShowType( aFileType ).GetData() ) );
236}
237
238
239bool PCB_IO_MGR::ConvertLibrary( const std::map<std::string, UTF8>& aOldFileProps, const wxString& aOldFilePath,
240 const wxString& aNewFilePath, REPORTER* aReporter )
241{
243
244 if( oldFileType == PCB_IO_MGR::FILE_TYPE_NONE )
245 return false;
246
247 // A nested library table has no plugin to enumerate it; reject it before dereferencing
248 // the null plugin below.
249 if( oldFileType == PCB_IO_MGR::NESTED_TABLE )
250 return false;
251
252 IO_RELEASER<PCB_IO> oldFilePI( PCB_IO_MGR::FindPlugin( oldFileType ) );
254
255 if( !oldFilePI || !kicadPI )
256 return false;
257
258 wxArrayString fpNames;
259 wxFileName newFileName( aNewFilePath );
260
261 if( newFileName.HasExt() )
262 {
263 wxString extraDir = newFileName.GetFullName();
264 newFileName.ClearExt();
265 newFileName.SetName( "" );
266 newFileName.AppendDir( extraDir );
267 }
268
269 if( !newFileName.DirExists() && !wxFileName::Mkdir( aNewFilePath, wxS_DIR_DEFAULT ) )
270 return false;
271
272 try
273 {
274 bool bestEfforts = false; // throw on first error
275 oldFilePI->FootprintEnumerate( fpNames, aOldFilePath, bestEfforts, &aOldFileProps );
276 std::map<std::string, UTF8> props { { "skip_cache_validation", "" } };
277
278 for ( const wxString& fpName : fpNames )
279 {
280 std::unique_ptr<const FOOTPRINT> fp( oldFilePI->GetEnumeratedFootprint( aOldFilePath, fpName,
281 &aOldFileProps ) );
282
283 try
284 {
285 kicadPI->FootprintSave( aNewFilePath, fp.get(), &props );
286 }
287 catch( ... )
288 {
289 // Footprints that cannot be saved are just skipped. This is not see
290 // as a fatal error.
291 // this can be just a illegal filename used for the footprint
292 if( aReporter )
293 {
294 aReporter->Report( wxString::Format( "Footprint \"%s\" can't be saved. Skipped",
295 fpName ),
297 }
298 }
299 }
300 }
301 catch( IO_ERROR& io_err )
302 {
303 if( aReporter )
304 {
305 aReporter->Report( wxString::Format( "Library '%s' Convert err: \"%s\"",
306 aOldFilePath,
307 io_err.What() ),
309 }
310
311 return false;
312 }
313 catch( ... )
314 {
315 return false;
316 }
317
318 return true;
319}
320
321
322// These text strings are "truth" for identifying the plugins. If you change the spellings,
323// you will obsolete library tables, so don't do it. Additions are OK.
324
325// clang-format off
328 wxT( "KiCad" ),
329 []() -> PCB_IO* { return new PCB_IO_KICAD_SEXPR; } );
330
333 wxT( "Legacy" ),
334 []() -> PCB_IO* { return new PCB_IO_KICAD_LEGACY; } );
335
336// Keep non-KiCad plugins in alphabetical order
337
340 wxT( "Allegro" ),
341 []() -> PCB_IO* { return new PCB_IO_ALLEGRO; } );
342
345 wxT( "Altium Circuit Maker" ),
346 []() -> PCB_IO* { return new PCB_IO_ALTIUM_CIRCUIT_MAKER; } );
347
350 wxT( "Altium Circuit Studio" ),
351 []() -> PCB_IO* { return new PCB_IO_ALTIUM_CIRCUIT_STUDIO; } );
352
355 wxT( "Altium Designer" ),
356 []() -> PCB_IO* { return new PCB_IO_ALTIUM_DESIGNER; } );
357
360 wxT( "CADSTAR PCB Archive" ),
361 []() -> PCB_IO* { return new PCB_IO_CADSTAR_ARCHIVE; } );
362
365 wxT( "Eagle" ),
366 []() -> PCB_IO* { return new PCB_IO_EAGLE; } );
367
370 wxT( "EasyEDA / JLCEDA Std" ),
371 []() -> PCB_IO* { return new PCB_IO_EASYEDA; });
372
375 wxT( "EasyEDA / JLCEDA Pro" ),
376 []() -> PCB_IO* { return new PCB_IO_EASYEDAPRO; });
377
380 wxT( "EasyEDA / JLCEDA Pro v3" ),
381 []() -> PCB_IO* { return new PCB_IO_EASYEDAPRO_V3; });
382
385 wxT( "Fabmaster" ),
386 []() -> PCB_IO* { return new PCB_IO_FABMASTER; } );
387
390 wxT( "gEDA / Lepton EDA" ),
391 []() -> PCB_IO* { return new PCB_IO_GEDA; } );
392
395 wxT( "P-Cad" ),
396 []() -> PCB_IO* { return new PCB_IO_PCAD; } );
397
400 wxT( "Solidworks PCB" ),
401 []() -> PCB_IO* { return new PCB_IO_SOLIDWORKS; } );
402
405 wxT( "IPC-2581" ),
406 []() -> PCB_IO* { return new PCB_IO_IPC2581; } );
407
410 wxT( "ODB++" ),
411 []() -> PCB_IO* { return new PCB_IO_ODBPP; } );
412
415 wxT( "PADS" ),
416 []() -> PCB_IO* { return new PCB_IO_PADS(); } );
417
420 wxT( "Sprint Layout" ),
421 []() -> PCB_IO* { return new PCB_IO_SPRINT_LAYOUT; } );
422
425 wxT( "DipTrace" ),
426 []() -> PCB_IO* { return new PCB_IO_DIPTRACE; } );
427
430 wxT( "Easy-PC" ),
431 []() -> PCB_IO* { return new PCB_IO_EASYPC; } );
432
435 wxT( "Protel Autotrax" ),
436 []() -> PCB_IO* { return new PCB_IO_AUTOTRAX; } );
437
440 wxT( "PADS Binary" ),
441 []() -> PCB_IO* { return new PCB_IO_PADS_BINARY(); } );
442// clang-format on
Information pertinent to a Pcbnew printed circuit board.
Definition board.h:410
Hold an error message and may be used when throwing exceptions containing meaningful error messages.
virtual const wxString What() const
A composite of Problem() and Where()
tl::expected< LIBRARY_TABLE_IR, LIBRARY_PARSE_ERROR > Parse(const std::filesystem::path &aPath)
static const wxString TABLE_TYPE_NAME
Read-only importer for Protel Autotrax (.PCB, "PCB FILE 4") and Easytrax (.PCB, "PCB FILE 5") layout ...
Works with Eagle 6.x XML board files and footprints to implement the Pcbnew PCB_IO API or a portion o...
A PCB_IO derivation for saving and loading Geda PCB files.
Definition pcb_io_geda.h:59
A PCB_IO derivation which could possibly be put into a DLL/DSO.
A PCB_IO derivation for saving and loading Pcbnew s-expression formatted files.
PCB_IO * Create(PCB_FILE_T aFileType) const
Definition pcb_io_mgr.h:120
const std::vector< ENTRY > & AllPlugins() const
Definition pcb_io_mgr.h:133
static PLUGIN_REGISTRY * Instance()
Definition pcb_io_mgr.h:99
static bool ConvertLibrary(const std::map< std::string, UTF8 > &aOldFileProps, const wxString &aOldFilePath, const wxString &aNewFilePath, REPORTER *aReporter)
Convert a schematic symbol library to the latest KiCad format.
static bool ImportPopulatesProjectSettings(PCB_FILE_T aFileType)
Return true when importing aFileType writes netclasses, rules or other settings that belong to the pr...
static PCB_FILE_T EnumFromStr(const wxString &aFileType)
Return the PCB_FILE_T from the corresponding plugin type name: "kicad", "legacy", etc.
PCB_FILE_T
The set of file types that the PCB_IO_MGR knows about, and for which there has been a plugin written,...
Definition pcb_io_mgr.h:52
@ KICAD_SEXP
S-expression Pcbnew file format.
Definition pcb_io_mgr.h:54
@ EASYPC
Easy-PC / DesignSpark PCB.
Definition pcb_io_mgr.h:76
@ GEDA_PCB
Geda PCB file formats.
Definition pcb_io_mgr.h:66
@ ALTIUM_DESIGNER
Definition pcb_io_mgr.h:59
@ LEGACY
Legacy Pcbnew file formats prior to s-expression.
Definition pcb_io_mgr.h:55
@ ALTIUM_CIRCUIT_MAKER
Definition pcb_io_mgr.h:57
@ ALTIUM_CIRCUIT_STUDIO
Definition pcb_io_mgr.h:58
@ CADSTAR_PCB_ARCHIVE
Definition pcb_io_mgr.h:60
@ PCB_FILE_UNKNOWN
0 is not a legal menu id on Mac
Definition pcb_io_mgr.h:53
static void Save(PCB_FILE_T aFileType, const wxString &aFileName, BOARD &aBoard, const std::map< std::string, UTF8 > *aProperties=nullptr)
Write either a full aBoard to a storage file in a format that this implementation knows about,...
static PCB_IO * FindPlugin(PCB_FILE_T aFileType)
Return a PCB_IO which the caller can use to import, export, save, or load design documents.
static PCB_FILE_T FindPluginTypeFromBoardPath(const wxString &aFileName, int aCtl=0)
Return a plugin type given a path for a board file.
static std::unique_ptr< BOARD > Load(PCB_FILE_T aFileType, const wxString &aFileName, const std::map< std::string, UTF8 > *aProperties=nullptr, PROJECT *aProject=nullptr, PROGRESS_REPORTER *aProgressReporter=nullptr)
Find the requested PCB_IO and if found, calls the PCB_IO::LoadBoard() function on it using the argume...
static PCB_FILE_T GuessPluginTypeFromLibPath(const wxString &aLibPath, int aCtl=0)
Return a plugin type given a footprint library's libPath.
static bool ImportGeneratesProjectLibrary(PCB_FILE_T aFileType)
Return true when importing aFileType should materialize a project footprint library.
static const wxString ShowType(PCB_FILE_T aFileType)
Return a brief name for a plugin given aFileType enum.
PCB I/O plugin for importing the native PADS Layout binary .pcb format, distinct from the ASCII forma...
A base class that BOARD loading and saving plugins should derive from.
Definition pcb_io.h:77
A progress reporter interface for use in multi-threaded environments.
Container for project specific data.
Definition project.h:63
A pure virtual class used to derive REPORTER objects from.
Definition reporter.h:73
virtual REPORTER & Report(const wxString &aText, SEVERITY aSeverity=RPT_SEVERITY_UNDEFINED)
Report a string with a given severity.
Definition reporter.h:102
#define _(s)
#define THROW_IO_ERROR(msg)
macro which captures the "call site" values of FILE_, __FUNCTION & LINE
std::unique_ptr< T > IO_RELEASER
Helper to hold and release an IO_BASE object when exceptions are thrown.
Definition io_mgr.h:33
#define KICTL_KICAD_ONLY
chosen file is from KiCad according to user
#define KICTL_NONKICAD_ONLY
chosen file is non-KiCad according to user
Pcbnew PCB_IO for DipTrace binary .dip board files.
PCB_IO for Number One Systems Easy-PC and RS DesignSpark PCB boards and symbol libraries (....
Geda PCB file plugin definition file.
static PCB_IO_MGR::REGISTER_PLUGIN registerODBPPPlugin(PCB_IO_MGR::ODBPP, wxT("ODB++"), []() -> PCB_IO *{ return new PCB_IO_ODBPP;})
static PCB_IO_MGR::REGISTER_PLUGIN registerEasyEDAProV3Plugin(PCB_IO_MGR::EASYEDAPRO_V3, wxT("EasyEDA / JLCEDA Pro v3"), []() -> PCB_IO *{ return new PCB_IO_EASYEDAPRO_V3;})
static PCB_IO_MGR::REGISTER_PLUGIN registerSolidworksPCBPlugin(PCB_IO_MGR::SOLIDWORKS_PCB, wxT("Solidworks PCB"), []() -> PCB_IO *{ return new PCB_IO_SOLIDWORKS;})
static PCB_IO_MGR::REGISTER_PLUGIN registerEasyEDAProPlugin(PCB_IO_MGR::EASYEDAPRO, wxT("EasyEDA / JLCEDA Pro"), []() -> PCB_IO *{ return new PCB_IO_EASYEDAPRO;})
static PCB_IO_MGR::REGISTER_PLUGIN registerPadsBinaryPlugin(PCB_IO_MGR::PADS_BINARY, wxT("PADS Binary"), []() -> PCB_IO *{ return new PCB_IO_PADS_BINARY();})
static PCB_IO_MGR::REGISTER_PLUGIN registerPadsPlugin(PCB_IO_MGR::PADS, wxT("PADS"), []() -> PCB_IO *{ return new PCB_IO_PADS();})
static PCB_IO_MGR::REGISTER_PLUGIN registerEasyEDAPlugin(PCB_IO_MGR::EASYEDA, wxT("EasyEDA / JLCEDA Std"), []() -> PCB_IO *{ return new PCB_IO_EASYEDA;})
static PCB_IO_MGR::REGISTER_PLUGIN registerGPCBPlugin(PCB_IO_MGR::GEDA_PCB, wxT("gEDA / Lepton EDA"), []() -> PCB_IO *{ return new PCB_IO_GEDA;})
static PCB_IO_MGR::REGISTER_PLUGIN registerKicadPlugin(PCB_IO_MGR::KICAD_SEXP, wxT("KiCad"), []() -> PCB_IO *{ return new PCB_IO_KICAD_SEXPR;})
static PCB_IO_MGR::REGISTER_PLUGIN registerIPC2581Plugin(PCB_IO_MGR::IPC2581, wxT("IPC-2581"), []() -> PCB_IO *{ return new PCB_IO_IPC2581;})
static PCB_IO_MGR::REGISTER_PLUGIN registerPcadPlugin(PCB_IO_MGR::PCAD, wxT("P-Cad"), []() -> PCB_IO *{ return new PCB_IO_PCAD;})
static PCB_IO_MGR::REGISTER_PLUGIN registerEaglePlugin(PCB_IO_MGR::EAGLE, wxT("Eagle"), []() -> PCB_IO *{ return new PCB_IO_EAGLE;})
static PCB_IO_MGR::REGISTER_PLUGIN registerEasyPcPlugin(PCB_IO_MGR::EASYPC, wxT("Easy-PC"), []() -> PCB_IO *{ return new PCB_IO_EASYPC;})
static PCB_IO_MGR::REGISTER_PLUGIN registerAltiumCircuitStudioPlugin(PCB_IO_MGR::ALTIUM_CIRCUIT_STUDIO, wxT("Altium Circuit Studio"), []() -> PCB_IO *{ return new PCB_IO_ALTIUM_CIRCUIT_STUDIO;})
static PCB_IO_MGR::REGISTER_PLUGIN registerAltiumDesignerPlugin(PCB_IO_MGR::ALTIUM_DESIGNER, wxT("Altium Designer"), []() -> PCB_IO *{ return new PCB_IO_ALTIUM_DESIGNER;})
static PCB_IO_MGR::REGISTER_PLUGIN registerCadstarArchivePlugin(PCB_IO_MGR::CADSTAR_PCB_ARCHIVE, wxT("CADSTAR PCB Archive"), []() -> PCB_IO *{ return new PCB_IO_CADSTAR_ARCHIVE;})
static PCB_IO_MGR::REGISTER_PLUGIN registerDipTracePlugin(PCB_IO_MGR::DIPTRACE, wxT("DipTrace"), []() -> PCB_IO *{ return new PCB_IO_DIPTRACE;})
static PCB_IO_MGR::REGISTER_PLUGIN registerLegacyPlugin(PCB_IO_MGR::LEGACY, wxT("Legacy"), []() -> PCB_IO *{ return new PCB_IO_KICAD_LEGACY;})
static PCB_IO_MGR::REGISTER_PLUGIN registerFabmasterPlugin(PCB_IO_MGR::FABMASTER, wxT("Fabmaster"), []() -> PCB_IO *{ return new PCB_IO_FABMASTER;})
static PCB_IO_MGR::REGISTER_PLUGIN registerAltiumCircuitMakerPlugin(PCB_IO_MGR::ALTIUM_CIRCUIT_MAKER, wxT("Altium Circuit Maker"), []() -> PCB_IO *{ return new PCB_IO_ALTIUM_CIRCUIT_MAKER;})
static PCB_IO_MGR::REGISTER_PLUGIN registerAutotraxPlugin(PCB_IO_MGR::AUTOTRAX, wxT("Protel Autotrax"), []() -> PCB_IO *{ return new PCB_IO_AUTOTRAX;})
static PCB_IO_MGR::REGISTER_PLUGIN registerSprintLayoutPlugin(PCB_IO_MGR::SPRINT_LAYOUT, wxT("Sprint Layout"), []() -> PCB_IO *{ return new PCB_IO_SPRINT_LAYOUT;})
static PCB_IO_MGR::REGISTER_PLUGIN registerAllegroPlugin(PCB_IO_MGR::ALLEGRO, wxT("Allegro"), []() -> PCB_IO *{ return new PCB_IO_ALLEGRO;})
Pcbnew PLUGIN for P-Cad 200x ASCII *.pcb format.
@ RPT_SEVERITY_WARNING
@ RPT_SEVERITY_ERROR
#define FMT_NOTFOUND
Register a plugin.
Definition pcb_io_mgr.h:152
Definition of file extensions used in Kicad.