38#include <api/common/types/base_types.pb.h>
40using namespace kiapi::common::commands;
41using types::CommandStatus;
42using types::DocumentType;
43using types::ItemRequestStatus;
77 if( aDocument.type() != DocumentType::DOCTYPE_FOOTPRINT )
80 e.set_status( ApiStatusCode::AS_UNHANDLED );
81 return tl::unexpected( e );
85 if( aDocument.lib_id().library_nickname().empty() )
89 if( !board || !
board->GetFirstFootprint() )
92 e.set_status( ApiStatusCode::AS_BAD_REQUEST );
93 e.set_error_message(
"no footprint is currently open" );
94 return tl::unexpected( e );
105 e.set_status( ApiStatusCode::AS_BAD_REQUEST );
106 e.set_error_message(
"no footprint is currently open" );
107 return tl::unexpected( e );
113 if( 0 != aDocument.lib_id().library_nickname().compare( actual_lib ) )
116 e.set_status( ApiStatusCode::AS_BAD_REQUEST );
117 e.set_error_message( fmt::format(
"the requested library is {} but the actual library is {}",
118 aDocument.lib_id().library_nickname(), actual_lib ) );
119 return tl::unexpected( e );
122 if( 0 != aDocument.lib_id().entry_name().compare( actual_name ) )
125 e.set_status( ApiStatusCode::AS_BAD_REQUEST );
126 e.set_error_message( fmt::format(
"the requested footprint name is {} but the actual name is {}",
127 aDocument.lib_id().entry_name(), actual_name ) );
128 return tl::unexpected( e );
136 const DocumentSpecifier& aDocument )
139 return tl::unexpected( documentValidation.error() );
141 if( std::optional<ApiResponseStatus> busy =
checkForBusy() )
142 return tl::unexpected( *busy );
146 if( !editorFootprint )
149 e.set_status( ApiStatusCode::AS_BAD_REQUEST );
150 e.set_error_message(
"no footprint is currently loaded" );
151 return tl::unexpected( e );
154 return editorFootprint;
161 if( std::optional<ApiResponseStatus> headless =
checkForHeadless(
"OpenLibraryItem" ) )
162 return tl::unexpected( *headless );
164 if( aCtx.
Request.type() != DocumentType::DOCTYPE_FOOTPRINT )
167 e.set_status( ApiStatusCode::AS_UNHANDLED );
168 return tl::unexpected( e );
173 wxString libraryName = aCtx.
Request.identifier().library_nickname();
174 wxString fpName = aCtx.
Request.identifier().entry_name();
176 LIB_ID fpid( libraryName, fpName );
180 std::unique_ptr<FOOTPRINT> footprint(
186 e.set_status( ApiStatusCode::AS_BAD_REQUEST );
187 e.set_error_message(
"could not open footprint" );
188 return tl::unexpected( e );
194 e.set_status( ApiStatusCode::AS_BAD_REQUEST );
195 e.set_error_message( fmt::format(
"could not open footprint due to IO error {}",
196 err.
Problem().ToStdString() ) );
197 return tl::unexpected( e );
208 if( aCtx.
Request.type() != DocumentType::DOCTYPE_FOOTPRINT )
211 e.set_status( ApiStatusCode::AS_UNHANDLED );
212 return tl::unexpected( e );
215 GetOpenDocumentsResponse response;
216 common::types::DocumentSpecifier doc;
220 if( !
board()->GetFirstFootprint() )
223 doc.set_type( DocumentType::DOCTYPE_FOOTPRINT );
227 if( !
project().IsNullProject() )
233 response.mutable_documents()->Add( std::move( doc ) );
244 return tl::unexpected( footprint.error() );
249 e.set_status( ApiStatusCode::AS_BAD_REQUEST );
250 e.set_error_message(
"failed to save footprint" );
251 return tl::unexpected( e );
264 return tl::unexpected( footprint.error() );
266 wxString pathStr = wxString::FromUTF8( aCtx.
Request.path() );
268 if( pathStr.IsEmpty() )
271 e.set_status( ApiStatusCode::AS_BAD_REQUEST );
272 e.set_error_message(
"path must contain the new footprint name, "
273 "optionally prefixed with a library nickname (e.g. \"lib:name\")" );
274 return tl::unexpected( e );
279 targetId.
Parse( pathStr );
283 if( libraryName.IsEmpty() )
289 std::unique_ptr<FOOTPRINT>
copy(
static_cast<FOOTPRINT*
>( ( *footprint )->Clone() ) );
290 copy->SetFPID(
LIB_ID( libraryName, newName ) );
295 e.set_status( ApiStatusCode::AS_BAD_REQUEST );
296 e.set_error_message( fmt::format(
"failed to save footprint copy '{}' to library '{}'",
297 newName.ToStdString(),
298 libraryName.ToStdString() ) );
299 return tl::unexpected( e );
309 if( std::optional<ApiResponseStatus> headless =
checkForHeadless(
"RevertDocument" ) )
310 return tl::unexpected( *headless );
313 return tl::unexpected( documentValidation.error() );
315 if( std::optional<ApiResponseStatus> busy =
checkForBusy() )
316 return tl::unexpected( *busy );
347 e.set_status( ApiStatusCode::AS_UNHANDLED );
348 return tl::unexpected( e );
351 if( std::optional<ApiResponseStatus> busy =
checkForBusy() )
352 return tl::unexpected( *busy );
354 GetItemsResponse response;
357 std::vector<BOARD_ITEM*> items;
358 std::set<KICAD_T> typesRequested, typesHandled;
362 if( aCtx.
Request.types().empty() )
365 for(
KICAD_T type : requestedTypes )
367 typesRequested.emplace( type );
369 if( typesHandled.count( type ) )
375 std::ranges::copy( footprint->
Pads(), std::back_inserter( items ) );
380 std::ranges::copy( footprint->
GetFields(), std::back_inserter( items ) );
392 if( item->Type() == type ||
BaseType( item->Type() ) == type )
393 items.emplace_back( item );
396 typesHandled.insert( type );
408 items.emplace_back( child );
417 std::ranges::copy( footprint->
Zones(), std::back_inserter( items ) );
422 std::ranges::copy( footprint->
Groups(), std::back_inserter( items ) );
429 if( body->GetExtruded()->m_height > 0 )
430 items.push_back( body );
441 if( typesHandled.empty() )
444 e.set_status( ApiStatusCode::AS_BAD_REQUEST );
445 e.set_error_message(
"none of the requested types are valid for a Footprint object" );
446 return tl::unexpected( e );
451 if( !typesRequested.count( item->Type() ) && !typesRequested.count(
BaseType( item->Type() ) ) )
454 google::protobuf::Any itemBuf;
455 item->Serialize( itemBuf );
456 response.mutable_items()->Add( std::move( itemBuf ) );
459 response.set_status( ItemRequestStatus::IRS_OK );
tl::expected< T, ApiResponseStatus > HANDLER_RESULT
API_HANDLER_BOARD(std::shared_ptr< BOARD_CONTEXT > aContext, EDA_BASE_FRAME *aFrame=nullptr)
std::vector< KICAD_T > parseRequestedItemTypes(const google::protobuf::RepeatedField< int > &aTypes)
PROJECT & project() const
std::optional< ApiResponseStatus > checkForHeadless(const std::string &aCommandName) const
HANDLER_RESULT< bool > validateDocument(const DocumentSpecifier &aDocument)
HANDLER_RESULT< std::optional< KIID > > validateItemHeaderDocument(const kiapi::common::types::ItemHeader &aHeader)
If the header is valid, returns the item container.
virtual std::optional< ApiResponseStatus > checkForBusy()
Checks if the editor can accept commands.
void registerHandler(HANDLER_RESULT< ResponseType >(HandlerType::*aHandler)(const HANDLER_CONTEXT< RequestType > &))
Registers an API command handler for the given message types.
Abstract interface for BOARD_ITEMs capable of storing other items inside.
A base class for any item which can be embedded within the BOARD container class, and therefore insta...
Information pertinent to a Pcbnew printed circuit board.
FOOTPRINT * GetFirstFootprint() const
Get the first footprint on the board or nullptr.
Hold an error message and may be used when throwing exceptions containing meaningful error messages.
virtual const wxString Problem() const
what was the problem?
A logical library item identifier and consists of various portions much like a URI.
int Parse(const UTF8 &aId, bool aFix=false)
Parse LIB_ID with the information from aId.
bool IsValid() const
Check if this LID_ID is valid.
const wxString GetUniStringLibItemName() const
Get strings for display messages in dialogs.
const wxString GetUniStringLibNickname() const
const UTF8 & GetLibItemName() const
const UTF8 & GetLibNickname() const
Return the logical library name portion of a LIB_ID.
A 3D body attached to a footprint (or, later, placed on a board).
static FOOTPRINT_LIBRARY_ADAPTER * FootprintLibAdapter(PROJECT *aProject)
static std::string ToStdString(const wxString &aStr)
Class to handle a set of BOARD_ITEMs.
RequestMessageType Request
constexpr KICAD_T BaseType(const KICAD_T aType)
Return the underlying type of the given type.
KICAD_T
The set of class identification values stored in EDA_ITEM::m_structType.
@ PCB_SHAPE_T
class PCB_SHAPE, a segment not on copper layers
@ PCB_GROUP_T
class PCB_GROUP, a set of BOARD_ITEMs
@ PCB_TEXTBOX_T
class PCB_TEXTBOX, wrapped text on a layer
@ PCB_ZONE_T
class ZONE, a copper pour area
@ PCB_TEXT_T
class PCB_TEXT, text on a layer
@ PCB_3D_BODY_T
class PCB_3D_BODY, a 3D body (extruded or model) on a footprint
@ PCB_FIELD_T
class PCB_FIELD, text associated with a footprint property
@ PCB_BARCODE_T
class PCB_BARCODE, a barcode (graphic item)
@ PCB_TABLECELL_T
class PCB_TABLECELL, PCB_TEXTBOX for use in tables
@ PCB_PAD_T
class PAD, a pad in a footprint
@ PCB_DIMENSION_T
class PCB_DIMENSION_BASE: abstract dimension meta-type
@ PCB_TABLE_T
class PCB_TABLE, table of PCB_TABLECELLs