KiCad PCB EDA Suite
Loading...
Searching...
No Matches
pcb_net_inspector_panel.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 along
17 * with this program. If not, see <http://www.gnu.org/licenses/>.
18 */
19
22
23#include <advanced_config.h>
26#include <confirm.h>
29#include <footprint.h>
30#include <pad.h>
31#include <pcb_edit_frame.h>
32#include <pcb_painter.h>
33#include <pcb_track.h>
34#include <pgm_base.h>
36#include <validators.h>
38#include <eda_pattern_match.h>
39
40#include <wx/wupdlock.h>
41#include <wx/filedlg.h>
42
43#include <algorithm>
44
46 NET_INSPECTOR_PANEL( parent, aFrame ),
47 m_zero_netitem( nullptr ),
48 m_frame( aFrame )
49{
51
52 m_data_model = new DATA_MODEL( *this );
53 m_netsList->AssociateModel( &*m_data_model );
54
55 // Rebuild nets list
56 buildNetsList( true );
57
58 // Register the panel to receive board change notifications
59 if( m_brd != nullptr )
60 {
62 m_brd->AddListener( this );
63 }
64
65 // Connect to board events
66 m_frame->Bind( EDA_EVT_UNITS_CHANGED, &PCB_NET_INSPECTOR_PANEL::onUnitsChanged, this );
67
68 // Connect to wxDataViewCtrl events
69 m_netsList->Bind( wxEVT_DATAVIEW_ITEM_EXPANDED, &PCB_NET_INSPECTOR_PANEL::OnExpandCollapseRow,
70 this );
71 m_netsList->Bind( wxEVT_DATAVIEW_ITEM_COLLAPSED, &PCB_NET_INSPECTOR_PANEL::OnExpandCollapseRow,
72 this );
73 m_netsList->Bind( wxEVT_DATAVIEW_COLUMN_HEADER_RIGHT_CLICK,
75 m_netsList->Bind( wxEVT_DATAVIEW_ITEM_CONTEXT_MENU,
77 m_netsList->Bind( wxEVT_DATAVIEW_ITEM_ACTIVATED,
79 m_netsList->Bind( wxEVT_DATAVIEW_COLUMN_SORTED,
81}
82
84{
86
87 m_netsList->AssociateModel( nullptr );
88
89 // Disconnect from board events
90 m_frame->Unbind( EDA_EVT_UNITS_CHANGED, &PCB_NET_INSPECTOR_PANEL::onUnitsChanged, this );
91
92 // Connect to wxDataViewCtrl events
93 m_netsList->Unbind( wxEVT_DATAVIEW_ITEM_EXPANDED, &PCB_NET_INSPECTOR_PANEL::OnExpandCollapseRow,
94 this );
95 m_netsList->Unbind( wxEVT_DATAVIEW_ITEM_COLLAPSED,
97 m_netsList->Unbind( wxEVT_DATAVIEW_COLUMN_HEADER_RIGHT_CLICK,
99 m_netsList->Unbind( wxEVT_DATAVIEW_ITEM_CONTEXT_MENU,
101 m_netsList->Unbind( wxEVT_DATAVIEW_ITEM_ACTIVATED,
103 m_netsList->Unbind( wxEVT_DATAVIEW_COLUMN_SORTED,
105}
106
107
108/*****************************************************************************************
109 *
110 * Grid / model columns configuration
111 *
112 * ***************************************************************************************/
113
114
116{
117 m_columns.clear();
118
119 // Set up the column display vector
120 m_columns.emplace_back( 0u, UNDEFINED_LAYER, _( "Name" ), _( "Net Name" ),
122 m_columns.emplace_back( 1u, UNDEFINED_LAYER, _( "Netclass" ), _( "Netclass" ),
124 m_columns.emplace_back( 2u, UNDEFINED_LAYER, _( "Total Length" ), _( "Net Length" ),
126 m_columns.emplace_back( 3u, UNDEFINED_LAYER, _( "Via Count" ), _( "Via Count" ),
128 m_columns.emplace_back( 4u, UNDEFINED_LAYER, _( "Via Length" ), _( "Via Length" ),
130 m_columns.emplace_back( 5u, UNDEFINED_LAYER, _( "Track Length" ), _( "Track Length" ),
132 m_columns.emplace_back( 6u, UNDEFINED_LAYER, _( "Die Length" ), _( "Die Length" ),
134 m_columns.emplace_back( 7u, UNDEFINED_LAYER, _( "Pad Count" ), _( "Pad Count" ),
136
137 std::vector<std::function<void( void )>> add_col{
138 [&]()
139 {
140 m_netsList->AppendTextColumn( m_columns[COLUMN_NAME].display_name,
141 m_columns[COLUMN_NAME], wxDATAVIEW_CELL_INERT, -1,
142 wxALIGN_LEFT,
143 wxDATAVIEW_COL_RESIZABLE | wxDATAVIEW_COL_SORTABLE );
144 },
145 [&]()
146 {
147 m_netsList->AppendTextColumn( m_columns[COLUMN_NETCLASS].display_name,
148 m_columns[COLUMN_NETCLASS], wxDATAVIEW_CELL_INERT, -1,
149 wxALIGN_LEFT,
150 wxDATAVIEW_COL_RESIZABLE | wxDATAVIEW_COL_REORDERABLE
151 | wxDATAVIEW_COL_SORTABLE );
152 },
153 [&]()
154 {
155 m_netsList->AppendTextColumn( m_columns[COLUMN_TOTAL_LENGTH].display_name,
156 m_columns[COLUMN_TOTAL_LENGTH], wxDATAVIEW_CELL_INERT, -1,
157 wxALIGN_CENTER,
158 wxDATAVIEW_COL_RESIZABLE | wxDATAVIEW_COL_REORDERABLE
159 | wxDATAVIEW_COL_SORTABLE );
160 },
161 [&]()
162 {
163 m_netsList->AppendTextColumn( m_columns[COLUMN_VIA_COUNT].display_name,
164 m_columns[COLUMN_VIA_COUNT], wxDATAVIEW_CELL_INERT, -1,
165 wxALIGN_CENTER,
166 wxDATAVIEW_COL_RESIZABLE | wxDATAVIEW_COL_REORDERABLE
167 | wxDATAVIEW_COL_SORTABLE );
168 },
169 [&]()
170 {
171 m_netsList->AppendTextColumn( m_columns[COLUMN_VIA_LENGTH].display_name,
172 m_columns[COLUMN_VIA_LENGTH], wxDATAVIEW_CELL_INERT, -1,
173 wxALIGN_CENTER,
174 wxDATAVIEW_COL_RESIZABLE | wxDATAVIEW_COL_REORDERABLE
175 | wxDATAVIEW_COL_SORTABLE );
176 },
177 [&]()
178 {
179 m_netsList->AppendTextColumn( m_columns[COLUMN_BOARD_LENGTH].display_name,
180 m_columns[COLUMN_BOARD_LENGTH], wxDATAVIEW_CELL_INERT, -1,
181 wxALIGN_CENTER,
182 wxDATAVIEW_COL_RESIZABLE | wxDATAVIEW_COL_REORDERABLE
183 | wxDATAVIEW_COL_SORTABLE );
184 },
185 [&]()
186 {
187 m_netsList->AppendTextColumn( m_columns[COLUMN_PAD_DIE_LENGTH].display_name,
188 m_columns[COLUMN_PAD_DIE_LENGTH], wxDATAVIEW_CELL_INERT,
189 -1, wxALIGN_CENTER,
190 wxDATAVIEW_COL_RESIZABLE | wxDATAVIEW_COL_REORDERABLE
191 | wxDATAVIEW_COL_SORTABLE );
192 },
193 [&]()
194 {
195 m_netsList->AppendTextColumn( m_columns[COLUMN_PAD_COUNT].display_name,
196 m_columns[COLUMN_PAD_COUNT], wxDATAVIEW_CELL_INERT, -1,
197 wxALIGN_CENTER,
198 wxDATAVIEW_COL_RESIZABLE | wxDATAVIEW_COL_REORDERABLE
199 | wxDATAVIEW_COL_SORTABLE );
200 }
201 };
202
203 // If we have not yet loaded the first board, use a dummy local settings object to ensure we
204 // don't over-write existing board settings (note that PCB_EDIT_FRAME loads the local settings
205 // object prior to loading the board; the two are not synced and we need to account for that)
206 PANEL_NET_INSPECTOR_SETTINGS* cfg = nullptr;
207
208 if( m_board_loaded )
209 {
211 cfg = &localSettings.m_NetInspectorPanel;
212 }
213 else
214 {
216 }
217
218 // Count number of copper layers
220
221 for( PCB_LAYER_ID layer : m_brd->GetEnabledLayers().Seq() )
222 {
223 if( IsCopperLayer( layer ) )
225 }
226
227 // Reset the column display settings if column count doesn't match
228 const int totalNumColumns = add_col.size() + m_num_copper_layers;
229
230 if( (int) cfg->col_order.size() != totalNumColumns
231 || (int) cfg->col_hidden.size() != totalNumColumns )
232 {
233 cfg->col_order.resize( totalNumColumns );
234 cfg->col_hidden.resize( totalNumColumns );
235
236 for( int i = 0; i < totalNumColumns; ++i )
237 {
238 cfg->col_order[i] = i;
239 cfg->col_hidden[i] = false;
240 }
241 }
242
243 // Check that all rows are unique to protect against corrupted settings data
244 std::set<int> col_order_set( cfg->col_order.begin(), cfg->col_order.end() );
245 if( col_order_set.size() != cfg->col_order.size() )
246 {
247 for( std::size_t i = 0; i < cfg->col_order.size(); ++i )
248 cfg->col_order[i] = i;
249 }
250
251 // Add column records for copper layers
252 for( PCB_LAYER_ID layer : m_brd->GetEnabledLayers().Seq() )
253 {
254 if( !IsCopperLayer( layer ) )
255 continue;
256
257 m_columns.emplace_back( m_columns.size(), layer, m_brd->GetLayerName( layer ),
259 }
260
261 // Add display columns in settings order
262 for( std::size_t i = 0; i < cfg->col_order.size(); ++i )
263 {
264 const int addModelColumn = cfg->col_order[i];
265
266 if( addModelColumn >= (int) add_col.size() )
267 {
268 m_netsList->AppendTextColumn( m_brd->GetLayerName( m_columns[addModelColumn].layer ),
269 m_columns[addModelColumn], wxDATAVIEW_CELL_INERT, -1,
270 wxALIGN_CENTER,
271 wxDATAVIEW_COL_RESIZABLE | wxDATAVIEW_COL_REORDERABLE
272 | wxDATAVIEW_COL_SORTABLE );
273 }
274 else
275 {
276 add_col.at( cfg->col_order[i] )();
277 }
278 }
279
280 // Set the name column as the expander row
281 if( wxDataViewColumn* col = getDisplayedColumnForModelField( COLUMN_NAME ) )
282 {
283 m_netsList->SetExpanderColumn( col );
284 }
285
287
288 // Delete the temporary config if used
289 if( !m_board_loaded )
290 {
291 delete cfg;
292 }
293}
294
295
297{
298 wxWindowUpdateLocker locker( m_netsList );
299
300 if( cfg->col_widths.size() != m_columns.size() )
301 {
302 int minValueWidth = GetTextExtent( wxT( "00000,000 mm" ) ).x;
303 int minNumberWidth = GetTextExtent( wxT( "000" ) ).x;
304 int minNameWidth = GetTextExtent( wxT( "MMMMMMMMMMMM" ) ).x;
305
306 // Considering left and right margins.
307 // For wxRenderGeneric it is 5px.
308 // Also account for the sorting arrow in the column header.
309 // Column 0 also needs space for any potential expander icons.
310 const int margins = 15;
311 const int extra_width = 30;
312
313 auto getTargetWidth =
314 [&]( int columnID )
315 {
316 switch( columnID )
317 {
318 case COLUMN_NAME: return minNameWidth + extra_width;
319 case COLUMN_NETCLASS: return minNameWidth + margins;
320 case COLUMN_VIA_COUNT: return minNumberWidth + margins;
321 case COLUMN_PAD_COUNT: return minNumberWidth + margins;
322 default: return minValueWidth + margins;
323 }
324 };
325
326 wxASSERT( m_columns.size() == cfg->col_order.size() );
327
328 for( size_t i = 0; i < m_columns.size(); ++i )
329 {
330 const int modelColumn = cfg->col_order[i];
331 int titleSize = GetTextExtent( m_columns[modelColumn].display_name ).x;
332 titleSize = modelColumn == COLUMN_NAME ? titleSize + extra_width : titleSize + margins;
333 const int valSize = getTargetWidth( modelColumn );
334 m_netsList->GetColumn( i )->SetWidth( std::max( titleSize, valSize ) );
335 }
336 }
337 else
338 {
339 wxASSERT( m_columns.size() == cfg->col_hidden.size() );
340 wxASSERT( m_columns.size() == cfg->col_widths.size() );
341
342 for( size_t ii = 0; ii < m_columns.size(); ++ii )
343 {
344 const int newWidth = cfg->col_widths[ii];
345 // Make sure we end up with something non-zero so we can resize it
346 m_netsList->GetColumn( ii )->SetWidth( std::max( newWidth, 10 ) );
347 m_netsList->GetColumn( ii )->SetHidden( cfg->col_hidden[ii] );
348 }
349 }
350
351 m_netsList->Refresh();
352}
353
354
355bool PCB_NET_INSPECTOR_PANEL::restoreSortColumn( int sortingColumnId, bool sortOrderAsc )
356{
357 if( sortingColumnId != -1 )
358 {
359 if( wxDataViewColumn* col = getDisplayedColumnForModelField( sortingColumnId ) )
360 {
361 col->SetSortOrder( sortOrderAsc );
362 m_data_model->Resort();
363 return true;
364 }
365 }
366
367 return false;
368}
369
370
372{
373 for( unsigned int i = 0; i < m_netsList->GetColumnCount(); ++i )
374 {
375 wxDataViewColumn* col = m_netsList->GetColumn( i );
376
377 if( (int) col->GetModelColumn() == columnId )
378 {
379 return col;
380 }
381 }
382
383 return nullptr;
384}
385
386
387/*****************************************************************************************
388 *
389 * Nets list generation
390 *
391 * ***************************************************************************************/
392
393
394void PCB_NET_INSPECTOR_PANEL::buildNetsList( bool rebuildColumns )
395{
396 // Only build the list of nets if there is a board present
397 if( !m_brd )
398 return;
399
401
404
405 // Refresh all filtering / grouping settings
411
412 // Attempt to keep any expanded groups open
414 {
415 cfg->expanded_rows.clear();
416 DATA_MODEL* model = static_cast<DATA_MODEL*>( m_netsList->GetModel() );
417
418 for( const auto& groupItems = model->getGroupDataViewItems();
419 auto& [groupName, groupItem] : groupItems )
420 {
421 if( m_netsList->IsExpanded( groupItem ) )
422 cfg->expanded_rows.push_back( groupName );
423 }
424 }
425
426 // when rebuilding the netlist, try to keep the row selection
427 wxDataViewItemArray sel;
428 m_netsList->GetSelections( sel );
429
430 std::vector<int> prev_selected_netcodes;
431 prev_selected_netcodes.reserve( sel.GetCount() );
432
433 for( unsigned int i = 0; i < sel.GetCount(); ++i )
434 {
435 const LIST_ITEM* item = static_cast<const LIST_ITEM*>( sel.Item( i ).GetID() );
436 prev_selected_netcodes.push_back( item->GetNetCode() );
437 }
438
439 int sorting_column_id = cfg->sorting_column;
440 bool sort_order_asc = cfg->sort_order_asc;
441
442 if( wxDataViewColumn* sorting_column = m_netsList->GetSortingColumn() )
443 {
444 if( !m_board_loading )
445 {
446 sorting_column_id = static_cast<int>( sorting_column->GetModelColumn() );
447 sort_order_asc = sorting_column->IsSortOrderAscending();
448 }
449
450 // On GTK, wxDVC will crash if you rebuild with a sorting column set.
451 sorting_column->UnsetAsSortKey();
452 }
453
454 if( rebuildColumns )
455 {
456 m_netsList->ClearColumns();
457 buildColumns();
458 }
459
460 m_data_model->deleteAllItems();
461
462 m_custom_group_rules.clear();
463
464 for( const wxString& rule : cfg->custom_group_rules )
465 m_custom_group_rules.push_back( std::make_unique<EDA_COMBINED_MATCHER>( rule, CTX_NET ) );
466
467 m_data_model->addCustomGroups();
468
469 std::vector<std::unique_ptr<LIST_ITEM>> new_items;
470
471 std::vector<CN_ITEM*> prefiltered_cn_items = relevantConnectivityItems();
472
473 struct NET_INFO
474 {
475 int netcode;
476 NETINFO_ITEM* net;
477 unsigned int pad_count;
478 };
479
480 struct NET_INFO_CMP_LESS
481 {
482 bool operator()( const NET_INFO& a, const NET_INFO& b ) const
483 {
484 return a.netcode < b.netcode;
485 }
486 bool operator()( const NET_INFO& a, int b ) const { return a.netcode < b; }
487 bool operator()( int a, const NET_INFO& b ) const { return a < b.netcode; }
488 };
489
490 std::vector<NET_INFO> nets;
491 nets.reserve( m_brd->GetNetInfo().NetsByNetcode().size() );
492
493 for( const std::pair<int, NETINFO_ITEM*> ni : m_brd->GetNetInfo().NetsByNetcode() )
494 {
495 if( ni.first == 0 )
496 m_zero_netitem = ni.second;
497
498 if( netFilterMatches( ni.second, cfg ) )
499 nets.emplace_back( NET_INFO{ ni.first, ni.second, 0 } );
500 }
501
502 // count the pads for each net. since the nets are sorted by netcode
503 // iterating over the footprints' pads is faster.
504 for( FOOTPRINT* footprint : m_brd->Footprints() )
505 {
506 for( PAD* pad : footprint->Pads() )
507 {
508 auto i = std::lower_bound( nets.begin(), nets.end(), pad->GetNetCode(),
509 NET_INFO_CMP_LESS() );
510
511 if( i != nets.end() && i->netcode == pad->GetNetCode() )
512 i->pad_count += 1;
513 }
514 }
515
516 for( NET_INFO& ni : nets )
517 {
518 if( m_show_zero_pad_nets || ni.pad_count > 0 )
519 new_items.emplace_back( buildNewItem( ni.net, ni.pad_count, prefiltered_cn_items ) );
520 }
521
522 m_data_model->addItems( std::move( new_items ) );
523
524 // Re-enable the sorting column
525 if( !restoreSortColumn( sorting_column_id, sort_order_asc ))
526 {
527 // By default sort by Name column
529 }
530
531 // Try to restore the expanded groups
532 if( m_board_loaded )
533 {
534 m_row_expanding = true;
535
536 std::vector<std::pair<wxString, wxDataViewItem>> groupItems =
537 m_data_model->getGroupDataViewItems();
538
539 for( wxString& groupName : cfg->expanded_rows )
540 {
541 auto pred =
542 [&groupName]( const std::pair<wxString, wxDataViewItem>& item )
543 {
544 return groupName == item.first;
545 };
546
547 auto tableItem = std::find_if( groupItems.begin(), groupItems.end(), pred );
548
549 if( tableItem != groupItems.end() )
550 m_netsList->Expand( tableItem->second );
551 }
552
553 m_row_expanding = false;
554 }
555
556 // try to restore the selected rows. Set the ones that we can't find any more to -1.
557 sel.Clear();
558
559 for( int& nc : prev_selected_netcodes )
560 {
561 std::optional<LIST_ITEM_ITER> r = m_data_model->findItem( nc );
562
563 if( r )
564 {
565 const std::unique_ptr<LIST_ITEM>& list_item = *r.value();
566 sel.Add( wxDataViewItem( list_item.get() ) );
567 }
568 else
569 {
570 nc = -1;
571 }
572 }
573
574 if( !sel.IsEmpty() )
575 {
576 m_netsList->SetSelections( sel );
577 m_netsList->EnsureVisible( sel.Item( 0 ) );
578 }
579 else
580 {
581 m_netsList->UnselectAll();
582 }
583
584 alg::delete_matching( prev_selected_netcodes, -1 );
585
586 m_in_build_nets_list = false;
587}
588
589
592{
593 if( cfg == nullptr )
594 {
596 cfg = &localSettings.m_NetInspectorPanel;
597 }
598
599 // Never show the unconnected net
600 if( aNet->GetNetCode() <= 0 )
601 return false;
602
603 wxString filterString = UnescapeString( m_searchCtrl->GetValue() ).Upper();
604 wxString netName = UnescapeString( aNet->GetNetname() ).Upper();
605 NETCLASS* netClass = aNet->GetNetClass();
606 wxString netClassName = UnescapeString( netClass->GetName() ).Upper();
607
608 bool matched = false;
609
610 // No filter - match all
611 if( filterString.Length() == 0 )
612 matched = true;
613
614 // Search on Netclass
615 if( !matched && cfg->filter_by_netclass && netClassName.Find( filterString ) != wxNOT_FOUND )
616 matched = true;
617
618 // Search on Net name
619 if( !matched && cfg->filter_by_net_name && netName.Find( filterString ) != wxNOT_FOUND )
620 matched = true;
621
622 // Remove unconnected nets if required
623 if( matched )
624 {
626 matched = !netName.StartsWith( wxT( "UNCONNECTED-(" ) );
627 }
628
629 return matched;
630}
631
632
634{
635 bool operator()( const CN_ITEM* a, const CN_ITEM* b ) const { return a->Net() < b->Net(); }
636
637 bool operator()( const CN_ITEM* a, int b ) const { return a->Net() < b; }
638
639 bool operator()( int a, const CN_ITEM* b ) const { return a < b->Net(); }
640};
641
642
643std::unique_ptr<PCB_NET_INSPECTOR_PANEL::LIST_ITEM>
645 const std::vector<CN_ITEM*>& aCNItems )
646{
647 std::unique_ptr<LIST_ITEM> new_item = std::make_unique<LIST_ITEM>( aNet );
648
649 new_item->SetPadCount( aPadCount );
650 new_item->SetLayerCount( m_brd->GetCopperLayerCount() );
651
652 const auto cn_items = std::equal_range( aCNItems.begin(), aCNItems.end(), aNet->GetNetCode(),
654
655 for( auto i = cn_items.first; i != cn_items.second; ++i )
656 {
657 BOARD_CONNECTED_ITEM* item = ( *i )->Parent();
658
659 if( item->Type() == PCB_PAD_T )
660 {
661 new_item->AddPadDieLength( static_cast<PAD*>( item )->GetPadToDieLength() );
662 }
663 else if( PCB_TRACK* track = dynamic_cast<PCB_TRACK*>( item ) )
664 {
665 new_item->AddLayerWireLength( track->GetLength(), track->GetLayer() );
666
667 if( item->Type() == PCB_VIA_T )
668 {
669 new_item->AddViaCount( 1 );
670 new_item->AddViaLength( calculateViaLength( track ) );
671 }
672 }
673 }
674
675 return new_item;
676}
677
678
680{
681 // pre-filter the connectivity items and sort them by netcode.
682 // this avoids quadratic runtime when building the whole net list and
683 // calculating the total length for each net.
684 const auto type_bits = std::bitset<MAX_STRUCT_TYPE_ID>()
685 .set( PCB_TRACE_T )
686 .set( PCB_ARC_T )
687 .set( PCB_VIA_T )
688 .set( PCB_PAD_T );
689
690 std::vector<CN_ITEM*> cn_items;
691 cn_items.reserve( 1024 );
692
693 for( CN_ITEM* cn_item : m_brd->GetConnectivity()->GetConnectivityAlgo()->ItemList() )
694 {
695 if( cn_item->Valid() && type_bits[cn_item->Parent()->Type()] )
696 cn_items.push_back( cn_item );
697 }
698
699 std::sort( cn_items.begin(), cn_items.end(), NETCODE_CMP_LESS() );
700
701 return cn_items;
702}
703
704
706{
707 const PCB_VIA* via = dynamic_cast<const PCB_VIA*>( aTrack );
708
709 if( !via )
710 return 0;
711
713
714 // Must be static to keep from raising its ugly head in performance profiles
715 static std::initializer_list<KICAD_T> traceAndPadTypes = { PCB_TRACE_T, PCB_ARC_T, PCB_PAD_T };
716
717 // calculate the via length individually from the board stackup and via's start and end layer.
718 if( bds.m_HasStackup )
719 {
720 PCB_LAYER_ID top_layer = UNDEFINED_LAYER;
721 PCB_LAYER_ID bottom_layer = UNDEFINED_LAYER;
722 LSET layers = bds.GetEnabledLayers();
723
724 for( auto layer_it = layers.copper_layers_begin();
725 layer_it != layers.copper_layers_end();
726 ++layer_it )
727 {
728 if( m_brd->GetConnectivity()->IsConnectedOnLayer( via, *layer_it, traceAndPadTypes ) )
729 {
730 if( top_layer == UNDEFINED_LAYER )
731 top_layer = PCB_LAYER_ID( *layer_it );
732 else
733 bottom_layer = PCB_LAYER_ID( *layer_it );
734 }
735 }
736
737 if( top_layer == UNDEFINED_LAYER )
738 top_layer = via->TopLayer();
739 if( bottom_layer == UNDEFINED_LAYER )
740 bottom_layer = via->BottomLayer();
741
742 const BOARD_STACKUP& stackup = bds.GetStackupDescriptor();
743 return stackup.GetLayerDistance( top_layer, bottom_layer );
744 }
745 else
746 {
747 int dielectricLayers = bds.GetCopperLayerCount() - 1;
748 // TODO: not all dielectric layers are the same thickness!
749 int layerThickness = bds.GetBoardThickness() / dielectricLayers;
750 int effectiveBottomLayer;
751
752 if( via->BottomLayer() == B_Cu )
753 effectiveBottomLayer = F_Cu + dielectricLayers;
754 else
755 effectiveBottomLayer = via->BottomLayer();
756
757 int layerCount = effectiveBottomLayer - via->TopLayer();
758
759 return layerCount * layerThickness;
760 }
761}
762
763
765{
766 // something for the specified net has changed, update that row.
767 // ignore nets that are not in our list because the filter doesn't match.
768 if( !netFilterMatches( aNet ) )
769 {
770 m_data_model->deleteItem( m_data_model->findItem( aNet ) );
771 return;
772 }
773
774 // if the net had no pads before, it might not be in the displayed list yet.
775 // if it had pads and now doesn't anymore, we might need to remove it from the list.
776 std::optional<LIST_ITEM_ITER> cur_net_row = m_data_model->findItem( aNet );
777
778 const unsigned int node_count = m_brd->GetNodesCount( aNet->GetNetCode() );
779
780 if( node_count == 0 && !m_show_zero_pad_nets )
781 {
782 m_data_model->deleteItem( cur_net_row );
783 return;
784 }
785
786 std::unique_ptr<LIST_ITEM> new_list_item = buildNewItem( aNet, node_count,
788
789 if( !cur_net_row )
790 {
791 m_data_model->addItem( std::move( new_list_item ) );
792 return;
793 }
794
795 const std::unique_ptr<LIST_ITEM>& cur_list_item = *cur_net_row.value();
796
797 if( cur_list_item->GetNetName() != new_list_item->GetNetName() )
798 {
799 // if the name has changed, it might require re-grouping.
800 // it's easier to remove and re-insert it
801 m_data_model->deleteItem( cur_net_row );
802 m_data_model->addItem( std::move( new_list_item ) );
803 }
804 else
805 {
806 // update fields only
807 cur_list_item->SetPadCount( new_list_item->GetPadCount() );
808 cur_list_item->SetViaCount( new_list_item->GetViaCount() );
809 cur_list_item->SetLayerWireLength( new_list_item->GetLayerWireLength() );
810 cur_list_item->SetPadDieLength( new_list_item->GetPadDieLength() );
811
812 updateDisplayedRowValues( cur_net_row );
813 }
814}
815
816
817/*****************************************************************************************
818 *
819 * Formatting helpers
820 *
821 * ***************************************************************************************/
822
823
825{
826 return wxString::Format( wxT( "%.3d" ), aNet->GetNetCode() );
827}
828
829
831{
832 return UnescapeString( aNet->GetNetname() );
833}
834
835
836wxString PCB_NET_INSPECTOR_PANEL::formatCount( unsigned int aValue ) const
837{
838 return wxString::Format( wxT( "%u" ), aValue );
839}
840
841
842wxString PCB_NET_INSPECTOR_PANEL::formatLength( int64_t aValue ) const
843{
844 return m_frame->MessageTextFromValue( static_cast<long long int>( aValue ),
845 // don't include unit label in the string when reporting
847}
848
849
850void PCB_NET_INSPECTOR_PANEL::updateDisplayedRowValues( const std::optional<LIST_ITEM_ITER>& aRow )
851{
852 if( !aRow )
853 return;
854
855 wxDataViewItemArray sel;
856 m_netsList->GetSelections( sel );
857
858 m_data_model->updateItem( aRow );
859
860 if( !sel.IsEmpty() )
861 {
862 m_netsList->SetSelections( sel );
863 m_netsList->EnsureVisible( sel.Item( 0 ) );
864 }
865}
866
867
868/*****************************************************************************************
869 *
870 * BOARD_LISTENER event handling
871 *
872 * ***************************************************************************************/
873
874
876{
878
879 if( m_brd )
880 m_brd->AddListener( this );
881
882 m_board_loaded = true;
883 m_board_loading = true;
884
886 auto& cfg = localSettings.m_NetInspectorPanel;
887 m_searchCtrl->SetValue( cfg.filter_text );
888
889 buildNetsList( true );
890
891 m_board_loading = false;
892}
893
895{
896 if( !IsShownOnScreen() )
897 return;
898
899 if( NETINFO_ITEM* net = dynamic_cast<NETINFO_ITEM*>( aBoardItem ) )
900 {
901 // a new net has been added to the board. add it to our list if it
902 // passes the netname filter test.
903
904 if( netFilterMatches( net ) )
905 {
906 std::unique_ptr<LIST_ITEM> new_item = std::make_unique<LIST_ITEM>( net );
907
908 // the new net could have some pads already assigned, count them.
909 new_item->SetPadCount( m_brd->GetNodesCount( net->GetNetCode() ) );
910 new_item->SetLayerCount( m_brd->GetCopperLayerCount() );
911
912 m_data_model->addItem( std::move( new_item ) );
913 }
914 }
915 else if( BOARD_CONNECTED_ITEM* i = dynamic_cast<BOARD_CONNECTED_ITEM*>( aBoardItem ) )
916 {
917 std::optional<LIST_ITEM_ITER> r = m_data_model->findItem( i->GetNet() );
918
919 if( r )
920 {
921 // try to handle frequent operations quickly.
922 if( PCB_TRACK* track = dynamic_cast<PCB_TRACK*>( i ) )
923 {
924 const std::unique_ptr<LIST_ITEM>& list_item = *r.value();
925 int len = track->GetLength();
926
927 list_item->AddLayerWireLength( len, track->GetLayer() );
928
929 if( track->Type() == PCB_VIA_T )
930 {
931 list_item->AddViaCount( 1 );
932 list_item->AddViaLength( calculateViaLength( track ) );
933 }
934
936 return;
937 }
938 }
939
940 // resort to generic slower net update otherwise.
941 updateNet( i->GetNet() );
942 }
943 else if( FOOTPRINT* footprint = dynamic_cast<FOOTPRINT*>( aBoardItem ) )
944 {
945 for( const PAD* pad : footprint->Pads() )
946 {
947 std::optional<LIST_ITEM_ITER> r = m_data_model->findItem( pad->GetNet() );
948
949 if( !r )
950 {
951 // if show-zero-pads is off, we might not have this net
952 // in our list yet, so add it first.
953 // notice that at this point we are very certain that this net
954 // will have at least one pad.
955
956 if( netFilterMatches( pad->GetNet() ) )
957 r = m_data_model->addItem( std::make_unique<LIST_ITEM>( pad->GetNet() ) );
958 }
959
960 if( r )
961 {
962 const std::unique_ptr<LIST_ITEM>& list_item = *r.value();
963 int len = pad->GetPadToDieLength();
964
965 list_item->AddPadCount( 1 );
966 list_item->AddPadDieLength( len );
967 list_item->SetLayerCount( m_brd->GetCopperLayerCount() );
968
969 if( list_item->GetPadCount() == 0 && !m_show_zero_pad_nets )
970 m_data_model->deleteItem( r );
971 else
973 }
974 }
975 }
976}
977
978
980 std::vector<BOARD_ITEM*>& aBoardItems )
981{
982 if( !IsShownOnScreen() )
983 return;
984
986
987 // Rebuild full netlist for large changes
988 if( aBoardItems.size() > threshold )
989 {
991 m_netsList->Refresh();
992 }
993 else
994 {
995 for( BOARD_ITEM* item : aBoardItems )
996 {
997 OnBoardItemAdded( aBoard, item );
998 }
999 }
1000}
1001
1002
1004{
1005 if( !IsShownOnScreen() )
1006 return;
1007
1008 if( NETINFO_ITEM* net = dynamic_cast<NETINFO_ITEM*>( aBoardItem ) )
1009 {
1010 m_data_model->deleteItem( m_data_model->findItem( net ) );
1011 }
1012 else if( FOOTPRINT* footprint = dynamic_cast<FOOTPRINT*>( aBoardItem ) )
1013 {
1014 for( const PAD* pad : footprint->Pads() )
1015 {
1016 std::optional<LIST_ITEM_ITER> r = m_data_model->findItem( pad->GetNet() );
1017
1018 if( r )
1019 {
1020 const std::unique_ptr<LIST_ITEM>& list_item = *r.value();
1021 int len = pad->GetPadToDieLength();
1022
1023 list_item->SubPadCount( 1 );
1024 list_item->SubPadDieLength( len );
1025
1026 if( list_item->GetPadCount() == 0 && !m_show_zero_pad_nets )
1027 m_data_model->deleteItem( r );
1028 else
1030 }
1031 }
1032 }
1033 else if( BOARD_CONNECTED_ITEM* i = dynamic_cast<BOARD_CONNECTED_ITEM*>( aBoardItem ) )
1034 {
1035 std::optional<LIST_ITEM_ITER> r = m_data_model->findItem( i->GetNet() );
1036
1037 if( r )
1038 {
1039 // try to handle frequent operations quickly.
1040 if( PCB_TRACK* track = dynamic_cast<PCB_TRACK*>( i ) )
1041 {
1042 const std::unique_ptr<LIST_ITEM>& list_item = *r.value();
1043 int len = track->GetLength();
1044
1045 list_item->SubLayerWireLength( len, track->GetLayer() );
1046
1047 if( track->Type() == PCB_VIA_T )
1048 {
1049 list_item->SubViaCount( 1 );
1050 list_item->SubViaLength( calculateViaLength( track ) );
1051 }
1052
1054 return;
1055 }
1056
1057 // resort to generic slower net update otherwise.
1058 updateNet( i->GetNet() );
1059 }
1060 }
1061}
1062
1063
1065 std::vector<BOARD_ITEM*>& aBoardItems )
1066{
1067 if( !IsShownOnScreen() )
1068 return;
1069
1071
1072 if( aBoardItems.size() > threshold )
1073 {
1074 buildNetsList();
1075 m_netsList->Refresh();
1076 }
1077 else
1078 {
1079 for( BOARD_ITEM* item : aBoardItems )
1080 {
1081 OnBoardItemRemoved( aBoard, item );
1082 }
1083 }
1084}
1085
1086
1088{
1089 if( !IsShownOnScreen() )
1090 return;
1091
1092 buildNetsList();
1093 m_netsList->Refresh();
1094}
1095
1096
1098{
1099 if( !IsShownOnScreen() )
1100 return;
1101
1102 if( dynamic_cast<BOARD_CONNECTED_ITEM*>( aBoardItem ) != nullptr
1103 || dynamic_cast<FOOTPRINT*>( aBoardItem ) != nullptr )
1104 {
1105 buildNetsList();
1106 m_netsList->Refresh();
1107 }
1108}
1109
1110
1112 std::vector<BOARD_ITEM*>& aBoardItems )
1113{
1114 if( !IsShownOnScreen() )
1115 return;
1116
1117 buildNetsList();
1118 m_netsList->Refresh();
1119}
1120
1121
1123 std::vector<BOARD_ITEM*>& aAddedItems,
1124 std::vector<BOARD_ITEM*>& aRemovedItems,
1125 std::vector<BOARD_ITEM*>& aChangedItems )
1126{
1127 if( !IsShownOnScreen() )
1128 return;
1129
1131
1132 // Rebuild the full list if the number of items affected is > the optimisation threshold
1133 // Note: Always rebuild for any changed items as there is no way to determine what property
1134 // of the item has changed in the net inspector data model
1135 if( aChangedItems.size() > 0 || aAddedItems.size() > threshold
1136 || aRemovedItems.size() > threshold )
1137 {
1138 buildNetsList();
1139 }
1140 else
1141 {
1142 OnBoardItemsAdded( aBoard, aAddedItems );
1143 OnBoardItemsRemoved( aBoard, aRemovedItems );
1144 }
1145
1146 m_netsList->Refresh();
1147}
1148
1149
1151{
1152 if( m_highlighting_nets || !IsShownOnScreen() )
1153 return;
1154
1155 if( !m_brd->IsHighLightNetON() )
1156 {
1157 m_netsList->UnselectAll();
1158 }
1159 else
1160 {
1161 const std::set<int>& selected_codes = m_brd->GetHighLightNetCodes();
1162
1163 wxDataViewItemArray new_selection;
1164 new_selection.Alloc( selected_codes.size() );
1165
1166 for( int code : selected_codes )
1167 {
1168 if( std::optional<LIST_ITEM_ITER> r = m_data_model->findItem( code ) )
1169 new_selection.Add( wxDataViewItem( &***r ) );
1170 }
1171
1172 m_netsList->SetSelections( new_selection );
1173
1174 if( !new_selection.IsEmpty() )
1175 m_netsList->EnsureVisible( new_selection.Item( 0 ) );
1176 }
1177}
1178
1179
1180/*****************************************************************************************
1181 *
1182 * UI-generated event handling
1183 *
1184 * ***************************************************************************************/
1185
1187{
1188 buildNetsList();
1190}
1191
1192
1194{
1195 bool multipleSelections = false;
1196 const LIST_ITEM* selItem = nullptr;
1197
1198 if( m_netsList->GetSelectedItemsCount() == 1 )
1199 {
1200 selItem = static_cast<const LIST_ITEM*>( m_netsList->GetSelection().GetID() );
1201 }
1202 else
1203 {
1204 if( m_netsList->GetSelectedItemsCount() > 1 )
1205 multipleSelections = true;
1206 }
1207
1208 wxMenu menu;
1209
1210 // Net edit menu items
1211 wxMenuItem* highlightNet = new wxMenuItem( &menu, ID_HIGHLIGHT_SELECTED_NETS,
1212 _( "Highlight Selected Net" ),
1213 wxEmptyString, wxITEM_NORMAL );
1214 menu.Append( highlightNet );
1215
1216 wxMenuItem* clearHighlighting = new wxMenuItem( &menu, ID_CLEAR_HIGHLIGHTING,
1217 _( "Clear Net Highlighting" ),
1218 wxEmptyString, wxITEM_NORMAL );
1219 menu.Append( clearHighlighting );
1220
1221 RENDER_SETTINGS* renderSettings = m_frame->GetCanvas()->GetView()->GetPainter()->GetSettings();
1222 const std::set<int>& selected_codes = renderSettings->GetHighlightNetCodes();
1223
1224 if( selected_codes.size() == 0 )
1225 clearHighlighting->Enable( false );
1226
1227 menu.AppendSeparator();
1228
1229 wxMenuItem* renameNet = new wxMenuItem( &menu, ID_RENAME_NET, _( "Rename Selected Net" ),
1230 wxEmptyString, wxITEM_NORMAL );
1231 menu.Append( renameNet );
1232
1233 wxMenuItem* deleteNet = new wxMenuItem( &menu, ID_DELETE_NET, _( "Delete Selected Net" ),
1234 wxEmptyString, wxITEM_NORMAL );
1235 menu.Append( deleteNet );
1236
1237 menu.AppendSeparator();
1238
1239 wxMenuItem* addNet = new wxMenuItem( &menu, ID_ADD_NET, _( "Add Net" ),
1240 wxEmptyString, wxITEM_NORMAL );
1241 menu.Append( addNet );
1242
1243 if( !selItem && !multipleSelections )
1244 {
1245 highlightNet->Enable( false );
1246 deleteNet->Enable( false );
1247 renameNet->Enable( false );
1248 }
1249 else
1250 {
1251 if( multipleSelections || selItem->GetIsGroup() )
1252 {
1253 highlightNet->SetItemLabel( _( "Highlight Selected Nets" ) );
1254 renameNet->Enable( false );
1255 deleteNet->SetItemLabel( _( "Delete Selected Nets" ) );
1256 }
1257 }
1258
1259 menu.AppendSeparator();
1260
1261 wxMenuItem* removeSelectedGroup = new wxMenuItem( &menu, ID_REMOVE_SELECTED_GROUP,
1262 _( "Remove Selected Custom Group" ),
1263 wxEmptyString, wxITEM_NORMAL );
1264 menu.Append( removeSelectedGroup );
1265
1266 if( !selItem || !selItem->GetIsGroup() )
1267 removeSelectedGroup->Enable( false );
1268
1269 menu.Bind( wxEVT_COMMAND_MENU_SELECTED, &PCB_NET_INSPECTOR_PANEL::onSettingsMenu, this );
1270
1271 PopupMenu( &menu );
1272}
1273
1274
1276{
1277 SaveSettings();
1278 buildNetsList();
1279}
1280
1281
1283{
1284 wxString newGroupName;
1285 NETNAME_VALIDATOR validator( &newGroupName );
1286
1287 WX_TEXT_ENTRY_DIALOG dlg( this, _( "Group name / pattern:" ), _( "New Group" ), newGroupName );
1288 wxStaticText* help = new wxStaticText( &dlg, wxID_ANY,
1289 _( "(Use /.../ to indicate a regular expression.)" ) );
1290 help->SetFont( KIUI::GetInfoFont( this ).Italic() );
1291 dlg.m_ContentSizer->Add( help, 0, wxALL|wxEXPAND, 5 );
1292 dlg.SetTextValidator( validator );
1293 dlg.GetSizer()->SetSizeHints( &dlg );
1294
1295 if( dlg.ShowModal() != wxID_OK || dlg.GetValue().IsEmpty() )
1296 return; //Aborted by user
1297
1298 newGroupName = UnescapeString( dlg.GetValue() );
1299
1300 if( newGroupName == "" )
1301 return;
1302
1303 if( std::find_if( m_custom_group_rules.begin(), m_custom_group_rules.end(),
1304 [&]( std::unique_ptr<EDA_COMBINED_MATCHER>& rule )
1305 {
1306 return rule->GetPattern().Upper() == newGroupName.Upper();
1307 } ) == m_custom_group_rules.end() )
1308 {
1309 m_custom_group_rules.push_back( std::make_unique<EDA_COMBINED_MATCHER>( newGroupName,
1310 CTX_NET ) );
1311 SaveSettings();
1312 }
1313
1314 buildNetsList();
1315}
1316
1317
1319{
1320 m_highlighting_nets = true;
1321
1325
1326 m_highlighting_nets = false;
1327}
1328
1329
1331{
1332 if( !m_row_expanding )
1333 SaveSettings();
1334}
1335
1336
1338{
1339 wxMenu menu;
1341 menu.Bind( wxEVT_COMMAND_MENU_SELECTED, &PCB_NET_INSPECTOR_PANEL::onSettingsMenu, this );
1342 PopupMenu( &menu );
1343}
1344
1345
1346void PCB_NET_INSPECTOR_PANEL::OnConfigButton( wxCommandEvent& event )
1347{
1349 auto& cfg = localSettings.m_NetInspectorPanel;
1350
1351 const LIST_ITEM* selItem = nullptr;
1352
1353 if( m_netsList->GetSelectedItemsCount() == 1 )
1354 {
1355 selItem = static_cast<const LIST_ITEM*>( m_netsList->GetSelection().GetID() );
1356 }
1357
1358 wxMenu menu;
1359
1360 // Filtering menu items
1361 wxMenuItem* filterByNetName = new wxMenuItem( &menu, ID_FILTER_BY_NET_NAME,
1362 _( "Filter by Net Name" ),
1363 wxEmptyString, wxITEM_CHECK );
1364 menu.Append( filterByNetName );
1365 filterByNetName->Check( cfg.filter_by_net_name );
1366
1367 wxMenuItem* filterByNetclass = new wxMenuItem( &menu, ID_FILTER_BY_NETCLASS,
1368 _( "Filter by Netclass" ),
1369 wxEmptyString, wxITEM_CHECK );
1370 menu.Append( filterByNetclass );
1371 filterByNetclass->Check( cfg.filter_by_netclass );
1372
1373 menu.AppendSeparator();
1374
1375 // Grouping menu items
1376 //wxMenuItem* groupConstraint =
1377 // new wxMenuItem( &menu, ID_GROUP_BY_CONSTRAINT, _( "Group by DRC Constraint" ),
1378 // wxEmptyString, wxITEM_CHECK );
1379 //groupConstraint->Check( m_group_by_constraint );
1380 //menu.Append( groupConstraint );
1381
1382 wxMenuItem* groupNetclass = new wxMenuItem( &menu, ID_GROUP_BY_NETCLASS,
1383 _( "Group by Netclass" ),
1384 wxEmptyString, wxITEM_CHECK );
1385 menu.Append( groupNetclass );
1386 groupNetclass->Check( m_group_by_netclass );
1387
1388 menu.AppendSeparator();
1389
1390 wxMenuItem* addGroup = new wxMenuItem( &menu, ID_ADD_GROUP, _( "Add Custom Group" ),
1391 wxEmptyString, wxITEM_NORMAL );
1392 menu.Append( addGroup );
1393
1394 wxMenuItem* removeSelectedGroup = new wxMenuItem( &menu, ID_REMOVE_SELECTED_GROUP,
1395 _( "Remove Selected Custom Group" ),
1396 wxEmptyString, wxITEM_NORMAL );
1397 menu.Append( removeSelectedGroup );
1398
1399 if( !selItem || !selItem->GetIsGroup() )
1400 removeSelectedGroup->Enable( false );
1401
1402 wxMenuItem* removeCustomGroups = new wxMenuItem( &menu, ID_REMOVE_GROUPS,
1403 _( "Remove All Custom Groups" ),
1404 wxEmptyString, wxITEM_NORMAL );
1405 menu.Append( removeCustomGroups );
1406 removeCustomGroups->Enable( m_custom_group_rules.size() != 0 );
1407
1408 menu.AppendSeparator();
1409
1410 wxMenuItem* showZeroNetPads = new wxMenuItem( &menu, ID_SHOW_ZERO_NET_PADS,
1411 _( "Show Zero Pad Nets" ),
1412 wxEmptyString, wxITEM_CHECK );
1413 menu.Append( showZeroNetPads );
1414 showZeroNetPads->Check( m_show_zero_pad_nets );
1415
1416 wxMenuItem* showUnconnectedNets = new wxMenuItem( &menu, ID_SHOW_UNCONNECTED_NETS,
1417 _( "Show Unconnected Nets" ),
1418 wxEmptyString, wxITEM_CHECK );
1419 menu.Append( showUnconnectedNets );
1420 showUnconnectedNets->Check( m_show_unconnected_nets );
1421
1422 menu.AppendSeparator();
1423
1424 // Report generation
1425 wxMenuItem* generateReport = new wxMenuItem( &menu, ID_GENERATE_REPORT,
1426 _( "Save Net Inspector Report" ),
1427 wxEmptyString, wxITEM_NORMAL );
1428 menu.Append( generateReport );
1429
1430 menu.AppendSeparator();
1431
1432 // Show / hide columns menu items
1433 wxMenu* colsMenu = new wxMenu();
1434 generateShowHideColumnMenu( colsMenu );
1435 menu.AppendSubMenu( colsMenu, _( "Show / Hide Columns" ) );
1436
1437 menu.Bind( wxEVT_COMMAND_MENU_SELECTED, &PCB_NET_INSPECTOR_PANEL::onSettingsMenu, this );
1438
1439 PopupMenu( &menu );
1440}
1441
1442
1444{
1445 for( int i = 1; i <= COLUMN_LAST_STATIC_COL; ++i )
1446 {
1447 wxMenuItem* opt = new wxMenuItem( target, ID_HIDE_COLUMN + i, m_columns[i].display_name,
1448 wxEmptyString, wxITEM_CHECK );
1449 wxDataViewColumn* col = getDisplayedColumnForModelField( i );
1450 target->Append( opt );
1451 opt->Check( !col->IsHidden() );
1452 }
1453
1454 target->AppendSeparator();
1455
1456 for( std::size_t i = COLUMN_LAST_STATIC_COL + 1; i < m_columns.size(); ++i )
1457 {
1458 wxMenuItem* opt = new wxMenuItem( target, ID_HIDE_COLUMN + i, m_columns[i].display_name,
1459 wxEmptyString, wxITEM_CHECK );
1460 wxDataViewColumn* col = getDisplayedColumnForModelField( i );
1461 target->Append( opt );
1462 opt->Check( !col->IsHidden() );
1463 }
1464}
1465
1466
1467void PCB_NET_INSPECTOR_PANEL::onSettingsMenu( wxCommandEvent& event )
1468{
1469 bool saveAndRebuild = true;
1470
1471 switch( event.GetId() )
1472 {
1473 case ID_ADD_NET:
1474 onAddNet();
1475 break;
1476
1477 case ID_RENAME_NET:
1479 break;
1480
1481 case ID_DELETE_NET:
1483 break;
1484
1485 case ID_ADD_GROUP:
1486 onAddGroup();
1487 break;
1488
1491 break;
1492
1495 break;
1496
1499 break;
1500
1503 break;
1504
1507 break;
1508
1509 case ID_REMOVE_GROUPS:
1510 m_custom_group_rules.clear();
1511 break;
1512
1515 break;
1516
1519 break;
1520
1521 case ID_GENERATE_REPORT:
1523 saveAndRebuild = false;
1524 break;
1525
1528 saveAndRebuild = false;
1529 break;
1530
1533 saveAndRebuild = false;
1534 break;
1535
1536 default:
1537 if( event.GetId() >= ID_HIDE_COLUMN )
1538 {
1539 const int columnId = event.GetId() - ID_HIDE_COLUMN;
1540 wxDataViewColumn* col = getDisplayedColumnForModelField( columnId );
1541 // Make sure we end up with something non-zero so we can resize it
1542 col->SetWidth( std::max( col->GetWidth(), 10 ) );
1543 col->SetHidden( !col->IsHidden() );
1544 }
1545 break;
1546 }
1547
1548 if( saveAndRebuild )
1549 {
1550 SaveSettings();
1551 buildNetsList();
1552 }
1553}
1554
1555
1557{
1558 if( m_netsList->GetSelectedItemsCount() == 1 )
1559 {
1560 auto* selItem = static_cast<const LIST_ITEM*>( m_netsList->GetSelection().GetID() );
1561
1562 if( selItem->GetIsGroup() )
1563 {
1564 wxString groupName = selItem->GetGroupName();
1565 auto groupIter = std::find_if( m_custom_group_rules.begin(), m_custom_group_rules.end(),
1566 [&]( std::unique_ptr<EDA_COMBINED_MATCHER>& rule )
1567 {
1568 return rule->GetPattern() == groupName;
1569 } );
1570
1571 if( groupIter != m_custom_group_rules.end() )
1572 {
1573 m_custom_group_rules.erase( groupIter );
1574 SaveSettings();
1575 buildNetsList();
1576 }
1577 }
1578 }
1579}
1580
1581
1583{
1584 wxFileDialog dlg( this, _( "Save Net Inspector Report File" ), "", "",
1585 _( "Report file" ) + AddFileExtListToFilter( { "csv" } ),
1586 wxFD_SAVE | wxFD_OVERWRITE_PROMPT );
1587
1588 if( dlg.ShowModal() == wxID_CANCEL )
1589 return;
1590
1591 wxTextFile f( dlg.GetPath() );
1592
1593 f.Create();
1594
1595 wxString txt;
1596
1597 m_in_reporting = true;
1598
1599 // Print Header:
1600 for( auto&& col : m_columns )
1601 {
1602 txt += '"';
1603
1604 if( col.has_units )
1605 {
1606 txt += wxString::Format( _( "%s (%s)" ),
1607 col.csv_name,
1609 }
1610 else
1611 {
1612 txt += col.csv_name;
1613 }
1614
1615 txt += wxT( "\";" );
1616 }
1617
1618 f.AddLine( txt );
1619
1620 // Print list of nets:
1621 const unsigned int num_rows = m_data_model->itemCount();
1622
1623 for( unsigned int row = 0; row < num_rows; row++ )
1624 {
1625 auto& i = m_data_model->itemAt( row );
1626
1627 if( i.GetIsGroup() || i.GetNetCode() == 0 )
1628 continue;
1629
1630 txt = "";
1631
1632 for( auto&& col : m_columns )
1633 {
1634 if( static_cast<int>( col.csv_flags ) & static_cast<int>( CSV_COLUMN_DESC::CSV_QUOTE ) )
1635 txt += '"' + m_data_model->valueAt( col.num, row ).GetString() + wxT( "\";" );
1636 else
1637 txt += m_data_model->valueAt( col.num, row ).GetString() + ';';
1638 }
1639
1640 f.AddLine( txt );
1641 }
1642
1643 m_in_reporting = false;
1644
1645 f.Write();
1646 f.Close();
1647}
1648
1649
1651{
1653}
1654
1655
1657{
1658 // ignore selection changes while the whole list is being rebuilt.
1660 return;
1661
1662 m_highlighting_nets = true;
1663
1664 RENDER_SETTINGS* renderSettings = m_frame->GetCanvas()->GetView()->GetPainter()->GetSettings();
1665
1666 if( m_netsList->HasSelection() )
1667 {
1668 wxDataViewItemArray sel;
1669 m_netsList->GetSelections( sel );
1670
1671 renderSettings->SetHighlight( false );
1672
1673 for( unsigned int i = 0; i < sel.GetCount(); ++i )
1674 {
1675 const LIST_ITEM* ii = static_cast<const LIST_ITEM*>( sel.Item( i ).GetID() );
1676
1677 if( ii->GetIsGroup() )
1678 {
1679 for( auto c = ii->ChildrenBegin(), end = ii->ChildrenEnd(); c != end; ++c )
1680 renderSettings->SetHighlight( true, ( *c )->GetNetCode(), true );
1681 }
1682 else
1683 {
1684 renderSettings->SetHighlight( true, ii->GetNetCode(), true );
1685 }
1686 }
1687 }
1688 else
1689 {
1690 renderSettings->SetHighlight( false );
1691 }
1692
1695
1696 m_highlighting_nets = false;
1697}
1698
1699
1700void PCB_NET_INSPECTOR_PANEL::OnColumnSorted( wxDataViewEvent& event )
1701{
1703 SaveSettings();
1704}
1705
1706
1708{
1709 // Rebuilt the nets list, and force rebuild of columns in case the stackup has chanaged
1710 buildNetsList( true );
1711 m_netsList->Refresh();
1712}
1713
1714
1716{
1717 wxString newNetName;
1718 NETNAME_VALIDATOR validator( &newNetName );
1719
1720 WX_TEXT_ENTRY_DIALOG dlg( this, _( "Net name:" ), _( "New Net" ), newNetName );
1721 dlg.SetTextValidator( validator );
1722
1723 while( true )
1724 {
1725 if( dlg.ShowModal() != wxID_OK || dlg.GetValue().IsEmpty() )
1726 return; //Aborted by user
1727
1728 newNetName = dlg.GetValue();
1729
1730 if( m_brd->FindNet( newNetName ) )
1731 {
1732 DisplayError( this,
1733 wxString::Format( _( "Net name '%s' is already in use." ), newNetName ) );
1734 newNetName = wxEmptyString;
1735 }
1736 else
1737 {
1738 break;
1739 }
1740 }
1741
1742 NETINFO_ITEM* newnet = new NETINFO_ITEM( m_brd, dlg.GetValue(), 0 );
1743
1744 m_brd->Add( newnet );
1745
1746 // We'll get an OnBoardItemAdded callback from this to update our listbox
1747 m_frame->OnModify();
1748}
1749
1750
1752{
1753 if( m_netsList->GetSelectedItemsCount() == 1 )
1754 {
1755 const LIST_ITEM* sel = static_cast<const LIST_ITEM*>( m_netsList->GetSelection().GetID() );
1756
1757 if( sel->GetIsGroup() )
1758 return;
1759
1760 NETINFO_ITEM* net = sel->GetNet();
1761 wxString fullNetName = net->GetNetname();
1762 wxString netPath;
1763 wxString shortNetName;
1764
1765 if( fullNetName.Contains( wxT( "/" ) ) )
1766 {
1767 netPath = fullNetName.BeforeLast( '/' ) + '/';
1768 shortNetName = fullNetName.AfterLast( '/' );
1769 }
1770 else
1771 {
1772 shortNetName = fullNetName;
1773 }
1774
1775 wxString unescapedShortName = UnescapeString( shortNetName );
1776
1777 WX_TEXT_ENTRY_DIALOG dlg( this, _( "Net name:" ), _( "Rename Net" ), unescapedShortName );
1778 NETNAME_VALIDATOR validator( &unescapedShortName );
1779 dlg.SetTextValidator( validator );
1780
1781 while( true )
1782 {
1783 if( dlg.ShowModal() != wxID_OK || dlg.GetValue() == unescapedShortName )
1784 return;
1785
1786 unescapedShortName = dlg.GetValue();
1787
1788 if( unescapedShortName.IsEmpty() )
1789 {
1790 DisplayError( this, wxString::Format( _( "Net name cannot be empty." ),
1791 unescapedShortName ) );
1792 continue;
1793 }
1794
1795 shortNetName = EscapeString( unescapedShortName, CTX_NETNAME );
1796 fullNetName = netPath + shortNetName;
1797
1798 if( m_brd->FindNet( shortNetName ) || m_brd->FindNet( fullNetName ) )
1799 {
1800 DisplayError( this, wxString::Format( _( "Net name '%s' is already in use." ),
1801 unescapedShortName ) );
1802 unescapedShortName = wxEmptyString;
1803 }
1804 else
1805 {
1806 break;
1807 }
1808 }
1809
1810 for( BOARD_CONNECTED_ITEM* boardItem : m_frame->GetBoard()->AllConnectedItems() )
1811 {
1812 if( boardItem->GetNet() == net )
1813 boardItem->SetFlags( CANDIDATE );
1814 else
1815 boardItem->ClearFlags( CANDIDATE );
1816 }
1817
1818 // the changed name might require re-grouping. remove/re-insert is easier.
1819 auto removed_item = m_data_model->deleteItem( m_data_model->findItem( net ) );
1820
1821 m_brd->Remove( net );
1822 net->SetNetname( fullNetName );
1823 m_brd->Add( net );
1824
1825 for( BOARD_CONNECTED_ITEM* boardItem : m_frame->GetBoard()->AllConnectedItems() )
1826 {
1827 if( boardItem->GetFlags() & CANDIDATE )
1828 boardItem->SetNet( net );
1829 }
1830
1831 buildNetsList();
1832
1833 if( std::optional<LIST_ITEM_ITER> r = m_data_model->findItem( net ) )
1834 m_netsList->Select( wxDataViewItem( r.value()->get() ) );
1835
1836 m_frame->OnModify();
1837
1838 // Currently only tracks and pads have netname annotations and need to be redrawn,
1839 // but zones are likely to follow. Since we don't have a way to ask what is current,
1840 // just refresh all items.
1843 }
1844}
1845
1846
1848{
1849 if( !m_netsList->HasSelection() )
1850 return;
1851
1852 wxDataViewItemArray sel;
1853 m_netsList->GetSelections( sel );
1854
1855 auto delete_one = [this]( const LIST_ITEM* i )
1856 {
1857 if( i->GetPadCount() == 0
1858 || IsOK( this, wxString::Format( _( "Net '%s' is in use. Delete anyway?" ),
1859 i->GetNetName() ) ) )
1860 {
1861 // This is a bit hacky, but it will do for now, since this is the only path
1862 // outside the netlist updater where you can remove a net from a BOARD.
1863 int removedCode = i->GetNetCode();
1864
1866 [removedCode]( KIGFX::VIEW_ITEM* aItem ) -> int
1867 {
1868 auto boardItem = dynamic_cast<BOARD_CONNECTED_ITEM*>( aItem );
1869
1870 if( boardItem && boardItem->GetNetCode() == removedCode )
1871 return KIGFX::REPAINT;
1872
1873 EDA_TEXT* text = dynamic_cast<EDA_TEXT*>( aItem );
1874
1875 if( text && text->HasTextVars() )
1876 {
1877 text->ClearRenderCache();
1878 text->ClearBoundingBoxCache();
1880 }
1881
1882 return 0;
1883 } );
1884
1885 m_brd->Remove( i->GetNet() );
1886 m_frame->OnModify();
1887
1888 // We'll get an OnBoardItemRemoved callback from this to update our listbox
1889 }
1890 };
1891
1892 for( unsigned int i = 0; i < sel.GetCount(); ++i )
1893 {
1894 const LIST_ITEM* ii = static_cast<const LIST_ITEM*>( sel.Item( i ).GetID() );
1895
1896 if( ii->GetIsGroup() )
1897 {
1898 if( ii->ChildrenCount() != 0
1899 && IsOK( this, wxString::Format( _( "Delete all nets in group '%s'?" ),
1900 ii->GetGroupName() ) ) )
1901 {
1902 // we can't be iterating the children container and deleting items from
1903 // it at the same time. thus take a copy of it first.
1904 std::vector<const LIST_ITEM*> children;
1905 children.reserve( ii->ChildrenCount() );
1906 std::copy( ii->ChildrenBegin(), ii->ChildrenEnd(), std::back_inserter( children ) );
1907
1908 for( const LIST_ITEM* c : children )
1909 delete_one( c );
1910 }
1911 }
1912 else
1913 {
1914 delete_one( ii );
1915 }
1916 }
1917}
1918
1919/*****************************************************************************************
1920 *
1921 * Application-generated event handling
1922 *
1923 * ***************************************************************************************/
1924
1925
1927{
1928 SaveSettings();
1929 buildNetsList( true );
1930 m_data_model->updateAllItems();
1931}
1932
1933
1934void PCB_NET_INSPECTOR_PANEL::onUnitsChanged( wxCommandEvent& event )
1935{
1936 m_data_model->updateAllItems();
1937 event.Skip();
1938}
1939
1940
1941/*****************************************************************************************
1942 *
1943 * Settings persistence
1944 *
1945 * ***************************************************************************************/
1946
1947
1949{
1950 // Don't save settings if a board has not yet been loaded - events fire while we set up the
1951 // panel which overwrites the settings we haven't yet loaded
1953 return;
1954
1956 auto& cfg = localSettings.m_NetInspectorPanel;
1957
1958 // User-defined filters / grouping
1959 cfg.filter_text = m_searchCtrl->GetValue();
1960 cfg.filter_by_net_name = m_filter_by_net_name;
1961 cfg.filter_by_netclass = m_filter_by_netclass;
1962 cfg.group_by_netclass = m_group_by_netclass;
1963 cfg.group_by_constraint = m_group_by_constraint;
1964 cfg.show_zero_pad_nets = m_show_zero_pad_nets;
1965 cfg.show_unconnected_nets = m_show_unconnected_nets;
1966
1967 // Grid sorting
1968 wxDataViewColumn* sortingCol = m_netsList->GetSortingColumn();
1969 cfg.sorting_column = sortingCol ? static_cast<int>( sortingCol->GetModelColumn() ) : -1;
1970 cfg.sort_order_asc = sortingCol ? sortingCol->IsSortOrderAscending() : true;
1971
1972 // Column arrangement / sizes
1973 cfg.col_order.resize( m_data_model->columnCount() );
1974 cfg.col_widths.resize( m_data_model->columnCount() );
1975 cfg.col_hidden.resize( m_data_model->columnCount() );
1976
1977 for( unsigned int ii = 0; ii < m_data_model->columnCount(); ++ii )
1978 {
1979 cfg.col_order[ii] = (int) m_netsList->GetColumn( ii )->GetModelColumn();
1980 cfg.col_widths[ii] = m_netsList->GetColumn( ii )->GetWidth();
1981 cfg.col_hidden[ii] = m_netsList->GetColumn( ii )->IsHidden();
1982 }
1983
1984 // Expanded rows
1985 cfg.expanded_rows.clear();
1986 std::vector<std::pair<wxString, wxDataViewItem>> groupItems =
1987 m_data_model->getGroupDataViewItems();
1988
1989 for( std::pair<wxString, wxDataViewItem>& item : groupItems )
1990 {
1991 if( m_netsList->IsExpanded( item.second ) )
1992 cfg.expanded_rows.push_back( item.first );
1993 }
1994
1995 // Customer group rules
1996 cfg.custom_group_rules.clear();
1997
1998 for( const std::unique_ptr<EDA_COMBINED_MATCHER>& rule : m_custom_group_rules )
1999 cfg.custom_group_rules.push_back( rule->GetPattern() );
2000}
static const ADVANCED_CFG & GetCfg()
Get the singleton instance's config, which is shared by all consumers.
A base class derived from BOARD_ITEM for items that can be connected and have a net,...
Container for design settings for a BOARD object.
LSET GetEnabledLayers() const
Return a bit-mask of all the layers that are enabled.
int GetBoardThickness() const
The full thickness of the board including copper and masks.
BOARD_STACKUP & GetStackupDescriptor()
A base class for any item which can be embedded within the BOARD container class, and therefore insta...
Definition: board_item.h:79
Manage layers needed to make a physical board.
int GetLayerDistance(PCB_LAYER_ID aFirstLayer, PCB_LAYER_ID aSecondLayer) const
Calculate the distance (height) between the two given copper layers.
Information pertinent to a Pcbnew printed circuit board.
Definition: board.h:295
const NETINFO_LIST & GetNetInfo() const
Definition: board.h:888
LSET GetEnabledLayers() const
A proxy function that calls the corresponding function in m_BoardSettings.
Definition: board.cpp:831
void Add(BOARD_ITEM *aItem, ADD_MODE aMode=ADD_MODE::INSERT, bool aSkipConnectivity=false) override
Removes an item from the container.
Definition: board.cpp:1056
const std::set< int > & GetHighLightNetCodes() const
Definition: board.h:546
const std::vector< BOARD_CONNECTED_ITEM * > AllConnectedItems()
Definition: board.cpp:2692
void AddListener(BOARD_LISTENER *aListener)
Add a listener to the board to receive calls whenever something on the board has been modified.
Definition: board.cpp:2747
NETINFO_ITEM * FindNet(int aNetcode) const
Search for a net with the given netcode.
Definition: board.cpp:1992
int GetCopperLayerCount() const
Definition: board.cpp:783
const FOOTPRINTS & Footprints() const
Definition: board.h:336
unsigned GetNodesCount(int aNet=-1) const
Definition: board.cpp:1727
bool IsHighLightNetON() const
Definition: board.h:562
const wxString GetLayerName(PCB_LAYER_ID aLayer) const
Return the name of a aLayer.
Definition: board.cpp:616
BOARD_DESIGN_SETTINGS & GetDesignSettings() const
Definition: board.cpp:948
void Remove(BOARD_ITEM *aBoardItem, REMOVE_MODE aMode=REMOVE_MODE::NORMAL) override
Removes an item from the container.
Definition: board.cpp:1207
std::shared_ptr< CONNECTIVITY_DATA > GetConnectivity() const
Return a list of missing connections between components/tracks.
Definition: board.h:489
CN_ITEM represents a BOARD_CONNETED_ITEM in the connectivity system (ie: a pad, track/arc/via,...
int Net() const
int ShowModal() override
virtual void Refresh(bool aEraseBackground=true, const wxRect *aRect=nullptr) override
KICAD_T Type() const
Returns the type of object.
Definition: eda_item.h:101
A mix-in class (via multiple inheritance) that handles texts such as labels, parts,...
Definition: eda_text.h:80
virtual RENDER_SETTINGS * GetSettings()=0
Return a pointer to current settings that are going to be used when drawing items.
Container for all the knowledge about how graphical objects are drawn on any output surface/device.
const std::set< int > & GetHighlightNetCodes() const
Return the netcode of currently highlighted net.
void SetHighlight(bool aEnabled, int aNetcode=-1, bool aMulti=false)
Turns on/off highlighting.
An abstract base class for deriving all objects that can be added to a VIEW.
Definition: view_item.h:86
void UpdateAllLayersColor()
Apply the new coloring scheme to all layers.
Definition: view.cpp:765
void UpdateAllItems(int aUpdateFlags)
Update all items in the view according to the given flags.
Definition: view.cpp:1549
PAINTER * GetPainter() const
Return the painter object used by the view for drawing #VIEW_ITEMS.
Definition: view.h:216
void UpdateAllItemsConditionally(int aUpdateFlags, std::function< bool(VIEW_ITEM *)> aCondition)
Update items in the view according to the given flags and condition.
Definition: view.cpp:1559
LSET is a set of PCB_LAYER_IDs.
Definition: lset.h:37
copper_layers_iterator copper_layers_end() const
Definition: lset.cpp:882
copper_layers_iterator copper_layers_begin() const
Definition: lset.cpp:876
LSEQ Seq(const LSEQ &aSequence) const
Return an LSEQ from the union of this LSET and a desired sequence.
Definition: lset.cpp:297
A collection of nets and the parameters used to route or test these nets.
Definition: netclass.h:45
const wxString GetName() const
Gets the name of this (maybe aggregate) netclass in a format for internal usage or for export to exte...
Definition: netclass.cpp:314
Handle the data for a net.
Definition: netinfo.h:56
void SetNetname(const wxString &aNewName)
Set the long netname to aNetName, the short netname to the last token in the long netname's path,...
Definition: netinfo.h:139
const wxString & GetNetname() const
Definition: netinfo.h:114
NETCLASS * GetNetClass()
Definition: netinfo.h:101
int GetNetCode() const
Definition: netinfo.h:108
const NETCODES_MAP & NetsByNetcode() const
Return the netcode map, at least for python.
Definition: netinfo.h:375
A base class used to implement docking net inspector panels.
wxDataViewCtrl * m_netsList
wxSearchCtrl * m_searchCtrl
Definition: pad.h:54
PCB_DRAW_PANEL_GAL * GetCanvas() const override
Return a pointer to GAL-based canvas of given EDA draw frame.
BOARD * GetBoard() const
virtual KIGFX::PCB_VIEW * GetView() const override
Return a pointer to the #VIEW instance used in the panel.
The main frame for Pcbnew.
void OnModify() override
Must be called after a board change to set the modified flag.
Data model for display in the Net Inspector panel.
std::vector< std::pair< wxString, wxDataViewItem > > getGroupDataViewItems()
Primary data item for entries in the Net Inspector list.
virtual void OnBoardItemRemoved(BOARD &aBoard, BOARD_ITEM *aBoardItem) override
virtual void OnBoardHighlightNetChanged(BOARD &aBoard) override
void generateReport()
Generates a CSV report from currently disaplyed data.
wxString formatCount(unsigned int aValue) const
PCB_NET_INSPECTOR_PANEL(wxWindow *parent, PCB_EDIT_FRAME *aFrame)
virtual void OnBoardItemsChanged(BOARD &aBoard, std::vector< BOARD_ITEM * > &aBoardItems) override
virtual void OnSearchTextChanged(wxCommandEvent &event) override
virtual void OnBoardItemsRemoved(BOARD &aBoard, std::vector< BOARD_ITEM * > &aBoardItems) override
virtual void OnBoardChanged() override
Update panel when board is changed.
void generateShowHideColumnMenu(wxMenu *target)
Generates a sub-menu for the show / hide columns submenu.
wxString formatNetCode(const NETINFO_ITEM *aNet) const
std::unique_ptr< LIST_ITEM > buildNewItem(NETINFO_ITEM *aNet, unsigned int aPadCount, const std::vector< CN_ITEM * > &aCNItems)
Constructs a LIST_ITEM for storage in the data model from a board net item.
std::vector< std::unique_ptr< EDA_COMBINED_MATCHER > > m_custom_group_rules
wxString formatNetName(const NETINFO_ITEM *aNet) const
void onSettingsMenu(wxCommandEvent &event)
std::vector< CN_ITEM * > relevantConnectivityItems() const
Filters connectivity items from a board update to remove those not related to net / track metrics.
unsigned int calculateViaLength(const PCB_TRACK *) const
Calculates the length of a via from the board stackup.
void highlightSelectedNets()
Highlight the currently selected net.
virtual void OnBoardItemsAdded(BOARD &aBoard, std::vector< BOARD_ITEM * > &aBoardItems) override
wxObjectDataPtr< DATA_MODEL > m_data_model
void updateNet(NETINFO_ITEM *aNet)
Updates the stored LIST_ITEMs for a given updated board net item.
virtual void OnLanguageChangedImpl() override
Reloads strings on an application language change.
void OnNetsListContextMenu(wxDataViewEvent &event)
virtual void OnBoardNetSettingsChanged(BOARD &aBoard) override
virtual void OnBoardCompositeUpdate(BOARD &aBoard, std::vector< BOARD_ITEM * > &aAddedItems, std::vector< BOARD_ITEM * > &aRemovedItems, std::vector< BOARD_ITEM * > &aChangedItems) override
void OnNetsListItemActivated(wxDataViewEvent &event)
void OnColumnSorted(wxDataViewEvent &event)
void updateDisplayedRowValues(const std::optional< LIST_ITEM_ITER > &aRow)
virtual void OnBoardItemAdded(BOARD &aBoard, BOARD_ITEM *aBoardItem) override
virtual void OnParentSetupChanged() override
Updates the netlist based on global board changes (e.g.
void OnHeaderContextMenu(wxCommandEvent &event)
bool netFilterMatches(NETINFO_ITEM *aNet, PANEL_NET_INSPECTOR_SETTINGS *cfg=nullptr) const
Filter to determine whether a board net should be included in the net inspector.
virtual void OnConfigButton(wxCommandEvent &event) override
void buildNetsList(bool rebuildColumns=false)
bool restoreSortColumn(int sortingColumnId, bool sortOrderAsc)
Sets the sort column in the grid to that showing the given model ID column.
wxString formatLength(int64_t aValue) const
virtual void SaveSettings() override
Persist the net inspector configuration to project / global settings.
void onUnitsChanged(wxCommandEvent &event)
void OnExpandCollapseRow(wxCommandEvent &event)
wxDataViewColumn * getDisplayedColumnForModelField(int columnId)
Fetches the displayed grid view column for the given model column ID.
void adjustListColumnSizes(PANEL_NET_INSPECTOR_SETTINGS *cfg)
Adjust the sizing of list columns.
virtual void OnBoardItemChanged(BOARD &aBoard, BOARD_ITEM *aBoardItem) override
std::vector< COLUMN_DESC > m_columns
All displayed (or hidden) columns.
virtual void OnShowPanel() override
Prepare the panel when shown in the editor.
virtual SETTINGS_MANAGER & GetSettingsManager() const
Definition: pgm_base.h:125
The project local settings are things that are attached to a particular project, but also might be pa...
PANEL_NET_INSPECTOR_SETTINGS m_NetInspectorPanel
The state of the net inspector panel.
virtual PROJECT_LOCAL_SETTINGS & GetLocalSettings() const
Definition: project.h:206
PROJECT & Prj() const
A helper while we are not MDI-capable – return the one and only project.
wxString MessageTextFromValue(double aValue, bool aAddUnitLabel=true, EDA_DATA_TYPE aType=EDA_DATA_TYPE::DISTANCE) const
A lower-precision version of StringFromValue().
EDA_UNITS GetUserUnits() const
wxBoxSizer * m_ContentSizer
A KICAD version of wxTextEntryDialog which supports the various improvements/work-arounds from DIALOG...
wxString GetValue() const
void SetTextValidator(wxTextValidatorStyle style)
bool IsOK(wxWindow *aParent, const wxString &aMessage)
Display a yes/no dialog with aMessage and returns the user response.
Definition: confirm.cpp:250
void DisplayError(wxWindow *aParent, const wxString &aText, int aDisplayTime)
Display an error or warning message box with aMessage.
Definition: confirm.cpp:170
This file is part of the common library.
#define _(s)
#define CANDIDATE
flag indicating that the structure is connected
Abstract pattern-matching tool and implementations.
@ CTX_NET
int m_NetInspectorBulkUpdateOptimisationThreshold
When updating the net inspector, it either recalculates all nets or iterates through items one-by-one...
bool IsCopperLayer(int aLayerId)
Test whether a layer is a copper layer.
Definition: layer_ids.h:618
PCB_LAYER_ID
A quick note on layer IDs:
Definition: layer_ids.h:60
@ B_Cu
Definition: layer_ids.h:65
@ UNDEFINED_LAYER
Definition: layer_ids.h:61
@ F_Cu
Definition: layer_ids.h:64
KICOMMON_API wxString GetLabel(EDA_UNITS aUnits, EDA_DATA_TYPE aType=EDA_DATA_TYPE::DISTANCE)
Get the units string for a given units type.
Definition: eda_units.cpp:156
@ REPAINT
Item needs to be redrawn.
Definition: view_item.h:58
@ GEOMETRY
Position or shape has changed.
Definition: view_item.h:55
KICOMMON_API wxFont GetInfoFont(wxWindow *aWindow)
Definition: ui_common.cpp:155
void delete_matching(_Container &__c, _Value __value)
Covers for the horrifically named std::remove and std::remove_if (neither of which remove anything).
Definition: kicad_algo.h:165
PGM_BASE & Pgm()
The global program "get" accessor.
Definition: pgm_base.cpp:1073
see class PGM_BASE
static bool highlightNet(TOOL_MANAGER *aToolMgr, const VECTOR2D &aPosition)
wxString UnescapeString(const wxString &aSource)
wxString EscapeString(const wxString &aSource, ESCAPE_CONTEXT aContext)
The Escape/Unescape routines use HTML-entity-reference-style encoding to handle characters which are:...
@ CTX_NETNAME
Definition: string_utils.h:53
bool operator()(const CN_ITEM *a, const CN_ITEM *b) const
bool operator()(int a, const CN_ITEM *b) const
bool operator()(const CN_ITEM *a, int b) const
Persisted state for the net inspector panel.
std::vector< wxString > expanded_rows
std::vector< wxString > custom_group_rules
VECTOR2I end
@ PCB_VIA_T
class PCB_VIA, a via (like a track segment on a copper layer)
Definition: typeinfo.h:97
@ PCB_PAD_T
class PAD, a pad in a footprint
Definition: typeinfo.h:87
@ PCB_ARC_T
class PCB_ARC, an arc track segment on a copper layer
Definition: typeinfo.h:98
@ PCB_TRACE_T
class PCB_TRACK, a track segment (segment on a copper layer)
Definition: typeinfo.h:96
Custom text control validator definitions.
wxString AddFileExtListToFilter(const std::vector< std::string > &aExts)
Build the wildcard extension file dialog wildcard filter to add to the base message dialog.
Definition of file extensions used in Kicad.