37#include <api/common/types/base_types.pb.h>
39using namespace kiapi::common::commands;
40using types::CommandStatus;
41using types::DocumentType;
42using types::ItemRequestStatus;
76 if( aDocument.type() != DocumentType::DOCTYPE_FOOTPRINT )
79 e.set_status( ApiStatusCode::AS_UNHANDLED );
80 return tl::unexpected( e );
84 if( aDocument.lib_id().library_nickname().empty() )
88 if( !board || !
board->GetFirstFootprint() )
91 e.set_status( ApiStatusCode::AS_BAD_REQUEST );
92 e.set_error_message(
"no footprint is currently open" );
93 return tl::unexpected( e );
104 e.set_status( ApiStatusCode::AS_BAD_REQUEST );
105 e.set_error_message(
"no footprint is currently open" );
106 return tl::unexpected( e );
112 if( 0 != aDocument.lib_id().library_nickname().compare( actual_lib ) )
115 e.set_status( ApiStatusCode::AS_BAD_REQUEST );
116 e.set_error_message( fmt::format(
"the requested library is {} but the actual library is {}",
117 aDocument.lib_id().library_nickname(), actual_lib ) );
118 return tl::unexpected( e );
121 if( 0 != aDocument.lib_id().entry_name().compare( actual_name ) )
124 e.set_status( ApiStatusCode::AS_BAD_REQUEST );
125 e.set_error_message( fmt::format(
"the requested footprint name is {} but the actual name is {}",
126 aDocument.lib_id().entry_name(), actual_name ) );
127 return tl::unexpected( e );
135 const DocumentSpecifier& aDocument )
138 return tl::unexpected( documentValidation.error() );
140 if( std::optional<ApiResponseStatus> busy =
checkForBusy() )
141 return tl::unexpected( *busy );
145 if( !editorFootprint )
148 e.set_status( ApiStatusCode::AS_BAD_REQUEST );
149 e.set_error_message(
"no footprint is currently loaded" );
150 return tl::unexpected( e );
153 return editorFootprint;
160 if( std::optional<ApiResponseStatus> headless =
checkForHeadless(
"OpenLibraryItem" ) )
161 return tl::unexpected( *headless );
163 if( aCtx.
Request.type() != DocumentType::DOCTYPE_FOOTPRINT )
166 e.set_status( ApiStatusCode::AS_UNHANDLED );
167 return tl::unexpected( e );
172 wxString libraryName = aCtx.
Request.identifier().library_nickname();
173 wxString fpName = aCtx.
Request.identifier().entry_name();
175 LIB_ID fpid( libraryName, fpName );
179 std::unique_ptr<FOOTPRINT> footprint(
185 e.set_status( ApiStatusCode::AS_BAD_REQUEST );
186 e.set_error_message(
"could not open footprint" );
187 return tl::unexpected( e );
193 e.set_status( ApiStatusCode::AS_BAD_REQUEST );
194 e.set_error_message( fmt::format(
"could not open footprint due to IO error {}",
195 err.
Problem().ToStdString() ) );
196 return tl::unexpected( e );
207 if( aCtx.
Request.type() != DocumentType::DOCTYPE_FOOTPRINT )
210 e.set_status( ApiStatusCode::AS_UNHANDLED );
211 return tl::unexpected( e );
214 GetOpenDocumentsResponse response;
215 common::types::DocumentSpecifier doc;
219 if( !
board()->GetFirstFootprint() )
222 doc.set_type( DocumentType::DOCTYPE_FOOTPRINT );
226 if( !
project().IsNullProject() )
232 response.mutable_documents()->Add( std::move( doc ) );
243 return tl::unexpected( footprint.error() );
248 e.set_status( ApiStatusCode::AS_BAD_REQUEST );
249 e.set_error_message(
"failed to save footprint" );
250 return tl::unexpected( e );
263 return tl::unexpected( footprint.error() );
265 wxString pathStr = wxString::FromUTF8( aCtx.
Request.path() );
267 if( pathStr.IsEmpty() )
270 e.set_status( ApiStatusCode::AS_BAD_REQUEST );
271 e.set_error_message(
"path must contain the new footprint name, "
272 "optionally prefixed with a library nickname (e.g. \"lib:name\")" );
273 return tl::unexpected( e );
278 targetId.
Parse( pathStr );
282 if( libraryName.IsEmpty() )
288 std::unique_ptr<FOOTPRINT>
copy(
static_cast<FOOTPRINT*
>( ( *footprint )->Clone() ) );
289 copy->SetFPID(
LIB_ID( libraryName, newName ) );
294 e.set_status( ApiStatusCode::AS_BAD_REQUEST );
295 e.set_error_message( fmt::format(
"failed to save footprint copy '{}' to library '{}'",
296 newName.ToStdString(),
297 libraryName.ToStdString() ) );
298 return tl::unexpected( e );
308 if( std::optional<ApiResponseStatus> headless =
checkForHeadless(
"RevertDocument" ) )
309 return tl::unexpected( *headless );
312 return tl::unexpected( documentValidation.error() );
314 if( std::optional<ApiResponseStatus> busy =
checkForBusy() )
315 return tl::unexpected( *busy );
346 e.set_status( ApiStatusCode::AS_UNHANDLED );
347 return tl::unexpected( e );
350 if( std::optional<ApiResponseStatus> busy =
checkForBusy() )
351 return tl::unexpected( *busy );
353 GetItemsResponse response;
356 std::vector<BOARD_ITEM*> items;
357 std::set<KICAD_T> typesRequested, typesInserted;
358 bool handledAnything =
false;
362 if( aCtx.
Request.types().empty() )
365 for(
KICAD_T type : requestedTypes )
367 typesRequested.emplace( type );
369 if( typesInserted.count( type ) )
376 handledAnything =
true;
378 std::copy( footprint->
Pads().begin(), footprint->
Pads().end(),
379 std::back_inserter( items ) );
387 handledAnything =
true;
390 std::back_inserter( items ) );
402 handledAnything =
true;
403 bool inserted =
false;
407 if( item->Type() == type )
409 items.emplace_back( item );
415 typesInserted.insert( type );
422 handledAnything =
true;
423 bool inserted =
false;
433 items.emplace_back( child );
447 handledAnything =
true;
448 bool inserted =
false;
452 switch( item->Type() )
459 items.emplace_back( item );
482 handledAnything =
true;
484 std::copy( footprint->
Zones().begin(), footprint->
Zones().end(),
485 std::back_inserter( items ) );
493 handledAnything =
true;
495 std::copy( footprint->
Groups().begin(), footprint->
Groups().end(),
496 std::back_inserter( items ) );
507 if( !handledAnything )
510 e.set_status( ApiStatusCode::AS_BAD_REQUEST );
511 e.set_error_message(
"none of the requested types are valid for a Footprint object" );
512 return tl::unexpected( e );
517 if( !typesRequested.count( item->Type() ) )
520 google::protobuf::Any itemBuf;
521 item->Serialize( itemBuf );
522 response.mutable_items()->Add( std::move( itemBuf ) );
525 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.
static FOOTPRINT_LIBRARY_ADAPTER * FootprintLibAdapter(PROJECT *aProject)
static std::string ToStdString(const wxString &aStr)
Class to handle a set of BOARD_ITEMs.
RequestMessageType Request
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_DIM_ORTHOGONAL_T
class PCB_DIM_ORTHOGONAL, a linear dimension constrained to x/y
@ PCB_DIM_LEADER_T
class PCB_DIM_LEADER, a leader dimension (graphic item)
@ PCB_DIM_CENTER_T
class PCB_DIM_CENTER, a center point marking (graphic item)
@ 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_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_DIM_ALIGNED_T
class PCB_DIM_ALIGNED, a linear dimension (graphic item)
@ 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
@ PCB_DIM_RADIAL_T
class PCB_DIM_RADIAL, a radius or diameter dimension