30using namespace kiapi::common::commands;
59 return tl::unexpected( valid.error() );
62 if( std::optional<ApiResponseStatus> busy =
checkForBusy() )
63 return tl::unexpected( *busy );
68 e.set_status( ApiStatusCode::AS_BAD_REQUEST );
69 e.set_error_message( fmt::format(
"the client {} already has a commit in progress",
71 return tl::unexpected( e );
76 BeginCommitResponse response;
80 response.mutable_id()->set_value(
id.AsStdString() );
97 return tl::unexpected( valid.error() );
100 if( std::optional<ApiResponseStatus> busy =
checkForBusy() )
101 return tl::unexpected( *busy );
106 e.set_status( ApiStatusCode::AS_BAD_REQUEST );
107 e.set_error_message( fmt::format(
"the client {} does not has a commit in progress",
109 return tl::unexpected( e );
115 const KIID&
id = pair.first;
116 const std::unique_ptr<COMMIT>& commit = pair.second;
118 EndCommitResponse response;
121 switch( aCtx.
Request.action() )
123 case kiapi::common::commands::CMA_DROP:
131 case kiapi::common::commands::CMA_COMMIT:
133 if( aCtx.
Request.id().value().compare(
id.AsStdString() ) != 0 )
136 e.set_status( ApiStatusCode::AS_BAD_REQUEST );
137 e.set_error_message( fmt::format(
"the id {} does not match the commit in progress",
139 return tl::unexpected( e );
162 return m_commits.at( aClientName ).second.get();
167 const wxString& aMessage )
183 return tl::unexpected( validation.error() );
190 const types::ItemHeader& aHeader )
192 if( !aHeader.has_document() || aHeader.document().type() !=
thisDocumentType() )
195 e.set_status( ApiStatusCode::AS_UNHANDLED );
197 return tl::unexpected( e );
202 if( !documentValidation )
203 return tl::unexpected( documentValidation.error() );
206 return tl::unexpected(
result.error() );
208 if( aHeader.has_container() && !aHeader.container().value().empty() )
210 return KIID( aHeader.container().value() );
223 if( !
m_frame->CanAcceptApiCommands() )
226 e.set_status( ApiStatusCode::AS_BUSY );
227 e.set_error_message(
"KiCad is busy and cannot respond to API requests right now" );
238 if( std::optional<ApiResponseStatus> busy =
checkForBusy() )
239 return tl::unexpected( *busy );
241 CreateItemsResponse response;
244 types::ItemHeader header;
245 header.CopyFrom( aCtx.
Request.header() );
247 if( aCtx.
Request.container().value().length() )
248 *header.mutable_container() = aCtx.
Request.container();
253 [&](
const ItemStatus& aStatus,
const google::protobuf::Any& aItem )
255 ItemCreationResult itemResult;
256 itemResult.mutable_status()->CopyFrom( aStatus );
257 itemResult.mutable_item()->CopyFrom( aItem );
258 response.mutable_created_items()->Add( std::move( itemResult ) );
262 return tl::unexpected(
result.error() );
264 response.set_status( *
result );
272 if( std::optional<ApiResponseStatus> busy =
checkForBusy() )
273 return tl::unexpected( *busy );
275 UpdateItemsResponse response;
280 [&](
const ItemStatus& aStatus,
const google::protobuf::Any& aItem )
282 ItemUpdateResult itemResult;
283 itemResult.mutable_status()->CopyFrom( aStatus );
284 itemResult.mutable_item()->CopyFrom( aItem );
285 response.mutable_updated_items()->Add( std::move( itemResult ) );
289 return tl::unexpected(
result.error() );
291 response.set_status( *
result );
303 e.set_status( ApiStatusCode::AS_UNHANDLED );
304 return tl::unexpected( e );
307 if( std::optional<ApiResponseStatus> busy =
checkForBusy() )
308 return tl::unexpected( *busy );
310 std::map<KIID, ItemDeletionStatus> itemsToDelete;
312 for(
const kiapi::common::types::KIID& kiidBuf : aCtx.
Request.item_ids() )
314 if( !kiidBuf.value().empty() )
316 KIID kiid( kiidBuf.value() );
317 itemsToDelete[kiid] = ItemDeletionStatus::IDS_NONEXISTENT;
321 if( itemsToDelete.empty() )
324 e.set_status( ApiStatusCode::AS_BAD_REQUEST );
325 e.set_error_message(
"no valid items to delete were given" );
326 return tl::unexpected( e );
331 DeleteItemsResponse response;
333 for(
const auto& [
id, status] : itemsToDelete )
335 ItemDeletionResult*
result = response.add_deleted_items();
336 result->mutable_id()->set_value(
id.AsStdString() );
337 result->set_status( status );
340 response.set_status( kiapi::common::types::ItemRequestStatus::IRS_OK );
352 e.set_status( ApiStatusCode::AS_UNHANDLED );
353 return tl::unexpected( e );
356 if( std::optional<ApiResponseStatus> busy =
checkForBusy() )
357 return tl::unexpected( *busy );
359 HitTestResponse response;
367 e.set_status( ApiStatusCode::AS_BAD_REQUEST );
368 e.set_error_message(
"the requested item ID is not present in the given document" );
369 return tl::unexpected( e );
374 int toleranceIu =
scale.NmToIU( aCtx.
Request.tolerance() );
376 if( ( *item )->HitTest( posIu, toleranceIu ) )
377 response.set_result( HitTestResult::HTR_HIT );
379 response.set_result( HitTestResult::HTR_NO_HIT );
389 return tl::unexpected( documentValidation.error() );
391 GetDocumentModifiedStateResponse response;
394 response.set_state(
m_frame->IsContentModified() ? DocumentModifiedState::DMS_MODIFIED
395 : DocumentModifiedState::DMS_UNMODIFIED );
402 std::vector<KICAD_T>
types;
404 for(
int typeRaw : aTypes )
406 auto typeMessage =
static_cast<types::KiCadObjectType
>( typeRaw );
409 types.emplace_back( type );
421 if( !documentValidation )
422 return tl::unexpected( documentValidation.error() );
429 e.set_status( AS_BAD_REQUEST );
430 e.set_error_message(
"this editor does not support a title block" );
431 return tl::unexpected( e );
436 types::TitleBlockInfo response;
438 response.set_title( block.
GetTitle().ToUTF8() );
439 response.set_date( block.
GetDate().ToUTF8() );
440 response.set_revision( block.
GetRevision().ToUTF8() );
441 response.set_company( block.
GetCompany().ToUTF8() );
442 response.set_comment1( block.
GetComment( 0 ).ToUTF8() );
443 response.set_comment2( block.
GetComment( 1 ).ToUTF8() );
444 response.set_comment3( block.
GetComment( 2 ).ToUTF8() );
445 response.set_comment4( block.
GetComment( 3 ).ToUTF8() );
446 response.set_comment5( block.
GetComment( 4 ).ToUTF8() );
447 response.set_comment6( block.
GetComment( 5 ).ToUTF8() );
448 response.set_comment7( block.
GetComment( 6 ).ToUTF8() );
449 response.set_comment8( block.
GetComment( 7 ).ToUTF8() );
450 response.set_comment9( block.
GetComment( 8 ).ToUTF8() );
461 if( !documentValidation )
462 return tl::unexpected( documentValidation.error() );
464 if( !aCtx.
Request.has_title_block() )
467 e.set_status( ApiStatusCode::AS_BAD_REQUEST );
468 e.set_error_message(
"SetTitleBlockInfo requires title_block" );
469 return tl::unexpected( e );
477 e.set_status( AS_BAD_REQUEST );
478 e.set_error_message(
"this editor does not support a title block" );
479 return tl::unexpected( e );
484 const types::TitleBlockInfo& request = aCtx.
Request.title_block();
486 block.
SetTitle( wxString::FromUTF8( request.title() ) );
487 block.
SetDate( wxString::FromUTF8( request.date() ) );
488 block.
SetRevision( wxString::FromUTF8( request.revision() ) );
489 block.
SetCompany( wxString::FromUTF8( request.company() ) );
490 block.
SetComment( 0, wxString::FromUTF8( request.comment1() ) );
491 block.
SetComment( 1, wxString::FromUTF8( request.comment2() ) );
492 block.
SetComment( 2, wxString::FromUTF8( request.comment3() ) );
493 block.
SetComment( 3, wxString::FromUTF8( request.comment4() ) );
494 block.
SetComment( 4, wxString::FromUTF8( request.comment5() ) );
495 block.
SetComment( 5, wxString::FromUTF8( request.comment6() ) );
496 block.
SetComment( 6, wxString::FromUTF8( request.comment7() ) );
497 block.
SetComment( 7, wxString::FromUTF8( request.comment8() ) );
498 block.
SetComment( 8, wxString::FromUTF8( request.comment9() ) );
502 return google::protobuf::Empty();
511 if( !documentValidation )
512 return tl::unexpected( documentValidation.error() );
519 e.set_status( AS_BAD_REQUEST );
520 e.set_error_message(
"this editor does not support page settings" );
521 return tl::unexpected( e );
526 types::PageSettings response;
532 response.set_orientation( pageInfo.
IsPortrait() ? types::PageOrientation::PO_PORTRAIT
533 : types::PageOrientation::PO_LANDSCAPE );
545 if( !documentValidation )
546 return tl::unexpected( documentValidation.error() );
548 if( !aCtx.
Request.has_page_settings() )
551 e.set_status( ApiStatusCode::AS_BAD_REQUEST );
552 e.set_error_message(
"SetPageSettings requires page_settings" );
553 return tl::unexpected( e );
561 e.set_status( AS_BAD_REQUEST );
562 e.set_error_message(
"this editor does not support page settings" );
563 return tl::unexpected( e );
566 const types::PageSettings& request = aCtx.
Request.page_settings();
573 if( !request.has_user_page_size() )
576 e.set_status( ApiStatusCode::AS_BAD_REQUEST );
577 e.set_error_message(
"custom page size requires user_page_size" );
578 return tl::unexpected( e );
589 bool portrait = ( request.orientation() == types::PageOrientation::PO_PORTRAIT );
590 pageInfo.
SetType( pageSizeType, portrait );
596 e.set_status( AS_BAD_REQUEST );
597 e.set_error_message(
"this editor does not support page settings" );
598 return tl::unexpected( e );
601 wxString drawingSheet( wxString::FromUTF8( request.drawing_sheet() ) );
606 types::PageSettings response;
612 response.set_orientation( pageInfo.
IsPortrait() ? types::PageOrientation::PO_PORTRAIT
613 : types::PageOrientation::PO_LANDSCAPE );
KICOMMON_API types::KiCadObjectType ToProtoEnum(KICAD_T aValue)
KICOMMON_API KICAD_T FromProtoEnum(types::KiCadObjectType aValue)
tl::expected< T, ApiResponseStatus > HANDLER_RESULT
constexpr EDA_IU_SCALE pcbIUScale
virtual std::unique_ptr< COMMIT > createCommit()=0
Override this to create an appropriate COMMIT subclass for the frame in question.
virtual bool setPageSettings(const DocumentSpecifier &aDocument, const PAGE_INFO &aPageInfo)
HANDLER_RESULT< bool > validateDocument(const DocumentSpecifier &aDocument)
HANDLER_RESULT< commands::DeleteItemsResponse > handleDeleteItems(const HANDLER_CONTEXT< commands::DeleteItems > &aCtx)
HANDLER_RESULT< types::PageSettings > handleSetPageSettings(const HANDLER_CONTEXT< commands::SetPageSettings > &aCtx)
virtual const EDA_IU_SCALE & getIuScale() const
Returns the internal-unit scale that the concrete editor uses.
virtual std::optional< EDA_ITEM * > getItemFromDocument(const DocumentSpecifier &aDocument, const KIID &aId)=0
HANDLER_RESULT< std::optional< KIID > > validateItemHeaderDocument(const kiapi::common::types::ItemHeader &aHeader)
If the header is valid, returns the item container.
virtual void setDrawingSheetFileName(const wxString &aFileName)
HANDLER_RESULT< types::PageSettings > handleGetPageSettings(const HANDLER_CONTEXT< commands::GetPageSettings > &aCtx)
HANDLER_RESULT< commands::EndCommitResponse > handleEndCommit(const HANDLER_CONTEXT< commands::EndCommit > &aCtx)
virtual tl::expected< bool, ApiResponseStatus > validateDocumentInternal(const DocumentSpecifier &aDocument) const =0
API_HANDLER_EDITOR(EDA_BASE_FRAME *aFrame=nullptr)
static std::vector< KICAD_T > parseRequestedItemTypes(const google::protobuf::RepeatedField< int > &aTypes)
virtual std::optional< PAGE_INFO > getPageSettings(const DocumentSpecifier &aDocument)
virtual HANDLER_RESULT< commands::GetDocumentModifiedStateResponse > handleGetDocumentModifiedState(const HANDLER_CONTEXT< commands::GetDocumentModifiedState > &aCtx)
virtual std::optional< TITLE_BLOCK * > getTitleBlock(const DocumentSpecifier &aDocument)
HANDLER_RESULT< commands::CreateItemsResponse > handleCreateItems(const HANDLER_CONTEXT< commands::CreateItems > &aCtx)
COMMIT * getCurrentCommit(const std::string &aClientName)
virtual void pushCurrentCommit(const std::string &aClientName, const wxString &aMessage)
virtual HANDLER_RESULT< ItemRequestStatus > handleCreateUpdateItemsInternal(bool aCreate, const std::string &aClientName, const types::ItemHeader &aHeader, const google::protobuf::RepeatedPtrField< google::protobuf::Any > &aItems, std::function< void(commands::ItemStatus, google::protobuf::Any)> aItemHandler)=0
std::set< std::string > m_activeClients
std::map< std::string, std::pair< KIID, std::unique_ptr< COMMIT > > > m_commits
HANDLER_RESULT< commands::UpdateItemsResponse > handleUpdateItems(const HANDLER_CONTEXT< commands::UpdateItems > &aCtx)
virtual void deleteItemsInternal(std::map< KIID, ItemDeletionStatus > &aItemsToDelete, const std::string &aClientName)=0
virtual wxString getDrawingSheetFileName()
virtual std::optional< ApiResponseStatus > checkForBusy()
Checks if the editor can accept commands.
HANDLER_RESULT< types::TitleBlockInfo > handleGetTitleBlockInfo(const HANDLER_CONTEXT< commands::GetTitleBlockInfo > &aCtx)
virtual types::DocumentType thisDocumentType() const =0
Override this to specify which document type this editor handles.
HANDLER_RESULT< google::protobuf::Empty > handleSetTitleBlockInfo(const HANDLER_CONTEXT< commands::SetTitleBlockInfo > &aCtx)
HANDLER_RESULT< commands::BeginCommitResponse > handleBeginCommit(const HANDLER_CONTEXT< commands::BeginCommit > &aCtx)
virtual void onModified()
HANDLER_RESULT< commands::HitTestResponse > handleHitTest(const HANDLER_CONTEXT< commands::HitTest > &aCtx)
static const wxString m_defaultCommitMessage
void registerHandler(HANDLER_RESULT< ResponseType >(HandlerType::*aHandler)(const HANDLER_CONTEXT< RequestType > &))
Registers an API command handler for the given message types.
Represent a set of changes (additions, deletions or modifications) of a data model (e....
The base frame for deriving all KiCad main window classes.
Describe the page size and margins of a paper page on which to eventually print or plot.
bool SetType(PAGE_SIZE_TYPE aPageSize, bool aIsPortrait=false)
Set the name of the page type and also the sizes and margins commonly associated with that type name.
static void SetCustomWidthMils(double aWidthInMils)
Set the width of Custom page in mils for any custom page constructed or made via SetType() after maki...
const VECTOR2D GetSizeIU(double aIUScale) const
Gets the page size in internal units.
static void SetCustomHeightMils(double aHeightInMils)
Set the height of Custom page in mils for any custom page constructed or made via SetType() after mak...
const PAGE_SIZE_TYPE & GetType() const
Hold the information shown in the lower right corner of a plot, printout, or editing view.
const wxString & GetCompany() const
void SetRevision(const wxString &aRevision)
void SetComment(int aIdx, const wxString &aComment)
const wxString & GetRevision() const
void SetTitle(const wxString &aTitle)
const wxString & GetDate() const
const wxString & GetComment(int aIdx) const
void SetCompany(const wxString &aCompany)
const wxString & GetTitle() const
void SetDate(const wxString &aDate)
Set the date field, and defaults to the current time and date.
Base window classes and related definitions.
KICOMMON_API VECTOR2I UnpackVector2(const types::Vector2 &aInput, const EDA_IU_SCALE &aScale)
KICOMMON_API void PackVector2(types::Vector2 &aOutput, const VECTOR2I &aInput, const EDA_IU_SCALE &aScale)
RequestMessageType Request
wxString result
Test unit parsing edge cases and error handling.
KICAD_T
The set of class identification values stored in EDA_ITEM::m_structType.
VECTOR2< int32_t > VECTOR2I
VECTOR2< double > VECTOR2D