KiCad PCB EDA Suite
Loading...
Searching...
No Matches
design_block_library_adapter.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 The KiCad Developers, see AUTHORS.txt for contributors.
5 * @author Jon Evans <[email protected]>
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
22#include "design_block.h"
23
25#include <design_block_io.h>
26#include <env_vars.h>
27#include <ki_exception.h>
28#include <trace_helpers.h>
29
30#include <magic_enum.hpp>
31#include <wx/log.h>
32
33
35
37
38
43
44
46{
47 return ENV_VAR::GetVersionedEnvVarName( wxS( "DESIGN_BLOCK_DIR" ) );
48}
49
50
52{
53 DESIGN_BLOCK_IO* ret = dynamic_cast<DESIGN_BLOCK_IO*>( aRow->plugin.get() );
54 wxCHECK( aRow->plugin && ret, nullptr );
55 return ret;
56}
57
58
60{
61 // TODO(JE) do we maintain a precondition that URIs are absolute paths after expansion?
63
65 {
66 wxString msg;
67 wxFileName fileName( row->URI() );
68
69 if( fileName.FileExists() )
70 return tl::unexpected( LIBRARY_TABLE_OK() );
71 else
72 msg = wxString::Format( _( "Nested table '%s' not found." ), row->URI() );
73
74 return tl::unexpected( LIBRARY_ERROR( msg ) );
75 }
77 {
78 wxLogTrace( traceLibraries, "Sym: Plugin type %s is unknown!", row->Type() );
79 wxString msg = wxString::Format( _( "Unknown library type %s " ), row->Type() );
80 return tl::unexpected( LIBRARY_ERROR( msg ) );
81 }
82
84 wxCHECK( plugin, tl::unexpected( LIBRARY_ERROR( _( "Internal error" ) ) ) );
85
86 return plugin;
87}
88
89
91{
92 return dbplugin( aRow );
93}
94
95
97{
98 wxArrayString dummyList;
99 std::map<std::string, UTF8> options = aLib->row->GetOptionsMap();
100 dbplugin( aLib )->DesignBlockEnumerate( dummyList, getUri( aLib->row ), false, &options );
101}
102
103
104std::optional<LIB_STATUS> DESIGN_BLOCK_LIBRARY_ADAPTER::LoadOne( LIB_DATA* aLib )
105{
107
108 std::map<std::string, UTF8> options = aLib->row->GetOptionsMap();
109
110 try
111 {
112 wxArrayString dummyList;
113 dbplugin( aLib )->DesignBlockEnumerate( dummyList, getUri( aLib->row ), false, &options );
114 wxLogTrace( traceLibraries, "DB: %s: library enumerated %zu items", aLib->row->Nickname(), dummyList.size() );
116 }
117 catch( IO_ERROR& e )
118 {
120 aLib->status.error = LIBRARY_ERROR( { e.What() } );
121 wxLogTrace( traceLibraries, "DB: %s: plugin threw exception: %s", aLib->row->Nickname(), e.What() );
122 }
123
124 return aLib->status;
125}
126
127
128std::optional<LIB_STATUS> DESIGN_BLOCK_LIBRARY_ADAPTER::LoadOne( const wxString& nickname )
129{
131
132 if( result.has_value() )
133 return LoadOne( *result );
134
135 return LIB_STATUS{
136 .load_status = LOAD_STATUS::LOAD_ERROR,
137 .error = LIBRARY_ERROR( { result.error() } )
138 };
139}
140
141
142std::vector<DESIGN_BLOCK*> DESIGN_BLOCK_LIBRARY_ADAPTER::GetDesignBlocks( const wxString& aNickname )
143{
144 std::vector<DESIGN_BLOCK*> blocks;
145
146 std::optional<const LIB_DATA*> maybeLib = fetchIfLoaded( aNickname );
147
148 if( !maybeLib )
149 return blocks;
150
151 const LIB_DATA* lib = *maybeLib;
152 std::map<std::string, UTF8> options = lib->row->GetOptionsMap();
153 wxArrayString blockNames;
154
155 try
156 {
157 dbplugin( lib )->DesignBlockEnumerate( blockNames, getUri( lib->row ), false, &options );
158 }
159 catch( IO_ERROR& e )
160 {
161 wxLogTrace( traceLibraries, "DB: Exception enumerating library %s: %s", lib->row->Nickname(), e.What() );
162 }
163
164 for( const wxString& blockName : blockNames )
165 {
166 try
167 {
168 blocks.emplace_back( dbplugin( lib )->DesignBlockLoad( getUri( lib->row ), blockName, false, &options ) );
169 }
170 catch( IO_ERROR& e )
171 {
172 wxLogTrace( traceLibraries, "DB: Exception enumerating design block %s: %s", blockName, e.What() );
173 }
174 }
175
176 return blocks;
177}
178
179
180std::vector<wxString> DESIGN_BLOCK_LIBRARY_ADAPTER::GetDesignBlockNames( const wxString& aNickname )
181{
182 // TODO(JE) can we kill wxArrayString in internal API?
183 wxArrayString namesAS;
184 std::vector<wxString> names;
185
186 if( std::optional<const LIB_DATA*> maybeLib = fetchIfLoaded( aNickname ) )
187 {
188 const LIB_DATA* lib = *maybeLib;
189 std::map<std::string, UTF8> options = lib->row->GetOptionsMap();
190
191 dbplugin( lib )->DesignBlockEnumerate( namesAS, getUri( lib->row ), true, &options );
192 }
193
194 for( const wxString& name : namesAS )
195 names.emplace_back( name );
196
197 return names;
198}
199
200
202 const wxString& aDesignBlockName, bool aKeepUUID )
203{
204 if( std::optional<const LIB_DATA*> maybeLib = fetchIfLoaded( aNickname ) )
205 {
206 const LIB_DATA* lib = *maybeLib;
207 std::map<std::string, UTF8> options = lib->row->GetOptionsMap();
208
209 try
210 {
211 if( DESIGN_BLOCK* db =
212 dbplugin( lib )->DesignBlockLoad( getUri( lib->row ), aDesignBlockName, aKeepUUID, &options ) )
213 {
214 db->GetLibId().SetLibNickname( aNickname );
215 return db;
216 }
217 }
218 catch( const IO_ERROR& ioe )
219 {
220 wxLogTrace( traceLibraries, "LoadDesignBlock: error loading %s:%s: %s", aNickname, aDesignBlockName,
221 ioe.What() );
222 }
223 }
224 else
225 {
226 wxLogTrace( traceLibraries, "LoadDesignBlock: requested library %s not loaded", aNickname );
227 }
228
229 return nullptr;
230}
231
232
233bool DESIGN_BLOCK_LIBRARY_ADAPTER::DesignBlockExists( const wxString& aNickname, const wxString& aDesignBlockName )
234{
235 if( std::optional<const LIB_DATA*> maybeLib = fetchIfLoaded( aNickname ) )
236 {
237 const LIB_DATA* lib = *maybeLib;
238 std::map<std::string, UTF8> options = lib->row->GetOptionsMap();
239
240 return dbplugin( lib )->DesignBlockExists( getUri( lib->row ), aDesignBlockName, &options );
241 }
242
243 return false;
244}
245
246
248 const wxString& aDesignBlockName )
249{
250 if( std::optional<const LIB_DATA*> maybeLib = fetchIfLoaded( aNickname ) )
251 {
252 const LIB_DATA* lib = *maybeLib;
253 std::map<std::string, UTF8> options = lib->row->GetOptionsMap();
254
255 return dbplugin( lib )->GetEnumeratedDesignBlock( getUri( lib->row ), aDesignBlockName, &options );
256 }
257
258 return nullptr;
259}
260
261
263 const DESIGN_BLOCK* aDesignBlock,
264 bool aOverwrite )
265{
266 if( std::optional<const LIB_DATA*> maybeLib = fetchIfLoaded( aNickname ) )
267 {
268 const LIB_DATA* lib = *maybeLib;
269 std::map<std::string, UTF8> options = lib->row->GetOptionsMap();
270
271 if( !aOverwrite && dbplugin( lib )->DesignBlockExists( getUri( lib->row ), aDesignBlock->GetName(), &options ) )
272 return SAVE_SKIPPED;
273
274 dbplugin( lib )->DesignBlockSave( getUri( lib->row ), aDesignBlock, &options );
275 }
276
277 return SAVE_OK;
278}
279
280
282 const wxString& aDesignBlockName )
283{
284 if( std::optional<const LIB_DATA*> maybeLib = fetchIfLoaded( aNickname ) )
285 {
286 const LIB_DATA* lib = *maybeLib;
287 std::map<std::string, UTF8> options = lib->row->GetOptionsMap();
288 return dbplugin( lib )->DesignBlockDelete( getUri( lib->row ), aDesignBlockName, &options );
289 }
290}
291
292
294{
295 if( std::optional<const LIB_DATA*> maybeLib = fetchIfLoaded( aNickname ) )
296 {
297 const LIB_DATA* lib = *maybeLib;
298 return plugin( lib )->IsLibraryWritable( getUri( lib->row ) );
299 }
300
301 return false;
302}
303
304
306 bool aKeepUUID )
307{
308 wxString nickname = aDesignBlockId.GetLibNickname();
309 wxString DesignBlockname = aDesignBlockId.GetLibItemName();
310
311 if( nickname.size() )
312 return LoadDesignBlock( nickname, DesignBlockname, aKeepUUID );
313
314 // nickname is empty, sequentially search (alphabetically) all libs/nicks for first match:
315 for( const wxString& library : GetLibraryNames() )
316 {
317 // DesignBlockLoad() returns NULL on not found, does not throw exception
318 // unless there's an IO_ERROR.
319 if( DESIGN_BLOCK* ret = LoadDesignBlock( library, DesignBlockname, aKeepUUID ) )
320 return ret;
321 }
322
323 return nullptr;
324}
const char * name
@ DESIGN_BLOCK_FILE_UNKNOWN
0 is not a legal menu id on Mac
static DESIGN_BLOCK_FILE_T EnumFromStr(const wxString &aFileType)
static DESIGN_BLOCK_IO * FindPlugin(DESIGN_BLOCK_FILE_T aFileType)
bool DesignBlockExists(const wxString &aLibraryPath, const wxString &aDesignBlockName, const std::map< std::string, UTF8 > *aProperties=nullptr)
void DesignBlockDelete(const wxString &aLibraryPath, const wxString &aDesignBlockName, const std::map< std::string, UTF8 > *aProperties=nullptr)
void DesignBlockSave(const wxString &aLibraryPath, const DESIGN_BLOCK *aDesignBlock, const std::map< std::string, UTF8 > *aProperties=nullptr)
const DESIGN_BLOCK * GetEnumeratedDesignBlock(const wxString &aLibraryPath, const wxString &aDesignBlockName, const std::map< std::string, UTF8 > *aProperties=nullptr)
void DesignBlockEnumerate(wxArrayString &aDesignBlockNames, const wxString &aLibraryPath, bool aBestEfforts, const std::map< std::string, UTF8 > *aProperties=nullptr)
std::vector< wxString > GetDesignBlockNames(const wxString &aNickname)
SAVE_T
The set of return values from DesignBlockSave() below.
std::vector< DESIGN_BLOCK * > GetDesignBlocks(const wxString &aNickname)
IO_BASE * plugin(const LIB_DATA *aRow) override
static DESIGN_BLOCK_IO * dbplugin(const LIB_DATA *aRow)
Helper to cast the ABC plugin in the LIB_DATA* to a concrete plugin.
void DeleteDesignBlock(const wxString &aNickname, const wxString &aDesignBlockName)
Delete the aDesignBlockName from the library given by aNickname.
LIBRARY_RESULT< IO_BASE * > createPlugin(const LIBRARY_TABLE_ROW *row) override
Creates a concrete plugin for the given row.
static LEAK_AT_EXIT< std::map< wxString, LIB_DATA > > GlobalLibraries
void enumerateLibrary(LIB_DATA *aLib) override
Override in derived class to perform library-specific enumeration.
DESIGN_BLOCK * LoadDesignBlock(const wxString &aNickname, const wxString &aDesignBlockName, bool aKeepUUID=false)
Load a design block having aDesignBlockName from the library given by aNickname.
DESIGN_BLOCK * DesignBlockLoadWithOptionalNickname(const LIB_ID &aDesignBlockId, bool aKeepUUID=false)
Load a design block having aDesignBlockId with possibly an empty nickname.
SAVE_T SaveDesignBlock(const wxString &aNickname, const DESIGN_BLOCK *aDesignBlock, bool aOverwrite=true)
Write aDesignBlock to an existing library given by aNickname.
DESIGN_BLOCK_LIBRARY_ADAPTER(LIBRARY_MANAGER &aManager)
bool IsDesignBlockLibWritable(const wxString &aNickname)
Return true if the library given by aNickname is writable.
std::optional< LIB_STATUS > LoadOne(LIB_DATA *aLib) override
const DESIGN_BLOCK * GetEnumeratedDesignBlock(const wxString &aNickname, const wxString &aDesignBlockName)
A version of #DesignBlockLoad() for use after #DesignBlockEnumerate() for more efficient cache manage...
bool DesignBlockExists(const wxString &aNickname, const wxString &aDesignBlockName)
Indicates whether or not the given design block already exists in the given library.
wxString GetName() const override
virtual bool IsLibraryWritable(const wxString &aLibraryPath)
Return true if the library at aLibraryPath is writable.
Definition io_base.cpp:60
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()
A wrapper for static data that should not be destroyed at program exit.
LIBRARY_MANAGER_ADAPTER(LIBRARY_MANAGER &aManager)
Constructs a type-specific adapter into the library manager.
LIBRARY_RESULT< LIB_DATA * > loadIfNeeded(const wxString &aNickname)
Fetches a loaded library, triggering a load of that library if it isn't loaded yet.
std::vector< wxString > GetLibraryNames() const
Returns a list of library nicknames that are available (skips any that failed to load)
static wxString getUri(const LIBRARY_TABLE_ROW *aRow)
std::optional< const LIB_DATA * > fetchIfLoaded(const wxString &aNickname) const
std::map< std::string, UTF8 > GetOptionsMap() const
const wxString & Type() const
const wxString & URI() const
const wxString & Nickname() const
A logical library item identifier and consists of various portions much like a URI.
Definition lib_id.h:49
const UTF8 & GetLibItemName() const
Definition lib_id.h:102
const UTF8 & GetLibNickname() const
Return the logical library name portion of a LIB_ID.
Definition lib_id.h:87
#define _(s)
Functions related to environment variables, including help functions.
const wxChar *const traceLibraries
Flag to enable library table and library manager tracing.
tl::expected< ResultType, LIBRARY_ERROR > LIBRARY_RESULT
KICOMMON_API wxString GetVersionedEnvVarName(const wxString &aBaseName)
Construct a versioned environment variable based on this KiCad major version.
Definition env_vars.cpp:77
Storage for an actual loaded library (including library content owned by the plugin)
LIB_STATUS status
std::unique_ptr< IO_BASE > plugin
const LIBRARY_TABLE_ROW * row
The overall status of a loaded or loading library.
std::optional< LIBRARY_ERROR > error
LOAD_STATUS load_status
wxString result
Test unit parsing edge cases and error handling.
wxLogTrace helper definitions.