KiCad PCB EDA Suite
Loading...
Searching...
No Matches
dialog_generators.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) 2023 Alex Shvartzkop <[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
8 * modify it under the terms of the GNU General Public License
9 * as published by the Free Software Foundation; either version 2
10 * of the License, or (at your option) any later version.
11 *
12 * This program is distributed in the hope that it will be useful,
13 * but WITHOUT ANY WARRANTY; without even the implied warranty of
14 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
15 * GNU 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
21#include "dialog_generators.h"
22
23#include <pcb_edit_frame.h>
24#include <board.h>
25#include <pcb_generator.h>
26#include <tool/tool_manager.h>
27#include <tools/pcb_actions.h>
29
30
32{
33 for( auto& [name, ptr] : m_dataModels )
34 {
35 if( ptr )
36 ptr->DecRef();
37 }
38
39 m_dataModels.clear();
40 m_columnNameTypes.clear();
41 m_dataViews.clear();
42}
43
44
45void DIALOG_GENERATORS::clearModel( const wxString& aName )
46{
47 if( m_dataModels[aName] )
48 {
49 m_dataModels[aName]->DeleteAllItems();
50 m_dataModels[aName]->ClearColumns();
51 }
52
53 m_columnNameTypes[aName].clear();
54}
55
56
57void DIALOG_GENERATORS::deleteModel( const wxString& aName )
58{
59 if( m_dataModels[aName] )
60 m_dataModels[aName]->DecRef();
61
62 for( size_t i = 0; i < m_Notebook->GetPageCount(); i++ )
63 {
64 wxWindow* page = m_Notebook->GetPage( i );
65 if( page->GetName() == aName )
66 {
67 m_Notebook->DeletePage( i );
68 break;
69 }
70 }
71
72 m_dataViews.erase( aName );
73 m_dataModels.erase( aName );
74 m_columnNameTypes.erase( aName );
75}
76
77
79{
80 wxString lastPageName;
81 std::set<wxString> lastUUIDs;
82
83 if( auto page = m_Notebook->GetCurrentPage() )
84 {
85 lastPageName = page->GetName();
86 wxDataViewCtrl* dataView = m_dataViews[lastPageName];
87
88 int uuidCol = dataView->GetColumnCount() - 1;
89
90 wxDataViewItemArray selections;
91 dataView->GetSelections( selections );
92
93 for( wxDataViewItem& item : selections )
94 {
95 wxVariant var;
96 dataView->GetModel()->GetValue( var, item, uuidCol );
97 lastUUIDs.emplace( var.GetString() );
98 }
99 }
100
101 int newPageId = -1;
102
103 std::map<wxString, std::map<KIID, std::vector<std::pair<wxString, wxVariant>>>> dataMap;
104
105 for( PCB_GENERATOR* gen : m_currentBoard->Generators() )
106 {
107 std::vector<std::pair<wxString, wxVariant>> rowData = gen->GetRowData();
108
109 const KIID uuid = gen->m_Uuid;
110 rowData.emplace_back( wxS( "UUID" ), uuid.AsString() );
111
112 dataMap[gen->GetName()][uuid] = rowData;
113 }
114
115 std::vector<wxString> toDelete;
116 for( size_t i = 0; i < m_Notebook->GetPageCount(); i++ )
117 {
118 wxWindow* page = m_Notebook->GetPage( i );
119
120 if( dataMap.find(page->GetName()) == dataMap.end() )
121 {
122 toDelete.emplace_back( page->GetName() );
123 }
124 }
125
126 for( const wxString& name : toDelete )
127 deleteModel( name );
128
129 for( auto& [typeName, uuidToRowMap] : dataMap )
130 {
131 bool exists = false;
132 for( size_t i = 0; i < m_Notebook->GetPageCount(); i++ )
133 {
134 if( m_Notebook->GetPage( i )->GetName() == typeName )
135 {
136 exists = true;
137 break;
138 }
139 }
140
141 if( exists )
142 {
143 clearModel( typeName );
144 }
145 else
146 {
147 wxString title = typeName + wxString::Format( " (%d)", int( uuidToRowMap.size() ) );
148 addPage( typeName, title );
149 }
150 }
151
152 for( auto& [typeName, uuidToRowMap] : dataMap )
153 {
154 std::vector<std::pair<wxString, wxString>>& thisColNameTypes = m_columnNameTypes[typeName];
155 std::map<wxString, int> nameToColIdMap;
156 std::set<wxString> columnsSet;
157
158 for( auto& [uuid, rowMap] : uuidToRowMap )
159 {
160 for( auto& [colName, value] : rowMap )
161 {
162 if( columnsSet.find( colName ) == columnsSet.end() )
163 {
164 int colId = columnsSet.size();
165 columnsSet.emplace( colName );
166
167 nameToColIdMap[colName] = colId;
168 thisColNameTypes.emplace_back( colName, "string" );
169 }
170 }
171 }
172
173 wxDataViewListStore* store = new wxDataViewListStore();
174
175 for( auto& [name, type] : thisColNameTypes )
176 store->AppendColumn( type );
177
178 int colCount = thisColNameTypes.size();
179
180 for( auto& [uuid, rowMap] : uuidToRowMap )
181 {
182 wxVector<wxVariant> values( colCount );
183
184 for( auto& [dataName, value] : rowMap )
185 {
186 values[nameToColIdMap[dataName]] = value;
187 }
188
189 store->AppendItem( values );
190 }
191
192 m_dataModels[typeName] = store;
193 }
194
195 m_Notebook->DeleteAllPages();
196
197 int pageId = 0;
198 for( auto& [typeName, model] : m_dataModels )
199 {
200 wxString title = typeName + wxString::Format( " (%d)", model->GetItemCount() );
201 wxDataViewCtrl* dataView = addPage( typeName, title );
202
203 if( typeName == lastPageName )
204 newPageId = pageId;
205
206 dataView->AssociateModel( model );
207
208 int colId = 0;
209 for( auto& [name, type] : m_columnNameTypes[typeName] )
210 {
211 int flags = wxDATAVIEW_COL_RESIZABLE | wxDATAVIEW_COL_SORTABLE;
212
213 if( name == wxS( "UUID" ) )
214 flags |= wxDATAVIEW_COL_HIDDEN;
215
216 dataView->AppendTextColumn( name, colId, wxDATAVIEW_CELL_INERT, wxCOL_WIDTH_AUTOSIZE,
217 wxALIGN_LEFT, flags );
218
219 colId++;
220 }
221
222 m_dataViews[typeName] = dataView;
223
224 pageId++;
225 }
226
227 if( newPageId != -1 )
228 {
229 m_Notebook->SetSelection( newPageId );
230
231 wxDataViewCtrl* dataView = m_dataViews[lastPageName];
232 int uuidCol = dataView->GetColumnCount() - 1;
233 wxDataViewListStore* model = m_dataModels[lastPageName];
234 size_t itemCount = model->GetItemCount();
235 wxDataViewItemArray newSelections;
236
237 for( size_t itemId = 0; itemId < itemCount; itemId++ )
238 {
239 wxVariant var;
240 model->GetValueByRow( var, itemId, uuidCol );
241
242 if( lastUUIDs.find( var.GetString() ) != lastUUIDs.end() )
243 newSelections.push_back( model->GetItem( itemId ) );
244 }
245
246 dataView->SetSelections( newSelections );
247 }
248}
249
250
251wxDataViewCtrl* DIALOG_GENERATORS::addPage( const wxString& aName, const wxString& aTitle )
252{
253 wxPanel* panelPage =
254 new wxPanel( m_Notebook, wxID_ANY, wxDefaultPosition, wxDefaultSize, wxTAB_TRAVERSAL );
255
256 panelPage->SetName( aName );
257
258 wxBoxSizer* bSizerPage1;
259 bSizerPage1 = new wxBoxSizer( wxVERTICAL );
260
261 bSizerPage1->SetMinSize( wxSize( -1, 320 ) );
262 wxDataViewCtrl* dataView = new wxDataViewCtrl( panelPage, wxID_ANY, wxDefaultPosition,
263 wxDefaultSize, wxDV_MULTIPLE | wxDV_ROW_LINES );
264
265 dataView->Bind( wxEVT_DATAVIEW_SELECTION_CHANGED, &DIALOG_GENERATORS::OnItemSelected, this );
266 dataView->SetLayoutDirection( wxLayout_LeftToRight );
267
268 bSizerPage1->Add( dataView, 1, wxEXPAND | wxALL, 5 );
269
270
271 bSizerPage1->Add( 0, 8, 0, wxEXPAND, 5 );
272
273
274 panelPage->SetSizer( bSizerPage1 );
275 panelPage->Layout();
276 bSizerPage1->Fit( panelPage );
277 m_Notebook->AddPage( panelPage, aTitle, false );
278
279 return dataView;
280}
281
282
283void DIALOG_GENERATORS::onUnitsChanged( wxCommandEvent& event )
284{
285 m_units = m_frame->GetUserUnits();
286
288
289 event.Skip();
290}
291
292
293void DIALOG_GENERATORS::onBoardChanged( wxCommandEvent& event )
294{
295 m_currentBoard = m_frame->GetBoard();
296
297 if( m_currentBoard != nullptr )
298 m_currentBoard->AddListener( this );
299
301
302 event.Skip();
303}
304
305
307{
309}
310
311
312void DIALOG_GENERATORS::OnBoardItemsAdded( BOARD& aBoard, std::vector<BOARD_ITEM*>& aBoardItems )
313{
315}
316
317
319{
321}
322
323
324void DIALOG_GENERATORS::OnBoardItemsRemoved( BOARD& aBoard, std::vector<BOARD_ITEM*>& aBoardItems )
325{
327}
328
329
331{
333}
334
335
336void DIALOG_GENERATORS::OnBoardItemsChanged( BOARD& aBoard, std::vector<BOARD_ITEM*>& aBoardItems )
337{
339}
340
341
343 std::vector<BOARD_ITEM*>& aAddedItems,
344 std::vector<BOARD_ITEM*>& aRemovedItems,
345 std::vector<BOARD_ITEM*>& aChangedItems )
346{
348}
349
350
351DIALOG_GENERATORS::DIALOG_GENERATORS( PCB_EDIT_FRAME* aEditorFrame, wxWindow* aParent ) :
352 DIALOG_GENERATORS_BASE( aParent )
353{
355
356 m_frame = aEditorFrame;
357 m_currentBoard = m_frame->GetBoard();
358
359 m_Notebook->DeleteAllPages();
360
362
363 Bind( EDA_EVT_UNITS_CHANGED, &DIALOG_GENERATORS::onUnitsChanged, this );
364 Bind( EDA_EVT_BOARD_CHANGED, &DIALOG_GENERATORS::onBoardChanged, this );
365
366 if( m_currentBoard != nullptr )
367 {
368 m_currentBoard->AddListener( this );
369 }
370}
371
372
374{
375 clearModels();
376
377 if( m_currentBoard != nullptr )
378 m_currentBoard->RemoveListener( this );
379}
380
381
383{
384 wxString pageName = m_Notebook->GetCurrentPage()->GetName();
385 return m_dataModels[pageName];
386}
387
388
389void DIALOG_GENERATORS::OnItemSelected( wxDataViewEvent& aEvent )
390{
391 wxDataViewListStore* model = getCurrentModel();
392 wxString pageName = m_Notebook->GetCurrentPage()->GetName();
393 wxDataViewCtrl* dataView = m_dataViews[pageName];
394
395 if( !model )
396 return;
397
398 int uuidCol = dataView->GetColumnCount() - 1;
399 std::vector<BOARD_ITEM*> boardItems;
400 EDA_ITEMS edaItems;
401
402 wxDataViewItemArray selections;
403 dataView->GetSelections( selections );
404
405 for( wxDataViewItem& viewItem : selections )
406 {
407 wxVariant var;
408 model->GetValue( var, viewItem, uuidCol );
409
410 BOARD_ITEM* brdItem = m_currentBoard->ResolveItem( var.GetString() );
411
412 if( !brdItem || brdItem->Type() != KICAD_T::PCB_GENERATOR_T )
413 continue;
414
415 boardItems.push_back( brdItem );
416 edaItems.push_back( brdItem );
417 }
418
419 m_frame->GetToolManager()->RunAction( ACTIONS::selectionClear );
420 m_frame->GetToolManager()->RunAction<EDA_ITEMS*>( ACTIONS::selectItems, &edaItems );
421 m_frame->FocusOnItems( boardItems );
422}
423
424
425void DIALOG_GENERATORS::OnRebuildSelectedClick( wxCommandEvent& event )
426{
428}
429
430
431void DIALOG_GENERATORS::OnRebuildTypeClick( wxCommandEvent& event )
432{
433 wxDataViewListStore* model = getCurrentModel();
434 wxString pageName = m_Notebook->GetCurrentPage()->GetName();
435
436 if( !model )
437 return;
438
439 int uuidCol = m_columnNameTypes[pageName].size() - 1;
440 EDA_ITEMS items;
441
442 for( size_t row = 0; row < model->GetItemCount(); row++ )
443 {
444 wxVariant var;
445 model->GetValueByRow( var, row, uuidCol );
446
447 BOARD_ITEM* item = m_currentBoard->ResolveItem( var.GetString() );
448
449 if( !item || item->Type() != KICAD_T::PCB_GENERATOR_T )
450 continue;
451
452 items.push_back( item );
453 }
454
455 m_frame->GetToolManager()->RunAction( ACTIONS::selectionClear );
456 m_frame->GetToolManager()->RunAction<EDA_ITEMS*>( ACTIONS::selectItems, &items );
457 m_frame->GetToolManager()->RunAction( PCB_ACTIONS::regenerateSelected );
459}
460
461
462void DIALOG_GENERATORS::OnRebuildAllClick( wxCommandEvent& event )
463{
464 m_frame->GetToolManager()->RunAction( PCB_ACTIONS::regenerateAll );
466}
467
468
469void DIALOG_GENERATORS::OnCancelClick( wxCommandEvent& event )
470{
471 GENERATOR_TOOL* genTool = m_frame->GetToolManager()->GetTool<GENERATOR_TOOL>();
472 genTool->DestroyManagerDialog();
473}
const char * name
static TOOL_ACTION selectionClear
Clear the current selection.
Definition actions.h:220
static TOOL_ACTION selectItems
Select a list of items (specified as the event parameter)
Definition actions.h:228
A base class for any item which can be embedded within the BOARD container class, and therefore insta...
Definition board_item.h:81
Information pertinent to a Pcbnew printed circuit board.
Definition board.h:372
DIALOG_GENERATORS_BASE(wxWindow *parent, wxWindowID id=wxID_ANY, const wxString &title=_("Generator Objects"), const wxPoint &pos=wxDefaultPosition, const wxSize &size=wxSize(-1,-1), long style=wxDEFAULT_DIALOG_STYLE|wxRESIZE_BORDER)
PCB_EDIT_FRAME * m_frame
void OnRebuildTypeClick(wxCommandEvent &event) override
virtual void OnBoardItemsChanged(BOARD &aBoard, std::vector< BOARD_ITEM * > &aBoardItems) override
DIALOG_GENERATORS(PCB_EDIT_FRAME *aEditorFrame, wxWindow *aParent)
void OnRebuildSelectedClick(wxCommandEvent &event) override
wxDataViewCtrl * addPage(const wxString &aName, const wxString &aTitle)
virtual void OnBoardCompositeUpdate(BOARD &aBoard, std::vector< BOARD_ITEM * > &aAddedItems, std::vector< BOARD_ITEM * > &aRemovedItems, std::vector< BOARD_ITEM * > &aChangedItems) override
void OnItemSelected(wxDataViewEvent &aEvent)
void deleteModel(const wxString &aName)
std::map< wxString, wxDataViewListStore * > m_dataModels
void OnCancelClick(wxCommandEvent &aEvent) override
void clearModel(const wxString &aName)
void OnRebuildAllClick(wxCommandEvent &event) override
virtual void OnBoardItemRemoved(BOARD &aBoard, BOARD_ITEM *aBoardItem) override
virtual void OnBoardItemAdded(BOARD &aBoard, BOARD_ITEM *aBoardItem) override
wxDataViewListStore * getCurrentModel()
std::map< wxString, wxDataViewCtrl * > m_dataViews
void onUnitsChanged(wxCommandEvent &event)
std::map< wxString, std::vector< std::pair< wxString, wxString > > > m_columnNameTypes
virtual void OnBoardItemsAdded(BOARD &aBoard, std::vector< BOARD_ITEM * > &aBoardItems) override
virtual void OnBoardItemsRemoved(BOARD &aBoard, std::vector< BOARD_ITEM * > &aBoardItems) override
virtual void OnBoardItemChanged(BOARD &aBoard, BOARD_ITEM *aBoardItem) override
void onBoardChanged(wxCommandEvent &event)
EDA_UNITS m_units
KICAD_T Type() const
Returns the type of object.
Definition eda_item.h:108
Handle actions specific to filling copper zones.
Definition kiid.h:44
wxString AsString() const
Definition kiid.cpp:242
static TOOL_ACTION regenerateAll
static TOOL_ACTION regenerateSelected
The main frame for Pcbnew.
#define DIALOG_GENERATORS_WINDOW_NAME
std::vector< EDA_ITEM * > EDA_ITEMS
KIBIS_MODEL * model
@ PCB_GENERATOR_T
class PCB_GENERATOR, generator on a layer
Definition typeinfo.h:84