23#include <magic_enum.hpp>
33#include <api/common/types/base_types.pb.h>
34#include <api/common/commands/editor_commands.pb.h>
35#include <api/common/types/library_types.pb.h>
39using namespace kiapi::common::commands;
40using kiapi::common::types::LibraryCommandStatus;
41using kiapi::common::types::LibraryLoadStatus;
42using kiapi::common::types::LibraryTableScope;
43using kiapi::common::types::LibraryType;
75 const wxString& aNickname )
const
87 e.set_status( ApiStatusCode::AS_UNHANDLED );
88 return tl::unexpected( e );
97 e.set_status( ApiStatusCode::AS_BAD_REQUEST );
98 e.set_error_message(
"no library adapter is available for this library type" );
99 return tl::unexpected( e );
102 std::vector<wxString> nicknames;
104 if( aCtx.
Request.nickname_size() > 0 )
106 for(
const std::string& nickname : aCtx.
Request.nickname() )
108 wxString nicknameStr = wxString::FromUTF8( nickname );
113 nicknames.emplace_back( nicknameStr );
119 nicknames.emplace_back( row->Nickname() );
122 LibraryItemsResponse response;
124 for(
const wxString& nickname : nicknames )
126 for(
const wxString& itemName :
getItemNames( *adapter, nickname ) )
128 kiapi::common::types::LibraryIdentifier*
id = response.add_items();
129 id->set_library_nickname( nickname.ToUTF8() );
130 id->set_entry_name( itemName.ToUTF8() );
141 aEntry.set_nickname( aRow.
Nickname().ToUTF8() );
142 aEntry.set_uri( aRow.
URI().ToUTF8() );
145 aEntry.set_description( aRow.
Description().ToUTF8() );
148 ( *aEntry.mutable_options() )[key] = value;
150 if( std::optional<LIBRARY_MANAGER_ADAPTER*> adapter =
Pgm().GetLibraryManager().Adapter( aTableType ) )
151 aEntry.set_writable( ( *adapter )->IsWritable( aRow.
Nickname() ) );
153 aEntry.set_disabled( aRow.
Disabled() );
154 aEntry.set_hidden( aRow.
Hidden() );
165 aEntry->set_error_message( aStatus.
error->message.ToUTF8() );
177 e.set_status( ApiStatusCode::AS_BAD_REQUEST );
178 e.set_error_message(
"unknown library table scope" );
179 return tl::unexpected( e );
183 LibraryStatusResponse response;
187 if( !aCtx.
Request.types().empty() )
191 for(
int typeProto : aCtx.
Request.types() )
198 e.set_status( ApiStatusCode::AS_BAD_REQUEST );
199 e.set_error_message( wxString::Format(
"invalid library table type %d", typeProto ).ToUTF8() );
200 return tl::unexpected( e );
203 types.push_back( type );
211 if( std::optional<LIBRARY_MANAGER_ADAPTER*> optAdapter = manager.
Adapter( tableType ) )
212 adapter = *optAdapter;
216 if( row->Disabled() )
219 kiapi::common::types::LibraryStatusEntry* entry = response.add_libraries();
223 if( std::optional<LIB_STATUS> status = adapter->
GetLibraryStatus( row->Nickname() ) )
242 []( LibraryCommandStatus::Code aCode,
const wxString& aMessage = wxEmptyString )
244 LibraryCommandStatus status;
245 status.set_code( aCode );
247 if( !aMessage.empty() )
248 status.set_error_message( aMessage.ToUTF8() );
253 if( aCtx.
Request.type() == LibraryType::LT_UNKNOWN )
256 e.set_status( ApiStatusCode::AS_BAD_REQUEST );
257 e.set_error_message(
"a valid library type is required" );
258 return tl::unexpected( e );
261 if( aCtx.
Request.scope() == LibraryTableScope::LTS_BOTH || aCtx.
Request.scope() == LibraryTableScope::LTS_UNKNOWN )
264 e.set_status( ApiStatusCode::AS_BAD_REQUEST );
265 e.set_error_message(
"LTS_BOTH is invalid for ReloadLibrary; choose one table" );
266 return tl::unexpected( e );
276 if( !manager.
Adapter( tableType ) )
279 e.set_status( ApiStatusCode::AS_UNHANDLED );
280 return tl::unexpected( e );
283 std::vector<wxString> nicknames;
285 if( aCtx.
Request.nickname_size() > 0 )
287 for(
const std::string& nickname : aCtx.
Request.nickname() )
288 nicknames.emplace_back( wxString::FromUTF8( nickname ) );
294 if( !row->Disabled() )
295 nicknames.emplace_back( row->Nickname() );
299 if( nicknames.empty() )
300 return makeStatus( LibraryCommandStatus::LCS_NOT_FOUND,
"No libraries found to reload" );
302 for(
const wxString& nickname : nicknames )
304 if( !manager.
GetRow( tableType, nickname, scope ) )
306 return makeStatus( LibraryCommandStatus::LCS_NOT_FOUND,
307 wxString::Format(
"Library '%s' not found", nickname ) );
311 for(
const wxString& nickname : nicknames )
318 return makeStatus( LibraryCommandStatus::LCS_OK );
325 auto makeStatus = []( LibraryCommandStatus::Code aCode,
const wxString& aMessage = wxEmptyString )
327 LibraryCommandStatus status;
328 status.set_code( aCode );
330 if( !aMessage.empty() )
331 status.set_error_message( aMessage.ToUTF8() );
339 e.set_status( ApiStatusCode::AS_UNIMPLEMENTED );
340 e.set_error_message(
"LoadAllLibraries is not available in GUI mode" );
341 return tl::unexpected( e );
344 std::map<LIBRARY_TABLE_TYPE, KIWAY::FACE_T> typesToLoad;
346 if( aCtx.
Request.type_size() == 0 )
354 for(
int protoRaw : aCtx.
Request.type() )
356 LibraryType protoType =
static_cast<LibraryType
>( protoRaw );
369 e.set_status( ApiStatusCode::AS_BAD_REQUEST );
371 wxString::Format(
"invalid library type %s", magic_enum::enum_name( protoType ) ).ToUTF8() );
372 return tl::unexpected( e );
382 e.set_status( ApiStatusCode::AS_NOT_READY );
383 e.set_error_message(
"internal error while attempting to load all libraries" );
384 return tl::unexpected( e );
389 for(
const auto& [type, face] : typesToLoad )
399 wxCHECK2(
kiface,
continue );
404 kiface->LoadAllLibraries();
407 return makeStatus( LibraryCommandStatus::LCS_OK );
416 LibraryCommandStatus status;
422 status.set_code( LibraryCommandStatus::LCS_OK );
433 e.set_status( ApiStatusCode::AS_UNHANDLED );
434 return tl::unexpected( e );
437 wxString projectPath = wxString::FromUTF8( aCtx.
Request.document().project().path() );
444 e.set_status( ApiStatusCode::AS_BAD_REQUEST );
445 e.set_error_message(
"the requested project is not open" );
446 return tl::unexpected( e );
454 e.set_status( ApiStatusCode::AS_BAD_REQUEST );
455 e.set_error_message(
"no library adapter is available for this library type" );
456 return tl::unexpected( e );
459 GetItemsResponse response;
460 response.mutable_header()->mutable_document()->CopyFrom( aCtx.
Request.document() );
461 google::protobuf::Any
any;
463 if( aCtx.
Request.item_ids().empty() )
466 e.set_status( ApiStatusCode::AS_BAD_REQUEST );
467 e.set_error_message(
"specify at least one lib_id to retrieve" );
468 return tl::unexpected( e );
471 std::map<wxString, std::vector<wxString>> byNickname;
473 for(
const kiapi::common::types::LibraryIdentifier&
id : aCtx.
Request.item_ids() )
475 byNickname[wxString::FromUTF8(
id.library_nickname() )].emplace_back( wxString::FromUTF8(
id.entry_name() ) );
478 for(
auto& [nickname, entryNames] : byNickname )
483 for(
const wxString& entryName : entryNames )
487 any.Swap( response.add_items() );
493 if( response.items().empty() )
496 e.set_status( ApiStatusCode::AS_BAD_REQUEST );
497 e.set_error_message(
"none of the requested items were found" );
498 return tl::unexpected( e );
501 response.set_status( kiapi::common::types::ItemRequestStatus::IRS_OK );
KICOMMON_API types::KiCadObjectType ToProtoEnum(KICAD_T aValue)
KICOMMON_API KICAD_T FromProtoEnum(types::KiCadObjectType aValue)
tl::expected< T, ApiResponseStatus > HANDLER_RESULT
static void packLibraryStatusEntry(kiapi::common::types::LibraryStatusEntry *aEntry, LIBRARY_TABLE_TYPE aTableType, const LIBRARY_TABLE_ROW &aRow, const LIB_STATUS &aStatus)
static void packTableEntry(kiapi::common::types::LibraryTableEntry &aEntry, LIBRARY_TABLE_TYPE aTableType, const LIBRARY_TABLE_ROW &aRow)
HANDLER_RESULT< kiapi::common::commands::LibraryItemsResponse > handleGetLibraryItems(const HANDLER_CONTEXT< kiapi::common::commands::GetLibraryItems > &aCtx)
HANDLER_RESULT< kiapi::common::commands::LibraryStatusResponse > handleGetLibraryStatuses(const HANDLER_CONTEXT< kiapi::common::commands::GetLibraryStatuses > &aCtx)
virtual bool packLibraryItem(const LIB_ID &aId, google::protobuf::Any &aOutput) const
~API_HANDLER_LIBRARIES() override
HANDLER_RESULT< kiapi::common::types::LibraryCommandStatus > handleReloadLibrary(const HANDLER_CONTEXT< kiapi::common::commands::ReloadLibrary > &aCtx)
kiapi::common::types::LibraryCommandStatus loadAllLibraries()
Starts a background load of all libraries of this handler's type.
virtual std::vector< wxString > getItemNames(LIBRARY_MANAGER_ADAPTER &aAdapter, const wxString &aNickname) const
Returns the names of all entries in the given library, or an empty vector if the library is not loade...
virtual LIBRARY_MANAGER_ADAPTER * adapterForProject(PROJECT &aProject) const
LIBRARY_TABLE_TYPE m_type
API_HANDLER_LIBRARIES(LIBRARY_TABLE_TYPE aType=LIBRARY_TABLE_TYPE::DESIGN_BLOCK)
std::function< void(KIFACE *)> m_handlerRegisterCallback
Invoked with a lazily-loaded KIFACE so its handlers can be registered on the server.
KIWAY * m_kiway
Used to lazily load kifaces for LoadAllLibraries in headless; null in GUI mode.
HANDLER_RESULT< kiapi::common::types::LibraryCommandStatus > handleLoadAllLibraries(const HANDLER_CONTEXT< kiapi::common::commands::LoadAllLibraries > &aCtx)
HANDLER_RESULT< kiapi::common::commands::GetItemsResponse > handleGetItemsFromLibrary(const HANDLER_CONTEXT< kiapi::common::commands::GetItemsFromLibrary > &aCtx)
void registerHandler(HANDLER_RESULT< ResponseType >(HandlerType::*aHandler)(const HANDLER_CONTEXT< RequestType > &))
Registers an API command handler for the given message types.
A minimalistic software bus for communications between various DLLs/DSOs (DSOs) within the same KiCad...
virtual KIFACE * KiFACE(FACE_T aFaceId, bool doLoad=true)
Return the KIFACE* given a FACE_T.
The interface used by the classes that actually can load IO plugins for the different parts of KiCad ...
std::optional< LIB_STATUS > GetLibraryStatus(const wxString &aNickname) const
Returns the status of a loaded library, or nullopt if the library hasn't been loaded (yet)
std::vector< LIBRARY_TABLE_ROW * > Rows(LIBRARY_TABLE_SCOPE aScope=LIBRARY_TABLE_SCOPE::BOTH, bool aIncludeInvalid=false) const
Like LIBRARY_MANAGER::Rows but filtered to the LIBRARY_TABLE_TYPE of this adapter.
void AsyncLoad()
Loads all available libraries for this adapter type in the background.
std::optional< LIB_STATUS > LoadLibraryEntry(const wxString &aNickname)
Synchronously loads the named library to LOADED state.
std::optional< LIBRARY_MANAGER_ADAPTER * > Adapter(LIBRARY_TABLE_TYPE aType) const
void ReloadLibraryEntry(LIBRARY_TABLE_TYPE aType, const wxString &aNickname, LIBRARY_TABLE_SCOPE aScope=LIBRARY_TABLE_SCOPE::BOTH)
std::optional< LIB_STATUS > LoadLibraryEntry(LIBRARY_TABLE_TYPE aType, const wxString &aNickname)
Synchronously loads the named library to LOADED state for the given type.
std::vector< LIBRARY_TABLE_ROW * > Rows(LIBRARY_TABLE_TYPE aType, LIBRARY_TABLE_SCOPE aScope=LIBRARY_TABLE_SCOPE::BOTH, bool aIncludeInvalid=false) const
Returns a flattened list of libraries of the given type.
std::optional< LIBRARY_TABLE_ROW * > GetRow(LIBRARY_TABLE_TYPE aType, const wxString &aNickname, LIBRARY_TABLE_SCOPE aScope=LIBRARY_TABLE_SCOPE::BOTH)
LIBRARY_TABLE_SCOPE Scope() const
std::map< std::string, UTF8 > GetOptionsMap() const
const wxString & Description() const
const wxString & URI() const
const wxString & Nickname() const
A logical library item identifier and consists of various portions much like a URI.
virtual SETTINGS_MANAGER & GetSettingsManager() const
virtual LIBRARY_MANAGER & GetLibraryManager() const
Container for project specific data.
virtual DESIGN_BLOCK_LIBRARY_ADAPTER * DesignBlockLibs()
Return the table of design block libraries.
PROJECT * GetProjectForPath(const wxString &aProjectPath) const
Return the active project iff its path matches aProjectPath, else nullptr.
PROJECT & Prj() const
A helper while we are not MDI-capable – return the one and only project.
A type-safe container of any type.
PGM_BASE & Pgm()
The global program "get" accessor.
RequestMessageType Request
Implement a participant in the KIWAY alchemy.
The overall status of a loaded or loading library.
std::optional< LIBRARY_ERROR > error
IFACE KIFACE_BASE kiface("pcb_test_frame", KIWAY::FACE_PCB)