KiCad PCB EDA Suite
Loading...
Searching...
No Matches
api_handler_editor.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
18 * along with this program. If not, see <https://www.gnu.org/licenses/>.
19 */
20
22
23#include <api/api_enums.h>
24#include <api/api_utils.h>
25#include <eda_base_frame.h>
26#include <eda_item.h>
27#include <title_block.h>
28#include <wx/wx.h>
29
30using namespace kiapi::common::commands;
31
32
48
49
52{
53 if( std::optional<ApiResponseStatus> busy = checkForBusy() )
54 return tl::unexpected( *busy );
55
56 // Before 11.0, commit requests had no header so we assume they are for the PCB editor
57 if( aCtx.Request.has_header() && !validateItemHeaderDocument( aCtx.Request.header() ) )
58 {
59 ApiResponseStatus e;
60 // No message needed for AS_UNHANDLED; this is an internal flag for the API server
61 e.set_status( ApiStatusCode::AS_UNHANDLED );
62 return tl::unexpected( e );
63 }
64
65 if( m_commits.count( aCtx.ClientName ) )
66 {
67 ApiResponseStatus e;
68 e.set_status( ApiStatusCode::AS_BAD_REQUEST );
69 e.set_error_message( fmt::format( "the client {} already has a commit in progress",
70 aCtx.ClientName ) );
71 return tl::unexpected( e );
72 }
73
74 wxASSERT( !m_activeClients.count( aCtx.ClientName ) );
75
76 BeginCommitResponse response;
77
78 KIID id;
79 m_commits[aCtx.ClientName] = std::make_pair( id, createCommit() );
80 response.mutable_id()->set_value( id.AsStdString() );
81
82 m_activeClients.insert( aCtx.ClientName );
83
84 return response;
85}
86
87
89 const HANDLER_CONTEXT<EndCommit>& aCtx )
90{
91 if( std::optional<ApiResponseStatus> busy = checkForBusy() )
92 return tl::unexpected( *busy );
93
94 // Before 11.0, commit requests had no header so we assume they are for the PCB editor
95 if( aCtx.Request.has_header() && !validateItemHeaderDocument( aCtx.Request.header() ) )
96 {
97 ApiResponseStatus e;
98 // No message needed for AS_UNHANDLED; this is an internal flag for the API server
99 e.set_status( ApiStatusCode::AS_UNHANDLED );
100 return tl::unexpected( e );
101 }
102
103 if( !m_commits.count( aCtx.ClientName ) )
104 {
105 ApiResponseStatus e;
106 e.set_status( ApiStatusCode::AS_BAD_REQUEST );
107 e.set_error_message( fmt::format( "the client {} does not has a commit in progress",
108 aCtx.ClientName ) );
109 return tl::unexpected( e );
110 }
111
112 wxASSERT( m_activeClients.count( aCtx.ClientName ) );
113
114 const std::pair<KIID, std::unique_ptr<COMMIT>>& pair = m_commits.at( aCtx.ClientName );
115 const KIID& id = pair.first;
116 const std::unique_ptr<COMMIT>& commit = pair.second;
117
118 EndCommitResponse response;
119
120 // Do not check IDs with drop; it is a safety net in case the id was lost on the client side
121 switch( aCtx.Request.action() )
122 {
123 case kiapi::common::commands::CMA_DROP:
124 {
125 commit->Revert();
126 m_commits.erase( aCtx.ClientName );
127 m_activeClients.erase( aCtx.ClientName );
128 break;
129 }
130
131 case kiapi::common::commands::CMA_COMMIT:
132 {
133 if( aCtx.Request.id().value().compare( id.AsStdString() ) != 0 )
134 {
135 ApiResponseStatus e;
136 e.set_status( ApiStatusCode::AS_BAD_REQUEST );
137 e.set_error_message( fmt::format( "the id {} does not match the commit in progress",
138 aCtx.Request.id().value() ) );
139 return tl::unexpected( e );
140 }
141
142 pushCurrentCommit( aCtx.ClientName, wxString( aCtx.Request.message().c_str(), wxConvUTF8 ) );
143 break;
144 }
145
146 default:
147 break;
148 }
149
150 return response;
151}
152
153
154COMMIT* API_HANDLER_EDITOR::getCurrentCommit( const std::string& aClientName )
155{
156 if( !m_commits.count( aClientName ) )
157 {
158 KIID id;
159 m_commits[aClientName] = std::make_pair( id, createCommit() );
160 }
161
162 return m_commits.at( aClientName ).second.get();
163}
164
165
166void API_HANDLER_EDITOR::pushCurrentCommit( const std::string& aClientName,
167 const wxString& aMessage )
168{
169 auto it = m_commits.find( aClientName );
170
171 if( it == m_commits.end() )
172 return;
173
174 it->second.second->Push( aMessage.IsEmpty() ? m_defaultCommitMessage : aMessage );
175 m_commits.erase( it );
176 m_activeClients.erase( aClientName );
177}
178
179
181{
182 if( tl::expected<bool, ApiResponseStatus> validation = validateDocumentInternal( aDocument ); !validation )
183 return tl::unexpected( validation.error() );
184
185 return true;
186}
187
188
190 const types::ItemHeader& aHeader )
191{
192 if( !aHeader.has_document() || aHeader.document().type() != thisDocumentType() )
193 {
194 ApiResponseStatus e;
195 e.set_status( ApiStatusCode::AS_UNHANDLED );
196 // No error message, this is a flag that the server should try a different handler
197 return tl::unexpected( e );
198 }
199
200 HANDLER_RESULT<bool> documentValidation = validateDocument( aHeader.document() );
201
202 if( !documentValidation )
203 return tl::unexpected( documentValidation.error() );
204
205 if( tl::expected<bool, ApiResponseStatus> result = validateDocumentInternal( aHeader.document() ); !result )
206 return tl::unexpected( result.error() );
207
208 if( aHeader.has_container() )
209 {
210 return KIID( aHeader.container().value() );
211 }
212
213 // Valid header, but no container provided
214 return std::nullopt;
215}
216
217
218std::optional<ApiResponseStatus> API_HANDLER_EDITOR::checkForBusy()
219{
220 if( !m_frame )
221 return std::nullopt;
222
223 if( !m_frame->CanAcceptApiCommands() )
224 {
225 ApiResponseStatus e;
226 e.set_status( ApiStatusCode::AS_BUSY );
227 e.set_error_message( "KiCad is busy and cannot respond to API requests right now" );
228 return e;
229 }
230
231 return std::nullopt;
232}
233
234
236 const HANDLER_CONTEXT<CreateItems>& aCtx )
237{
238 if( std::optional<ApiResponseStatus> busy = checkForBusy() )
239 return tl::unexpected( *busy );
240
241 CreateItemsResponse response;
242
244 aCtx.ClientName,
245 aCtx.Request.header(), aCtx.Request.items(),
246 [&]( const ItemStatus& aStatus, const google::protobuf::Any& aItem )
247 {
248 ItemCreationResult itemResult;
249 itemResult.mutable_status()->CopyFrom( aStatus );
250 itemResult.mutable_item()->CopyFrom( aItem );
251 response.mutable_created_items()->Add( std::move( itemResult ) );
252 } );
253
254 if( !result.has_value() )
255 return tl::unexpected( result.error() );
256
257 response.set_status( *result );
258 return response;
259}
260
261
263 const HANDLER_CONTEXT<UpdateItems>& aCtx )
264{
265 if( std::optional<ApiResponseStatus> busy = checkForBusy() )
266 return tl::unexpected( *busy );
267
268 UpdateItemsResponse response;
269
271 aCtx.ClientName,
272 aCtx.Request.header(), aCtx.Request.items(),
273 [&]( const ItemStatus& aStatus, const google::protobuf::Any& aItem )
274 {
275 ItemUpdateResult itemResult;
276 itemResult.mutable_status()->CopyFrom( aStatus );
277 itemResult.mutable_item()->CopyFrom( aItem );
278 response.mutable_updated_items()->Add( std::move( itemResult ) );
279 } );
280
281 if( !result.has_value() )
282 return tl::unexpected( result.error() );
283
284 response.set_status( *result );
285 return response;
286}
287
288
290 const HANDLER_CONTEXT<DeleteItems>& aCtx )
291{
292 if( std::optional<ApiResponseStatus> busy = checkForBusy() )
293 return tl::unexpected( *busy );
294
295 if( !validateItemHeaderDocument( aCtx.Request.header() ) )
296 {
297 ApiResponseStatus e;
298 // No message needed for AS_UNHANDLED; this is an internal flag for the API server
299 e.set_status( ApiStatusCode::AS_UNHANDLED );
300 return tl::unexpected( e );
301 }
302
303 std::map<KIID, ItemDeletionStatus> itemsToDelete;
304
305 for( const kiapi::common::types::KIID& kiidBuf : aCtx.Request.item_ids() )
306 {
307 if( !kiidBuf.value().empty() )
308 {
309 KIID kiid( kiidBuf.value() );
310 itemsToDelete[kiid] = ItemDeletionStatus::IDS_NONEXISTENT;
311 }
312 }
313
314 if( itemsToDelete.empty() )
315 {
316 ApiResponseStatus e;
317 e.set_status( ApiStatusCode::AS_BAD_REQUEST );
318 e.set_error_message( "no valid items to delete were given" );
319 return tl::unexpected( e );
320 }
321
322 deleteItemsInternal( itemsToDelete, aCtx.ClientName );
323
324 DeleteItemsResponse response;
325
326 for( const auto& [id, status] : itemsToDelete )
327 {
328 ItemDeletionResult* result = response.add_deleted_items();
329 result->mutable_id()->set_value( id.AsStdString() );
330 result->set_status( status );
331 }
332
333 response.set_status( kiapi::common::types::ItemRequestStatus::IRS_OK );
334 return response;
335}
336
337
339 const HANDLER_CONTEXT<HitTest>& aCtx )
340{
341 if( std::optional<ApiResponseStatus> busy = checkForBusy() )
342 return tl::unexpected( *busy );
343
344 if( !validateItemHeaderDocument( aCtx.Request.header() ) )
345 {
346 ApiResponseStatus e;
347 // No message needed for AS_UNHANDLED; this is an internal flag for the API server
348 e.set_status( ApiStatusCode::AS_UNHANDLED );
349 return tl::unexpected( e );
350 }
351
352 HitTestResponse response;
353
354 std::optional<EDA_ITEM*> item = getItemFromDocument( aCtx.Request.header().document(),
355 KIID( aCtx.Request.id().value() ) );
356
357 if( !item )
358 {
359 ApiResponseStatus e;
360 e.set_status( ApiStatusCode::AS_BAD_REQUEST );
361 e.set_error_message( "the requested item ID is not present in the given document" );
362 return tl::unexpected( e );
363 }
364
365 const EDA_IU_SCALE& scale = getIuScale();
366 VECTOR2I posIu = UnpackVector2( aCtx.Request.position(), scale );
367 int toleranceIu = scale.NmToIU( aCtx.Request.tolerance() );
368
369 if( ( *item )->HitTest( posIu, toleranceIu ) )
370 response.set_result( HitTestResult::HTR_HIT );
371 else
372 response.set_result( HitTestResult::HTR_NO_HIT );
373
374 return response;
375}
376
377
380{
381 if( HANDLER_RESULT<bool> documentValidation = validateDocument( aCtx.Request.document() ); !documentValidation )
382 return tl::unexpected( documentValidation.error() );
383
384 GetDocumentModifiedStateResponse response;
385
386 wxCHECK( m_frame, response );
387 response.set_state( m_frame->IsContentModified() ? DocumentModifiedState::DMS_MODIFIED
388 : DocumentModifiedState::DMS_UNMODIFIED );
389 return response;
390}
391
392
393std::vector<KICAD_T> API_HANDLER_EDITOR::parseRequestedItemTypes( const google::protobuf::RepeatedField<int>& aTypes )
394{
395 std::vector<KICAD_T> types;
396
397 for( int typeRaw : aTypes )
398 {
399 auto typeMessage = static_cast<types::KiCadObjectType>( typeRaw );
400
401 if( KICAD_T type = FromProtoEnum<KICAD_T>( typeMessage ); type != TYPE_NOT_INIT )
402 types.emplace_back( type );
403 }
404
405 return types;
406}
407
408
411{
412 HANDLER_RESULT<bool> documentValidation = validateDocument( aCtx.Request.document() );
413
414 if( !documentValidation )
415 return tl::unexpected( documentValidation.error() );
416
417 std::optional<TITLE_BLOCK*> optBlock = getTitleBlock( aCtx.Request.document() );
418
419 if( !optBlock )
420 {
421 ApiResponseStatus e;
422 e.set_status( AS_BAD_REQUEST );
423 e.set_error_message( "this editor does not support a title block" );
424 return tl::unexpected( e );
425 }
426
427 TITLE_BLOCK& block = **optBlock;
428
429 types::TitleBlockInfo response;
430
431 response.set_title( block.GetTitle().ToUTF8() );
432 response.set_date( block.GetDate().ToUTF8() );
433 response.set_revision( block.GetRevision().ToUTF8() );
434 response.set_company( block.GetCompany().ToUTF8() );
435 response.set_comment1( block.GetComment( 0 ).ToUTF8() );
436 response.set_comment2( block.GetComment( 1 ).ToUTF8() );
437 response.set_comment3( block.GetComment( 2 ).ToUTF8() );
438 response.set_comment4( block.GetComment( 3 ).ToUTF8() );
439 response.set_comment5( block.GetComment( 4 ).ToUTF8() );
440 response.set_comment6( block.GetComment( 5 ).ToUTF8() );
441 response.set_comment7( block.GetComment( 6 ).ToUTF8() );
442 response.set_comment8( block.GetComment( 7 ).ToUTF8() );
443 response.set_comment9( block.GetComment( 8 ).ToUTF8() );
444
445 return response;
446}
447
448
451{
452 HANDLER_RESULT<bool> documentValidation = validateDocument( aCtx.Request.document() );
453
454 if( !documentValidation )
455 return tl::unexpected( documentValidation.error() );
456
457 if( !aCtx.Request.has_title_block() )
458 {
459 ApiResponseStatus e;
460 e.set_status( ApiStatusCode::AS_BAD_REQUEST );
461 e.set_error_message( "SetTitleBlockInfo requires title_block" );
462 return tl::unexpected( e );
463 }
464
465 std::optional<TITLE_BLOCK*> optBlock = getTitleBlock( aCtx.Request.document() );
466
467 if( !optBlock )
468 {
469 ApiResponseStatus e;
470 e.set_status( AS_BAD_REQUEST );
471 e.set_error_message( "this editor does not support a title block" );
472 return tl::unexpected( e );
473 }
474
475 TITLE_BLOCK& block = **optBlock;
476
477 const types::TitleBlockInfo& request = aCtx.Request.title_block();
478
479 block.SetTitle( wxString::FromUTF8( request.title() ) );
480 block.SetDate( wxString::FromUTF8( request.date() ) );
481 block.SetRevision( wxString::FromUTF8( request.revision() ) );
482 block.SetCompany( wxString::FromUTF8( request.company() ) );
483 block.SetComment( 0, wxString::FromUTF8( request.comment1() ) );
484 block.SetComment( 1, wxString::FromUTF8( request.comment2() ) );
485 block.SetComment( 2, wxString::FromUTF8( request.comment3() ) );
486 block.SetComment( 3, wxString::FromUTF8( request.comment4() ) );
487 block.SetComment( 4, wxString::FromUTF8( request.comment5() ) );
488 block.SetComment( 5, wxString::FromUTF8( request.comment6() ) );
489 block.SetComment( 6, wxString::FromUTF8( request.comment7() ) );
490 block.SetComment( 7, wxString::FromUTF8( request.comment8() ) );
491 block.SetComment( 8, wxString::FromUTF8( request.comment9() ) );
492
493 onModified();
494
495 return google::protobuf::Empty();
496}
497
498
501{
502 HANDLER_RESULT<bool> documentValidation = validateDocument( aCtx.Request.document() );
503
504 if( !documentValidation )
505 return tl::unexpected( documentValidation.error() );
506
507 std::optional<PAGE_INFO> optPageInfo = getPageSettings( aCtx.Request.document() );
508
509 if( !optPageInfo )
510 {
511 ApiResponseStatus e;
512 e.set_status( AS_BAD_REQUEST );
513 e.set_error_message( "this editor does not support page settings" );
514 return tl::unexpected( e );
515 }
516
517 PAGE_INFO& pageInfo = *optPageInfo;
518
519 types::PageSettings response;
520 response.set_page_size( ToProtoEnum<PAGE_SIZE_TYPE, types::PageSize>( pageInfo.GetType() ) );
521
522 if( pageInfo.IsCustom() )
523 PackVector2( *response.mutable_user_page_size(), pageInfo.GetSizeIU( pcbIUScale.IU_PER_MILS ) );
524
525 response.set_orientation( pageInfo.IsPortrait() ? types::PageOrientation::PO_PORTRAIT
526 : types::PageOrientation::PO_LANDSCAPE );
527 response.set_drawing_sheet( getDrawingSheetFileName().ToUTF8() );
528
529 return response;
530}
531
532
535{
536 HANDLER_RESULT<bool> documentValidation = validateDocument( aCtx.Request.document() );
537
538 if( !documentValidation )
539 return tl::unexpected( documentValidation.error() );
540
541 if( !aCtx.Request.has_page_settings() )
542 {
543 ApiResponseStatus e;
544 e.set_status( ApiStatusCode::AS_BAD_REQUEST );
545 e.set_error_message( "SetPageSettings requires page_settings" );
546 return tl::unexpected( e );
547 }
548
549 std::optional<PAGE_INFO> optPageInfo = getPageSettings( aCtx.Request.document() );
550
551 if( !optPageInfo )
552 {
553 ApiResponseStatus e;
554 e.set_status( AS_BAD_REQUEST );
555 e.set_error_message( "this editor does not support page settings" );
556 return tl::unexpected( e );
557 }
558
559 const types::PageSettings& request = aCtx.Request.page_settings();
560
561 PAGE_INFO pageInfo = *optPageInfo;
562 PAGE_SIZE_TYPE pageSizeType = FromProtoEnum<PAGE_SIZE_TYPE>( request.page_size() );
563
564 if( pageSizeType == PAGE_SIZE_TYPE::User )
565 {
566 if( !request.has_user_page_size() )
567 {
568 ApiResponseStatus e;
569 e.set_status( ApiStatusCode::AS_BAD_REQUEST );
570 e.set_error_message( "custom page size requires user_page_size" );
571 return tl::unexpected( e );
572 }
573
574 VECTOR2D sizeIu = UnpackVector2( request.user_page_size() );
575 PAGE_INFO::SetCustomWidthMils( pcbIUScale.IUToMils( sizeIu.x ) );
576 PAGE_INFO::SetCustomHeightMils( pcbIUScale.IUToMils( sizeIu.y ) );
577
578 pageInfo.SetType( PAGE_SIZE_TYPE::User );
579 }
580 else
581 {
582 bool portrait = ( request.orientation() == types::PageOrientation::PO_PORTRAIT );
583 pageInfo.SetType( pageSizeType, portrait );
584 }
585
586 if( !setPageSettings( aCtx.Request.document(), pageInfo ) )
587 {
588 ApiResponseStatus e;
589 e.set_status( AS_BAD_REQUEST );
590 e.set_error_message( "this editor does not support page settings" );
591 return tl::unexpected( e );
592 }
593
594 wxString drawingSheet( wxString::FromUTF8( request.drawing_sheet() ) );
595 setDrawingSheetFileName( drawingSheet );
596
597 onModified();
598
599 types::PageSettings response;
600 response.set_page_size( ToProtoEnum<PAGE_SIZE_TYPE, types::PageSize>( pageInfo.GetType() ) );
601
602 if( pageInfo.IsCustom() )
603 PackVector2( *response.mutable_user_page_size(), pageInfo.GetSizeIU( pcbIUScale.IU_PER_MILS ) );
604
605 response.set_orientation( pageInfo.IsPortrait() ? types::PageOrientation::PO_PORTRAIT
606 : types::PageOrientation::PO_LANDSCAPE );
607 response.set_drawing_sheet( getDrawingSheetFileName().ToUTF8() );
608
609 return response;
610}
KICOMMON_API types::KiCadObjectType ToProtoEnum(KICAD_T aValue)
KICOMMON_API KICAD_T FromProtoEnum(types::KiCadObjectType aValue)
Definition api_enums.cpp:55
tl::expected< T, ApiResponseStatus > HANDLER_RESULT
Definition api_handler.h:45
constexpr EDA_IU_SCALE pcbIUScale
Definition base_units.h:121
virtual std::unique_ptr< COMMIT > createCommit()=0
Override this to create an appropriate COMMIT subclass for the frame in question.
virtual bool setPageSettings(const DocumentSpecifier &aDocument, const PAGE_INFO &aPageInfo)
HANDLER_RESULT< bool > validateDocument(const DocumentSpecifier &aDocument)
HANDLER_RESULT< commands::DeleteItemsResponse > handleDeleteItems(const HANDLER_CONTEXT< commands::DeleteItems > &aCtx)
HANDLER_RESULT< types::PageSettings > handleSetPageSettings(const HANDLER_CONTEXT< commands::SetPageSettings > &aCtx)
virtual const EDA_IU_SCALE & getIuScale() const
Returns the internal-unit scale that the concrete editor uses.
virtual std::optional< EDA_ITEM * > getItemFromDocument(const DocumentSpecifier &aDocument, const KIID &aId)=0
HANDLER_RESULT< std::optional< KIID > > validateItemHeaderDocument(const kiapi::common::types::ItemHeader &aHeader)
If the header is valid, returns the item container.
virtual void setDrawingSheetFileName(const wxString &aFileName)
HANDLER_RESULT< types::PageSettings > handleGetPageSettings(const HANDLER_CONTEXT< commands::GetPageSettings > &aCtx)
HANDLER_RESULT< commands::EndCommitResponse > handleEndCommit(const HANDLER_CONTEXT< commands::EndCommit > &aCtx)
virtual tl::expected< bool, ApiResponseStatus > validateDocumentInternal(const DocumentSpecifier &aDocument) const =0
API_HANDLER_EDITOR(EDA_BASE_FRAME *aFrame=nullptr)
static std::vector< KICAD_T > parseRequestedItemTypes(const google::protobuf::RepeatedField< int > &aTypes)
virtual std::optional< PAGE_INFO > getPageSettings(const DocumentSpecifier &aDocument)
virtual HANDLER_RESULT< commands::GetDocumentModifiedStateResponse > handleGetDocumentModifiedState(const HANDLER_CONTEXT< commands::GetDocumentModifiedState > &aCtx)
virtual std::optional< TITLE_BLOCK * > getTitleBlock(const DocumentSpecifier &aDocument)
HANDLER_RESULT< commands::CreateItemsResponse > handleCreateItems(const HANDLER_CONTEXT< commands::CreateItems > &aCtx)
COMMIT * getCurrentCommit(const std::string &aClientName)
virtual void pushCurrentCommit(const std::string &aClientName, const wxString &aMessage)
virtual HANDLER_RESULT< ItemRequestStatus > handleCreateUpdateItemsInternal(bool aCreate, const std::string &aClientName, const types::ItemHeader &aHeader, const google::protobuf::RepeatedPtrField< google::protobuf::Any > &aItems, std::function< void(commands::ItemStatus, google::protobuf::Any)> aItemHandler)=0
std::set< std::string > m_activeClients
std::map< std::string, std::pair< KIID, std::unique_ptr< COMMIT > > > m_commits
HANDLER_RESULT< commands::UpdateItemsResponse > handleUpdateItems(const HANDLER_CONTEXT< commands::UpdateItems > &aCtx)
virtual void deleteItemsInternal(std::map< KIID, ItemDeletionStatus > &aItemsToDelete, const std::string &aClientName)=0
virtual wxString getDrawingSheetFileName()
virtual std::optional< ApiResponseStatus > checkForBusy()
Checks if the editor can accept commands.
HANDLER_RESULT< types::TitleBlockInfo > handleGetTitleBlockInfo(const HANDLER_CONTEXT< commands::GetTitleBlockInfo > &aCtx)
virtual types::DocumentType thisDocumentType() const =0
Override this to specify which document type this editor handles.
HANDLER_RESULT< google::protobuf::Empty > handleSetTitleBlockInfo(const HANDLER_CONTEXT< commands::SetTitleBlockInfo > &aCtx)
HANDLER_RESULT< commands::BeginCommitResponse > handleBeginCommit(const HANDLER_CONTEXT< commands::BeginCommit > &aCtx)
virtual void onModified()
HANDLER_RESULT< commands::HitTestResponse > handleHitTest(const HANDLER_CONTEXT< commands::HitTest > &aCtx)
EDA_BASE_FRAME * m_frame
static const wxString m_defaultCommitMessage
void registerHandler(HANDLER_RESULT< ResponseType >(HandlerType::*aHandler)(const HANDLER_CONTEXT< RequestType > &))
Registers an API command handler for the given message types.
Definition api_handler.h:93
Represent a set of changes (additions, deletions or modifications) of a data model (e....
Definition commit.h:68
The base frame for deriving all KiCad main window classes.
Definition kiid.h:46
Describe the page size and margins of a paper page on which to eventually print or plot.
Definition page_info.h:75
bool SetType(PAGE_SIZE_TYPE aPageSize, bool aIsPortrait=false)
Set the name of the page type and also the sizes and margins commonly associated with that type name.
static void SetCustomWidthMils(double aWidthInMils)
Set the width of Custom page in mils for any custom page constructed or made via SetType() after maki...
const VECTOR2D GetSizeIU(double aIUScale) const
Gets the page size in internal units.
Definition page_info.h:173
bool IsCustom() const
bool IsPortrait() const
Definition page_info.h:124
static void SetCustomHeightMils(double aHeightInMils)
Set the height of Custom page in mils for any custom page constructed or made via SetType() after mak...
const PAGE_SIZE_TYPE & GetType() const
Definition page_info.h:98
Hold the information shown in the lower right corner of a plot, printout, or editing view.
Definition title_block.h:38
const wxString & GetCompany() const
Definition title_block.h:93
void SetRevision(const wxString &aRevision)
Definition title_block.h:78
void SetComment(int aIdx, const wxString &aComment)
Definition title_block.h:98
const wxString & GetRevision() const
Definition title_block.h:83
void SetTitle(const wxString &aTitle)
Definition title_block.h:55
const wxString & GetDate() const
Definition title_block.h:73
const wxString & GetComment(int aIdx) const
void SetCompany(const wxString &aCompany)
Definition title_block.h:88
const wxString & GetTitle() const
Definition title_block.h:60
void SetDate(const wxString &aDate)
Set the date field, and defaults to the current time and date.
Definition title_block.h:68
Base window classes and related definitions.
KICOMMON_API VECTOR2I UnpackVector2(const types::Vector2 &aInput, const EDA_IU_SCALE &aScale)
KICOMMON_API void PackVector2(types::Vector2 &aOutput, const VECTOR2I &aInput, const EDA_IU_SCALE &aScale)
PAGE_SIZE_TYPE
Definition page_info.h:46
const int scale
std::string ClientName
Definition api_handler.h:51
RequestMessageType Request
Definition api_handler.h:52
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:70
@ TYPE_NOT_INIT
Definition typeinfo.h:73
VECTOR2< int32_t > VECTOR2I
Definition vector2d.h:683
VECTOR2< double > VECTOR2D
Definition vector2d.h:682