KiCad PCB EDA Suite
Loading...
Searching...
No Matches
api_handler_sch.cpp
Go to the documentation of this file.
1/*
2 * This program source code file is part of KiCad, a free EDA CAD application.
3 *
4 * Copyright (C) 2024 Jon Evans <[email protected]>
5 * Copyright The KiCad Developers, see AUTHORS.txt for contributors.
6 *
7 * This program is free software: you can redistribute it and/or modify it
8 * under the terms of the GNU General Public License as published by the
9 * Free Software Foundation, either version 3 of the License, or (at your
10 * option) any later version.
11 *
12 * This program is distributed in the hope that it will be useful, but
13 * WITHOUT ANY WARRANTY; without even the implied warranty of
14 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
15 * General Public License for more details.
16 *
17 * You should have received a copy of the GNU General Public License along
18 * with this program. If not, see <http://www.gnu.org/licenses/>.
19 */
20
21#include <api/api_handler_sch.h>
22#include <api/api_enums.h>
23#include <api/api_sch_utils.h>
24#include <api/api_utils.h>
25#include <api/sch_context.h>
26#include <magic_enum.hpp>
27#include <base_screen.h>
31#include <kiway.h>
32#include <sch_field.h>
33#include <sch_group.h>
34#include <sch_commit.h>
35#include <sch_edit_frame.h>
36#include <sch_label.h>
37#include <sch_screen.h>
38#include <sch_sheet.h>
39#include <sch_sheet_path.h>
40#include <sch_sheet_pin.h>
41#include <sch_symbol.h>
42#include <schematic.h>
43#include <wx/filename.h>
44
45#include <api/common/types/base_types.pb.h>
46
47using namespace kiapi::common::commands;
48using kiapi::common::types::CommandStatus;
49using kiapi::common::types::DocumentType;
50using kiapi::common::types::ItemRequestStatus;
51
52
53std::set<KICAD_T> API_HANDLER_SCH::s_allowedTypes = {
54 // SCH_MARKER_T,
64 // SCH_TABLE_T,
72};
73
74
76{
77 types::RunJobResponse response;
78 WX_STRING_REPORTER reporter;
79 int exitCode = aKiway->ProcessJob( KIWAY::FACE_SCH, &aJob, &reporter );
80
81 for( const JOB_OUTPUT& output : aJob.GetOutputs() )
82 response.add_output_path( output.m_outputPath.ToUTF8() );
83
84 if( exitCode == 0 )
85 {
86 response.set_status( types::JobStatus::JS_SUCCESS );
87 return response;
88 }
89
90 response.set_status( types::JobStatus::JS_ERROR );
91 response.set_message( fmt::format( "Schematic export job '{}' failed with exit code {}: {}",
92 aJob.GetType(), exitCode,
93 reporter.GetMessages().ToStdString() ) );
94 return response;
95}
96
97
102
103
104API_HANDLER_SCH::API_HANDLER_SCH( std::shared_ptr<SCH_CONTEXT> aContext,
105 SCH_EDIT_FRAME* aFrame ) :
106 API_HANDLER_EDITOR( aFrame ),
107 m_frame( aFrame ),
108 m_context( std::move( aContext ) )
109{
110 using namespace kiapi::schematic::jobs;
111 using namespace kiapi::schematic::types;
112
117
133}
134
135
136std::unique_ptr<COMMIT> API_HANDLER_SCH::createCommit()
137{
138 return std::make_unique<SCH_COMMIT>( m_frame );
139}
140
141
143{
144 wxCHECK( m_context, nullptr );
145 return m_context->GetSchematic();
146}
147
148
149std::optional<SCH_ITEM*> API_HANDLER_SCH::getItemById( const KIID& aId, SCH_SHEET_PATH* aPathOut ) const
150{
151 if( !schematic()->HasHierarchy() )
153
154 SCH_ITEM* item = schematic()->ResolveItem( aId, aPathOut, true );
155
156 if( !item )
157 return std::nullopt;
158
159 return item;
160}
161
162
163tl::expected<bool, ApiResponseStatus>
164API_HANDLER_SCH::validateDocumentInternal( const DocumentSpecifier& aDocument ) const
165{
166 if( aDocument.type() != DocumentType::DOCTYPE_SCHEMATIC )
167 {
168 ApiResponseStatus e;
169 e.set_status( ApiStatusCode::AS_BAD_REQUEST );
170 e.set_error_message( "the requested document is not a schematic" );
171 return tl::unexpected( e );
172 }
173
174 const PROJECT& prj = m_context->Prj();
175
176 if( aDocument.project().name().compare( prj.GetProjectName().ToUTF8() ) != 0 )
177 {
178 ApiResponseStatus e;
179 e.set_status( ApiStatusCode::AS_BAD_REQUEST );
180 e.set_error_message( fmt::format( "the requested project {} is not open",
181 aDocument.project().name() ) );
182 return tl::unexpected( e );
183 }
184
185 if( aDocument.project().path().compare( prj.GetProjectPath().ToUTF8() ) != 0 )
186 {
187 ApiResponseStatus e;
188 e.set_status( ApiStatusCode::AS_BAD_REQUEST );
189 e.set_error_message( fmt::format( "the requested project {} is not open at path {}",
190 aDocument.project().name(),
191 aDocument.project().path() ) );
192 return tl::unexpected( e );
193 }
194
195 if( aDocument.has_sheet_path() )
196 {
197 KIID_PATH path = UnpackSheetPath( aDocument.sheet_path() );
198
199 if( !schematic()->Hierarchy().HasPath( path ) )
200 {
201 ApiResponseStatus e;
202 e.set_status( ApiStatusCode::AS_BAD_REQUEST );
203 e.set_error_message( fmt::format( "the requested sheet path {} is not valid for this schematic",
204 path.AsString().ToStdString() ) );
205 return tl::unexpected( e );
206 }
207 }
208
209 return true;
210}
211
212
215{
216 if( aCtx.Request.type() != DocumentType::DOCTYPE_SCHEMATIC )
217 {
218 ApiResponseStatus e;
219
220 // No message needed for AS_UNHANDLED; this is an internal flag for the API server
221 e.set_status( ApiStatusCode::AS_UNHANDLED );
222 return tl::unexpected( e );
223 }
224
225 GetOpenDocumentsResponse response;
226 common::types::DocumentSpecifier doc;
227
228 wxFileName fn( m_context->GetCurrentFileName() );
229
230 doc.set_type( DocumentType::DOCTYPE_SCHEMATIC );
231
232 if( std::optional<SCH_SHEET_PATH> path = m_context->GetCurrentSheet() )
233 PackSheetPath( *doc.mutable_sheet_path(), path->Path() );
234
235 PackProject( *doc.mutable_project(), m_context->Prj() );
236
237 response.mutable_documents()->Add( std::move( doc ) );
238 return response;
239}
240
241
242void API_HANDLER_SCH::filterValidSchTypes( std::set<KICAD_T>& aTypeList )
243{
244 std::erase_if( aTypeList,
245 []( KICAD_T aType )
246 {
247 return !s_allowedTypes.contains( aType );
248 } );
249}
250
251
253{
254 if( std::optional<ApiResponseStatus> busy = checkForBusy() )
255 return tl::unexpected( *busy );
256
257 if( HANDLER_RESULT<std::optional<KIID>> valid = validateItemHeaderDocument( aCtx.Request.header() );
258 !valid.has_value() )
259 {
260 return tl::unexpected( valid.error() );
261 }
262
263 std::set<KICAD_T> typesRequested, typesInserted;
264
265 for( KICAD_T type : parseRequestedItemTypes( aCtx.Request.types() ) )
266 typesRequested.insert( type );
267
268 filterValidSchTypes( typesRequested );
269
270 if( typesRequested.empty() )
271 {
272 ApiResponseStatus e;
273 e.set_status( ApiStatusCode::AS_BAD_REQUEST );
274 e.set_error_message( "none of the requested types are valid for a Schematic object" );
275 return tl::unexpected( e );
276 }
277
278 SCH_SHEET_LIST hierarchy = schematic()->Hierarchy();
279 std::optional<SCH_SHEET_PATH> pathFilter;
280
281 if( aCtx.Request.header().document().has_sheet_path() )
282 {
283 KIID_PATH kp = UnpackSheetPath( aCtx.Request.header().document().sheet_path() );
284 pathFilter = hierarchy.GetSheetPathByKIIDPath( kp );
285 }
286
287 std::map<KICAD_T, std::vector<std::pair<EDA_ITEM*, SCH_SHEET_PATH>>> itemMap;
288
289 auto processScreen =
290 [&]( const SCH_SHEET_PATH& aPath )
291 {
292 const SCH_SCREEN* aScreen = aPath.LastScreen();
293
294 for( SCH_ITEM* aItem : aScreen->Items() )
295 {
296 itemMap[ aItem->Type() ].emplace_back( aItem, aPath );
297
298 aItem->RunOnChildren(
299 [&]( SCH_ITEM* aChild )
300 {
301 itemMap[ aChild->Type() ].emplace_back( aChild, aPath );
302 },
304 }
305 };
306
307 if( pathFilter )
308 {
309 processScreen( *pathFilter );
310 }
311 else
312 {
313 for( const SCH_SHEET_PATH& path : hierarchy )
314 processScreen( path );
315 }
316
317 GetItemsResponse response;
318 google::protobuf::Any any;
319
320 for( KICAD_T type : parseRequestedItemTypes( aCtx.Request.types() ) )
321 {
322 if( !s_allowedTypes.contains( type ) )
323 continue;
324
325 if( typesInserted.contains( type ) )
326 continue;
327
328 for( const auto& [item, itemPath] : itemMap[type] )
329 {
330 if( item->Type() == SCH_SYMBOL_T )
331 {
332 kiapi::schematic::types::SchematicSymbolInstance symbol;
333
334 if( !PackSymbol( &symbol, static_cast<SCH_SYMBOL*>( item ), itemPath ) )
335 continue;
336
337 any.PackFrom( symbol );
338 }
339 else if( item->Type() == SCH_SHEET_T )
340 {
341 kiapi::schematic::types::SheetSymbol sheet;
342
343 if( !PackSheet( &sheet, static_cast<SCH_SHEET*>( item ), itemPath ) )
344 continue;
345
346 any.PackFrom( sheet );
347 }
348 else
349 {
350 item->Serialize( any );
351 }
352
353 response.mutable_items()->Add( std::move( any ) );
354 }
355 }
356
357 response.set_status( ItemRequestStatus::IRS_OK );
358 return response;
359}
360
361
363{
364 if( std::optional<ApiResponseStatus> busy = checkForBusy() )
365 return tl::unexpected( *busy );
366
367 if( !validateItemHeaderDocument( aCtx.Request.header() ) )
368 {
369 ApiResponseStatus e;
370 e.set_status( ApiStatusCode::AS_UNHANDLED );
371 return tl::unexpected( e );
372 }
373
374 SCH_SHEET_LIST hierarchy = schematic()->Hierarchy();
375 std::optional<SCH_SHEET_PATH> pathFilter;
376
377 if( aCtx.Request.header().document().has_sheet_path() )
378 {
379 KIID_PATH kp = UnpackSheetPath( aCtx.Request.header().document().sheet_path() );
380 pathFilter = hierarchy.GetSheetPathByKIIDPath( kp );
381 }
382
383 GetItemsResponse response;
384 SCH_ITEM* item = nullptr;
385 google::protobuf::Any any;
386
387 for( const types::KIID& idProto : aCtx.Request.items() )
388 {
389 KIID id( idProto.value() );
390
391 SCH_SHEET_PATH itemPath;
392
393 if( pathFilter )
394 {
395 item = pathFilter->ResolveItem( id );
396 itemPath = *pathFilter;
397 }
398 else
399 {
400 item = hierarchy.ResolveItem( id, &itemPath, true );
401 }
402
403 if( !item || !s_allowedTypes.contains( item->Type() ) )
404 continue;
405
406 if( item->Type() == SCH_SYMBOL_T )
407 {
408 kiapi::schematic::types::SchematicSymbolInstance symbol;
409
410 if( !PackSymbol( &symbol, static_cast<SCH_SYMBOL*>( item ), itemPath ) )
411 continue;
412
413 any.PackFrom( symbol );
414 }
415 else if( item->Type() == SCH_SHEET_T )
416 {
417 kiapi::schematic::types::SheetSymbol sheet;
418
419 if( !PackSheet( &sheet, static_cast<SCH_SHEET*>( item ), itemPath ) )
420 continue;
421
422 any.PackFrom( sheet );
423 }
424 else
425 {
426 item->Serialize( any );
427 }
428
429 response.mutable_items()->Add( std::move( any ) );
430 }
431
432 if( response.items().empty() )
433 {
434 ApiResponseStatus e;
435 e.set_status( ApiStatusCode::AS_BAD_REQUEST );
436 e.set_error_message( "none of the requested IDs were found or valid" );
437 return tl::unexpected( e );
438 }
439
440 response.set_status( ItemRequestStatus::IRS_OK );
441 return response;
442}
443
444
446{
447 if( !aContainer )
448 {
449 ApiResponseStatus e;
450 e.set_status( ApiStatusCode::AS_BAD_REQUEST );
451 e.set_error_message( "Tried to create an item in a null container" );
452 return tl::unexpected( e );
453 }
454
455 if( !s_allowedTypes.contains( aType ) )
456 {
457 ApiResponseStatus e;
458 e.set_status( ApiStatusCode::AS_BAD_REQUEST );
459 e.set_error_message( fmt::format( "type {} is not supported by the schematic API handler",
460 magic_enum::enum_name( aType ) ) );
461 return tl::unexpected( e );
462 }
463
464 if( aType == SCH_PIN_T && !dynamic_cast<SCH_SYMBOL*>( aContainer ) )
465 {
466 ApiResponseStatus e;
467 e.set_status( ApiStatusCode::AS_BAD_REQUEST );
468 e.set_error_message( fmt::format( "Tried to create a pin in {}, which is not a symbol",
469 aContainer->GetFriendlyName().ToStdString() ) );
470 return tl::unexpected( e );
471 }
472 else if( aType == SCH_SHEET_T && !dynamic_cast<SCH_SCREEN*>( aContainer ) )
473 {
474 ApiResponseStatus e;
475 e.set_status( ApiStatusCode::AS_BAD_REQUEST );
476 e.set_error_message( fmt::format( "Tried to create a sheet symbol in {}, which is not a "
477 "schematic sheet",
478 aContainer->GetFriendlyName().ToStdString() ) );
479 return tl::unexpected( e );
480 }
481 else if( aType == SCH_SYMBOL_T && !dynamic_cast<SCH_SCREEN*>( aContainer ) )
482 {
483 ApiResponseStatus e;
484 e.set_status( ApiStatusCode::AS_BAD_REQUEST );
485 e.set_error_message( fmt::format( "Tried to create a symbol in {}, which is not a "
486 "schematic sheet",
487 aContainer->GetFriendlyName().ToStdString() ) );
488 return tl::unexpected( e );
489 }
490
491 std::unique_ptr<EDA_ITEM> created = CreateItemForType( aType, aContainer );
492
493 if( created && !created->GetParent() )
494 created->SetParent( aContainer );
495
496 if( !created )
497 {
498 ApiResponseStatus e;
499 e.set_status( ApiStatusCode::AS_BAD_REQUEST );
500 e.set_error_message( fmt::format( "Tried to create an item of type {}, which is unhandled",
501 magic_enum::enum_name( aType ) ) );
502 return tl::unexpected( e );
503 }
504
505 return created;
506}
507
508
510 const std::string& aClientName,
511 const types::ItemHeader &aHeader,
512 const google::protobuf::RepeatedPtrField<google::protobuf::Any>& aItems,
513 std::function<void( ItemStatus, google::protobuf::Any )> aItemHandler )
514{
515 ApiResponseStatus e;
516
517 auto containerResult = validateItemHeaderDocument( aHeader );
518
519 if( !containerResult && containerResult.error().status() == ApiStatusCode::AS_UNHANDLED )
520 {
521 // No message needed for AS_UNHANDLED; this is an internal flag for the API server
522 e.set_status( ApiStatusCode::AS_UNHANDLED );
523 return tl::unexpected( e );
524 }
525 else if( !containerResult )
526 {
527 e.CopyFrom( containerResult.error() );
528 return tl::unexpected( e );
529 }
530
531 SCH_SHEET_LIST hierarchy = schematic()->Hierarchy();
532 SCH_SCREEN* targetScreen = schematic()->GetCurrentScreen();
533 SCH_SHEET_PATH targetPath = m_context->GetCurrentSheet().value_or( *hierarchy.begin() );
534
535 if( aHeader.document().has_sheet_path() )
536 {
537 KIID_PATH kp = UnpackSheetPath( aHeader.document().sheet_path() );
538 if( std::optional<SCH_SHEET_PATH> path = hierarchy.GetSheetPathByKIIDPath( kp ) )
539 {
540 targetPath = *path;
541 targetScreen = targetPath.LastScreen();
542 }
543 }
544
545 SCH_COMMIT* commit = static_cast<SCH_COMMIT*>( getCurrentCommit( aClientName ) );
546
547 for( const google::protobuf::Any& anyItem : aItems )
548 {
549 ItemStatus status;
550 std::optional<KICAD_T> type = TypeNameFromAny( anyItem );
551
552 if( !type )
553 {
554 status.set_code( ItemStatusCode::ISC_INVALID_TYPE );
555 status.set_error_message( fmt::format( "Could not decode a valid type from {}",
556 anyItem.type_url() ) );
557 aItemHandler( status, anyItem );
558 continue;
559 }
560
561 EDA_ITEM* container = targetScreen;
562
563 HANDLER_RESULT<std::unique_ptr<EDA_ITEM>> creationResult = createItemForType( *type, container );
564
565 if( !creationResult )
566 {
567 status.set_code( ItemStatusCode::ISC_INVALID_TYPE );
568 status.set_error_message( creationResult.error().error_message() );
569 aItemHandler( status, anyItem );
570 continue;
571 }
572
573 std::unique_ptr<EDA_ITEM> item( std::move( *creationResult ) );
574
575 bool unpacked = false;
576
577 if( *type == SCH_SYMBOL_T )
578 {
579 kiapi::schematic::types::SchematicSymbolInstance symbol;
580 unpacked = anyItem.UnpackTo( &symbol )
581 && UnpackSymbol( static_cast<SCH_SYMBOL*>( item.get() ), symbol );
582 }
583 else if( *type == SCH_SHEET_T )
584 {
585 kiapi::schematic::types::SheetSymbol sheetProto;
586 unpacked = anyItem.UnpackTo( &sheetProto );
587
588 if( unpacked )
589 {
590 SCH_SHEET* sheet = static_cast<SCH_SHEET*>( item.get() );
591
592 if( tl::expected<bool, ApiResponseStatus> result = UnpackSheet( sheet, sheetProto );
593 result.has_value() )
594 {
595 unpacked = *result;
596 SCH_SHEET_INSTANCE instance;
597
598 if( !sheet->GetInstances().empty() )
599 instance = *sheet->GetInstances().begin();
600
601 if( instance.m_PageNumber.IsEmpty() )
602 instance.m_PageNumber = hierarchy.GetNextPageNumber();
603
604 if( instance.m_Path.empty() )
605 {
606 SCH_SHEET_PATH newPath( targetPath );
607 newPath.push_back( sheet );
608 instance.m_Path = newPath.Path();
609 }
610
611 sheet->AddInstance( instance );
612 }
613 else
614 {
615 return tl::unexpected( result.error() );
616 }
617 }
618 }
619 else
620 {
621 unpacked = item->Deserialize( anyItem );
622 }
623
624 if( !unpacked )
625 {
626 e.set_status( ApiStatusCode::AS_BAD_REQUEST );
627 e.set_error_message( fmt::format( "could not unpack {} from request",
628 item->GetClass().ToStdString() ) );
629 return tl::unexpected( e );
630 }
631
632 SCH_ITEM* existingItem = nullptr;
633 SCH_SHEET_PATH existingPath;
634
635 existingItem = targetPath.ResolveItem( item->m_Uuid );
636
637 if( existingItem )
638 existingPath = targetPath;
639
640 if( aCreate && existingItem )
641 {
642 status.set_code( ItemStatusCode::ISC_EXISTING );
643 status.set_error_message( fmt::format( "an item with UUID {} already exists",
644 item->m_Uuid.AsStdString() ) );
645 aItemHandler( status, anyItem );
646 continue;
647 }
648 else if( !aCreate && !existingItem )
649 {
650 status.set_code( ItemStatusCode::ISC_NONEXISTENT );
651 status.set_error_message( fmt::format( "an item with UUID {} does not exist",
652 item->m_Uuid.AsStdString() ) );
653 aItemHandler( status, anyItem );
654 continue;
655 }
656
657 if( !aCreate )
658 {
659 SCH_SCREEN* itemScreen = existingPath.LastScreen();
660
661 if( itemScreen != targetScreen )
662 {
663 status.set_code( ItemStatusCode::ISC_INVALID_DATA );
664 status.set_error_message( fmt::format( "item {} exists on a different sheet than targeted",
665 item->m_Uuid.AsStdString() ) );
666 aItemHandler( status, anyItem );
667 continue;
668 }
669 }
670
671 if( *type == SCH_SHEET_T )
672 {
673 SCH_SHEET* sheet = static_cast<SCH_SHEET*>( item.get() );
674
675 if( aCreate && !sheet->GetScreen() )
676 sheet->SetScreen( new SCH_SCREEN( schematic() ) );
677
678 SCH_SHEET_PATH parentPath;
679
680 if( aCreate )
681 parentPath = targetPath;
682 else
683 parentPath = existingPath;
684
685 wxString destFilePath = parentPath.LastScreen()->GetFileName();
686
687 if( !destFilePath.IsEmpty() )
688 {
689 SCH_SHEET_LIST schematicSheets = schematic()->Hierarchy();
690 SCH_SHEET_LIST loadedSheets( sheet );
691
692 if( schematicSheets.TestForRecursion( loadedSheets, destFilePath ) )
693 {
694 status.set_code( ItemStatusCode::ISC_INVALID_DATA );
695 status.set_error_message( "sheet update would create recursive hierarchy" );
696 aItemHandler( status, anyItem );
697 continue;
698 }
699 }
700 }
701
702 status.set_code( ItemStatusCode::ISC_OK );
703 google::protobuf::Any newItem;
704
705 if( aCreate )
706 {
707 SCH_ITEM* createdItem = static_cast<SCH_ITEM*>( item.release() );
708 commit->Add( createdItem, targetScreen );
709
710 if( !createdItem )
711 {
712 e.set_status( ApiStatusCode::AS_BAD_REQUEST );
713 e.set_error_message( "could not add the requested item to its parent container" );
714 return tl::unexpected( e );
715 }
716
717 if( createdItem->Type() == SCH_SYMBOL_T )
718 {
719 kiapi::schematic::types::SchematicSymbolInstance symbol;
720
721 if( PackSymbol( &symbol, static_cast<SCH_SYMBOL*>( createdItem ), targetPath ) )
722 newItem.PackFrom( symbol );
723 }
724 else if( createdItem->Type() == SCH_SHEET_T )
725 {
726 kiapi::schematic::types::SheetSymbol sheet;
727
728 if( PackSheet( &sheet, static_cast<SCH_SHEET*>( createdItem ), targetPath ) )
729 newItem.PackFrom( sheet );
730 }
731 else
732 {
733 createdItem->Serialize( newItem );
734 }
735 }
736 else
737 {
738 commit->Modify( existingItem, targetScreen );
739 existingItem->SwapItemData( static_cast<SCH_ITEM*>( item.get() ) );
740
741 if( existingItem->Type() == SCH_SYMBOL_T )
742 {
743 SCH_SHEET_PATH path = existingPath;
744 kiapi::schematic::types::SchematicSymbolInstance symbol;
745
746 if( PackSymbol( &symbol, static_cast<SCH_SYMBOL*>( existingItem ), path ) )
747 newItem.PackFrom( symbol );
748 }
749 else if( existingItem->Type() == SCH_SHEET_T )
750 {
751 SCH_SHEET_PATH path = existingPath;
752 kiapi::schematic::types::SheetSymbol sheet;
753
754 if( PackSheet( &sheet, static_cast<SCH_SHEET*>( existingItem ), path ) )
755 newItem.PackFrom( sheet );
756 }
757 else
758 {
759 existingItem->Serialize( newItem );
760 }
761 }
762
763 aItemHandler( status, newItem );
764 }
765
766 if( !m_activeClients.contains( aClientName ) )
767 {
768 pushCurrentCommit( aClientName, aCreate ? _( "Created items via API" )
769 : _( "Modified items via API" ) );
770 }
771
772
773 return ItemRequestStatus::IRS_OK;
774}
775
776
777void API_HANDLER_SCH::deleteItemsInternal( std::map<KIID, ItemDeletionStatus>& aItemsToDelete,
778 const std::string& aClientName )
779{
780 SCH_SHEET_LIST hierarchy = schematic()->Hierarchy();
781 COMMIT* commit = getCurrentCommit( aClientName );
782
783 for( auto& [id, status] : aItemsToDelete )
784 {
786 SCH_ITEM* item = hierarchy.ResolveItem( id, &path, true );
787
788 if( !item )
789 continue;
790
791 if( !s_allowedTypes.contains( item->Type() ) )
792 {
793 status = ItemDeletionStatus::IDS_IMMUTABLE;
794 continue;
795 }
796
797 commit->Remove( item, path.LastScreen() );
798 status = ItemDeletionStatus::IDS_OK;
799 }
800
801 if( !m_activeClients.contains( aClientName ) )
802 pushCurrentCommit( aClientName, _( "Deleted items via API" ) );
803}
804
805
806std::optional<EDA_ITEM*> API_HANDLER_SCH::getItemFromDocument( const DocumentSpecifier& aDocument, const KIID& aId )
807{
808 if( !validateDocument( aDocument ) )
809 return std::nullopt;
810
811 SCH_ITEM* item = schematic()->Hierarchy().ResolveItem( aId, nullptr, true );
812
813 if( !item)
814 return std::nullopt;
815
816 return item;
817}
818
819
820std::optional<TITLE_BLOCK*> API_HANDLER_SCH::getTitleBlock()
821{
822 wxCHECK( m_context->GetCurrentSheet(), std::nullopt );
823 return &m_context->GetCurrentSheet()->LastScreen()->GetTitleBlock();
824}
825
826
827std::optional<PAGE_INFO> API_HANDLER_SCH::getPageSettings()
828{
829 wxCHECK( m_context->GetCurrentSheet(), std::nullopt );
830 return m_context->GetCurrentSheet()->LastScreen()->GetPageSettings();
831}
832
833
835{
836 wxCHECK( m_context->GetCurrentSheet(), false );
837 m_context->GetCurrentSheet()->LastScreen()->SetPageSettings( aPageInfo );
838 return true;
839}
840
841
846
847
848void API_HANDLER_SCH::setDrawingSheetFileName( const wxString& aFileName )
849{
852
853 if( m_frame )
854 m_frame->LoadDrawingSheet();
855}
856
857
859{
860 if( m_frame )
861 {
862 m_frame->Refresh();
863 m_frame->OnModify();
864 }
865}
866
867
870{
871 if( std::optional<ApiResponseStatus> busy = checkForBusy() )
872 return tl::unexpected( *busy );
873
874 HANDLER_RESULT<bool> documentValidation = validateDocument( aCtx.Request.job_settings().document() );
875
876 if( !documentValidation )
877 return tl::unexpected( documentValidation.error() );
878
879 auto plotJob = std::make_unique<JOB_EXPORT_SCH_PLOT_SVG>();
880 plotJob->m_filename = m_context->GetCurrentFileName();
881
882 if( !aCtx.Request.job_settings().output_path().empty() )
883 plotJob->SetConfiguredOutputPath( wxString::FromUTF8( aCtx.Request.job_settings().output_path() ) );
884
885 const kiapi::schematic::jobs::SchematicPlotSettings& settings = aCtx.Request.plot_settings();
886
887 plotJob->m_drawingSheet = wxString::FromUTF8( settings.drawing_sheet() );
888 plotJob->m_defaultFont = wxString::FromUTF8( settings.default_font() );
889 plotJob->m_variant = wxString::FromUTF8( settings.variant() );
890 plotJob->m_plotAll = settings.plot_all();
891 plotJob->m_plotDrawingSheet = settings.plot_drawing_sheet();
892 plotJob->m_show_hop_over = settings.show_hop_over();
893 plotJob->m_blackAndWhite = settings.black_and_white();
894 plotJob->m_useBackgroundColor = settings.use_background_color();
895 plotJob->m_minPenWidth = settings.min_pen_width();
896 plotJob->m_theme = wxString::FromUTF8( settings.theme() );
897
898 plotJob->m_plotPages.clear();
899
900 for( const std::string& page : settings.plot_pages() )
901 plotJob->m_plotPages.push_back( wxString::FromUTF8( page ) );
902
903 if( aCtx.Request.plot_settings().page_size() != kiapi::schematic::jobs::SchematicJobPageSize::SJPS_UNKNOWN )
904 {
905 plotJob->m_pageSizeSelect = FromProtoEnum<JOB_PAGE_SIZE>( aCtx.Request.plot_settings().page_size() );
906 }
907
908 return ExecuteSchematicJob( m_context->GetKiway(), *plotJob );
909}
910
911
914{
915 if( std::optional<ApiResponseStatus> busy = checkForBusy() )
916 return tl::unexpected( *busy );
917
918 HANDLER_RESULT<bool> documentValidation = validateDocument( aCtx.Request.job_settings().document() );
919
920 if( !documentValidation )
921 return tl::unexpected( documentValidation.error() );
922
923 auto plotJob = std::make_unique<JOB_EXPORT_SCH_PLOT_DXF>();
924 plotJob->m_filename = m_context->GetCurrentFileName();
925
926 if( !aCtx.Request.job_settings().output_path().empty() )
927 plotJob->SetConfiguredOutputPath( wxString::FromUTF8( aCtx.Request.job_settings().output_path() ) );
928
929 const kiapi::schematic::jobs::SchematicPlotSettings& settings = aCtx.Request.plot_settings();
930
931 plotJob->m_drawingSheet = wxString::FromUTF8( settings.drawing_sheet() );
932 plotJob->m_defaultFont = wxString::FromUTF8( settings.default_font() );
933 plotJob->m_variant = wxString::FromUTF8( settings.variant() );
934 plotJob->m_plotAll = settings.plot_all();
935 plotJob->m_plotDrawingSheet = settings.plot_drawing_sheet();
936 plotJob->m_show_hop_over = settings.show_hop_over();
937 plotJob->m_blackAndWhite = settings.black_and_white();
938 plotJob->m_useBackgroundColor = settings.use_background_color();
939 plotJob->m_minPenWidth = settings.min_pen_width();
940 plotJob->m_theme = wxString::FromUTF8( settings.theme() );
941
942 plotJob->m_plotPages.clear();
943
944 for( const std::string& page : settings.plot_pages() )
945 plotJob->m_plotPages.push_back( wxString::FromUTF8( page ) );
946
947 if( aCtx.Request.plot_settings().page_size() != kiapi::schematic::jobs::SchematicJobPageSize::SJPS_UNKNOWN )
948 {
949 plotJob->m_pageSizeSelect = FromProtoEnum<JOB_PAGE_SIZE>( aCtx.Request.plot_settings().page_size() );
950 }
951
952 return ExecuteSchematicJob( m_context->GetKiway(), *plotJob );
953}
954
955
958{
959 if( std::optional<ApiResponseStatus> busy = checkForBusy() )
960 return tl::unexpected( *busy );
961
962 HANDLER_RESULT<bool> documentValidation = validateDocument( aCtx.Request.job_settings().document() );
963
964 if( !documentValidation )
965 return tl::unexpected( documentValidation.error() );
966
967 auto plotJob = std::make_unique<JOB_EXPORT_SCH_PLOT_PDF>( false );
968 plotJob->m_filename = m_context->GetCurrentFileName();
969
970 if( !aCtx.Request.job_settings().output_path().empty() )
971 plotJob->SetConfiguredOutputPath( wxString::FromUTF8( aCtx.Request.job_settings().output_path() ) );
972
973 const kiapi::schematic::jobs::SchematicPlotSettings& settings = aCtx.Request.plot_settings();
974
975 plotJob->m_drawingSheet = wxString::FromUTF8( settings.drawing_sheet() );
976 plotJob->m_defaultFont = wxString::FromUTF8( settings.default_font() );
977 plotJob->m_variant = wxString::FromUTF8( settings.variant() );
978 plotJob->m_plotAll = settings.plot_all();
979 plotJob->m_plotDrawingSheet = settings.plot_drawing_sheet();
980 plotJob->m_show_hop_over = settings.show_hop_over();
981 plotJob->m_blackAndWhite = settings.black_and_white();
982 plotJob->m_useBackgroundColor = settings.use_background_color();
983 plotJob->m_minPenWidth = settings.min_pen_width();
984 plotJob->m_theme = wxString::FromUTF8( settings.theme() );
985
986 plotJob->m_plotPages.clear();
987
988 for( const std::string& page : settings.plot_pages() )
989 plotJob->m_plotPages.push_back( wxString::FromUTF8( page ) );
990
991 if( aCtx.Request.plot_settings().page_size() != kiapi::schematic::jobs::SchematicJobPageSize::SJPS_UNKNOWN )
992 {
993 plotJob->m_pageSizeSelect = FromProtoEnum<JOB_PAGE_SIZE>( aCtx.Request.plot_settings().page_size() );
994 }
995
996 plotJob->m_PDFPropertyPopups = aCtx.Request.property_popups();
997 plotJob->m_PDFHierarchicalLinks = aCtx.Request.hierarchical_links();
998 plotJob->m_PDFMetadata = aCtx.Request.include_metadata();
999
1000 return ExecuteSchematicJob( m_context->GetKiway(), *plotJob );
1001}
1002
1003
1006{
1007 if( std::optional<ApiResponseStatus> busy = checkForBusy() )
1008 return tl::unexpected( *busy );
1009
1010 HANDLER_RESULT<bool> documentValidation = validateDocument( aCtx.Request.job_settings().document() );
1011
1012 if( !documentValidation )
1013 return tl::unexpected( documentValidation.error() );
1014
1015 auto plotJob = std::make_unique<JOB_EXPORT_SCH_PLOT_PS>();
1016 plotJob->m_filename = m_context->GetCurrentFileName();
1017
1018 if( !aCtx.Request.job_settings().output_path().empty() )
1019 plotJob->SetConfiguredOutputPath( wxString::FromUTF8( aCtx.Request.job_settings().output_path() ) );
1020
1021 const kiapi::schematic::jobs::SchematicPlotSettings& settings = aCtx.Request.plot_settings();
1022
1023 plotJob->m_drawingSheet = wxString::FromUTF8( settings.drawing_sheet() );
1024 plotJob->m_defaultFont = wxString::FromUTF8( settings.default_font() );
1025 plotJob->m_variant = wxString::FromUTF8( settings.variant() );
1026 plotJob->m_plotAll = settings.plot_all();
1027 plotJob->m_plotDrawingSheet = settings.plot_drawing_sheet();
1028 plotJob->m_show_hop_over = settings.show_hop_over();
1029 plotJob->m_blackAndWhite = settings.black_and_white();
1030 plotJob->m_useBackgroundColor = settings.use_background_color();
1031 plotJob->m_minPenWidth = settings.min_pen_width();
1032 plotJob->m_theme = wxString::FromUTF8( settings.theme() );
1033
1034 plotJob->m_plotPages.clear();
1035
1036 for( const std::string& page : settings.plot_pages() )
1037 plotJob->m_plotPages.push_back( wxString::FromUTF8( page ) );
1038
1039 if( aCtx.Request.plot_settings().page_size() != kiapi::schematic::jobs::SchematicJobPageSize::SJPS_UNKNOWN )
1040 {
1041 plotJob->m_pageSizeSelect = FromProtoEnum<JOB_PAGE_SIZE>( aCtx.Request.plot_settings().page_size() );
1042 }
1043
1044 return ExecuteSchematicJob( m_context->GetKiway(), *plotJob );
1045}
1046
1047
1050{
1051 if( std::optional<ApiResponseStatus> busy = checkForBusy() )
1052 return tl::unexpected( *busy );
1053
1054 HANDLER_RESULT<bool> documentValidation = validateDocument( aCtx.Request.job_settings().document() );
1055
1056 if( !documentValidation )
1057 return tl::unexpected( documentValidation.error() );
1058
1059 if( aCtx.Request.format() == kiapi::schematic::jobs::SchematicNetlistFormat::SNF_UNKNOWN )
1060 {
1061 ApiResponseStatus e;
1062 e.set_status( ApiStatusCode::AS_BAD_REQUEST );
1063 e.set_error_message( "RunSchematicJobExportNetlist requires a valid format" );
1064 return tl::unexpected( e );
1065 }
1066
1067 JOB_EXPORT_SCH_NETLIST netlistJob;
1068 netlistJob.m_filename = m_context->GetCurrentFileName();
1069
1070 if( !aCtx.Request.job_settings().output_path().empty() )
1071 netlistJob.SetConfiguredOutputPath( wxString::FromUTF8( aCtx.Request.job_settings().output_path() ) );
1072
1073 netlistJob.format = FromProtoEnum<JOB_EXPORT_SCH_NETLIST::FORMAT>( aCtx.Request.format() );
1074
1075 if( !aCtx.Request.variant_name().empty() )
1076 netlistJob.m_variantNames.emplace_back( wxString::FromUTF8( aCtx.Request.variant_name() ) );
1077
1078 return ExecuteSchematicJob( m_context->GetKiway(), netlistJob );
1079}
1080
1081
1084{
1085 if( std::optional<ApiResponseStatus> busy = checkForBusy() )
1086 return tl::unexpected( *busy );
1087
1088 HANDLER_RESULT<bool> documentValidation = validateDocument( aCtx.Request.job_settings().document() );
1089
1090 if( !documentValidation )
1091 return tl::unexpected( documentValidation.error() );
1092
1093 JOB_EXPORT_SCH_BOM bomJob;
1094 bomJob.m_filename = m_context->GetCurrentFileName();
1095
1096 if( !aCtx.Request.job_settings().output_path().empty() )
1097 bomJob.SetConfiguredOutputPath( wxString::FromUTF8( aCtx.Request.job_settings().output_path() ) );
1098
1099 bomJob.m_bomFmtPresetName = wxString::FromUTF8( aCtx.Request.format().preset_name() );
1100 bomJob.m_fieldDelimiter = wxString::FromUTF8( aCtx.Request.format().field_delimiter() );
1101 bomJob.m_stringDelimiter = wxString::FromUTF8( aCtx.Request.format().string_delimiter() );
1102 bomJob.m_refDelimiter = wxString::FromUTF8( aCtx.Request.format().ref_delimiter() );
1103 bomJob.m_refRangeDelimiter = wxString::FromUTF8( aCtx.Request.format().ref_range_delimiter() );
1104 bomJob.m_keepTabs = aCtx.Request.format().keep_tabs();
1105 bomJob.m_keepLineBreaks = aCtx.Request.format().keep_line_breaks();
1106
1107 bomJob.m_bomPresetName = wxString::FromUTF8( aCtx.Request.fields().preset_name() );
1108 bomJob.m_sortField = wxString::FromUTF8( aCtx.Request.fields().sort_field() );
1109 bomJob.m_filterString = wxString::FromUTF8( aCtx.Request.fields().filter() );
1110
1111 if( aCtx.Request.fields().sort_direction() == kiapi::schematic::jobs::BOMSortDirection::BSD_ASCENDING )
1112 {
1113 bomJob.m_sortAsc = true;
1114 }
1115 else if( aCtx.Request.fields().sort_direction() == kiapi::schematic::jobs::BOMSortDirection::BSD_DESCENDING )
1116 {
1117 bomJob.m_sortAsc = false;
1118 }
1119
1120 for( const kiapi::schematic::jobs::BOMField& field : aCtx.Request.fields().fields() )
1121 {
1122 bomJob.m_fieldsOrdered.emplace_back( wxString::FromUTF8( field.name() ) );
1123 bomJob.m_fieldsLabels.emplace_back( wxString::FromUTF8( field.label() ) );
1124
1125 if( field.group_by() )
1126 bomJob.m_fieldsGroupBy.emplace_back( wxString::FromUTF8( field.name() ) );
1127 }
1128
1129 bomJob.m_excludeDNP = aCtx.Request.exclude_dnp();
1130 bomJob.m_groupSymbols = aCtx.Request.group_symbols();
1131
1132 if( !aCtx.Request.variant_name().empty() )
1133 bomJob.m_variantNames.emplace_back( wxString::FromUTF8( aCtx.Request.variant_name() ) );
1134
1135 return ExecuteSchematicJob( m_context->GetKiway(), bomJob );
1136}
1137
1138
1139void API_HANDLER_SCH::packSheetInstance( kiapi::schematic::types::SheetInstance* aInstance, SCH_SHEET_PATH& aPath,
1140 SCH_SHEET* aSheet )
1141{
1142 aPath.push_back( aSheet );
1143
1144 PackSheetPath( *aInstance->mutable_path(), aPath.Path() );
1145
1146 wxString sheetName = aSheet->GetShownName( false );
1147
1148 if( sheetName.IsEmpty() && aSheet->GetScreen() )
1149 {
1150 wxFileName fn( aSheet->GetScreen()->GetFileName() );
1151 sheetName = fn.GetName();
1152 }
1153
1154 aInstance->set_name( sheetName.ToUTF8() );
1155 aInstance->set_filename( aSheet->GetFileName().ToUTF8() );
1156 aInstance->set_page_number( aPath.GetPageNumber().ToUTF8() );
1157
1158 if( aSheet->GetScreen() )
1159 {
1160 std::vector<SCH_ITEM*> childSheets;
1161 aSheet->GetScreen()->GetSheets( &childSheets );
1162
1163 std::ranges::sort( childSheets,
1164 [&]( SCH_ITEM* a, SCH_ITEM* b )
1165 {
1166 SCH_SHEET_PATH pathA = aPath;
1167 pathA.push_back( static_cast<SCH_SHEET*>( a ) );
1168
1169 SCH_SHEET_PATH pathB = aPath;
1170 pathB.push_back( static_cast<SCH_SHEET*>( b ) );
1171
1172 return pathA.ComparePageNum( pathB ) < 0;
1173 } );
1174
1175 for( SCH_ITEM* childItem : childSheets )
1176 {
1177 SCH_SHEET* childSheet = static_cast<SCH_SHEET*>( childItem );
1178 kiapi::schematic::types::SheetInstance* childInstance = aInstance->add_children();
1179 packSheetInstance( childInstance, aPath, childSheet );
1180 }
1181 }
1182
1183 aPath.pop_back();
1184}
1185
1186
1189{
1190 HANDLER_RESULT<bool> documentValidation = validateDocument( aCtx.Request.document() );
1191
1192 if( !documentValidation )
1193 return tl::unexpected( documentValidation.error() );
1194
1195 kiapi::schematic::types::SchematicHierarchyResponse response;
1196 response.mutable_document()->CopyFrom( aCtx.Request.document() );
1197
1198 if( !schematic()->HasHierarchy() )
1200
1202 std::vector<SCH_SHEET*> topLevelSheets = schematic()->GetTopLevelSheets();
1203
1204 std::ranges::sort( topLevelSheets,
1205 [&]( SCH_SHEET* a, SCH_SHEET* b )
1206 {
1207 SCH_SHEET_PATH pathA;
1208 pathA.push_back( a );
1209
1210 SCH_SHEET_PATH pathB;
1211 pathB.push_back( b );
1212
1213 return pathA.ComparePageNum( pathB ) < 0;
1214 } );
1215
1216 for( SCH_SHEET* topSheet : topLevelSheets )
1217 {
1218 kiapi::schematic::types::SheetInstance* instance = response.add_top_level_sheets();
1219 packSheetInstance( instance, path, topSheet );
1220 }
1221
1222 return response;
1223}
KICAD_T FromProtoEnum(types::KiCadObjectType aValue)
Definition api_enums.cpp:44
tl::expected< T, ApiResponseStatus > HANDLER_RESULT
Definition api_handler.h:45
HANDLER_RESULT< types::RunJobResponse > ExecuteSchematicJob(KIWAY *aKiway, JOB &aJob)
std::unique_ptr< EDA_ITEM > CreateItemForType(KICAD_T aType, EDA_ITEM *aContainer)
tl::expected< bool, ApiResponseStatus > UnpackSheet(SCH_SHEET *aOutput, const kiapi::schematic::types::SheetSymbol &aInput)
bool PackSheet(kiapi::schematic::types::SheetSymbol *aOutput, const SCH_SHEET *aInput, const SCH_SHEET_PATH &aPath)
bool PackSymbol(kiapi::schematic::types::SchematicSymbolInstance *aOutput, const SCH_SYMBOL *aInput, const SCH_SHEET_PATH &aPath)
bool UnpackSymbol(SCH_SYMBOL *aOutput, const kiapi::schematic::types::SchematicSymbolInstance &aInput)
BASE_SCREEN class implementation.
HANDLER_RESULT< bool > validateDocument(const DocumentSpecifier &aDocument)
HANDLER_RESULT< types::PageSettings > handleSetPageSettings(const HANDLER_CONTEXT< commands::SetPageSettings > &aCtx)
HANDLER_RESULT< std::optional< KIID > > validateItemHeaderDocument(const kiapi::common::types::ItemHeader &aHeader)
If the header is valid, returns the item container.
HANDLER_RESULT< types::PageSettings > handleGetPageSettings(const HANDLER_CONTEXT< commands::GetPageSettings > &aCtx)
API_HANDLER_EDITOR(EDA_BASE_FRAME *aFrame=nullptr)
static std::vector< KICAD_T > parseRequestedItemTypes(const google::protobuf::RepeatedField< int > &aTypes)
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::optional< TITLE_BLOCK * > getTitleBlock() override
wxString getDrawingSheetFileName() override
SCH_EDIT_FRAME * m_frame
HANDLER_RESULT< kiapi::schematic::types::SchematicHierarchyResponse > handleGetSchematicHierarchy(const HANDLER_CONTEXT< kiapi::schematic::types::GetSchematicHierarchy > &aCtx)
std::unique_ptr< COMMIT > createCommit() override
Override this to create an appropriate COMMIT subclass for the frame in question.
SCHEMATIC * schematic() const
HANDLER_RESULT< types::RunJobResponse > handleRunSchematicJobExportPdf(const HANDLER_CONTEXT< kiapi::schematic::jobs::RunSchematicJobExportPdf > &aCtx)
static std::set< KICAD_T > s_allowedTypes
HANDLER_RESULT< commands::GetItemsResponse > handleGetItemsById(const HANDLER_CONTEXT< commands::GetItemsById > &aCtx)
std::optional< SCH_ITEM * > getItemById(const KIID &aId, SCH_SHEET_PATH *aPathOut=nullptr) const
bool setPageSettings(const PAGE_INFO &aPageInfo) override
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)
void filterValidSchTypes(std::set< KICAD_T > &aTypeList)
HANDLER_RESULT< types::RunJobResponse > handleRunSchematicJobExportBOM(const HANDLER_CONTEXT< kiapi::schematic::jobs::RunSchematicJobExportBOM > &aCtx)
std::optional< PAGE_INFO > getPageSettings() override
HANDLER_RESULT< types::RunJobResponse > handleRunSchematicJobExportPs(const HANDLER_CONTEXT< kiapi::schematic::jobs::RunSchematicJobExportPs > &aCtx)
void onModified() override
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)
void deleteItemsInternal(std::map< KIID, ItemDeletionStatus > &aItemsToDelete, const std::string &aClientName) override
void packSheetInstance(kiapi::schematic::types::SheetInstance *aInstance, SCH_SHEET_PATH &aPath, SCH_SHEET *aSheet)
tl::expected< bool, ApiResponseStatus > validateDocumentInternal(const DocumentSpecifier &aDocument) const override
void setDrawingSheetFileName(const wxString &aFileName) override
HANDLER_RESULT< commands::GetItemsResponse > handleGetItems(const HANDLER_CONTEXT< commands::GetItems > &aCtx)
void registerHandler(HANDLER_RESULT< ResponseType >(HandlerType::*aHandler)(const HANDLER_CONTEXT< RequestType > &))
Registers an API command handler for the given message types.
Definition api_handler.h:93
static wxString m_DrawingSheetFileName
the name of the drawing sheet file, or empty to use the default drawing sheet
Definition base_screen.h:85
Represent a set of changes (additions, deletions or modifications) of a data model (e....
Definition commit.h:72
COMMIT & Remove(EDA_ITEM *aItem, BASE_SCREEN *aScreen=nullptr)
Remove a new item from the model.
Definition commit.h:90
COMMIT & Modify(EDA_ITEM *aItem, BASE_SCREEN *aScreen=nullptr, RECURSE_MODE aRecurse=RECURSE_MODE::NO_RECURSE)
Modify a given item in the model.
Definition commit.h:106
COMMIT & Add(EDA_ITEM *aItem, BASE_SCREEN *aScreen=nullptr)
Add a new item to the model.
Definition commit.h:78
A base class for most all the KiCad significant classes used in schematics and boards.
Definition eda_item.h:100
KICAD_T Type() const
Returns the type of object.
Definition eda_item.h:112
virtual wxString GetFriendlyName() const
Definition eda_item.cpp:411
std::vector< wxString > m_fieldsLabels
std::vector< wxString > m_fieldsOrdered
std::vector< wxString > m_fieldsGroupBy
std::vector< wxString > m_variantNames
std::vector< wxString > m_variantNames
An simple container class that lets us dispatch output jobs to kifaces.
Definition job.h:184
void SetConfiguredOutputPath(const wxString &aPath)
Sets the configured output path for the job, this path is always saved to file.
Definition job.cpp:157
const std::vector< JOB_OUTPUT > & GetOutputs()
Definition job.h:215
const std::string & GetType() const
Definition job.h:195
Definition kiid.h:48
A minimalistic software bus for communications between various DLLs/DSOs (DSOs) within the same KiCad...
Definition kiway.h:315
int ProcessJob(KIWAY::FACE_T aFace, JOB *aJob, REPORTER *aReporter=nullptr, PROGRESS_REPORTER *aProgressReporter=nullptr)
Definition kiway.cpp:750
@ FACE_SCH
eeschema DSO
Definition kiway.h:322
Describe the page size and margins of a paper page on which to eventually print or plot.
Definition page_info.h:79
Container for project specific data.
Definition project.h:66
virtual const wxString GetProjectPath() const
Return the full path of the project.
Definition project.cpp:187
virtual const wxString GetProjectName() const
Return the short name of the project.
Definition project.cpp:199
Holds all the data relating to one schematic.
Definition schematic.h:89
SCHEMATIC_SETTINGS & Settings() const
SCH_SCREEN * GetCurrentScreen() const
Definition schematic.h:198
SCH_ITEM * ResolveItem(const KIID &aID, SCH_SHEET_PATH *aPathOut=nullptr, bool aAllowNullptrReturn=false) const
Definition schematic.h:127
SCH_SHEET_LIST Hierarchy() const
Return the full schematic flattened hierarchical sheet list.
std::vector< SCH_SHEET * > GetTopLevelSheets() const
Get the list of top-level sheets.
void RefreshHierarchy()
Schematic editor (Eeschema) main window.
Base class for any item which can be embedded within the SCHEMATIC container class,...
Definition sch_item.h:168
void SwapItemData(SCH_ITEM *aImage)
Swap data between aItem and aImage.
Definition sch_item.cpp:636
EE_RTREE & Items()
Get the full RTree, usually for iterating.
Definition sch_screen.h:119
const wxString & GetFileName() const
Definition sch_screen.h:154
void GetSheets(std::vector< SCH_ITEM * > *aItems) const
Similar to Items().OfType( SCH_SHEET_T ), but return the sheets in a deterministic order (L-R,...
A container for handling SCH_SHEET_PATH objects in a flattened hierarchy.
std::optional< SCH_SHEET_PATH > GetSheetPathByKIIDPath(const KIID_PATH &aPath, bool aIncludeLastSheet=true) const
Finds a SCH_SHEET_PATH that matches the provided KIID_PATH.
SCH_ITEM * ResolveItem(const KIID &aID, SCH_SHEET_PATH *aPathOut=nullptr, bool aAllowNullptrReturn=false) const
Fetch a SCH_ITEM by ID.
wxString GetNextPageNumber() const
bool TestForRecursion(const SCH_SHEET_LIST &aSrcSheetHierarchy, const wxString &aDestFileName)
Test every SCH_SHEET_PATH in this SCH_SHEET_LIST to verify if adding the sheets stored in aSrcSheetHi...
Handle access to a stack of flattened SCH_SHEET objects by way of a path for creating a flattened sch...
int ComparePageNum(const SCH_SHEET_PATH &aSheetPathToTest) const
Compare sheets by their page number.
KIID_PATH Path() const
Get the sheet path as an KIID_PATH.
SCH_ITEM * ResolveItem(const KIID &aID) const
Fetch a SCH_ITEM by ID.
SCH_SCREEN * LastScreen()
wxString GetPageNumber() const
void push_back(SCH_SHEET *aSheet)
Forwarded method from std::vector.
void pop_back()
Forwarded method from std::vector.
Sheet symbol placed in a schematic, and is the entry point for a sub schematic.
Definition sch_sheet.h:48
wxString GetFileName() const
Return the filename corresponding to this sheet.
Definition sch_sheet.h:374
void AddInstance(const SCH_SHEET_INSTANCE &aInstance)
SCH_SCREEN * GetScreen() const
Definition sch_sheet.h:143
void SetScreen(SCH_SCREEN *aScreen)
Set the SCH_SCREEN associated with this sheet to aScreen.
wxString GetShownName(bool aAllowExtraText) const
Definition sch_sheet.h:136
const std::vector< SCH_SHEET_INSTANCE > & GetInstances() const
Definition sch_sheet.h:509
Schematic symbol object.
Definition sch_symbol.h:76
virtual void Serialize(google::protobuf::Any &aContainer) const
Serializes this object to the given Any message.
A wrapper for reporting to a wxString object.
Definition reporter.h:193
const wxString & GetMessages() const
Definition reporter.cpp:105
A type-safe container of any type.
Definition ki_any.h:93
#define _(s)
@ NO_RECURSE
Definition eda_item.h:54
KICOMMON_API void PackProject(types::ProjectSpecifier &aOutput, const PROJECT &aInput)
KICOMMON_API KIID_PATH UnpackSheetPath(const types::SheetPath &aInput)
KICOMMON_API std::optional< KICAD_T > TypeNameFromAny(const google::protobuf::Any &aMessage)
Definition api_utils.cpp:35
KICOMMON_API void PackSheetPath(types::SheetPath &aOutput, const KIID_PATH &aInput)
STL namespace.
std::shared_ptr< SCH_CONTEXT > CreateSchFrameContext(SCH_EDIT_FRAME *aFrame)
Class to handle a set of SCH_ITEMs.
Definition of the SCH_SHEET_PATH and SCH_SHEET_LIST classes for Eeschema.
RequestMessageType Request
Definition api_handler.h:52
A simple container for sheet instance information.
std::string path
nlohmann::json output
wxString result
Test unit parsing edge cases and error handling.
KICAD_T
The set of class identification values stored in EDA_ITEM::m_structType.
Definition typeinfo.h:75
@ SCH_GROUP_T
Definition typeinfo.h:174
@ SCH_LINE_T
Definition typeinfo.h:164
@ SCH_NO_CONNECT_T
Definition typeinfo.h:161
@ SCH_SYMBOL_T
Definition typeinfo.h:173
@ SCH_DIRECTIVE_LABEL_T
Definition typeinfo.h:172
@ SCH_LABEL_T
Definition typeinfo.h:168
@ SCH_SHEET_T
Definition typeinfo.h:176
@ SCH_SHAPE_T
Definition typeinfo.h:150
@ SCH_HIER_LABEL_T
Definition typeinfo.h:170
@ SCH_BUS_BUS_ENTRY_T
Definition typeinfo.h:163
@ SCH_TEXT_T
Definition typeinfo.h:152
@ SCH_BUS_WIRE_ENTRY_T
Definition typeinfo.h:162
@ SCH_BITMAP_T
Definition typeinfo.h:165
@ SCH_TEXTBOX_T
Definition typeinfo.h:153
@ SCH_GLOBAL_LABEL_T
Definition typeinfo.h:169
@ SCH_JUNCTION_T
Definition typeinfo.h:160
@ SCH_PIN_T
Definition typeinfo.h:154