26#include <magic_enum.hpp>
33#include <wx/filename.h>
35#include <api/common/types/base_types.pb.h>
37using namespace kiapi::common::commands;
38using kiapi::common::types::CommandStatus;
39using kiapi::common::types::DocumentType;
40using kiapi::common::types::ItemRequestStatus;
45 types::RunJobResponse response;
50 response.add_output_path(
output.m_outputPath.ToUTF8() );
54 response.set_status( types::JobStatus::JS_SUCCESS );
58 response.set_status( types::JobStatus::JS_ERROR );
59 response.set_message( fmt::format(
"Schematic export job '{}' failed with exit code {}: {}",
98 return std::make_unique<SCH_COMMIT>(
m_frame );
104 if( aDocument.type() != DocumentType::DOCTYPE_SCHEMATIC )
118 if( aCtx.
Request.type() != DocumentType::DOCTYPE_SCHEMATIC )
123 e.set_status( ApiStatusCode::AS_UNHANDLED );
124 return tl::unexpected( e );
127 GetOpenDocumentsResponse response;
128 common::types::DocumentSpecifier doc;
130 wxFileName fn(
m_context->GetCurrentFileName() );
132 doc.set_type( DocumentType::DOCTYPE_SCHEMATIC );
133 doc.set_board_filename( fn.GetFullName() );
135 response.mutable_documents()->Add( std::move( doc ) );
143 if( std::optional<ApiResponseStatus> busy =
checkForBusy() )
144 return tl::unexpected( *busy );
148 if( !documentValidation )
149 return tl::unexpected( documentValidation.error() );
151 auto plotJob = std::make_unique<JOB_EXPORT_SCH_PLOT_SVG>();
152 plotJob->m_filename =
m_context->GetCurrentFileName();
154 if( !aCtx.
Request.job_settings().output_path().empty() )
155 plotJob->SetConfiguredOutputPath( wxString::FromUTF8( aCtx.
Request.job_settings().output_path() ) );
157 const kiapi::schematic::jobs::SchematicPlotSettings& settings = aCtx.
Request.plot_settings();
159 plotJob->m_drawingSheet = wxString::FromUTF8( settings.drawing_sheet() );
160 plotJob->m_defaultFont = wxString::FromUTF8( settings.default_font() );
161 plotJob->m_variant = wxString::FromUTF8( settings.variant() );
162 plotJob->m_plotAll = settings.plot_all();
163 plotJob->m_plotDrawingSheet = settings.plot_drawing_sheet();
164 plotJob->m_show_hop_over = settings.show_hop_over();
165 plotJob->m_blackAndWhite = settings.black_and_white();
166 plotJob->m_useBackgroundColor = settings.use_background_color();
167 plotJob->m_minPenWidth = settings.min_pen_width();
168 plotJob->m_theme = wxString::FromUTF8( settings.theme() );
170 plotJob->m_plotPages.clear();
172 for(
const std::string& page : settings.plot_pages() )
173 plotJob->m_plotPages.push_back( wxString::FromUTF8( page ) );
175 if( aCtx.
Request.plot_settings().page_size() != kiapi::schematic::jobs::SchematicJobPageSize::SJPS_UNKNOWN )
187 if( std::optional<ApiResponseStatus> busy =
checkForBusy() )
188 return tl::unexpected( *busy );
192 if( !documentValidation )
193 return tl::unexpected( documentValidation.error() );
195 auto plotJob = std::make_unique<JOB_EXPORT_SCH_PLOT_DXF>();
196 plotJob->m_filename =
m_context->GetCurrentFileName();
198 if( !aCtx.
Request.job_settings().output_path().empty() )
199 plotJob->SetConfiguredOutputPath( wxString::FromUTF8( aCtx.
Request.job_settings().output_path() ) );
201 const kiapi::schematic::jobs::SchematicPlotSettings& settings = aCtx.
Request.plot_settings();
203 plotJob->m_drawingSheet = wxString::FromUTF8( settings.drawing_sheet() );
204 plotJob->m_defaultFont = wxString::FromUTF8( settings.default_font() );
205 plotJob->m_variant = wxString::FromUTF8( settings.variant() );
206 plotJob->m_plotAll = settings.plot_all();
207 plotJob->m_plotDrawingSheet = settings.plot_drawing_sheet();
208 plotJob->m_show_hop_over = settings.show_hop_over();
209 plotJob->m_blackAndWhite = settings.black_and_white();
210 plotJob->m_useBackgroundColor = settings.use_background_color();
211 plotJob->m_minPenWidth = settings.min_pen_width();
212 plotJob->m_theme = wxString::FromUTF8( settings.theme() );
214 plotJob->m_plotPages.clear();
216 for(
const std::string& page : settings.plot_pages() )
217 plotJob->m_plotPages.push_back( wxString::FromUTF8( page ) );
219 if( aCtx.
Request.plot_settings().page_size() != kiapi::schematic::jobs::SchematicJobPageSize::SJPS_UNKNOWN )
231 if( std::optional<ApiResponseStatus> busy =
checkForBusy() )
232 return tl::unexpected( *busy );
236 if( !documentValidation )
237 return tl::unexpected( documentValidation.error() );
239 auto plotJob = std::make_unique<JOB_EXPORT_SCH_PLOT_PDF>(
false );
240 plotJob->m_filename =
m_context->GetCurrentFileName();
242 if( !aCtx.
Request.job_settings().output_path().empty() )
243 plotJob->SetConfiguredOutputPath( wxString::FromUTF8( aCtx.
Request.job_settings().output_path() ) );
245 const kiapi::schematic::jobs::SchematicPlotSettings& settings = aCtx.
Request.plot_settings();
247 plotJob->m_drawingSheet = wxString::FromUTF8( settings.drawing_sheet() );
248 plotJob->m_defaultFont = wxString::FromUTF8( settings.default_font() );
249 plotJob->m_variant = wxString::FromUTF8( settings.variant() );
250 plotJob->m_plotAll = settings.plot_all();
251 plotJob->m_plotDrawingSheet = settings.plot_drawing_sheet();
252 plotJob->m_show_hop_over = settings.show_hop_over();
253 plotJob->m_blackAndWhite = settings.black_and_white();
254 plotJob->m_useBackgroundColor = settings.use_background_color();
255 plotJob->m_minPenWidth = settings.min_pen_width();
256 plotJob->m_theme = wxString::FromUTF8( settings.theme() );
258 plotJob->m_plotPages.clear();
260 for(
const std::string& page : settings.plot_pages() )
261 plotJob->m_plotPages.push_back( wxString::FromUTF8( page ) );
263 if( aCtx.
Request.plot_settings().page_size() != kiapi::schematic::jobs::SchematicJobPageSize::SJPS_UNKNOWN )
268 plotJob->m_PDFPropertyPopups = aCtx.
Request.property_popups();
269 plotJob->m_PDFHierarchicalLinks = aCtx.
Request.hierarchical_links();
270 plotJob->m_PDFMetadata = aCtx.
Request.include_metadata();
279 if( std::optional<ApiResponseStatus> busy =
checkForBusy() )
280 return tl::unexpected( *busy );
284 if( !documentValidation )
285 return tl::unexpected( documentValidation.error() );
287 auto plotJob = std::make_unique<JOB_EXPORT_SCH_PLOT_PS>();
288 plotJob->m_filename =
m_context->GetCurrentFileName();
290 if( !aCtx.
Request.job_settings().output_path().empty() )
291 plotJob->SetConfiguredOutputPath( wxString::FromUTF8( aCtx.
Request.job_settings().output_path() ) );
293 const kiapi::schematic::jobs::SchematicPlotSettings& settings = aCtx.
Request.plot_settings();
295 plotJob->m_drawingSheet = wxString::FromUTF8( settings.drawing_sheet() );
296 plotJob->m_defaultFont = wxString::FromUTF8( settings.default_font() );
297 plotJob->m_variant = wxString::FromUTF8( settings.variant() );
298 plotJob->m_plotAll = settings.plot_all();
299 plotJob->m_plotDrawingSheet = settings.plot_drawing_sheet();
300 plotJob->m_show_hop_over = settings.show_hop_over();
301 plotJob->m_blackAndWhite = settings.black_and_white();
302 plotJob->m_useBackgroundColor = settings.use_background_color();
303 plotJob->m_minPenWidth = settings.min_pen_width();
304 plotJob->m_theme = wxString::FromUTF8( settings.theme() );
306 plotJob->m_plotPages.clear();
308 for(
const std::string& page : settings.plot_pages() )
309 plotJob->m_plotPages.push_back( wxString::FromUTF8( page ) );
311 if( aCtx.
Request.plot_settings().page_size() != kiapi::schematic::jobs::SchematicJobPageSize::SJPS_UNKNOWN )
323 if( std::optional<ApiResponseStatus> busy =
checkForBusy() )
324 return tl::unexpected( *busy );
328 if( !documentValidation )
329 return tl::unexpected( documentValidation.error() );
331 if( aCtx.
Request.format() == kiapi::schematic::jobs::SchematicNetlistFormat::SNF_UNKNOWN )
334 e.set_status( ApiStatusCode::AS_BAD_REQUEST );
335 e.set_error_message(
"RunSchematicJobExportNetlist requires a valid format" );
336 return tl::unexpected( e );
342 if( !aCtx.
Request.job_settings().output_path().empty() )
347 if( !aCtx.
Request.variant_name().empty() )
357 if( std::optional<ApiResponseStatus> busy =
checkForBusy() )
358 return tl::unexpected( *busy );
362 if( !documentValidation )
363 return tl::unexpected( documentValidation.error() );
368 if( !aCtx.
Request.job_settings().output_path().empty() )
383 if( aCtx.
Request.fields().sort_direction() == kiapi::schematic::jobs::BOMSortDirection::BSD_ASCENDING )
387 else if( aCtx.
Request.fields().sort_direction() == kiapi::schematic::jobs::BOMSortDirection::BSD_DESCENDING )
392 for(
const kiapi::schematic::jobs::BOMField& field : aCtx.
Request.fields().fields() )
394 bomJob.
m_fieldsOrdered.emplace_back( wxString::FromUTF8( field.name() ) );
395 bomJob.
m_fieldsLabels.emplace_back( wxString::FromUTF8( field.label() ) );
397 if( field.group_by() )
398 bomJob.
m_fieldsGroupBy.emplace_back( wxString::FromUTF8( field.name() ) );
404 if( !aCtx.
Request.variant_name().empty() )
417 e.set_status( ApiStatusCode::AS_BAD_REQUEST );
418 e.set_error_message(
"Tried to create an item in a null container" );
419 return tl::unexpected( e );
425 e.set_status( ApiStatusCode::AS_BAD_REQUEST );
426 e.set_error_message( fmt::format(
"Tried to create a pin in {}, which is not a symbol",
428 return tl::unexpected( e );
433 e.set_status( ApiStatusCode::AS_BAD_REQUEST );
434 e.set_error_message( fmt::format(
"Tried to create a symbol in {}, which is not a "
437 return tl::unexpected( e );
445 e.set_status( ApiStatusCode::AS_BAD_REQUEST );
446 e.set_error_message( fmt::format(
"Tried to create an item of type {}, which is unhandled",
447 magic_enum::enum_name( aType ) ) );
448 return tl::unexpected( e );
456 const std::string& aClientName,
457 const types::ItemHeader &aHeader,
458 const google::protobuf::RepeatedPtrField<google::protobuf::Any>& aItems,
459 std::function<
void( ItemStatus, google::protobuf::Any )> aItemHandler )
465 if( !containerResult && containerResult.error().status() == ApiStatusCode::AS_UNHANDLED )
468 e.set_status( ApiStatusCode::AS_UNHANDLED );
469 return tl::unexpected( e );
471 else if( !containerResult )
473 e.CopyFrom( containerResult.error() );
474 return tl::unexpected( e );
480 std::map<KIID, EDA_ITEM*> itemUuidMap;
482 std::for_each( screenItems.
begin(), screenItems.
end(),
485 itemUuidMap[aItem->m_Uuid] = aItem;
490 if( containerResult->has_value() )
492 const KIID& containerId = **containerResult;
494 if( itemUuidMap.count( containerId ) )
496 container = itemUuidMap.at( containerId );
500 e.set_status( ApiStatusCode::AS_BAD_REQUEST );
501 e.set_error_message( fmt::format(
502 "The requested container {} is not a valid schematic item container",
504 return tl::unexpected( e );
509 e.set_status( ApiStatusCode::AS_BAD_REQUEST );
510 e.set_error_message( fmt::format(
511 "The requested container {} does not exist in this document",
513 return tl::unexpected( e );
519 for(
const google::protobuf::Any& anyItem : aItems )
526 status.set_code( ItemStatusCode::ISC_INVALID_TYPE );
527 status.set_error_message( fmt::format(
"Could not decode a valid type from {}",
528 anyItem.type_url() ) );
529 aItemHandler( status, anyItem );
536 if( !creationResult )
538 status.set_code( ItemStatusCode::ISC_INVALID_TYPE );
539 status.set_error_message( creationResult.error().error_message() );
540 aItemHandler( status, anyItem );
544 std::unique_ptr<EDA_ITEM> item( std::move( *creationResult ) );
546 if( !item->Deserialize( anyItem ) )
548 e.set_status( ApiStatusCode::AS_BAD_REQUEST );
549 e.set_error_message( fmt::format(
"could not unpack {} from request",
550 item->GetClass().ToStdString() ) );
551 return tl::unexpected( e );
554 if( aCreate && itemUuidMap.count( item->m_Uuid ) )
556 status.set_code( ItemStatusCode::ISC_EXISTING );
557 status.set_error_message( fmt::format(
"an item with UUID {} already exists",
558 item->m_Uuid.AsStdString() ) );
559 aItemHandler( status, anyItem );
562 else if( !aCreate && !itemUuidMap.count( item->m_Uuid ) )
564 status.set_code( ItemStatusCode::ISC_NONEXISTENT );
565 status.set_error_message( fmt::format(
"an item with UUID {} does not exist",
566 item->m_Uuid.AsStdString() ) );
567 aItemHandler( status, anyItem );
571 status.set_code( ItemStatusCode::ISC_OK );
572 google::protobuf::Any newItem;
576 item->Serialize( newItem );
577 commit->
Add( item.release(), screen );
584 EDA_ITEM* edaItem = itemUuidMap[item->m_Uuid];
588 schItem->SwapItemData(
static_cast<SCH_ITEM*
>( item.get() ) );
589 schItem->Serialize( newItem );
590 commit->
Modify( schItem, screen );
601 aItemHandler( status, newItem );
605 return ItemRequestStatus::IRS_OK;
610 const std::string& aClientName )
KICAD_T FromProtoEnum(types::KiCadObjectType aValue)
tl::expected< T, ApiResponseStatus > HANDLER_RESULT
HANDLER_RESULT< types::RunJobResponse > ExecuteSchematicJob(KIWAY *aKiway, JOB &aJob)
std::unique_ptr< EDA_ITEM > CreateItemForType(KICAD_T aType, EDA_ITEM *aContainer)
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.
API_HANDLER_EDITOR(EDA_BASE_FRAME *aFrame=nullptr)
COMMIT * getCurrentCommit(const std::string &aClientName)
virtual void pushCurrentCommit(const std::string &aClientName, const wxString &aMessage)
std::set< std::string > m_activeClients
virtual std::optional< ApiResponseStatus > checkForBusy()
Checks if the editor can accept commands.
HANDLER_RESULT< types::RunJobResponse > handleRunSchematicJobExportDxf(const HANDLER_CONTEXT< kiapi::schematic::jobs::RunSchematicJobExportDxf > &aCtx)
std::unique_ptr< COMMIT > createCommit() override
Override this to create an appropriate COMMIT subclass for the frame in question.
HANDLER_RESULT< types::RunJobResponse > handleRunSchematicJobExportPdf(const HANDLER_CONTEXT< kiapi::schematic::jobs::RunSchematicJobExportPdf > &aCtx)
std::shared_ptr< SCH_CONTEXT > m_context
std::optional< EDA_ITEM * > getItemFromDocument(const DocumentSpecifier &aDocument, const KIID &aId) override
HANDLER_RESULT< types::RunJobResponse > handleRunSchematicJobExportSvg(const HANDLER_CONTEXT< kiapi::schematic::jobs::RunSchematicJobExportSvg > &aCtx)
HANDLER_RESULT< std::unique_ptr< EDA_ITEM > > createItemForType(KICAD_T aType, EDA_ITEM *aContainer)
HANDLER_RESULT< types::RunJobResponse > handleRunSchematicJobExportBOM(const HANDLER_CONTEXT< kiapi::schematic::jobs::RunSchematicJobExportBOM > &aCtx)
HANDLER_RESULT< types::RunJobResponse > handleRunSchematicJobExportPs(const HANDLER_CONTEXT< kiapi::schematic::jobs::RunSchematicJobExportPs > &aCtx)
API_HANDLER_SCH(SCH_EDIT_FRAME *aFrame)
HANDLER_RESULT< types::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) override
HANDLER_RESULT< commands::GetOpenDocumentsResponse > handleGetOpenDocuments(const HANDLER_CONTEXT< commands::GetOpenDocuments > &aCtx)
HANDLER_RESULT< types::RunJobResponse > handleRunSchematicJobExportNetlist(const HANDLER_CONTEXT< kiapi::schematic::jobs::RunSchematicJobExportNetlist > &aCtx)
bool validateDocumentInternal(const DocumentSpecifier &aDocument) const override
void deleteItemsInternal(std::map< KIID, ItemDeletionStatus > &aItemsToDelete, const std::string &aClientName) override
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....
COMMIT & Modify(EDA_ITEM *aItem, BASE_SCREEN *aScreen=nullptr, RECURSE_MODE aRecurse=RECURSE_MODE::NO_RECURSE)
Modify a given item in the model.
COMMIT & Add(EDA_ITEM *aItem, BASE_SCREEN *aScreen=nullptr)
Add a new item to the model.
A base class for most all the KiCad significant classes used in schematics and boards.
virtual wxString GetFriendlyName() const
Implement an R-tree for fast spatial and type indexing of schematic items.
ee_rtree::Iterator begin() const
Return a read/write iterator that points to the first.
ee_rtree::Iterator end() const
Return a read/write iterator that points to one past the last element in the EE_RTREE.
std::vector< wxString > m_fieldsLabels
std::vector< wxString > m_fieldsOrdered
wxString m_refRangeDelimiter
std::vector< wxString > m_fieldsGroupBy
std::vector< wxString > m_variantNames
wxString m_stringDelimiter
wxString m_fieldDelimiter
wxString m_bomFmtPresetName
std::vector< wxString > m_variantNames
An simple container class that lets us dispatch output jobs to kifaces.
void SetConfiguredOutputPath(const wxString &aPath)
Sets the configured output path for the job, this path is always saved to file.
const std::vector< JOB_OUTPUT > & GetOutputs()
const std::string & GetType() const
std::string AsStdString() const
A minimalistic software bus for communications between various DLLs/DSOs (DSOs) within the same KiCad...
int ProcessJob(KIWAY::FACE_T aFace, JOB *aJob, REPORTER *aReporter=nullptr, PROGRESS_REPORTER *aProgressReporter=nullptr)
Holds all the data relating to one schematic.
Schematic editor (Eeschema) main window.
Base class for any item which can be embedded within the SCHEMATIC container class,...
EE_RTREE & Items()
Get the full RTree, usually for iterating.
A wrapper for reporting to a wxString object.
const wxString & GetMessages() const
KICOMMON_API std::optional< KICAD_T > TypeNameFromAny(const google::protobuf::Any &aMessage)
std::shared_ptr< SCH_CONTEXT > CreateSchFrameContext(SCH_EDIT_FRAME *aFrame)
RequestMessageType Request
KICAD_T
The set of class identification values stored in EDA_ITEM::m_structType.