KiCad PCB EDA Suite
Loading...
Searching...
No Matches
api_handler_symbol.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 The KiCad Developers, see AUTHORS.txt for contributors.
5 *
6 * This program is free software: you can redistribute it and/or modify it
7 * under the terms of the GNU General Public License as published by the
8 * Free Software Foundation, either version 3 of the License, or (at your
9 * option) any later version.
10 *
11 * This program is distributed in the hope that it will be useful, but
12 * WITHOUT ANY WARRANTY; without even the implied warranty of
13 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
14 * General Public License for more details.
15 *
16 * You should have received a copy of the GNU General Public License
17 * along with this program. If not, see <https://www.gnu.org/licenses/>.
18 */
19
21
22#include <api/api_sch_utils.h>
23#include <api/api_utils.h>
24#include <view/view.h>
25#include <fmt.h>
26#include <magic_enum.hpp>
27#include <base_units.h>
28#include <lib_symbol.h>
29#include <project.h>
30#include <sch_bitmap.h>
31#include <sch_commit.h>
32#include <sch_field.h>
33#include <sch_pin.h>
34#include <sch_screen.h>
35#include <sch_shape.h>
36#include <sch_table.h>
37#include <sch_text.h>
38#include <sch_textbox.h>
39#include <symbol_edit_frame.h>
41
42#include <wx/filename.h>
43
44using namespace kiapi::common::commands;
45using kiapi::common::commands::DocumentModifiedState;
46using kiapi::common::types::DocumentType;
47using kiapi::common::types::ItemRequestStatus;
48
49
50std::set<KICAD_T> API_HANDLER_SYMBOL::s_allowedTypes = {
53};
54
55
60
61
75
76
78{
79 return static_cast<SYMBOL_EDIT_FRAME*>( m_frame );
80}
81
82
83std::unique_ptr<COMMIT> API_HANDLER_SYMBOL::createCommit()
84{
85 if( m_frame )
86 return std::make_unique<SCH_COMMIT>( static_cast<SYMBOL_EDIT_FRAME*>( m_frame ) );
87
88 return std::make_unique<SCH_COMMIT>( context()->GetToolManager(), /* aIsLibEditor */ true );
89}
90
91
92tl::expected<bool, ApiResponseStatus>
93API_HANDLER_SYMBOL::validateDocumentInternal( const DocumentSpecifier& aDocument ) const
94{
95 if( aDocument.type() != DocumentType::DOCTYPE_SYMBOL )
96 {
97 ApiResponseStatus e;
98 e.set_status( ApiStatusCode::AS_UNHANDLED );
99 return tl::unexpected( e );
100 }
101
102 const PROJECT& prj = context()->Prj();
103
104 if( aDocument.has_project() )
105 {
106 if( aDocument.project().name().compare( prj.GetProjectName().ToUTF8() ) != 0 )
107 {
108 ApiResponseStatus e;
109 e.set_status( ApiStatusCode::AS_BAD_REQUEST );
110 e.set_error_message( fmt::format( "the requested project {} is not open", aDocument.project().name() ) );
111 return tl::unexpected( e );
112 }
113
114 if( aDocument.project().path().compare( prj.GetProjectPath().ToUTF8() ) != 0 )
115 {
116 ApiResponseStatus e;
117 e.set_status( ApiStatusCode::AS_BAD_REQUEST );
118 e.set_error_message( fmt::format( "the requested project {} is not open at path {}",
119 aDocument.project().name(), aDocument.project().path() ) );
120 return tl::unexpected( e );
121 }
122 }
123
124 LIB_ID loaded = context()->GetLoadedLibId();
125
126 // An empty library nickname addresses an unsaved new symbol
127 if( aDocument.lib_id().library_nickname().empty() )
128 {
129 if( loaded.GetLibItemName().empty() )
130 {
131 ApiResponseStatus e;
132 e.set_status( ApiStatusCode::AS_BAD_REQUEST );
133 e.set_error_message( "no symbol is currently open" );
134 return tl::unexpected( e );
135 }
136
137 return true;
138 }
139
140 if( !loaded.IsValid() )
141 {
142 ApiResponseStatus e;
143 e.set_status( ApiStatusCode::AS_BAD_REQUEST );
144 e.set_error_message( "no symbol is currently open" );
145 return tl::unexpected( e );
146 }
147
148 if( aDocument.lib_id().library_nickname() != loaded.GetUniStringLibNickname().ToStdString() )
149 {
150 ApiResponseStatus e;
151 e.set_status( ApiStatusCode::AS_BAD_REQUEST );
152 e.set_error_message( fmt::format( "the requested library is {} but the open library is {}",
153 aDocument.lib_id().library_nickname(),
154 loaded.GetUniStringLibNickname().ToStdString() ) );
155 return tl::unexpected( e );
156 }
157
158 if( aDocument.lib_id().entry_name() != loaded.GetUniStringLibItemName().ToStdString() )
159 {
160 ApiResponseStatus e;
161 e.set_status( ApiStatusCode::AS_BAD_REQUEST );
162 e.set_error_message( fmt::format( "the requested symbol is {} but the open symbol is {}",
163 aDocument.lib_id().entry_name(),
164 loaded.GetUniStringLibItemName().ToStdString() ) );
165 return tl::unexpected( e );
166 }
167
168 return true;
169}
170
173{
174 if( aCtx.Request.type() != DocumentType::DOCTYPE_SYMBOL )
175 {
176 ApiResponseStatus e;
177 e.set_status( ApiStatusCode::AS_UNHANDLED );
178 return tl::unexpected( e );
179 }
180
181 GetOpenDocumentsResponse response;
182
183 if( !context()->GetCurSymbol() )
184 return response;
185
186 types::DocumentSpecifier doc;
187 LIB_ID libId = context()->GetCurSymbol()->GetLibId();
188
189 doc.set_type( DocumentType::DOCTYPE_SYMBOL );
190 doc.mutable_lib_id()->set_library_nickname( libId.GetUniStringLibNickname().ToStdString() );
191 doc.mutable_lib_id()->set_entry_name( libId.GetUniStringLibItemName().ToStdString() );
192
193 PROJECT& prj = context()->Prj();
194
195 if( !prj.IsNullProject() )
196 {
197 doc.mutable_project()->set_name( prj.GetProjectName().ToUTF8() );
198 doc.mutable_project()->set_path( prj.GetProjectPath().ToUTF8() );
199 }
200
201 response.mutable_documents()->Add( std::move( doc ) );
202 return response;
203}
204
205
208{
209 if( aCtx.Request.type() != DocumentType::DOCTYPE_SYMBOL )
210 {
211 ApiResponseStatus e;
212 e.set_status( ApiStatusCode::AS_UNHANDLED );
213 return tl::unexpected( e );
214 }
215
216 LIB_ID libId = UnpackLibId( aCtx.Request.identifier() );
217
218 if( !libId.IsValid() )
219 {
220 ApiResponseStatus e;
221 e.set_status( ApiStatusCode::AS_BAD_REQUEST );
222 e.set_error_message( fmt::format( "could not parse library identifier {}.{}",
223 aCtx.Request.identifier().library_nickname(),
224 aCtx.Request.identifier().entry_name() ) );
225 return tl::unexpected( e );
226 }
227
228 if( !context()->LoadSymbol( libId ) )
229 {
230 ApiResponseStatus e;
231 e.set_status( ApiStatusCode::AS_BAD_REQUEST );
232 e.set_error_message( fmt::format( "could not open symbol {}.{}",
233 aCtx.Request.identifier().library_nickname(),
234 aCtx.Request.identifier().entry_name() ) );
235 return tl::unexpected( e );
236 }
237
238 return Empty();
239}
240
241
243{
244 if( context()->GetLoadedLibId().GetLibNickname().empty() )
245 {
246 ApiResponseStatus e;
247 e.set_status( ApiStatusCode::AS_BAD_REQUEST );
248 e.set_error_message( "the open symbol has no library yet; use SaveCopyOfDocument with a "
249 "path to save it" );
250 return tl::unexpected( e );
251 }
252
253 if( HANDLER_RESULT<bool> documentValidation = validateDocument( aCtx.Request.document() ); !documentValidation )
254 return tl::unexpected( documentValidation.error() );
255
256 if( std::optional<ApiResponseStatus> busy = checkForBusy() )
257 return tl::unexpected( *busy );
258
259 if( !context()->SaveSymbol() )
260 {
261 ApiResponseStatus e;
262 e.set_status( ApiStatusCode::AS_BAD_REQUEST );
263 e.set_error_message( "failed to save symbol (is the library read-only?)" );
264 return tl::unexpected( e );
265 }
266
267 return Empty();
268}
269
270
273{
274 HANDLER_RESULT<bool> documentValidation = validateDocument( aCtx.Request.document() );
275
276 if( !documentValidation )
277 return tl::unexpected( documentValidation.error() );
278
279 if( std::optional<ApiResponseStatus> busy = checkForBusy() )
280 return tl::unexpected( *busy );
281
282 wxFileName libPath( wxString::FromUTF8( aCtx.Request.path() ) );
283
284 if( !libPath.IsOk() || !libPath.IsDirWritable() )
285 {
286 ApiResponseStatus e;
287 e.set_status( ApiStatusCode::AS_BAD_REQUEST );
288 e.set_error_message( fmt::format( "save path '{}' could not be opened", libPath.GetFullPath().ToStdString() ) );
289 return tl::unexpected( e );
290 }
291
292 if( libPath.FileExists() && ( !libPath.IsFileWritable() || !aCtx.Request.options().overwrite() ) )
293 {
294 ApiResponseStatus e;
295 e.set_status( ApiStatusCode::AS_BAD_REQUEST );
296 e.set_error_message(
297 fmt::format( "save path '{}' exists and cannot be overwritten", libPath.GetFullPath().ToStdString() ) );
298 return tl::unexpected( e );
299 }
300
301 if( libPath.GetExt() != wxString( FILEEXT::KiCadSymbolLibFileExtension ) )
302 {
303 ApiResponseStatus e;
304 e.set_status( ApiStatusCode::AS_BAD_REQUEST );
305 e.set_error_message(
306 fmt::format( "save path '{}' must have a kicad_sym extension", libPath.GetFullPath().ToStdString() ) );
307 return tl::unexpected( e );
308 }
309
310 if( !context()->SaveSymbolCopy( libPath.GetFullPath(), aCtx.Request.options().overwrite() ) )
311 {
312 ApiResponseStatus e;
313 e.set_status( ApiStatusCode::AS_BAD_REQUEST );
314 e.set_error_message( "failed to save symbol copy" );
315 return tl::unexpected( e );
316 }
317
318 return Empty();
319}
320
321
323{
324 if( HANDLER_RESULT<bool> documentValidation = validateDocument( aCtx.Request.document() ); !documentValidation )
325 {
326 return tl::unexpected( documentValidation.error() );
327 }
328
329 if( std::optional<ApiResponseStatus> busy = checkForBusy() )
330 return tl::unexpected( *busy );
331
332 if( !context()->RevertSymbol() )
333 {
334 ApiResponseStatus e;
335 e.set_status( ApiStatusCode::AS_BAD_REQUEST );
336 e.set_error_message( "failed to revert symbol" );
337 return tl::unexpected( e );
338 }
339
340 return Empty();
341}
342
343
346{
347 if( HANDLER_RESULT<std::optional<KIID>> valid = validateItemHeaderDocument( aCtx.Request.header() );
348 !valid.has_value() )
349 {
350 return tl::unexpected( valid.error() );
351 }
352
353 if( std::optional<ApiResponseStatus> busy = checkForBusy() )
354 return tl::unexpected( *busy );
355
357
358 if( !symbol )
359 {
360 ApiResponseStatus e;
361 e.set_status( ApiStatusCode::AS_BAD_REQUEST );
362 e.set_error_message( "no symbol is currently loaded" );
363 return tl::unexpected( e );
364 }
365
366 GetItemsResponse response;
367 std::set<KICAD_T> typesRequested;
368 std::vector<KICAD_T> requestedTypes = parseRequestedItemTypes( aCtx.Request.types() );
369
370 if( aCtx.Request.types().empty() )
371 requestedTypes.assign( s_allowedTypes.begin(), s_allowedTypes.end() );
372
373 for( KICAD_T type : requestedTypes )
374 {
375 if( !s_allowedTypes.contains( type ) )
376 continue;
377
378 typesRequested.insert( type );
379 }
380
381 if( typesRequested.empty() )
382 {
383 ApiResponseStatus e;
384 e.set_status( ApiStatusCode::AS_BAD_REQUEST );
385 e.set_error_message( "none of the requested types are valid for a Symbol object" );
386 return tl::unexpected( e );
387 }
388
389 auto emitItem = [&]( EDA_ITEM* item )
390 {
391 if( !item || !typesRequested.contains( item->Type() ) )
392 return;
393
394 google::protobuf::Any any;
395 item->Serialize( any );
396 response.mutable_items()->Add( std::move( any ) );
397 };
398
399 if( typesRequested.contains( LIB_SYMBOL_T ) )
400 emitItem( symbol );
401
402 for( SCH_ITEM& item : symbol->GetDrawItems() )
403 emitItem( &item );
404
405 response.set_status( ItemRequestStatus::IRS_OK );
406 return response;
407}
408
409
412{
413 if( HANDLER_RESULT<std::optional<KIID>> valid = validateItemHeaderDocument( aCtx.Request.header() );
414 !valid.has_value() )
415 {
416 return tl::unexpected( valid.error() );
417 }
418
419 if( std::optional<ApiResponseStatus> busy = checkForBusy() )
420 return tl::unexpected( *busy );
421
423
424 if( !symbol )
425 {
426 ApiResponseStatus e;
427 e.set_status( ApiStatusCode::AS_BAD_REQUEST );
428 e.set_error_message( "no symbol is currently loaded" );
429 return tl::unexpected( e );
430 }
431
432 GetItemsResponse response;
433
434 for( const types::KIID& idProto : aCtx.Request.items() )
435 {
436 KIID id( idProto.value() );
437
438 if( id == symbol->m_Uuid )
439 {
440 google::protobuf::Any any;
441 symbol->Serialize( any );
442 response.mutable_items()->Add( std::move( any ) );
443 continue;
444 }
445
446 for( SCH_ITEM& item : symbol->GetDrawItems() )
447 {
448 if( item.m_Uuid != id || !s_allowedTypes.contains( item.Type() ) )
449 continue;
450
451 google::protobuf::Any any;
452 item.Serialize( any );
453 response.mutable_items()->Add( std::move( any ) );
454 break;
455 }
456 }
457
458 response.set_status( ItemRequestStatus::IRS_OK );
459 return response;
460}
461
462
463std::optional<EDA_ITEM*> API_HANDLER_SYMBOL::getItemFromDocument( const DocumentSpecifier& aDocument, const KIID& aId )
464{
465 if( !validateDocument( aDocument ).has_value() )
466 return std::nullopt;
467
469
470 if( !symbol )
471 return std::nullopt;
472
473 if( symbol->m_Uuid == aId )
474 return std::optional<EDA_ITEM*>( symbol );
475
476 for( SCH_ITEM& item : symbol->GetDrawItems() )
477 {
478 if( item.m_Uuid == aId )
479 return std::optional<EDA_ITEM*>( &item );
480 }
481
482 return std::nullopt;
483}
484
485
487 bool aCreate, const std::string& aClientName, const types::ItemHeader& aHeader,
488 const google::protobuf::RepeatedPtrField<google::protobuf::Any>& aItems,
489 std::function<void( ItemStatus, google::protobuf::Any )> aItemHandler )
490{
491 ApiResponseStatus e;
492
494
495 if( !containerResult && containerResult.error().status() == ApiStatusCode::AS_UNHANDLED )
496 {
497 e.set_status( ApiStatusCode::AS_UNHANDLED );
498 return tl::unexpected( e );
499 }
500 else if( !containerResult )
501 {
502 e.CopyFrom( containerResult.error() );
503 return tl::unexpected( e );
504 }
505
507
508 if( !symbol )
509 {
510 e.set_status( ApiStatusCode::AS_BAD_REQUEST );
511 e.set_error_message( "no symbol is currently loaded" );
512 return tl::unexpected( e );
513 }
514
515 if( containerResult->has_value() && **containerResult != symbol->m_Uuid )
516 {
517 e.set_status( ApiStatusCode::AS_BAD_REQUEST );
518 e.set_error_message( fmt::format( "the requested container {} is not the open symbol",
519 ( *containerResult )->AsString().ToStdString() ) );
520 return tl::unexpected( e );
521 }
522
523 SCH_SCREEN* screen = context()->GetScreen();
524 SCH_COMMIT* commit = static_cast<SCH_COMMIT*>( getCurrentCommit( aClientName ) );
525
526 for( const google::protobuf::Any& anyItem : aItems )
527 {
528 ItemStatus status;
529 std::optional<KICAD_T> type = TypeNameFromAny( anyItem );
530
531 if( !type )
532 {
533 status.set_code( ItemStatusCode::ISC_INVALID_TYPE );
534 status.set_error_message( fmt::format( "Could not decode a valid type from {}", anyItem.type_url() ) );
535 aItemHandler( status, anyItem );
536 continue;
537 }
538
539 if( !s_allowedTypes.contains( *type ) )
540 {
541 status.set_code( ItemStatusCode::ISC_INVALID_TYPE );
542 status.set_error_message( fmt::format( "type {} is not supported by the symbol editor API handler",
543 magic_enum::enum_name( *type ) ) );
544 aItemHandler( status, anyItem );
545 continue;
546 }
547
548 if( *type == LIB_SYMBOL_T )
549 {
550 status.set_code( ItemStatusCode::ISC_INVALID_TYPE );
551 status.set_error_message( "whole-symbol create/update is not supported; "
552 "edit the symbol's child items instead" );
553 aItemHandler( status, anyItem );
554 continue;
555 }
556
557 if( *type == SCH_FIELD_T )
558 {
559 status.set_code( ItemStatusCode::ISC_INVALID_TYPE );
560 status.set_error_message( "fields must be edited through the parent symbol's properties" );
561 aItemHandler( status, anyItem );
562 continue;
563 }
564
565 std::unique_ptr<EDA_ITEM> created = CreateItemForType( *type, symbol );
566
567 if( !created )
568 {
569 status.set_code( ItemStatusCode::ISC_INVALID_TYPE );
570 status.set_error_message(
571 fmt::format( "could not create an item of type {}", magic_enum::enum_name( *type ) ) );
572 aItemHandler( status, anyItem );
573 continue;
574 }
575
576 if( !created->Deserialize( anyItem ) )
577 {
578 status.set_code( ItemStatusCode::ISC_INVALID_DATA );
579 status.set_error_message(
580 fmt::format( "could not unpack {} from request", created->GetClass().ToStdString() ) );
581 aItemHandler( status, anyItem );
582 continue;
583 }
584
585 SCH_ITEM* newItem = static_cast<SCH_ITEM*>( created.get() );
586
587 if( newItem->Type() == SCH_FIELD_T && static_cast<SCH_FIELD*>( newItem )->IsMandatory() )
588 {
589 status.set_code( ItemStatusCode::ISC_INVALID_DATA );
590 status.set_error_message( "mandatory fields cannot be created or replaced directly" );
591 aItemHandler( status, anyItem );
592 continue;
593 }
594
595 // Look up the existing item by UUID
596 SCH_ITEM* existingItem = nullptr;
597
598 for( SCH_ITEM& item : symbol->GetDrawItems() )
599 {
600 if( item.m_Uuid == newItem->m_Uuid )
601 {
602 existingItem = &item;
603 break;
604 }
605 }
606
607 if( aCreate && existingItem )
608 {
609 status.set_code( ItemStatusCode::ISC_EXISTING );
610 status.set_error_message(
611 fmt::format( "an item with UUID {} already exists", newItem->m_Uuid.AsStdString() ) );
612 aItemHandler( status, anyItem );
613 continue;
614 }
615 else if( !aCreate && !existingItem )
616 {
617 status.set_code( ItemStatusCode::ISC_NONEXISTENT );
618 status.set_error_message(
619 fmt::format( "an item with UUID {} does not exist", newItem->m_Uuid.AsStdString() ) );
620 aItemHandler( status, anyItem );
621 continue;
622 }
623
624 if( !aCreate && existingItem->Type() != *type )
625 {
626 status.set_code( ItemStatusCode::ISC_INVALID_DATA );
627 status.set_error_message(
628 fmt::format( "item {} is not of the requested type", newItem->m_Uuid.AsStdString() ) );
629 aItemHandler( status, anyItem );
630 continue;
631 }
632
633 status.set_code( ItemStatusCode::ISC_OK );
634 google::protobuf::Any responseItem;
635
636 commit->Modify( symbol, screen );
637
638 if( aCreate )
639 {
640 if( newItem->Type() == SCH_PIN_T )
641 const_cast<KIID&>( newItem->m_Uuid ) = KIID();
642
643 newItem->SetParent( symbol );
644 symbol->AddDrawItem( newItem, false );
645 created.release();
646 newItem->Serialize( responseItem );
647
648 if( m_frame && frame()->GetCanvas() )
649 frame()->GetCanvas()->GetView()->Add( newItem );
650 }
651 else
652 {
653 SCH_ITEM* updated = existingItem;
654 updated->SwapItemData( newItem );
655 updated->Serialize( responseItem );
656
657 if( m_frame && frame()->GetCanvas() )
658 frame()->GetCanvas()->GetView()->Update( updated, KIGFX::GEOMETRY );
659 }
660
661 aItemHandler( status, responseItem );
662 }
663
664 if( !m_activeClients.contains( aClientName ) )
665 {
666 pushCurrentCommit( aClientName, aCreate ? _( "Created items via API" ) : _( "Modified items via API" ) );
667 }
668
669 return ItemRequestStatus::IRS_OK;
670}
671
672
673void API_HANDLER_SYMBOL::deleteItemsInternal( std::map<KIID, ItemDeletionStatus>& aItemsToDelete,
674 const std::string& aClientName )
675{
677
678 if( !symbol )
679 return;
680
681 SCH_SCREEN* screen = context()->GetScreen();
682 SCH_COMMIT* commit = static_cast<SCH_COMMIT*>( getCurrentCommit( aClientName ) );
683
684 for( auto& [id, status] : aItemsToDelete )
685 {
686 if( status != ItemDeletionStatus::IDS_NONEXISTENT )
687 continue;
688
689 SCH_ITEM* item = nullptr;
690
691 for( SCH_ITEM& candidate : symbol->GetDrawItems() )
692 {
693 if( candidate.m_Uuid == id )
694 {
695 item = &candidate;
696 break;
697 }
698 }
699
700 if( !item || !s_allowedTypes.contains( item->Type() ) )
701 {
702 status = ItemDeletionStatus::IDS_IMMUTABLE;
703 continue;
704 }
705
706 if( item->Type() == SCH_FIELD_T && static_cast<SCH_FIELD*>( item )->IsMandatory() )
707 {
708 status = ItemDeletionStatus::IDS_IMMUTABLE;
709 continue;
710 }
711
712 commit->Modify( symbol, screen );
713
714 if( m_frame && frame()->GetCanvas() )
715 frame()->GetCanvas()->GetView()->Remove( item );
716
717 symbol->RemoveDrawItem( item );
718 status = ItemDeletionStatus::IDS_OK;
719 }
720
721 if( !m_activeClients.contains( aClientName ) )
722 pushCurrentCommit( aClientName, _( "Deleted items via API" ) );
723}
724
725
727{
728 if( frame() )
729 frame()->OnModify();
730
732}
733
734
735void API_HANDLER_SYMBOL::pushCurrentCommit( const std::string& aClientName, const wxString& aMessage )
736{
737 API_HANDLER_EDITOR::pushCurrentCommit( aClientName, aMessage );
738 onModified();
739}
740
741
744{
745 if( HANDLER_RESULT<bool> documentValidation = validateDocument( aCtx.Request.document() ); !documentValidation )
746 return tl::unexpected( documentValidation.error() );
747
748 GetDocumentModifiedStateResponse response;
749 response.set_state( context()->IsContentModified() ? DocumentModifiedState::DMS_MODIFIED
750 : DocumentModifiedState::DMS_UNMODIFIED );
751 return response;
752}
tl::expected< T, ApiResponseStatus > HANDLER_RESULT
Definition api_handler.h:47
std::unique_ptr< EDA_ITEM > CreateItemForType(KICAD_T aType, EDA_ITEM *aContainer)
HANDLER_RESULT< bool > validateDocument(const DocumentSpecifier &aDocument)
HANDLER_RESULT< std::optional< KIID > > validateItemHeaderDocument(const kiapi::common::types::ItemHeader &aHeader)
If the header is valid, returns the item container.
API_HANDLER_EDITOR(EDA_BASE_FRAME *aFrame=nullptr)
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.
EDA_BASE_FRAME * m_frame
HANDLER_RESULT< commands::GetItemsResponse > handleGetItems(const HANDLER_CONTEXT< commands::GetItems > &aCtx)
tl::expected< bool, ApiResponseStatus > validateDocumentInternal(const DocumentSpecifier &aDocument) const override
std::unique_ptr< COMMIT > createCommit() override
Override this to create an appropriate COMMIT subclass for the frame in question.
HANDLER_RESULT< Empty > handleSaveDocument(const HANDLER_CONTEXT< commands::SaveDocument > &aCtx)
SYMBOL_EDITOR_CONTEXT * context() const
static std::set< KICAD_T > s_allowedTypes
LIB_SYMBOL * symbol() const
HANDLER_RESULT< Empty > handleRevertDocument(const HANDLER_CONTEXT< commands::RevertDocument > &aCtx)
HANDLER_RESULT< commands::GetDocumentModifiedStateResponse > handleGetDocumentModifiedState(const HANDLER_CONTEXT< commands::GetDocumentModifiedState > &aCtx) override
void deleteItemsInternal(std::map< KIID, ItemDeletionStatus > &aItemsToDelete, const std::string &aClientName) override
HANDLER_RESULT< Empty > handleOpenLibraryItem(const HANDLER_CONTEXT< commands::OpenLibraryItem > &aCtx)
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
API_HANDLER_SYMBOL(SYMBOL_EDIT_FRAME *aFrame)
std::shared_ptr< SYMBOL_EDITOR_CONTEXT > m_context
HANDLER_RESULT< commands::GetOpenDocumentsResponse > handleGetOpenDocuments(const HANDLER_CONTEXT< commands::GetOpenDocuments > &aCtx)
HANDLER_RESULT< Empty > handleSaveCopyOfDocument(const HANDLER_CONTEXT< commands::SaveCopyOfDocument > &aCtx)
void pushCurrentCommit(const std::string &aClientName, const wxString &aMessage) override
SYMBOL_EDIT_FRAME * frame() const
std::optional< EDA_ITEM * > getItemFromDocument(const DocumentSpecifier &aDocument, const KIID &aId) override
HANDLER_RESULT< commands::GetItemsResponse > handleGetItemsById(const HANDLER_CONTEXT< commands::GetItemsById > &aCtx)
void registerHandler(HANDLER_RESULT< ResponseType >(HandlerType::*aHandler)(const HANDLER_CONTEXT< RequestType > &))
Registers an API command handler for the given message types.
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:102
A base class for most all the KiCad significant classes used in schematics and boards.
Definition eda_item.h:98
const KIID m_Uuid
Definition eda_item.h:599
KICAD_T Type() const
Returns the type of object.
Definition eda_item.h:110
virtual void SetParent(EDA_ITEM *aParent)
Definition eda_item.cpp:153
void Update(const KIGFX::VIEW_ITEM *aItem, int aUpdateFlags) const override
For dynamic VIEWs, inform the associated VIEW that the graphical representation of this item has chan...
Definition sch_view.cpp:73
virtual void Add(VIEW_ITEM *aItem, int aDrawPriority=-1)
Add a VIEW_ITEM to the view.
Definition view.cpp:297
virtual void Remove(VIEW_ITEM *aItem)
Remove a VIEW_ITEM from the view.
Definition view.cpp:412
Definition kiid.h:46
std::string AsStdString() const
Definition kiid.cpp:270
A logical library item identifier and consists of various portions much like a URI.
Definition lib_id.h:45
bool IsValid() const
Check if this LID_ID is valid.
Definition lib_id.h:168
const wxString GetUniStringLibItemName() const
Get strings for display messages in dialogs.
Definition lib_id.h:108
const wxString GetUniStringLibNickname() const
Definition lib_id.h:84
const UTF8 & GetLibItemName() const
Definition lib_id.h:98
Define a library symbol object.
Definition lib_symbol.h:114
const LIB_ID & GetLibId() const override
Definition lib_symbol.h:190
Container for project specific data.
Definition project.h:63
virtual const wxString GetProjectPath() const
Return the full path of the project.
Definition project.cpp:183
virtual const wxString GetProjectName() const
Return the short name of the project.
Definition project.cpp:195
virtual bool IsNullProject() const
Check if this project is a null project (i.e.
Definition project.cpp:201
SCH_DRAW_PANEL * GetCanvas() const override
Return a pointer to GAL-based canvas of given EDA draw frame.
Commit for the schematic and symbol editors.
Definition sch_commit.h:54
KIGFX::SCH_VIEW * GetView() const override
Return a pointer to the KIGFX::VIEW instance used in the panel.
bool IsMandatory() const
Base class for any item which can be embedded within the SCHEMATIC container class,...
Definition sch_item.h:170
void SwapItemData(SCH_ITEM *aImage)
Swap data between aItem and aImage.
Definition sch_item.cpp:840
virtual void Serialize(google::protobuf::Any &aContainer) const
Serializes this object to the given Any message.
virtual LIB_ID GetLoadedLibId() const =0
virtual LIB_SYMBOL * GetCurSymbol() const =0
virtual SCH_SCREEN * GetScreen() const =0
virtual void SetContentModified(bool aModified=true)=0
virtual PROJECT & Prj() const =0
The symbol library editor main window.
void OnModify() override
Must be called after a schematic change in order to set the "modify" flag of the current symbol.
bool empty() const
Definition utf8.h:105
A type-safe container of any type.
Definition ki_any.h:92
static bool empty(const wxTextEntryBase *aCtrl)
#define _(s)
static const std::string KiCadSymbolLibFileExtension
@ GEOMETRY
Position or shape has changed.
Definition view_item.h:51
KICOMMON_API std::optional< KICAD_T > TypeNameFromAny(const google::protobuf::Any &aMessage)
Definition api_utils.cpp:50
KICOMMON_API LIB_ID UnpackLibId(const types::LibraryIdentifier &aId)
STL namespace.
RequestMessageType Request
Definition api_handler.h:54
std::shared_ptr< SYMBOL_EDITOR_CONTEXT > CreateSymbolEditorFrameContext(SYMBOL_EDIT_FRAME *aFrame)
KICAD_T
The set of class identification values stored in EDA_ITEM::m_structType.
Definition typeinfo.h:70
@ SCH_TABLE_T
Definition typeinfo.h:161
@ LIB_SYMBOL_T
Definition typeinfo.h:144
@ SCH_TABLECELL_T
Definition typeinfo.h:162
@ SCH_FIELD_T
Definition typeinfo.h:146
@ SCH_SHAPE_T
Definition typeinfo.h:145
@ SCH_TEXT_T
Definition typeinfo.h:147
@ SCH_BITMAP_T
Definition typeinfo.h:160
@ SCH_TEXTBOX_T
Definition typeinfo.h:148
@ SCH_PIN_T
Definition typeinfo.h:149
Definition of file extensions used in Kicad.