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 <connection_graph.h>
35#include <sch_commit.h>
36#include <sch_edit_frame.h>
37#include <sch_label.h>
38#include <sch_screen.h>
39#include <sch_sheet.h>
40#include <sch_sheet_path.h>
41#include <sch_sheet_pin.h>
42#include <sch_symbol.h>
43#include <schematic.h>
44#include <wx/filename.h>
45
46#include <api/common/types/base_types.pb.h>
47
48using namespace kiapi::common::commands;
49using kiapi::common::types::CommandStatus;
50using kiapi::common::types::DocumentType;
51using kiapi::common::types::ItemRequestStatus;
52
53
54std::set<KICAD_T> API_HANDLER_SCH::s_allowedTypes = {
55 // SCH_MARKER_T,
65 // SCH_TABLE_T,
73};
74
75
77{
78 types::RunJobResponse response;
79 WX_STRING_REPORTER reporter;
80 int exitCode = aKiway->ProcessJob( KIWAY::FACE_SCH, &aJob, &reporter );
81
82 for( const JOB_OUTPUT& output : aJob.GetOutputs() )
83 response.add_output_path( output.m_outputPath.ToUTF8() );
84
85 if( exitCode == 0 )
86 {
87 response.set_status( types::JobStatus::JS_SUCCESS );
88 return response;
89 }
90
91 response.set_status( types::JobStatus::JS_ERROR );
92 response.set_message( fmt::format( "Schematic export job '{}' failed with exit code {}: {}",
93 aJob.GetType(), exitCode,
94 reporter.GetMessages().ToStdString() ) );
95 return response;
96}
97
98
103
104
105API_HANDLER_SCH::API_HANDLER_SCH( std::shared_ptr<SCH_CONTEXT> aContext,
106 SCH_EDIT_FRAME* aFrame ) :
107 API_HANDLER_EDITOR( aFrame ),
108 m_frame( aFrame ),
109 m_context( std::move( aContext ) )
110{
111 using namespace kiapi::schematic::jobs;
112 using namespace kiapi::schematic::types;
113
118
135}
136
137
138std::unique_ptr<COMMIT> API_HANDLER_SCH::createCommit()
139{
140 return std::make_unique<SCH_COMMIT>( m_frame );
141}
142
143
145{
146 wxCHECK( m_context, nullptr );
147 return m_context->GetSchematic();
148}
149
150
151std::optional<SCH_ITEM*> API_HANDLER_SCH::getItemById( const KIID& aId, SCH_SHEET_PATH* aPathOut ) const
152{
153 if( !schematic()->HasHierarchy() )
155
156 SCH_ITEM* item = schematic()->ResolveItem( aId, aPathOut, true );
157
158 if( !item )
159 return std::nullopt;
160
161 return item;
162}
163
164
165tl::expected<bool, ApiResponseStatus>
166API_HANDLER_SCH::validateDocumentInternal( const DocumentSpecifier& aDocument ) const
167{
168 if( aDocument.type() != DocumentType::DOCTYPE_SCHEMATIC )
169 {
170 ApiResponseStatus e;
171 e.set_status( ApiStatusCode::AS_BAD_REQUEST );
172 e.set_error_message( "the requested document is not a schematic" );
173 return tl::unexpected( e );
174 }
175
176 const PROJECT& prj = m_context->Prj();
177
178 if( aDocument.project().name().compare( prj.GetProjectName().ToUTF8() ) != 0 )
179 {
180 ApiResponseStatus e;
181 e.set_status( ApiStatusCode::AS_BAD_REQUEST );
182 e.set_error_message( fmt::format( "the requested project {} is not open",
183 aDocument.project().name() ) );
184 return tl::unexpected( e );
185 }
186
187 if( aDocument.project().path().compare( prj.GetProjectPath().ToUTF8() ) != 0 )
188 {
189 ApiResponseStatus e;
190 e.set_status( ApiStatusCode::AS_BAD_REQUEST );
191 e.set_error_message( fmt::format( "the requested project {} is not open at path {}",
192 aDocument.project().name(),
193 aDocument.project().path() ) );
194 return tl::unexpected( e );
195 }
196
197 if( aDocument.has_sheet_path() )
198 {
199 KIID_PATH path = UnpackSheetPath( aDocument.sheet_path() );
200
201 if( !schematic()->Hierarchy().HasPath( path ) )
202 {
203 ApiResponseStatus e;
204 e.set_status( ApiStatusCode::AS_BAD_REQUEST );
205 e.set_error_message( fmt::format( "the requested sheet path {} is not valid for this schematic",
206 path.AsString().ToStdString() ) );
207 return tl::unexpected( e );
208 }
209 }
210
211 return true;
212}
213
214
217{
218 if( aCtx.Request.type() != DocumentType::DOCTYPE_SCHEMATIC )
219 {
220 ApiResponseStatus e;
221
222 // No message needed for AS_UNHANDLED; this is an internal flag for the API server
223 e.set_status( ApiStatusCode::AS_UNHANDLED );
224 return tl::unexpected( e );
225 }
226
227 GetOpenDocumentsResponse response;
228 common::types::DocumentSpecifier doc;
229
230 wxFileName fn( m_context->GetCurrentFileName() );
231
232 doc.set_type( DocumentType::DOCTYPE_SCHEMATIC );
233
234 if( std::optional<SCH_SHEET_PATH> path = m_context->GetCurrentSheet() )
235 PackSheetPath( *doc.mutable_sheet_path(), path->Path() );
236
237 PackProject( *doc.mutable_project(), m_context->Prj() );
238
239 response.mutable_documents()->Add( std::move( doc ) );
240 return response;
241}
242
243
244void API_HANDLER_SCH::filterValidSchTypes( std::set<KICAD_T>& aTypeList )
245{
246 std::erase_if( aTypeList,
247 []( KICAD_T aType )
248 {
249 return !s_allowedTypes.contains( aType );
250 } );
251}
252
253
255{
256 if( std::optional<ApiResponseStatus> busy = checkForBusy() )
257 return tl::unexpected( *busy );
258
259 if( HANDLER_RESULT<std::optional<KIID>> valid = validateItemHeaderDocument( aCtx.Request.header() );
260 !valid.has_value() )
261 {
262 return tl::unexpected( valid.error() );
263 }
264
265 std::set<KICAD_T> typesRequested, typesInserted;
266
267 for( KICAD_T type : parseRequestedItemTypes( aCtx.Request.types() ) )
268 typesRequested.insert( type );
269
270 filterValidSchTypes( typesRequested );
271
272 if( typesRequested.empty() )
273 {
274 ApiResponseStatus e;
275 e.set_status( ApiStatusCode::AS_BAD_REQUEST );
276 e.set_error_message( "none of the requested types are valid for a Schematic object" );
277 return tl::unexpected( e );
278 }
279
280 SCH_SHEET_LIST hierarchy = schematic()->Hierarchy();
281 std::optional<SCH_SHEET_PATH> pathFilter;
282
283 if( aCtx.Request.header().document().has_sheet_path() )
284 {
285 KIID_PATH kp = UnpackSheetPath( aCtx.Request.header().document().sheet_path() );
286 pathFilter = hierarchy.GetSheetPathByKIIDPath( kp );
287 }
288
289 std::map<KICAD_T, std::vector<std::pair<EDA_ITEM*, SCH_SHEET_PATH>>> itemMap;
290
291 auto processScreen =
292 [&]( const SCH_SHEET_PATH& aPath )
293 {
294 const SCH_SCREEN* aScreen = aPath.LastScreen();
295
296 for( SCH_ITEM* aItem : aScreen->Items() )
297 {
298 itemMap[ aItem->Type() ].emplace_back( aItem, aPath );
299
300 aItem->RunOnChildren(
301 [&]( SCH_ITEM* aChild )
302 {
303 itemMap[ aChild->Type() ].emplace_back( aChild, aPath );
304 },
306 }
307 };
308
309 if( pathFilter )
310 {
311 processScreen( *pathFilter );
312 }
313 else
314 {
315 for( const SCH_SHEET_PATH& path : hierarchy )
316 processScreen( path );
317 }
318
319 GetItemsResponse response;
320 google::protobuf::Any any;
321
322 for( KICAD_T type : parseRequestedItemTypes( aCtx.Request.types() ) )
323 {
324 if( !s_allowedTypes.contains( type ) )
325 continue;
326
327 if( typesInserted.contains( type ) )
328 continue;
329
330 for( const auto& [item, itemPath] : itemMap[type] )
331 {
332 if( item->Type() == SCH_SYMBOL_T )
333 {
334 kiapi::schematic::types::SchematicSymbolInstance symbol;
335
336 if( !PackSymbol( &symbol, static_cast<SCH_SYMBOL*>( item ), itemPath ) )
337 continue;
338
339 any.PackFrom( symbol );
340 }
341 else if( item->Type() == SCH_SHEET_T )
342 {
343 kiapi::schematic::types::SheetSymbol sheet;
344
345 if( !PackSheet( &sheet, static_cast<SCH_SHEET*>( item ), itemPath ) )
346 continue;
347
348 any.PackFrom( sheet );
349 }
350 else
351 {
352 item->Serialize( any );
353 }
354
355 response.mutable_items()->Add( std::move( any ) );
356 }
357 }
358
359 response.set_status( ItemRequestStatus::IRS_OK );
360 return response;
361}
362
363
365{
366 if( std::optional<ApiResponseStatus> busy = checkForBusy() )
367 return tl::unexpected( *busy );
368
369 if( !validateItemHeaderDocument( aCtx.Request.header() ) )
370 {
371 ApiResponseStatus e;
372 e.set_status( ApiStatusCode::AS_UNHANDLED );
373 return tl::unexpected( e );
374 }
375
376 SCH_SHEET_LIST hierarchy = schematic()->Hierarchy();
377 std::optional<SCH_SHEET_PATH> pathFilter;
378
379 if( aCtx.Request.header().document().has_sheet_path() )
380 {
381 KIID_PATH kp = UnpackSheetPath( aCtx.Request.header().document().sheet_path() );
382 pathFilter = hierarchy.GetSheetPathByKIIDPath( kp );
383 }
384
385 GetItemsResponse response;
386 SCH_ITEM* item = nullptr;
387 google::protobuf::Any any;
388
389 for( const types::KIID& idProto : aCtx.Request.items() )
390 {
391 KIID id( idProto.value() );
392
393 SCH_SHEET_PATH itemPath;
394
395 if( pathFilter )
396 {
397 item = pathFilter->ResolveItem( id );
398 itemPath = *pathFilter;
399 }
400 else
401 {
402 item = hierarchy.ResolveItem( id, &itemPath, true );
403 }
404
405 if( !item || !s_allowedTypes.contains( item->Type() ) )
406 continue;
407
408 if( item->Type() == SCH_SYMBOL_T )
409 {
410 kiapi::schematic::types::SchematicSymbolInstance symbol;
411
412 if( !PackSymbol( &symbol, static_cast<SCH_SYMBOL*>( item ), itemPath ) )
413 continue;
414
415 any.PackFrom( symbol );
416 }
417 else if( item->Type() == SCH_SHEET_T )
418 {
419 kiapi::schematic::types::SheetSymbol sheet;
420
421 if( !PackSheet( &sheet, static_cast<SCH_SHEET*>( item ), itemPath ) )
422 continue;
423
424 any.PackFrom( sheet );
425 }
426 else
427 {
428 item->Serialize( any );
429 }
430
431 response.mutable_items()->Add( std::move( any ) );
432 }
433
434 if( response.items().empty() )
435 {
436 ApiResponseStatus e;
437 e.set_status( ApiStatusCode::AS_BAD_REQUEST );
438 e.set_error_message( "none of the requested IDs were found or valid" );
439 return tl::unexpected( e );
440 }
441
442 response.set_status( ItemRequestStatus::IRS_OK );
443 return response;
444}
445
446
448{
449 if( !aContainer )
450 {
451 ApiResponseStatus e;
452 e.set_status( ApiStatusCode::AS_BAD_REQUEST );
453 e.set_error_message( "Tried to create an item in a null container" );
454 return tl::unexpected( e );
455 }
456
457 if( !s_allowedTypes.contains( aType ) )
458 {
459 ApiResponseStatus e;
460 e.set_status( ApiStatusCode::AS_BAD_REQUEST );
461 e.set_error_message( fmt::format( "type {} is not supported by the schematic API handler",
462 magic_enum::enum_name( aType ) ) );
463 return tl::unexpected( e );
464 }
465
466 if( aType == SCH_PIN_T && !dynamic_cast<SCH_SYMBOL*>( aContainer ) )
467 {
468 ApiResponseStatus e;
469 e.set_status( ApiStatusCode::AS_BAD_REQUEST );
470 e.set_error_message( fmt::format( "Tried to create a pin in {}, which is not a symbol",
471 aContainer->GetFriendlyName().ToStdString() ) );
472 return tl::unexpected( e );
473 }
474 else if( aType == SCH_SHEET_T && !dynamic_cast<SCH_SCREEN*>( aContainer ) )
475 {
476 ApiResponseStatus e;
477 e.set_status( ApiStatusCode::AS_BAD_REQUEST );
478 e.set_error_message( fmt::format( "Tried to create a sheet symbol in {}, which is not a "
479 "schematic sheet",
480 aContainer->GetFriendlyName().ToStdString() ) );
481 return tl::unexpected( e );
482 }
483 else if( aType == SCH_SYMBOL_T && !dynamic_cast<SCH_SCREEN*>( aContainer ) )
484 {
485 ApiResponseStatus e;
486 e.set_status( ApiStatusCode::AS_BAD_REQUEST );
487 e.set_error_message( fmt::format( "Tried to create a symbol in {}, which is not a "
488 "schematic sheet",
489 aContainer->GetFriendlyName().ToStdString() ) );
490 return tl::unexpected( e );
491 }
492
493 std::unique_ptr<EDA_ITEM> created = CreateItemForType( aType, aContainer );
494
495 if( created && !created->GetParent() )
496 created->SetParent( aContainer );
497
498 if( !created )
499 {
500 ApiResponseStatus e;
501 e.set_status( ApiStatusCode::AS_BAD_REQUEST );
502 e.set_error_message( fmt::format( "Tried to create an item of type {}, which is unhandled",
503 magic_enum::enum_name( aType ) ) );
504 return tl::unexpected( e );
505 }
506
507 return created;
508}
509
510
512 const std::string& aClientName,
513 const types::ItemHeader &aHeader,
514 const google::protobuf::RepeatedPtrField<google::protobuf::Any>& aItems,
515 std::function<void( ItemStatus, google::protobuf::Any )> aItemHandler )
516{
517 ApiResponseStatus e;
518
519 auto containerResult = validateItemHeaderDocument( aHeader );
520
521 if( !containerResult && containerResult.error().status() == ApiStatusCode::AS_UNHANDLED )
522 {
523 // No message needed for AS_UNHANDLED; this is an internal flag for the API server
524 e.set_status( ApiStatusCode::AS_UNHANDLED );
525 return tl::unexpected( e );
526 }
527 else if( !containerResult )
528 {
529 e.CopyFrom( containerResult.error() );
530 return tl::unexpected( e );
531 }
532
533 SCH_SHEET_LIST hierarchy = schematic()->Hierarchy();
534 SCH_SCREEN* targetScreen = schematic()->GetCurrentScreen();
535 SCH_SHEET_PATH targetPath = m_context->GetCurrentSheet().value_or( *hierarchy.begin() );
536
537 if( aHeader.document().has_sheet_path() )
538 {
539 KIID_PATH kp = UnpackSheetPath( aHeader.document().sheet_path() );
540 if( std::optional<SCH_SHEET_PATH> path = hierarchy.GetSheetPathByKIIDPath( kp ) )
541 {
542 targetPath = *path;
543 targetScreen = targetPath.LastScreen();
544 }
545 }
546
547 SCH_COMMIT* commit = static_cast<SCH_COMMIT*>( getCurrentCommit( aClientName ) );
548
549 for( const google::protobuf::Any& anyItem : aItems )
550 {
551 ItemStatus status;
552 std::optional<KICAD_T> type = TypeNameFromAny( anyItem );
553
554 if( !type )
555 {
556 status.set_code( ItemStatusCode::ISC_INVALID_TYPE );
557 status.set_error_message( fmt::format( "Could not decode a valid type from {}",
558 anyItem.type_url() ) );
559 aItemHandler( status, anyItem );
560 continue;
561 }
562
563 EDA_ITEM* container = targetScreen;
564
565 HANDLER_RESULT<std::unique_ptr<EDA_ITEM>> creationResult = createItemForType( *type, container );
566
567 if( !creationResult )
568 {
569 status.set_code( ItemStatusCode::ISC_INVALID_TYPE );
570 status.set_error_message( creationResult.error().error_message() );
571 aItemHandler( status, anyItem );
572 continue;
573 }
574
575 std::unique_ptr<EDA_ITEM> item( std::move( *creationResult ) );
576
577 bool unpacked = false;
578
579 if( *type == SCH_SYMBOL_T )
580 {
581 kiapi::schematic::types::SchematicSymbolInstance symbol;
582 unpacked = anyItem.UnpackTo( &symbol )
583 && UnpackSymbol( static_cast<SCH_SYMBOL*>( item.get() ), symbol );
584 }
585 else if( *type == SCH_SHEET_T )
586 {
587 kiapi::schematic::types::SheetSymbol sheetProto;
588 unpacked = anyItem.UnpackTo( &sheetProto );
589
590 if( unpacked )
591 {
592 SCH_SHEET* sheet = static_cast<SCH_SHEET*>( item.get() );
593
594 if( tl::expected<bool, ApiResponseStatus> result = UnpackSheet( sheet, sheetProto );
595 result.has_value() )
596 {
597 unpacked = *result;
598 SCH_SHEET_INSTANCE instance;
599
600 if( !sheet->GetInstances().empty() )
601 instance = *sheet->GetInstances().begin();
602
603 if( instance.m_PageNumber.IsEmpty() )
604 instance.m_PageNumber = hierarchy.GetNextPageNumber();
605
606 if( instance.m_Path.empty() )
607 {
608 SCH_SHEET_PATH newPath( targetPath );
609 newPath.push_back( sheet );
610 instance.m_Path = newPath.Path();
611 }
612
613 sheet->AddInstance( instance );
614 }
615 else
616 {
617 return tl::unexpected( result.error() );
618 }
619 }
620 }
621 else
622 {
623 unpacked = item->Deserialize( anyItem );
624 }
625
626 if( !unpacked )
627 {
628 e.set_status( ApiStatusCode::AS_BAD_REQUEST );
629 e.set_error_message( fmt::format( "could not unpack {} from request",
630 item->GetClass().ToStdString() ) );
631 return tl::unexpected( e );
632 }
633
634 SCH_ITEM* existingItem = nullptr;
635 SCH_SHEET_PATH existingPath;
636
637 existingItem = targetPath.ResolveItem( item->m_Uuid );
638
639 if( existingItem )
640 existingPath = targetPath;
641
642 if( aCreate && existingItem )
643 {
644 status.set_code( ItemStatusCode::ISC_EXISTING );
645 status.set_error_message( fmt::format( "an item with UUID {} already exists",
646 item->m_Uuid.AsStdString() ) );
647 aItemHandler( status, anyItem );
648 continue;
649 }
650 else if( !aCreate && !existingItem )
651 {
652 status.set_code( ItemStatusCode::ISC_NONEXISTENT );
653 status.set_error_message( fmt::format( "an item with UUID {} does not exist",
654 item->m_Uuid.AsStdString() ) );
655 aItemHandler( status, anyItem );
656 continue;
657 }
658
659 if( !aCreate )
660 {
661 SCH_SCREEN* itemScreen = existingPath.LastScreen();
662
663 if( itemScreen != targetScreen )
664 {
665 status.set_code( ItemStatusCode::ISC_INVALID_DATA );
666 status.set_error_message( fmt::format( "item {} exists on a different sheet than targeted",
667 item->m_Uuid.AsStdString() ) );
668 aItemHandler( status, anyItem );
669 continue;
670 }
671 }
672
673 if( *type == SCH_SHEET_T )
674 {
675 SCH_SHEET* sheet = static_cast<SCH_SHEET*>( item.get() );
676
677 if( aCreate && !sheet->GetScreen() )
678 sheet->SetScreen( new SCH_SCREEN( schematic() ) );
679
680 SCH_SHEET_PATH parentPath;
681
682 if( aCreate )
683 parentPath = targetPath;
684 else
685 parentPath = existingPath;
686
687 wxString destFilePath = parentPath.LastScreen()->GetFileName();
688
689 if( !destFilePath.IsEmpty() )
690 {
691 SCH_SHEET_LIST schematicSheets = schematic()->Hierarchy();
692 SCH_SHEET_LIST loadedSheets( sheet );
693
694 if( schematicSheets.TestForRecursion( loadedSheets, destFilePath ) )
695 {
696 status.set_code( ItemStatusCode::ISC_INVALID_DATA );
697 status.set_error_message( "sheet update would create recursive hierarchy" );
698 aItemHandler( status, anyItem );
699 continue;
700 }
701 }
702 }
703
704 status.set_code( ItemStatusCode::ISC_OK );
705 google::protobuf::Any newItem;
706
707 if( aCreate )
708 {
709 SCH_ITEM* createdItem = static_cast<SCH_ITEM*>( item.release() );
710 commit->Add( createdItem, targetScreen );
711
712 if( !createdItem )
713 {
714 e.set_status( ApiStatusCode::AS_BAD_REQUEST );
715 e.set_error_message( "could not add the requested item to its parent container" );
716 return tl::unexpected( e );
717 }
718
719 if( createdItem->Type() == SCH_SYMBOL_T )
720 {
721 kiapi::schematic::types::SchematicSymbolInstance symbol;
722
723 if( PackSymbol( &symbol, static_cast<SCH_SYMBOL*>( createdItem ), targetPath ) )
724 newItem.PackFrom( symbol );
725 }
726 else if( createdItem->Type() == SCH_SHEET_T )
727 {
728 kiapi::schematic::types::SheetSymbol sheet;
729
730 if( PackSheet( &sheet, static_cast<SCH_SHEET*>( createdItem ), targetPath ) )
731 newItem.PackFrom( sheet );
732 }
733 else
734 {
735 createdItem->Serialize( newItem );
736 }
737 }
738 else
739 {
740 commit->Modify( existingItem, targetScreen );
741 existingItem->SwapItemData( static_cast<SCH_ITEM*>( item.get() ) );
742
743 if( existingItem->Type() == SCH_SYMBOL_T )
744 {
745 SCH_SHEET_PATH path = existingPath;
746 kiapi::schematic::types::SchematicSymbolInstance symbol;
747
748 if( PackSymbol( &symbol, static_cast<SCH_SYMBOL*>( existingItem ), path ) )
749 newItem.PackFrom( symbol );
750 }
751 else if( existingItem->Type() == SCH_SHEET_T )
752 {
753 SCH_SHEET_PATH path = existingPath;
754 kiapi::schematic::types::SheetSymbol sheet;
755
756 if( PackSheet( &sheet, static_cast<SCH_SHEET*>( existingItem ), path ) )
757 newItem.PackFrom( sheet );
758 }
759 else
760 {
761 existingItem->Serialize( newItem );
762 }
763 }
764
765 aItemHandler( status, newItem );
766 }
767
768 if( !m_activeClients.contains( aClientName ) )
769 {
770 pushCurrentCommit( aClientName, aCreate ? _( "Created items via API" )
771 : _( "Modified items via API" ) );
772 }
773
774
775 return ItemRequestStatus::IRS_OK;
776}
777
778
779void API_HANDLER_SCH::deleteItemsInternal( std::map<KIID, ItemDeletionStatus>& aItemsToDelete,
780 const std::string& aClientName )
781{
782 SCH_SHEET_LIST hierarchy = schematic()->Hierarchy();
783 COMMIT* commit = getCurrentCommit( aClientName );
784
785 for( auto& [id, status] : aItemsToDelete )
786 {
788 SCH_ITEM* item = hierarchy.ResolveItem( id, &path, true );
789
790 if( !item )
791 continue;
792
793 if( !s_allowedTypes.contains( item->Type() ) )
794 {
795 status = ItemDeletionStatus::IDS_IMMUTABLE;
796 continue;
797 }
798
799 commit->Remove( item, path.LastScreen() );
800 status = ItemDeletionStatus::IDS_OK;
801 }
802
803 if( !m_activeClients.contains( aClientName ) )
804 pushCurrentCommit( aClientName, _( "Deleted items via API" ) );
805}
806
807
808std::optional<EDA_ITEM*> API_HANDLER_SCH::getItemFromDocument( const DocumentSpecifier& aDocument, const KIID& aId )
809{
810 if( !validateDocument( aDocument ) )
811 return std::nullopt;
812
813 SCH_ITEM* item = schematic()->Hierarchy().ResolveItem( aId, nullptr, true );
814
815 if( !item)
816 return std::nullopt;
817
818 return item;
819}
820
821
822std::optional<TITLE_BLOCK*> API_HANDLER_SCH::getTitleBlock()
823{
824 wxCHECK( m_context->GetCurrentSheet(), std::nullopt );
825 return &m_context->GetCurrentSheet()->LastScreen()->GetTitleBlock();
826}
827
828
829std::optional<PAGE_INFO> API_HANDLER_SCH::getPageSettings()
830{
831 wxCHECK( m_context->GetCurrentSheet(), std::nullopt );
832 return m_context->GetCurrentSheet()->LastScreen()->GetPageSettings();
833}
834
835
837{
838 wxCHECK( m_context->GetCurrentSheet(), false );
839 m_context->GetCurrentSheet()->LastScreen()->SetPageSettings( aPageInfo );
840 return true;
841}
842
843
848
849
850void API_HANDLER_SCH::setDrawingSheetFileName( const wxString& aFileName )
851{
854
855 if( m_frame )
856 m_frame->LoadDrawingSheet();
857}
858
859
861{
862 if( m_frame )
863 {
864 m_frame->Refresh();
865 m_frame->OnModify();
866 }
867}
868
869
872{
873 if( std::optional<ApiResponseStatus> busy = checkForBusy() )
874 return tl::unexpected( *busy );
875
876 HANDLER_RESULT<bool> documentValidation = validateDocument( aCtx.Request.job_settings().document() );
877
878 if( !documentValidation )
879 return tl::unexpected( documentValidation.error() );
880
881 auto plotJob = std::make_unique<JOB_EXPORT_SCH_PLOT_SVG>();
882 plotJob->m_filename = m_context->GetCurrentFileName();
883
884 if( !aCtx.Request.job_settings().output_path().empty() )
885 plotJob->SetConfiguredOutputPath( wxString::FromUTF8( aCtx.Request.job_settings().output_path() ) );
886
887 const kiapi::schematic::jobs::SchematicPlotSettings& settings = aCtx.Request.plot_settings();
888
889 plotJob->m_drawingSheet = wxString::FromUTF8( settings.drawing_sheet() );
890 plotJob->m_defaultFont = wxString::FromUTF8( settings.default_font() );
891 plotJob->m_variant = wxString::FromUTF8( settings.variant() );
892 plotJob->m_plotAll = settings.plot_all();
893 plotJob->m_plotDrawingSheet = settings.plot_drawing_sheet();
894 plotJob->m_show_hop_over = settings.show_hop_over();
895 plotJob->m_blackAndWhite = settings.black_and_white();
896 plotJob->m_useBackgroundColor = settings.use_background_color();
897 plotJob->m_minPenWidth = settings.min_pen_width();
898 plotJob->m_theme = wxString::FromUTF8( settings.theme() );
899
900 plotJob->m_plotPages.clear();
901
902 for( const std::string& page : settings.plot_pages() )
903 plotJob->m_plotPages.push_back( wxString::FromUTF8( page ) );
904
905 if( aCtx.Request.plot_settings().page_size() != kiapi::schematic::jobs::SchematicJobPageSize::SJPS_UNKNOWN )
906 {
907 plotJob->m_pageSizeSelect = FromProtoEnum<JOB_PAGE_SIZE>( aCtx.Request.plot_settings().page_size() );
908 }
909
910 return ExecuteSchematicJob( m_context->GetKiway(), *plotJob );
911}
912
913
916{
917 if( std::optional<ApiResponseStatus> busy = checkForBusy() )
918 return tl::unexpected( *busy );
919
920 HANDLER_RESULT<bool> documentValidation = validateDocument( aCtx.Request.job_settings().document() );
921
922 if( !documentValidation )
923 return tl::unexpected( documentValidation.error() );
924
925 auto plotJob = std::make_unique<JOB_EXPORT_SCH_PLOT_DXF>();
926 plotJob->m_filename = m_context->GetCurrentFileName();
927
928 if( !aCtx.Request.job_settings().output_path().empty() )
929 plotJob->SetConfiguredOutputPath( wxString::FromUTF8( aCtx.Request.job_settings().output_path() ) );
930
931 const kiapi::schematic::jobs::SchematicPlotSettings& settings = aCtx.Request.plot_settings();
932
933 plotJob->m_drawingSheet = wxString::FromUTF8( settings.drawing_sheet() );
934 plotJob->m_defaultFont = wxString::FromUTF8( settings.default_font() );
935 plotJob->m_variant = wxString::FromUTF8( settings.variant() );
936 plotJob->m_plotAll = settings.plot_all();
937 plotJob->m_plotDrawingSheet = settings.plot_drawing_sheet();
938 plotJob->m_show_hop_over = settings.show_hop_over();
939 plotJob->m_blackAndWhite = settings.black_and_white();
940 plotJob->m_useBackgroundColor = settings.use_background_color();
941 plotJob->m_minPenWidth = settings.min_pen_width();
942 plotJob->m_theme = wxString::FromUTF8( settings.theme() );
943
944 plotJob->m_plotPages.clear();
945
946 for( const std::string& page : settings.plot_pages() )
947 plotJob->m_plotPages.push_back( wxString::FromUTF8( page ) );
948
949 if( aCtx.Request.plot_settings().page_size() != kiapi::schematic::jobs::SchematicJobPageSize::SJPS_UNKNOWN )
950 {
951 plotJob->m_pageSizeSelect = FromProtoEnum<JOB_PAGE_SIZE>( aCtx.Request.plot_settings().page_size() );
952 }
953
954 return ExecuteSchematicJob( m_context->GetKiway(), *plotJob );
955}
956
957
960{
961 if( std::optional<ApiResponseStatus> busy = checkForBusy() )
962 return tl::unexpected( *busy );
963
964 HANDLER_RESULT<bool> documentValidation = validateDocument( aCtx.Request.job_settings().document() );
965
966 if( !documentValidation )
967 return tl::unexpected( documentValidation.error() );
968
969 auto plotJob = std::make_unique<JOB_EXPORT_SCH_PLOT_PDF>( false );
970 plotJob->m_filename = m_context->GetCurrentFileName();
971
972 if( !aCtx.Request.job_settings().output_path().empty() )
973 plotJob->SetConfiguredOutputPath( wxString::FromUTF8( aCtx.Request.job_settings().output_path() ) );
974
975 const kiapi::schematic::jobs::SchematicPlotSettings& settings = aCtx.Request.plot_settings();
976
977 plotJob->m_drawingSheet = wxString::FromUTF8( settings.drawing_sheet() );
978 plotJob->m_defaultFont = wxString::FromUTF8( settings.default_font() );
979 plotJob->m_variant = wxString::FromUTF8( settings.variant() );
980 plotJob->m_plotAll = settings.plot_all();
981 plotJob->m_plotDrawingSheet = settings.plot_drawing_sheet();
982 plotJob->m_show_hop_over = settings.show_hop_over();
983 plotJob->m_blackAndWhite = settings.black_and_white();
984 plotJob->m_useBackgroundColor = settings.use_background_color();
985 plotJob->m_minPenWidth = settings.min_pen_width();
986 plotJob->m_theme = wxString::FromUTF8( settings.theme() );
987
988 plotJob->m_plotPages.clear();
989
990 for( const std::string& page : settings.plot_pages() )
991 plotJob->m_plotPages.push_back( wxString::FromUTF8( page ) );
992
993 if( aCtx.Request.plot_settings().page_size() != kiapi::schematic::jobs::SchematicJobPageSize::SJPS_UNKNOWN )
994 {
995 plotJob->m_pageSizeSelect = FromProtoEnum<JOB_PAGE_SIZE>( aCtx.Request.plot_settings().page_size() );
996 }
997
998 plotJob->m_PDFPropertyPopups = aCtx.Request.property_popups();
999 plotJob->m_PDFHierarchicalLinks = aCtx.Request.hierarchical_links();
1000 plotJob->m_PDFMetadata = aCtx.Request.include_metadata();
1001
1002 return ExecuteSchematicJob( m_context->GetKiway(), *plotJob );
1003}
1004
1005
1008{
1009 if( std::optional<ApiResponseStatus> busy = checkForBusy() )
1010 return tl::unexpected( *busy );
1011
1012 HANDLER_RESULT<bool> documentValidation = validateDocument( aCtx.Request.job_settings().document() );
1013
1014 if( !documentValidation )
1015 return tl::unexpected( documentValidation.error() );
1016
1017 auto plotJob = std::make_unique<JOB_EXPORT_SCH_PLOT_PS>();
1018 plotJob->m_filename = m_context->GetCurrentFileName();
1019
1020 if( !aCtx.Request.job_settings().output_path().empty() )
1021 plotJob->SetConfiguredOutputPath( wxString::FromUTF8( aCtx.Request.job_settings().output_path() ) );
1022
1023 const kiapi::schematic::jobs::SchematicPlotSettings& settings = aCtx.Request.plot_settings();
1024
1025 plotJob->m_drawingSheet = wxString::FromUTF8( settings.drawing_sheet() );
1026 plotJob->m_defaultFont = wxString::FromUTF8( settings.default_font() );
1027 plotJob->m_variant = wxString::FromUTF8( settings.variant() );
1028 plotJob->m_plotAll = settings.plot_all();
1029 plotJob->m_plotDrawingSheet = settings.plot_drawing_sheet();
1030 plotJob->m_show_hop_over = settings.show_hop_over();
1031 plotJob->m_blackAndWhite = settings.black_and_white();
1032 plotJob->m_useBackgroundColor = settings.use_background_color();
1033 plotJob->m_minPenWidth = settings.min_pen_width();
1034 plotJob->m_theme = wxString::FromUTF8( settings.theme() );
1035
1036 plotJob->m_plotPages.clear();
1037
1038 for( const std::string& page : settings.plot_pages() )
1039 plotJob->m_plotPages.push_back( wxString::FromUTF8( page ) );
1040
1041 if( aCtx.Request.plot_settings().page_size() != kiapi::schematic::jobs::SchematicJobPageSize::SJPS_UNKNOWN )
1042 {
1043 plotJob->m_pageSizeSelect = FromProtoEnum<JOB_PAGE_SIZE>( aCtx.Request.plot_settings().page_size() );
1044 }
1045
1046 return ExecuteSchematicJob( m_context->GetKiway(), *plotJob );
1047}
1048
1049
1052{
1053 if( std::optional<ApiResponseStatus> busy = checkForBusy() )
1054 return tl::unexpected( *busy );
1055
1056 HANDLER_RESULT<bool> documentValidation = validateDocument( aCtx.Request.job_settings().document() );
1057
1058 if( !documentValidation )
1059 return tl::unexpected( documentValidation.error() );
1060
1061 if( aCtx.Request.format() == kiapi::schematic::jobs::SchematicNetlistFormat::SNF_UNKNOWN )
1062 {
1063 ApiResponseStatus e;
1064 e.set_status( ApiStatusCode::AS_BAD_REQUEST );
1065 e.set_error_message( "RunSchematicJobExportNetlist requires a valid format" );
1066 return tl::unexpected( e );
1067 }
1068
1069 JOB_EXPORT_SCH_NETLIST netlistJob;
1070 netlistJob.m_filename = m_context->GetCurrentFileName();
1071
1072 if( !aCtx.Request.job_settings().output_path().empty() )
1073 netlistJob.SetConfiguredOutputPath( wxString::FromUTF8( aCtx.Request.job_settings().output_path() ) );
1074
1075 netlistJob.format = FromProtoEnum<JOB_EXPORT_SCH_NETLIST::FORMAT>( aCtx.Request.format() );
1076
1077 if( !aCtx.Request.variant_name().empty() )
1078 netlistJob.m_variantNames.emplace_back( wxString::FromUTF8( aCtx.Request.variant_name() ) );
1079
1080 return ExecuteSchematicJob( m_context->GetKiway(), netlistJob );
1081}
1082
1083
1086{
1087 if( std::optional<ApiResponseStatus> busy = checkForBusy() )
1088 return tl::unexpected( *busy );
1089
1090 HANDLER_RESULT<bool> documentValidation = validateDocument( aCtx.Request.job_settings().document() );
1091
1092 if( !documentValidation )
1093 return tl::unexpected( documentValidation.error() );
1094
1095 JOB_EXPORT_SCH_BOM bomJob;
1096 bomJob.m_filename = m_context->GetCurrentFileName();
1097
1098 if( !aCtx.Request.job_settings().output_path().empty() )
1099 bomJob.SetConfiguredOutputPath( wxString::FromUTF8( aCtx.Request.job_settings().output_path() ) );
1100
1101 bomJob.m_bomFmtPresetName = wxString::FromUTF8( aCtx.Request.format().preset_name() );
1102 bomJob.m_fieldDelimiter = wxString::FromUTF8( aCtx.Request.format().field_delimiter() );
1103 bomJob.m_stringDelimiter = wxString::FromUTF8( aCtx.Request.format().string_delimiter() );
1104 bomJob.m_refDelimiter = wxString::FromUTF8( aCtx.Request.format().ref_delimiter() );
1105 bomJob.m_refRangeDelimiter = wxString::FromUTF8( aCtx.Request.format().ref_range_delimiter() );
1106 bomJob.m_keepTabs = aCtx.Request.format().keep_tabs();
1107 bomJob.m_keepLineBreaks = aCtx.Request.format().keep_line_breaks();
1108
1109 bomJob.m_bomPresetName = wxString::FromUTF8( aCtx.Request.fields().preset_name() );
1110 bomJob.m_sortField = wxString::FromUTF8( aCtx.Request.fields().sort_field() );
1111 bomJob.m_filterString = wxString::FromUTF8( aCtx.Request.fields().filter() );
1112
1113 if( aCtx.Request.fields().sort_direction() == kiapi::schematic::jobs::BOMSortDirection::BSD_ASCENDING )
1114 {
1115 bomJob.m_sortAsc = true;
1116 }
1117 else if( aCtx.Request.fields().sort_direction() == kiapi::schematic::jobs::BOMSortDirection::BSD_DESCENDING )
1118 {
1119 bomJob.m_sortAsc = false;
1120 }
1121
1122 for( const kiapi::schematic::jobs::BOMField& field : aCtx.Request.fields().fields() )
1123 {
1124 bomJob.m_fieldsOrdered.emplace_back( wxString::FromUTF8( field.name() ) );
1125 bomJob.m_fieldsLabels.emplace_back( wxString::FromUTF8( field.label() ) );
1126
1127 if( field.group_by() )
1128 bomJob.m_fieldsGroupBy.emplace_back( wxString::FromUTF8( field.name() ) );
1129 }
1130
1131 bomJob.m_excludeDNP = aCtx.Request.exclude_dnp();
1132 bomJob.m_groupSymbols = aCtx.Request.group_symbols();
1133
1134 if( !aCtx.Request.variant_name().empty() )
1135 bomJob.m_variantNames.emplace_back( wxString::FromUTF8( aCtx.Request.variant_name() ) );
1136
1137 return ExecuteSchematicJob( m_context->GetKiway(), bomJob );
1138}
1139
1140
1141void API_HANDLER_SCH::packSheetInstance( kiapi::schematic::types::SheetInstance* aInstance, SCH_SHEET_PATH& aPath,
1142 SCH_SHEET* aSheet )
1143{
1144 aPath.push_back( aSheet );
1145
1146 PackSheetPath( *aInstance->mutable_path(), aPath.Path() );
1147
1148 wxString sheetName = aSheet->GetShownName( false );
1149
1150 if( sheetName.IsEmpty() && aSheet->GetScreen() )
1151 {
1152 wxFileName fn( aSheet->GetScreen()->GetFileName() );
1153 sheetName = fn.GetName();
1154 }
1155
1156 aInstance->set_name( sheetName.ToUTF8() );
1157 aInstance->set_filename( aSheet->GetFileName().ToUTF8() );
1158 aInstance->set_page_number( aPath.GetPageNumber().ToUTF8() );
1159
1160 if( aSheet->GetScreen() )
1161 {
1162 std::vector<SCH_ITEM*> childSheets;
1163 aSheet->GetScreen()->GetSheets( &childSheets );
1164
1165 std::ranges::sort( childSheets,
1166 [&]( SCH_ITEM* a, SCH_ITEM* b )
1167 {
1168 SCH_SHEET_PATH pathA = aPath;
1169 pathA.push_back( static_cast<SCH_SHEET*>( a ) );
1170
1171 SCH_SHEET_PATH pathB = aPath;
1172 pathB.push_back( static_cast<SCH_SHEET*>( b ) );
1173
1174 return pathA.ComparePageNum( pathB ) < 0;
1175 } );
1176
1177 for( SCH_ITEM* childItem : childSheets )
1178 {
1179 SCH_SHEET* childSheet = static_cast<SCH_SHEET*>( childItem );
1180 kiapi::schematic::types::SheetInstance* childInstance = aInstance->add_children();
1181 packSheetInstance( childInstance, aPath, childSheet );
1182 }
1183 }
1184
1185 aPath.pop_back();
1186}
1187
1188
1191{
1192 HANDLER_RESULT<bool> documentValidation = validateDocument( aCtx.Request.document() );
1193
1194 if( !documentValidation )
1195 return tl::unexpected( documentValidation.error() );
1196
1197 kiapi::schematic::types::SchematicHierarchyResponse response;
1198 response.mutable_document()->CopyFrom( aCtx.Request.document() );
1199
1200 if( !schematic()->HasHierarchy() )
1202
1204 std::vector<SCH_SHEET*> topLevelSheets = schematic()->GetTopLevelSheets();
1205
1206 std::ranges::sort( topLevelSheets,
1207 [&]( SCH_SHEET* a, SCH_SHEET* b )
1208 {
1209 SCH_SHEET_PATH pathA;
1210 pathA.push_back( a );
1211
1212 SCH_SHEET_PATH pathB;
1213 pathB.push_back( b );
1214
1215 return pathA.ComparePageNum( pathB ) < 0;
1216 } );
1217
1218 for( SCH_SHEET* topSheet : topLevelSheets )
1219 {
1220 kiapi::schematic::types::SheetInstance* instance = response.add_top_level_sheets();
1221 packSheetInstance( instance, path, topSheet );
1222 }
1223
1224 return response;
1225}
1226
1227
1230{
1231 if( std::optional<ApiResponseStatus> busy = checkForBusy() )
1232 return tl::unexpected( *busy );
1233
1234 HANDLER_RESULT<bool> documentValidation = validateDocument( aCtx.Request.document() );
1235
1236 if( !documentValidation )
1237 return tl::unexpected( documentValidation.error() );
1238
1239 std::vector<KICAD_T> types = parseRequestedItemTypes( aCtx.Request.types() );
1240 const bool filterByType = aCtx.Request.types_size() > 0;
1241
1242 if( filterByType && types.empty() )
1243 {
1244 ApiResponseStatus e;
1245 e.set_status( ApiStatusCode::AS_BAD_REQUEST );
1246 e.set_error_message( "none of the requested types are valid for a Schematic object" );
1247 return tl::unexpected( e );
1248 }
1249
1250 std::set<KICAD_T> typeFilter( types.begin(), types.end() );
1251
1252 CONNECTION_GRAPH* connectionGraph = schematic()->ConnectionGraph();
1253
1254 if( !connectionGraph )
1255 {
1256 ApiResponseStatus e;
1257 e.set_status( ApiStatusCode::AS_BAD_REQUEST );
1258 e.set_error_message( "schematic has no connection graph" );
1259 return tl::unexpected( e );
1260 }
1261
1262 kiapi::schematic::types::SchematicNetlistResponse response;
1263 response.mutable_document()->CopyFrom( aCtx.Request.document() );
1264
1265 for( const auto& [key, subgraphList] : connectionGraph->GetNetMap() )
1266 {
1267 if( subgraphList.empty() )
1268 continue;
1269
1270 CONNECTION_SUBGRAPH* firstSubgraph = subgraphList[0];
1271
1272 if( firstSubgraph->GetDriverConnection() && firstSubgraph->GetDriverConnection()->IsBus() )
1273 continue;
1274
1276 continue;
1277
1278 kiapi::schematic::types::SchematicNet* net = response.add_nets();
1279 net->set_name( key.Name.ToUTF8() );
1280
1281 for( CONNECTION_SUBGRAPH* subGraph : subgraphList )
1282 {
1283 kiapi::schematic::types::SchematicNetSheetContents* sheetContents = net->add_sheets();
1284 PackSheetPath( *sheetContents->mutable_path(), subGraph->GetSheet().Path() );
1285
1286 for( SCH_ITEM* item : subGraph->GetItems() )
1287 {
1288 if( filterByType && !typeFilter.contains( item->Type() ) )
1289 continue;
1290
1291 sheetContents->add_items()->set_value( item->m_Uuid.AsStdString() );
1292 }
1293 }
1294 }
1295
1296 return response;
1297}
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< kiapi::schematic::types::SchematicNetlistResponse > handleGetSchematicNetlist(const HANDLER_CONTEXT< kiapi::schematic::types::GetSchematicNetlist > &aCtx)
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
Calculate the connectivity of a schematic and generates netlists.
const NET_MAP & GetNetMap() const
A subgraph is a set of items that are electrically connected on a single sheet.
static PRIORITY GetDriverPriority(SCH_ITEM *aDriver)
Return the priority (higher is more important) of a candidate driver.
const SCH_CONNECTION * GetDriverConnection() const
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.
CONNECTION_GRAPH * ConnectionGraph() const
Definition schematic.h:200
std::vector< SCH_SHEET * > GetTopLevelSheets() const
Get the list of top-level sheets.
void RefreshHierarchy()
bool IsBus() const
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