1 /*
2 * This program source code file is part of KiCad, a free EDA CAD application.
3 *
4 * Copyright (C) 2004 Jean-Pierre Charras, jp.charras ar wanadoo.fr
5 * Copyright (C) 2008 Wayne Stambaugh <stambaughw@gmail.com>
6 * Copyright (C) 2004-2021 KiCad Developers, see AUTHORS.txt for contributors.
7 *
8 * This program is free software; you can redistribute it and/or
9 * modify it under the terms of the GNU General Public License
10 * as published by the Free Software Foundation; either version 2
11 * of the License, or (at your option) any later version.
12 *
13 * This program is distributed in the hope that it will be useful,
14 * but WITHOUT ANY WARRANTY; without even the implied warranty of
15 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
16 * GNU General Public License for more details.
17 *
18 * You should have received a copy of the GNU General Public License
19 * along with this program; if not, you may find one here:
20 * http://www.gnu.org/licenses/old-licenses/gpl-2.0.html
21 * or you may search the http://www.gnu.org website for the version 2 license,
22 * or you may write to the Free Software Foundation, Inc.,
23 * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA
24 */
25
26 /**
27 * @file libarch.cpp
28 * @brief Module for generation of symbol archive files.
29 */
30
31 #include <confirm.h>
32 #include <wildcards_and_files_ext.h>
33
34 #include <sch_edit_frame.h>
35 #include <symbol_lib_table.h>
36 #include <symbol_library.h>
37 #include <sch_symbol.h>
38 #include <sch_sheet.h>
39 #include <schematic.h>
40
41
CreateArchiveLibraryCacheFile(bool aUseCurrentSheetFilename)42 bool SCH_EDIT_FRAME::CreateArchiveLibraryCacheFile( bool aUseCurrentSheetFilename )
43 {
44 wxFileName fn;
45
46 if( aUseCurrentSheetFilename )
47 fn = GetScreen()->GetFileName();
48 else
49 fn = Schematic().RootScreen()->GetFileName();
50
51 fn.SetName( fn.GetName() + "-cache" );
52 fn.SetExt( LegacySymbolLibFileExtension );
53
54 bool success = CreateArchiveLibrary( fn.GetFullPath() );
55
56 // Update the schematic symbol library links.
57 // because the lib cache has changed
58 SCH_SCREENS schematic( Schematic().Root() );
59 schematic.UpdateSymbolLinks();
60
61 return success;
62 }
63
64
CreateArchiveLibrary(const wxString & aFileName)65 bool SCH_EDIT_FRAME::CreateArchiveLibrary( const wxString& aFileName )
66 {
67 wxString tmp;
68 wxString errorMsg;
69 SCH_SCREENS screens( Schematic().Root() );
70
71 // Create a new empty library to archive symbols:
72 std::unique_ptr<SYMBOL_LIB> archLib = std::make_unique<SYMBOL_LIB>( SCH_LIB_TYPE::LT_EESCHEMA,
73 aFileName );
74
75 // Save symbols to file only when the library will be fully filled
76 archLib->EnableBuffering();
77
78 /* Examine all screens (not hierarchical sheets) used in the schematic and build a
79 * library of unique symbols found in all screens. Complex hierarchies are not a
80 * problem because we just want to know the library symbols used in the schematic
81 * not their reference.
82 */
83 for( SCH_SCREEN* screen = screens.GetFirst(); screen; screen = screens.GetNext() )
84 {
85
86 for( SCH_ITEM* aItem : screen->Items().OfType( SCH_SYMBOL_T ) )
87 {
88 LIB_SYMBOL* libSymbol = nullptr;
89 SCH_SYMBOL* symbol = static_cast<SCH_SYMBOL*>( aItem );
90
91 try
92 {
93 if( archLib->FindSymbol( symbol->GetLibId() ) )
94 continue;
95
96 libSymbol = GetLibSymbol( symbol->GetLibId(), true );
97 }
98 catch( const IO_ERROR& )
99 {
100 // Queue up error messages for later.
101 tmp.Printf( _( "Failed to add symbol %s to library file '%s'." ),
102 symbol->GetLibId().GetUniStringLibItemName(),
103 aFileName );
104
105 // Don't bail out here. Attempt to add as many of the symbols to the library
106 // as possible.
107 }
108 catch( ... )
109 {
110 tmp = _( "Unexpected exception occurred." );
111 }
112
113 if( libSymbol )
114 {
115 std::unique_ptr<LIB_SYMBOL> flattenedSymbol = libSymbol->Flatten();
116
117 // Use the full LIB_ID as the symbol name to prevent symbol name collisions.
118 flattenedSymbol->SetName( symbol->GetLibId().GetUniStringLibId() );
119
120 // AddSymbol() does first clone the symbol before adding.
121 archLib->AddSymbol( flattenedSymbol.get() );
122 }
123 else
124 {
125 tmp.Printf( _( "Symbol %s not found in any library or cache." ),
126 symbol->GetLibId().GetUniStringLibId() );
127 }
128
129 if( !tmp.empty() && !errorMsg.Contains( symbol->GetLibId().GetUniStringLibId() ) )
130 {
131 if( errorMsg.empty() )
132 errorMsg += tmp;
133 else
134 errorMsg += "\n" + tmp;
135 }
136 }
137 }
138
139 if( !errorMsg.empty() )
140 {
141 tmp.Printf( _( "Errors occurred creating symbol library %s." ), aFileName );
142 DisplayErrorMessage( this, tmp, errorMsg );
143 }
144
145 archLib->EnableBuffering( false );
146
147 try
148 {
149 archLib->Save( false );
150 }
151 catch( const IO_ERROR& ioe )
152 {
153 errorMsg.Printf( _( "Failed to save symbol library file '%s'." ), aFileName );
154 DisplayErrorMessage( this, errorMsg, ioe.What() );
155 return false;
156 }
157 catch( std::exception& error )
158 {
159 errorMsg.Printf( _( "Failed to save symbol library file '%s'." ), aFileName );
160 DisplayErrorMessage( this, errorMsg, error.what() );
161 return false;
162 }
163
164 return true;
165 }
166