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
20#include <properties/property.h>
23
24#include <advanced_config.h>
26#include <confirm.h>
29#include <footprint.h>
32#include <pad.h>
33#include <pcb_edit_frame.h>
34#include <pcb_painter.h>
35#include <pgm_base.h>
37#include <string_utils.h>
38#include <validators.h>
40#include <eda_pattern_match.h>
41#include <map>
42#include <cmath>
43
44#include <wx/wupdlock.h>
45#include <wx/filedlg.h>
46#include <kiplatform/ui.h>
47
48#include <algorithm>
49#include <thread_pool.h>
51
53 NET_INSPECTOR_PANEL( parent, aFrame ),
54 m_frame( aFrame ),
55 m_dataModel( new DATA_MODEL( *this ) )
56{
57 m_board = m_frame->GetBoard();
58
59 m_netsList->AssociateModel( &*m_dataModel );
60
61 // Rebuild nets list
62 buildNetsList( true );
63
64 // Register the panel to receive board change notifications
65 if( m_board != nullptr )
66 {
68 m_board->AddListener( this );
69 }
70
71 // Connect to board events
72 m_frame->Bind( EDA_EVT_UNITS_CHANGED, &PCB_NET_INSPECTOR_PANEL::onUnitsChanged, this );
73
74 // Connect to wxDataViewCtrl events
75 m_netsList->Bind( wxEVT_DATAVIEW_ITEM_EXPANDED, &PCB_NET_INSPECTOR_PANEL::OnExpandCollapseRow, this );
76 m_netsList->Bind( wxEVT_DATAVIEW_ITEM_COLLAPSED, &PCB_NET_INSPECTOR_PANEL::OnExpandCollapseRow, this );
77 m_netsList->Bind( wxEVT_DATAVIEW_COLUMN_HEADER_RIGHT_CLICK, &PCB_NET_INSPECTOR_PANEL::OnHeaderContextMenu, this );
78 m_netsList->Bind( wxEVT_DATAVIEW_ITEM_CONTEXT_MENU, &PCB_NET_INSPECTOR_PANEL::OnNetsListContextMenu, this );
79 m_netsList->Bind( wxEVT_DATAVIEW_ITEM_ACTIVATED, &PCB_NET_INSPECTOR_PANEL::OnNetsListItemActivated, this );
80 m_netsList->Bind( wxEVT_DATAVIEW_COLUMN_SORTED, &PCB_NET_INSPECTOR_PANEL::OnColumnSorted, this );
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, this );
94 m_netsList->Unbind( wxEVT_DATAVIEW_ITEM_COLLAPSED, &PCB_NET_INSPECTOR_PANEL::OnExpandCollapseRow, this );
95 m_netsList->Unbind( wxEVT_DATAVIEW_COLUMN_HEADER_RIGHT_CLICK, &PCB_NET_INSPECTOR_PANEL::OnHeaderContextMenu, this );
96 m_netsList->Unbind( wxEVT_DATAVIEW_ITEM_CONTEXT_MENU, &PCB_NET_INSPECTOR_PANEL::OnNetsListContextMenu, this );
97 m_netsList->Unbind( wxEVT_DATAVIEW_ITEM_ACTIVATED, &PCB_NET_INSPECTOR_PANEL::OnNetsListItemActivated, this );
98 m_netsList->Unbind( wxEVT_DATAVIEW_COLUMN_SORTED, &PCB_NET_INSPECTOR_PANEL::OnColumnSorted, this );
99}
100
101
102/*****************************************************************************************
103 *
104 * Grid / model columns configuration
105 *
106 * ***************************************************************************************/
107
108
110{
111 m_columns.clear();
112
113 // Set up the column display vector
114 m_columns.emplace_back( 0u, UNDEFINED_LAYER, _( "Name" ), _( "Net Name" ), CSV_COLUMN_DESC::CSV_QUOTE, false );
115 m_columns.emplace_back( 1u, UNDEFINED_LAYER, _( "Net Chain" ), _( "Net Chain" ), CSV_COLUMN_DESC::CSV_QUOTE, false );
116 m_columns.emplace_back( 2u, UNDEFINED_LAYER, _( "Netclass" ), _( "Netclass" ), CSV_COLUMN_DESC::CSV_QUOTE, false );
117
119 {
120 m_columns.emplace_back( 3u, UNDEFINED_LAYER, _( "Total Delay" ), _( "Net Delay" ), CSV_COLUMN_DESC::CSV_NONE,
121 true );
122 }
123 else
124 {
125 m_columns.emplace_back( 3u, UNDEFINED_LAYER, _( "Total Length" ), _( "Net Length" ), CSV_COLUMN_DESC::CSV_NONE,
126 true );
127 }
128
129 m_columns.emplace_back( 4u, UNDEFINED_LAYER, _( "Net Chain Length" ), _( "Net Chain Length" ), CSV_COLUMN_DESC::CSV_NONE,
130 true );
131
132 m_columns.emplace_back( 5u, UNDEFINED_LAYER, _( "Via Count" ), _( "Via Count" ), CSV_COLUMN_DESC::CSV_NONE, false );
133
135 {
136 m_columns.emplace_back( 6u, UNDEFINED_LAYER, _( "Via Delay" ), _( "Via Delay" ), CSV_COLUMN_DESC::CSV_NONE,
137 true );
138 m_columns.emplace_back( 7u, UNDEFINED_LAYER, _( "Track Delay" ), _( "Track Delay" ), CSV_COLUMN_DESC::CSV_NONE,
139 true );
140 m_columns.emplace_back( 8u, UNDEFINED_LAYER, _( "Die Delay" ), _( "Die Delay" ), CSV_COLUMN_DESC::CSV_NONE,
141 true );
142 }
143 else
144 {
145 m_columns.emplace_back( 6u, UNDEFINED_LAYER, _( "Via Length" ), _( "Via Length" ), CSV_COLUMN_DESC::CSV_NONE,
146 true );
147 m_columns.emplace_back( 7u, UNDEFINED_LAYER, _( "Track Length" ), _( "Track Length" ),
149 m_columns.emplace_back( 8u, UNDEFINED_LAYER, _( "Die Length" ), _( "Die Length" ), CSV_COLUMN_DESC::CSV_NONE,
150 true );
151 }
152
153 m_columns.emplace_back( 9u, UNDEFINED_LAYER, _( "Pad Count" ), _( "Pad Count" ), CSV_COLUMN_DESC::CSV_NONE, false );
154
155 const std::vector<std::function<void( void )>> add_col{
156 [&]()
157 {
158 m_netsList->AppendTextColumn( m_columns[COLUMN_NAME].display_name, m_columns[COLUMN_NAME],
159 wxDATAVIEW_CELL_INERT, -1, wxALIGN_LEFT,
160 wxDATAVIEW_COL_RESIZABLE|wxDATAVIEW_COL_SORTABLE );
161 },
162 [&]()
163 {
164 m_netsList->AppendTextColumn( m_columns[COLUMN_NET_CHAIN].display_name, m_columns[COLUMN_NET_CHAIN],
165 wxDATAVIEW_CELL_INERT, -1, wxALIGN_LEFT,
166 wxDATAVIEW_COL_RESIZABLE|wxDATAVIEW_COL_REORDERABLE|wxDATAVIEW_COL_SORTABLE );
167 },
168 [&]()
169 {
170 m_netsList->AppendTextColumn( m_columns[COLUMN_NETCLASS].display_name, m_columns[COLUMN_NETCLASS],
171 wxDATAVIEW_CELL_INERT, -1, wxALIGN_LEFT,
172 wxDATAVIEW_COL_RESIZABLE|wxDATAVIEW_COL_REORDERABLE|wxDATAVIEW_COL_SORTABLE );
173 },
174 [&]()
175 {
176 m_netsList->AppendTextColumn( m_columns[COLUMN_TOTAL_LENGTH].display_name, m_columns[COLUMN_TOTAL_LENGTH],
177 wxDATAVIEW_CELL_INERT, -1, wxALIGN_CENTER,
178 wxDATAVIEW_COL_RESIZABLE|wxDATAVIEW_COL_REORDERABLE|wxDATAVIEW_COL_SORTABLE );
179 },
180 [&]()
181 {
182 m_netsList->AppendTextColumn( m_columns[COLUMN_NET_CHAIN_LENGTH].display_name,
183 m_columns[COLUMN_NET_CHAIN_LENGTH], wxDATAVIEW_CELL_INERT, -1, wxALIGN_CENTER,
184 wxDATAVIEW_COL_RESIZABLE|wxDATAVIEW_COL_REORDERABLE|wxDATAVIEW_COL_SORTABLE );
185 },
186 [&]()
187 {
188 m_netsList->AppendTextColumn( m_columns[COLUMN_VIA_COUNT].display_name, m_columns[COLUMN_VIA_COUNT],
189 wxDATAVIEW_CELL_INERT, -1, wxALIGN_CENTER,
190 wxDATAVIEW_COL_RESIZABLE|wxDATAVIEW_COL_REORDERABLE|wxDATAVIEW_COL_SORTABLE );
191 },
192 [&]()
193 {
194 m_netsList->AppendTextColumn( m_columns[COLUMN_VIA_LENGTH].display_name, m_columns[COLUMN_VIA_LENGTH],
195 wxDATAVIEW_CELL_INERT, -1, wxALIGN_CENTER,
196 wxDATAVIEW_COL_RESIZABLE|wxDATAVIEW_COL_REORDERABLE|wxDATAVIEW_COL_SORTABLE );
197 },
198 [&]()
199 {
200 m_netsList->AppendTextColumn( m_columns[COLUMN_BOARD_LENGTH].display_name, m_columns[COLUMN_BOARD_LENGTH],
201 wxDATAVIEW_CELL_INERT, -1, wxALIGN_CENTER,
202 wxDATAVIEW_COL_RESIZABLE|wxDATAVIEW_COL_REORDERABLE|wxDATAVIEW_COL_SORTABLE );
203 },
204 [&]()
205 {
206 m_netsList->AppendTextColumn( m_columns[COLUMN_PAD_DIE_LENGTH].display_name,
207 m_columns[COLUMN_PAD_DIE_LENGTH], wxDATAVIEW_CELL_INERT, -1, wxALIGN_CENTER,
208 wxDATAVIEW_COL_RESIZABLE|wxDATAVIEW_COL_REORDERABLE|wxDATAVIEW_COL_SORTABLE );
209 },
210 [&]()
211 {
212 m_netsList->AppendTextColumn( m_columns[COLUMN_PAD_COUNT].display_name, m_columns[COLUMN_PAD_COUNT],
213 wxDATAVIEW_CELL_INERT, -1, wxALIGN_CENTER,
214 wxDATAVIEW_COL_RESIZABLE|wxDATAVIEW_COL_REORDERABLE|wxDATAVIEW_COL_SORTABLE );
215 }
216 };
217
218 // If we have not yet loaded the first board, use a dummy local settings object to ensure we
219 // don't over-write existing board settings (note that PCB_EDIT_FRAME loads the local settings
220 // object prior to loading the board; the two are not synced and we need to account for that)
221 PANEL_NET_INSPECTOR_SETTINGS* cfg = nullptr;
222
223 if( m_boardLoaded )
224 {
226 cfg = &localSettings.m_NetInspectorPanel;
227 }
228 else
229 {
231 }
232
233 // Reset the column display settings if column count doesn't match
234 const int totalNumColumns = (int) add_col.size() + m_board->GetCopperLayerCount();
235
236 if( (int) cfg->col_order.size() != totalNumColumns
237 || (int) cfg->col_hidden.size() != totalNumColumns )
238 {
239 cfg->col_order.resize( totalNumColumns );
240 cfg->col_hidden.resize( totalNumColumns );
241
242 for( int i = 0; i < totalNumColumns; ++i )
243 {
244 cfg->col_order[i] = i;
245 cfg->col_hidden[i] = false;
246 }
247 }
248
249 // Check that all rows are unique to protect against corrupted settings data
250 std::set<int> col_order_set( cfg->col_order.begin(), cfg->col_order.end() );
251
252 if( col_order_set.size() != cfg->col_order.size() )
253 {
254 for( std::size_t i = 0; i < cfg->col_order.size(); ++i )
255 cfg->col_order[i] = static_cast<int>( i );
256 }
257
258 // Add column records for copper layers
259 for( PCB_LAYER_ID layer : m_board->GetEnabledLayers().Seq() )
260 {
261 if( !IsCopperLayer( layer ) )
262 continue;
263
264 m_columns.emplace_back( m_columns.size(), layer, m_board->GetLayerName( layer ), m_board->GetLayerName( layer ),
266 }
267
268 // Add display columns in settings order
269 for( const int i : cfg->col_order )
270 {
271 const int addModelColumn = i;
272
273 if( addModelColumn >= (int) add_col.size() )
274 {
275 m_netsList->AppendTextColumn( m_board->GetLayerName( m_columns[addModelColumn].layer ),
276 m_columns[addModelColumn], wxDATAVIEW_CELL_INERT, -1, wxALIGN_CENTER,
277 wxDATAVIEW_COL_RESIZABLE|wxDATAVIEW_COL_REORDERABLE|wxDATAVIEW_COL_SORTABLE );
278 }
279 else
280 {
281 add_col.at( i )();
282 }
283 }
284
285 // Set the name column as the expander row
286 if( wxDataViewColumn* col = getDisplayedColumnForModelField( COLUMN_NAME ) )
287 {
288 m_netsList->SetExpanderColumn( col );
289 }
290
292
293 // Delete the temporary config if used
294 if( !m_boardLoaded )
295 delete cfg;
296}
297
298
300{
301 constexpr int margins = 15;
302 constexpr int extra_width = 30;
303
304 int headerWidth = GetTextExtent( m_columns[aModelColumn].display_name ).x;
305 headerWidth += ( aModelColumn == COLUMN_NAME ) ? extra_width : margins;
306
307 return headerWidth;
308}
309
310
311void PCB_NET_INSPECTOR_PANEL::autosizeColumn( wxDataViewColumn* aCol )
312{
313 if( !aCol || aCol->IsHidden() )
314 return;
315
316 const unsigned int modelCol = aCol->GetModelColumn();
317
318 if( modelCol >= m_columns.size() )
319 return;
320
321 constexpr int margins = 15;
322 constexpr int extra_width = 30;
323 const bool isNameCol = ( modelCol == COLUMN_NAME );
324 const int padding = isNameCol ? extra_width : margins;
325 const int indent = m_netsList->GetIndent();
326
327 int maxWidth = getMinColumnWidth( modelCol );
328
329 for( unsigned int row = 0; row < m_dataModel->itemCount(); ++row )
330 {
331 wxVariant value = m_dataModel->valueAt( modelCol, row );
332 int textWidth = GetTextExtent( value.GetString() ).x + padding;
333 maxWidth = std::max( maxWidth, textWidth );
334
335 const LIST_ITEM& item = m_dataModel->itemAt( row );
336
337 if( item.GetIsGroup() )
338 {
339 for( auto it = item.ChildrenBegin(); it != item.ChildrenEnd(); ++it )
340 {
341 wxVariant childValue = m_dataModel->valueForItem( *it, modelCol );
342 int childWidth = GetTextExtent( childValue.GetString() ).x + padding;
343
344 if( isNameCol )
345 childWidth += indent;
346
347 maxWidth = std::max( maxWidth, childWidth );
348 }
349 }
350 }
351
352 aCol->SetWidth( maxWidth );
353}
354
355
357{
358 wxWindowUpdateLocker locker( m_netsList );
359
360 if( cfg->col_widths.size() != m_columns.size() )
361 {
362 int minValueWidth = GetTextExtent( wxT( "00000,000 mm" ) ).x;
363 int minNumberWidth = GetTextExtent( wxT( "000" ) ).x;
364 int minNameWidth = GetTextExtent( wxT( "MMMMMMMMMMMM" ) ).x;
365
366 // Considering left and right margins.
367 // For wxRenderGeneric it is 5px.
368 // Also account for the sorting arrow in the column header.
369 // Column 0 also needs space for any potential expander icons.
370 constexpr int margins = 15;
371 constexpr int extra_width = 30;
372
373 auto getTargetWidth =
374 [&]( int columnID )
375 {
376 switch( columnID )
377 {
378 case COLUMN_NAME: return minNameWidth + extra_width;
379 case COLUMN_NETCLASS: return minNameWidth + margins;
380 case COLUMN_VIA_COUNT: return minNumberWidth + margins;
381 case COLUMN_PAD_COUNT: return minNumberWidth + margins;
382 default: return minValueWidth + margins;
383 }
384 };
385
386 wxASSERT( m_columns.size() == cfg->col_order.size() );
387
388 for( size_t i = 0; i < m_columns.size(); ++i )
389 {
390 const int modelColumn = cfg->col_order[i];
391 int titleSize = GetTextExtent( m_columns[modelColumn].display_name ).x;
392 titleSize = modelColumn == COLUMN_NAME ? titleSize + extra_width : titleSize + margins;
393 const int valSize = getTargetWidth( modelColumn );
394 m_netsList->GetColumn( i )->SetWidth( std::max( titleSize, valSize ) );
395 }
396 }
397 else
398 {
399 wxASSERT( m_columns.size() == cfg->col_hidden.size() );
400 wxASSERT( m_columns.size() == cfg->col_widths.size() );
401
402 for( size_t ii = 0; ii < m_columns.size(); ++ii )
403 {
404 const int modelCol = static_cast<int>( m_netsList->GetColumn( ii )->GetModelColumn() );
405 const int minWidth = getMinColumnWidth( modelCol );
406 const int newWidth = cfg->col_widths[ii];
407
408 m_netsList->GetColumn( ii )->SetWidth( std::max( newWidth, minWidth ) );
409 m_netsList->GetColumn( ii )->SetHidden( cfg->col_hidden[ii] );
410 }
411 }
412
413 m_netsList->Refresh();
414}
415
416
417bool PCB_NET_INSPECTOR_PANEL::restoreSortColumn( const int sortingColumnId, const bool sortOrderAsc ) const
418{
419 if( sortingColumnId != -1 )
420 {
421 if( wxDataViewColumn* col = getDisplayedColumnForModelField( sortingColumnId ) )
422 {
423 col->SetSortOrder( sortOrderAsc );
424 m_dataModel->Resort();
425 return true;
426 }
427 }
428
429 return false;
430}
431
432
433wxDataViewColumn* PCB_NET_INSPECTOR_PANEL::getDisplayedColumnForModelField( const int columnId ) const
434{
435 for( unsigned int i = 0; i < m_netsList->GetColumnCount(); ++i )
436 {
437 wxDataViewColumn* col = m_netsList->GetColumn( i );
438
439 if( static_cast<int>( col->GetModelColumn() ) == columnId )
440 return col;
441 }
442
443 return nullptr;
444}
445
446
447/*****************************************************************************************
448 *
449 * Nets list generation
450 *
451 * ***************************************************************************************/
452
453
454void PCB_NET_INSPECTOR_PANEL::buildNetsList( const bool rebuildColumns )
455{
456 // Only build the list of nets if there is a board present
457 if( !m_board )
458 return;
459
460 m_inBuildNetsList = true;
461
462 m_netsList->Freeze();
463
464 m_dataModel->SetIsTimeDomain( m_showTimeDomainDetails );
465
468
469 // Refresh all filtering / grouping settings
477
478 // Attempt to keep any expanded groups open
480 {
481 cfg->expanded_rows.clear();
482 DATA_MODEL* model = static_cast<DATA_MODEL*>( m_netsList->GetModel() );
483
484 for( const auto& [groupName, groupItem] : model->getGroupDataViewItems() )
485 {
486 if( m_netsList->IsExpanded( groupItem ) )
487 cfg->expanded_rows.push_back( groupName );
488 }
489 }
490
491 // When rebuilding the netlist, try to keep the row selection
492 wxDataViewItemArray sel;
493 m_netsList->GetSelections( sel );
494
495 std::vector<int> prev_selected_netcodes;
496 prev_selected_netcodes.reserve( sel.GetCount() );
497
498 for( unsigned int i = 0; i < sel.GetCount(); ++i )
499 {
500 const LIST_ITEM* item = static_cast<const LIST_ITEM*>( sel.Item( i ).GetID() );
501 prev_selected_netcodes.push_back( item->GetNetCode() );
502 }
503
504 int sorting_column_id = cfg->sorting_column;
505 bool sort_order_asc = cfg->sort_order_asc;
506
507 if( wxDataViewColumn* sorting_column = m_netsList->GetSortingColumn() )
508 {
509 if( !m_boardLoading )
510 {
511 sorting_column_id = static_cast<int>( sorting_column->GetModelColumn() );
512 sort_order_asc = sorting_column->IsSortOrderAscending();
513 }
514
515 // On GTK, wxDVC will crash if we rebuild with a sorting column set.
516 sorting_column->UnsetAsSortKey();
517 }
518
519 if( rebuildColumns )
520 {
521 m_netsList->ClearColumns();
522 buildColumns();
523 }
524
525 m_dataModel->deleteAllItems();
526 m_custom_group_rules.clear();
527
528 for( const wxString& rule : cfg->custom_group_rules )
529 m_custom_group_rules.push_back( std::make_unique<EDA_COMBINED_MATCHER>( rule, CTX_NET ) );
530
531 m_dataModel->addCustomGroups();
532
533 std::vector<NETINFO_ITEM*> netCodes;
534
535 for( NETINFO_ITEM* ni : m_board->GetNetInfo() )
536 {
537 if( netFilterMatches( ni, cfg ) )
538 netCodes.emplace_back( ni );
539 }
540
541 std::ranges::sort( netCodes,
542 []( const NETINFO_ITEM* a, const NETINFO_ITEM* b )
543 {
544 return a->GetNetCode() < b->GetNetCode();
545 } );
546
547 std::vector<std::unique_ptr<LIST_ITEM>> lengths = calculateNets( netCodes, m_showZeroPadNets );
548
549 m_dataModel->addItems( lengths );
550
551 // Try to re-enable the sorting column
552 if( !restoreSortColumn( sorting_column_id, sort_order_asc ))
553 {
554 // By default, sort by Name column
556 }
557
558 // Try to restore the expanded groups
559 if( m_boardLoaded )
560 {
561 m_rowExpanding = true;
562
563 std::vector<std::pair<wxString, wxDataViewItem>> groupItems = m_dataModel->getGroupDataViewItems();
564
565 for( wxString& groupName : cfg->expanded_rows )
566 {
567 auto pred =
568 [&groupName]( const std::pair<wxString, wxDataViewItem>& item )
569 {
570 return groupName == item.first;
571 };
572
573 auto tableItem = std::ranges::find_if( groupItems, pred );
574
575 if( tableItem != groupItems.end() )
576 m_netsList->Expand( tableItem->second );
577 }
578
579 m_rowExpanding = false;
580 }
581
582 // Try to restore the selected rows
583 sel.Clear();
584
585 for( const int& nc : prev_selected_netcodes )
586 {
587 if( std::optional<LIST_ITEM_ITER> r = m_dataModel->findItem( nc ) )
588 {
589 const std::unique_ptr<LIST_ITEM>& list_item = *r.value();
590 sel.Add( wxDataViewItem( list_item.get() ) );
591 }
592 }
593
594 m_netsList->Thaw(); // Must thaw before reselecting to avoid windows selection bug
595
596 if( !sel.IsEmpty() )
597 {
598 m_netsList->SetSelections( sel );
599 m_netsList->EnsureVisible( sel.Item( 0 ) );
600 }
601 else
602 {
603 m_netsList->UnselectAll();
604 }
605
606 m_inBuildNetsList = false;
607}
608
609
612{
613 if( cfg == nullptr )
614 {
616 cfg = &localSettings.m_NetInspectorPanel;
617 }
618
619 // Never show an unconnected net
620 if( aNet->GetNetCode() <= 0 )
621 return false;
622
623 const wxString filterString = UnescapeString( m_searchCtrl->GetValue() ).Upper();
624 const wxString netName = UnescapeString( aNet->GetNetname() ).Upper();
625 const NETCLASS* netClass = aNet->GetNetClass();
626 const wxString netClassName = UnescapeString( netClass->GetName() ).Upper();
627
628 bool matched = false;
629
630 // No filter - match all
631 if( filterString.Length() == 0 )
632 matched = true;
633
634 // Search on net class
635 if( !matched && cfg->filter_by_netclass && netClassName.Find( filterString ) != wxNOT_FOUND )
636 matched = true;
637
638 // Search on net name
639 if( !matched && cfg->filter_by_net_name && netName.Find( filterString ) != wxNOT_FOUND )
640 matched = true;
641
642 // Remove unconnected nets if required
643 if( matched )
644 {
646 matched = !netName.StartsWith( wxT( "UNCONNECTED-(" ) );
647 }
648
649 return matched;
650}
651
652
654{
655 bool operator()( const CN_ITEM* a, const CN_ITEM* b ) const { return a->Net() < b->Net(); }
656
657 bool operator()( const CN_ITEM* a, int b ) const { return a->Net() < b; }
658
659 bool operator()( int a, const CN_ITEM* b ) const { return a < b->Net(); }
660};
661
662
664{
665 // Pre-filter the connectivity items and sort them by netcode. This avoids quadratic runtime when building the whole
666 // net list.
667 const auto type_bits = std::bitset<MAX_STRUCT_TYPE_ID>().set( PCB_TRACE_T )
668 .set( PCB_ARC_T )
669 .set( PCB_VIA_T )
670 .set( PCB_PAD_T );
671
672 std::vector<CN_ITEM*> cn_items;
673 cn_items.reserve( 1024 );
674
675 for( CN_ITEM* cn_item : m_board->GetConnectivity()->GetConnectivityAlgo()->ItemList() )
676 {
677 if( cn_item->Valid() && type_bits[cn_item->Parent()->Type()] )
678 cn_items.push_back( cn_item );
679 }
680
681 std::ranges::sort( cn_items, NETCODE_CMP_LESS() );
682
683 return cn_items;
684}
685
686
687std::vector<std::unique_ptr<PCB_NET_INSPECTOR_PANEL::LIST_ITEM>>
688PCB_NET_INSPECTOR_PANEL::calculateNets( const std::vector<NETINFO_ITEM*>& aNetCodes, bool aIncludeZeroPadNets ) const
689{
690 std::vector<std::unique_ptr<LIST_ITEM>> results;
691
692 LENGTH_DELAY_CALCULATION* calc = m_board->GetLengthCalculation();
693 const std::vector<CN_ITEM*> conItems = relevantConnectivityItems();
694
695 // First assemble the LENGTH_CALCULATION_ITEMs for board items which match the nets we need to recompute
696 // Precondition: conItems and aNetCodes are sorted in increasing netcode value
697 // Functionality: This extracts any items from conItems which have a netcode which is present in aNetCodes
698 std::unordered_map<int, std::vector<LENGTH_DELAY_CALCULATION_ITEM>> netItemsMap;
699 std::vector<NETINFO_ITEM*> foundNets;
700
701 auto itemItr = conItems.begin();
702 auto netCodeItr = aNetCodes.begin();
703
704 while( itemItr != conItems.end() && netCodeItr != aNetCodes.end() )
705 {
706 const int curNetCode = ( *netCodeItr )->GetNetCode();
707 const int curItemNetCode = ( *itemItr )->Net();
708
709 if( curItemNetCode == curNetCode )
710 {
711 if( foundNets.empty() || foundNets.back() != *netCodeItr )
712 foundNets.emplace_back( *netCodeItr );
713
714 // Take the item
715 LENGTH_DELAY_CALCULATION_ITEM lengthItem = calc->GetLengthCalculationItem( ( *itemItr )->Parent() );
716 netItemsMap[curItemNetCode].emplace_back( std::move( lengthItem ) );
717 ++itemItr;
718 }
719 else if( curItemNetCode < curNetCode )
720 {
721 // Fast-forward through items
722 while( itemItr != conItems.end() && ( *itemItr )->Net() < curNetCode )
723 ++itemItr;
724 }
725 else if( curItemNetCode > curNetCode )
726 {
727 // Fast-forward through required net codes
728 while( netCodeItr != aNetCodes.end() && curItemNetCode > ( *netCodeItr )->GetNetCode() )
729 ++netCodeItr;
730 }
731 }
732
733 // Now calculate the length statistics for each net. This includes potentially expensive path optimisations, so
734 // parallelize this work.
735 std::mutex resultsMutex;
737
738 auto resultsFuture = tp.submit_loop(
739 0, foundNets.size(),
740 [&, this, calc]( const int i )
741 {
742 int netCode = foundNets[i]->GetNetCode();
743
744 constexpr PATH_OPTIMISATIONS opts = { .OptimiseVias = true,
745 .MergeTracks = true,
746 .OptimiseTracesInPads = true,
747 .InferViaInPad = false };
748
749 LENGTH_DELAY_STATS lengthDetails = calc->CalculateLengthDetails(
750 netItemsMap[netCode],
751 opts,
752 nullptr,
753 nullptr,
757
758 if( aIncludeZeroPadNets || lengthDetails.NumPads > 0 )
759 {
760 std::unique_ptr<LIST_ITEM> new_item = std::make_unique<LIST_ITEM>( foundNets[i] );
761
762 new_item->SetPadCount( lengthDetails.NumPads );
763 new_item->SetLayerCount( m_board->GetCopperLayerCount() );
764 new_item->SetPadDieLength( lengthDetails.PadToDieLength );
765 new_item->SetPadDieDelay( lengthDetails.PadToDieDelay );
766 new_item->SetViaCount( lengthDetails.NumVias );
767 new_item->SetViaLength( lengthDetails.ViaLength );
768 new_item->SetViaDelay( lengthDetails.ViaDelay );
769 new_item->SetLayerWireLengths( *lengthDetails.LayerLengths );
770
771 if( m_showTimeDomainDetails )
772 new_item->SetLayerWireDelays( *lengthDetails.LayerDelays );
773
774 new_item->SetNetChainName( foundNets[i]->GetNetChain() );
775 new_item->SetNetChainLength( lengthDetails.TotalLength() );
776
777 std::scoped_lock lock( resultsMutex );
778 results.emplace_back( std::move( new_item ) );
779 }
780 } );
781
782 resultsFuture.get();
783
784 std::map<wxString, int64_t> netChainLengths;
785
786 for( const std::unique_ptr<LIST_ITEM>& item : results )
787 {
788 if( !item->GetNetChainName().IsEmpty() )
789 netChainLengths[item->GetNetChainName()] += item->GetTotalLength();
790 }
791
792 for( FOOTPRINT* fp : m_board->Footprints() )
793 {
794 std::vector<PAD*> chainPads;
795
796 for( PAD* pad : fp->Pads() )
797 {
798 if( pad->GetNet() && !pad->GetNet()->GetNetChain().IsEmpty() )
799 chainPads.push_back( pad );
800 }
801
802 for( size_t i = 0; i < chainPads.size(); ++i )
803 {
804 for( size_t j = i + 1; j < chainPads.size(); ++j )
805 {
806 NETINFO_ITEM* netA = chainPads[i]->GetNet();
807 NETINFO_ITEM* netB = chainPads[j]->GetNet();
808
809 if( netA->GetNetChain() == netB->GetNetChain()
810 && netA->GetNetCode() != netB->GetNetCode() )
811 {
812 VECTOR2I p1 = chainPads[i]->GetPosition();
813 VECTOR2I p2 = chainPads[j]->GetPosition();
814 int64_t dx = p1.x - p2.x;
815 int64_t dy = p1.y - p2.y;
816 int64_t dist = KiROUND( std::hypot( (double) dx, (double) dy ) );
817 netChainLengths[netA->GetNetChain()] += dist;
818 }
819 }
820 }
821 }
822
823 for( std::unique_ptr<LIST_ITEM>& item : results )
824 {
825 if( !item->GetNetChainName().IsEmpty() )
826 item->SetNetChainLength( netChainLengths[item->GetNetChainName()] );
827 }
828
829 return results;
830}
831
832
833/*****************************************************************************************
834 *
835 * Formatting helpers
836 *
837 * ***************************************************************************************/
838
839
841{
842 return wxString::Format( wxT( "%.3d" ), aNet->GetNetCode() );
843}
844
845
847{
848 return UnescapeString( aNet->GetNetname() );
849}
850
851
852wxString PCB_NET_INSPECTOR_PANEL::formatCount( const unsigned int aValue )
853{
854 return wxString::Format( wxT( "%u" ), aValue );
855}
856
857
858wxString PCB_NET_INSPECTOR_PANEL::formatLength( const int64_t aValue ) const
859{
860 return m_frame->MessageTextFromValue( aValue,
861 // don't include unit label in the string when reporting
862 !m_inReporting );
863}
864
865wxString PCB_NET_INSPECTOR_PANEL::formatDelay( const int64_t aValue ) const
866{
867 return m_frame->MessageTextFromValue( aValue,
868 // don't include unit label in the string when reporting
870}
871
872
873void PCB_NET_INSPECTOR_PANEL::updateDisplayedRowValues( const std::optional<LIST_ITEM_ITER>& aRow ) const
874{
875 if( !aRow )
876 return;
877
878 wxDataViewItemArray sel;
879 m_netsList->GetSelections( sel );
880
881 m_dataModel->updateItem( aRow );
882
883 if( !sel.IsEmpty() )
884 {
885 m_netsList->SetSelections( sel );
886 m_netsList->EnsureVisible( sel.Item( 0 ) );
887 }
888}
889
890
891/*****************************************************************************************
892 *
893 * BOARD_LISTENER event handling
894 *
895 * ***************************************************************************************/
896
897
899{
900 m_board = m_frame->GetBoard();
901
902 if( m_board )
903 m_board->AddListener( this );
904
905 m_boardLoaded = true;
906 m_boardLoading = true;
907
909 auto& cfg = localSettings.m_NetInspectorPanel;
910 m_searchCtrl->SetValue( cfg.filter_text );
911
912 buildNetsList( true );
913
914 m_boardLoading = false;
915}
916
917
919{
920 const std::vector<BOARD_ITEM*> item{ aBoardItem };
921 updateBoardItems( item );
922}
923
924
925void PCB_NET_INSPECTOR_PANEL::OnBoardItemsAdded( BOARD& aBoard, std::vector<BOARD_ITEM*>& aBoardItems )
926{
927 updateBoardItems( aBoardItems );
928}
929
930
931void PCB_NET_INSPECTOR_PANEL::updateBoardItems( const std::vector<BOARD_ITEM*>& aBoardItems )
932{
933 if( !IsShownOnScreen() )
934 return;
935
936 // Rebuild full list for large changes
937 if( aBoardItems.size()
938 > static_cast<size_t>( ADVANCED_CFG::GetCfg().m_NetInspectorBulkUpdateOptimisationThreshold ) )
939 {
941 }
942 else
943 {
944 std::vector<NETINFO_ITEM*> changedNets;
945
946 for( BOARD_ITEM* boardItem : aBoardItems )
947 {
948 if( NETINFO_ITEM* net = dynamic_cast<NETINFO_ITEM*>( boardItem ) )
949 {
950 // A new net has been added to the board. Add it to our list if it passes the netname filter test.
951 if( netFilterMatches( net ) )
952 changedNets.emplace_back( net );
953 }
954 else if( BOARD_CONNECTED_ITEM* i = dynamic_cast<BOARD_CONNECTED_ITEM*>( boardItem ) )
955 {
956 changedNets.emplace_back( i->GetNet() );
957 }
958 else if( FOOTPRINT* footprint = dynamic_cast<FOOTPRINT*>( boardItem ) )
959 {
960 for( const PAD* pad : footprint->Pads() )
961 {
962 if( netFilterMatches( pad->GetNet() ) )
963 changedNets.emplace_back( pad->GetNet() );
964 }
965 }
966 }
967
968 std::ranges::sort( changedNets,
969 []( const NETINFO_ITEM* a, const NETINFO_ITEM* b )
970 {
971 return a->GetNetCode() < b->GetNetCode();
972 } );
973
974 updateNets( changedNets );
975 }
976
977 m_netsList->Refresh();
978}
979
980
981void PCB_NET_INSPECTOR_PANEL::updateNets( const std::vector<NETINFO_ITEM*>& aNets ) const
982{
983 std::vector<NETINFO_ITEM*> netsToUpdate;
984 std::unordered_set<NETINFO_ITEM*> netsToDelete;
985
986 for( NETINFO_ITEM* net : aNets )
987 {
988 // Add all nets to the deletion list - we will prune this later to only contain unhandled nets
989 netsToDelete.insert( net );
990
991 // Only calculate nets that match the current filter
992 if( netFilterMatches( net ) )
993 netsToUpdate.emplace_back( net );
994 }
995
996 wxWindowUpdateLocker updateLocker( m_netsList );
997
998 std::vector<std::unique_ptr<LIST_ITEM>> newListItems = calculateNets( aNets, true );
999
1000 for( std::unique_ptr<LIST_ITEM>& newListItem : newListItems )
1001 {
1002 // Remove the handled net from the deletion list
1003 netsToDelete.erase( newListItem->GetNet() );
1004
1005 std::optional<LIST_ITEM_ITER> curNetRow = m_dataModel->findItem( newListItem->GetNetCode() );
1006
1007 if( !m_showZeroPadNets && newListItem->GetPadCount() == 0 )
1008 {
1009 m_dataModel->deleteItem( curNetRow );
1010 continue;
1011 }
1012
1013 if( !curNetRow )
1014 {
1015 m_dataModel->addItem( std::move( newListItem ) );
1016 continue;
1017 }
1018
1019 const std::unique_ptr<LIST_ITEM>& curListItem = *curNetRow.value();
1020
1021 if( curListItem->GetNetName() != newListItem->GetNetName() )
1022 {
1023 // If the name has changed, it might require re-grouping. It's easier to remove and re-insert it.
1024 m_dataModel->deleteItem( curNetRow );
1025 m_dataModel->addItem( std::move( newListItem ) );
1026 }
1027 else
1028 {
1029 curListItem->SetPadCount( newListItem->GetPadCount() );
1030 curListItem->SetPadDieLength( newListItem->GetPadDieLength() );
1031 curListItem->SetPadDieDelay( newListItem->GetPadDieDelay() );
1032 curListItem->SetViaCount( newListItem->GetViaCount() );
1033 curListItem->SetViaLength( newListItem->GetViaLength() );
1034 curListItem->SetViaDelay( newListItem->GetViaDelay() );
1035 curListItem->SetLayerWireLengths( newListItem->GetLayerWireLengths() );
1036 curListItem->SetNetChainName( newListItem->GetNetChainName() );
1037 curListItem->SetNetChainLength( newListItem->GetNetChainLength() );
1038
1040 curListItem->SetLayerWireDelays( newListItem->GetLayerWireDelays() );
1041
1042 updateDisplayedRowValues( curNetRow );
1043 }
1044 }
1045
1046 // Delete any nets we have not yet handled
1047 for( const NETINFO_ITEM* netToDelete : netsToDelete )
1048 m_dataModel->deleteItem( m_dataModel->findItem( netToDelete->GetNetCode() ) );
1049}
1050
1051
1053{
1054 const std::vector<BOARD_ITEM*> item{ aBoardItem };
1055 updateBoardItems( item );
1056}
1057
1058
1059void PCB_NET_INSPECTOR_PANEL::OnBoardItemsRemoved( BOARD& aBoard, std::vector<BOARD_ITEM*>& aBoardItems )
1060{
1061 updateBoardItems( aBoardItems );
1062}
1063
1064
1066{
1067 if( !IsShownOnScreen() )
1068 return;
1069
1070 buildNetsList();
1071}
1072
1073
1075{
1076 const std::vector<BOARD_ITEM*> item{ aBoardItem };
1077 updateBoardItems( item );
1078}
1079
1080
1081void PCB_NET_INSPECTOR_PANEL::OnBoardItemsChanged( BOARD& aBoard, std::vector<BOARD_ITEM*>& aBoardItems )
1082{
1083 updateBoardItems( aBoardItems );
1084}
1085
1086
1088 std::vector<BOARD_ITEM*>& aAddedItems,
1089 std::vector<BOARD_ITEM*>& aRemovedItems,
1090 std::vector<BOARD_ITEM*>& aChangedItems )
1091{
1092 if( !IsShownOnScreen() )
1093 return;
1094
1095 std::vector<BOARD_ITEM*> allItems{ aAddedItems.begin(), aAddedItems.end() };
1096 allItems.insert( allItems.end(), aRemovedItems.begin(), aRemovedItems.end() );
1097 allItems.insert( allItems.end(), aChangedItems.begin(), aChangedItems.end() );
1098 updateBoardItems( allItems );
1099}
1100
1101
1103{
1104 if( m_highlightingNets || !IsShownOnScreen() )
1105 return;
1106
1107 if( !m_board->IsHighLightNetON() )
1108 {
1109 m_netsList->UnselectAll();
1110 }
1111 else
1112 {
1113 const std::set<int>& selected_codes = m_board->GetHighLightNetCodes();
1114
1115 wxDataViewItemArray new_selection;
1116 new_selection.Alloc( selected_codes.size() );
1117
1118 for( const int code : selected_codes )
1119 {
1120 if( std::optional<LIST_ITEM_ITER> r = m_dataModel->findItem( code ) )
1121 new_selection.Add( wxDataViewItem( &***r ) );
1122 }
1123
1124 m_netsList->SetSelections( new_selection );
1125
1126 if( !new_selection.IsEmpty() )
1127 m_netsList->EnsureVisible( new_selection.Item( 0 ) );
1128 }
1129}
1130
1131
1132/*****************************************************************************************
1133 *
1134 * UI-generated event handling
1135 *
1136 * ***************************************************************************************/
1137
1143
1144
1146{
1147 bool multipleSelections = false;
1148 const LIST_ITEM* selItem = nullptr;
1149
1150 if( m_netsList->GetSelectedItemsCount() == 1 )
1151 {
1152 selItem = static_cast<const LIST_ITEM*>( m_netsList->GetSelection().GetID() );
1153 }
1154 else
1155 {
1156 if( m_netsList->GetSelectedItemsCount() > 1 )
1157 multipleSelections = true;
1158 }
1159
1160 wxMenu menu;
1161
1162 // Net edit menu items
1163 wxMenuItem* highlightNet = new wxMenuItem( &menu, ID_HIGHLIGHT_SELECTED_NETS, _( "Highlight Selected Net" ),
1164 wxEmptyString, wxITEM_NORMAL );
1165 menu.Append( highlightNet );
1166
1167 wxMenuItem* clearHighlighting = new wxMenuItem( &menu, ID_CLEAR_HIGHLIGHTING, _( "Clear Net Highlighting" ),
1168 wxEmptyString, wxITEM_NORMAL );
1169 menu.Append( clearHighlighting );
1170
1171 RENDER_SETTINGS* renderSettings = m_frame->GetCanvas()->GetView()->GetPainter()->GetSettings();
1172 const std::set<int>& selected_codes = renderSettings->GetHighlightNetCodes();
1173
1174 if( selected_codes.size() == 0 )
1175 clearHighlighting->Enable( false );
1176
1177 menu.AppendSeparator();
1178
1179 wxMenuItem* renameNet = new wxMenuItem( &menu, ID_RENAME_NET, _( "Rename Selected Net..." ), wxEmptyString,
1180 wxITEM_NORMAL );
1181 menu.Append( renameNet );
1182
1183 wxMenuItem* deleteNet = new wxMenuItem( &menu, ID_DELETE_NET, _( "Delete Selected Net" ), wxEmptyString,
1184 wxITEM_NORMAL );
1185 menu.Append( deleteNet );
1186
1187 menu.AppendSeparator();
1188
1189 wxMenuItem* addNet = new wxMenuItem( &menu, ID_ADD_NET, _( "Add Net..." ), wxEmptyString, wxITEM_NORMAL );
1190 menu.Append( addNet );
1191
1192 if( !selItem && !multipleSelections )
1193 {
1194 highlightNet->Enable( false );
1195 deleteNet->Enable( false );
1196 renameNet->Enable( false );
1197 }
1198 else
1199 {
1200 if( multipleSelections || selItem->GetIsGroup() )
1201 {
1202 highlightNet->SetItemLabel( _( "Highlight Selected Nets" ) );
1203 renameNet->Enable( false );
1204 deleteNet->SetItemLabel( _( "Delete Selected Nets" ) );
1205 }
1206 }
1207
1208 menu.AppendSeparator();
1209
1210 wxMenuItem* removeSelectedGroup = new wxMenuItem( &menu, ID_REMOVE_SELECTED_GROUP,
1211 _( "Remove Selected Custom Group" ),
1212 wxEmptyString, wxITEM_NORMAL );
1213 menu.Append( removeSelectedGroup );
1214
1215 if( !selItem || !selItem->GetIsGroup() )
1216 removeSelectedGroup->Enable( false );
1217
1218 menu.Bind( wxEVT_COMMAND_MENU_SELECTED, &PCB_NET_INSPECTOR_PANEL::onContextMenuSelection, this );
1219
1220 PopupMenu( &menu );
1221}
1222
1223
1225{
1226 SaveSettings();
1227 buildNetsList();
1228}
1229
1230
1232{
1233 wxString newGroupName;
1234 NETNAME_VALIDATOR validator( &newGroupName );
1235
1236 WX_TEXT_ENTRY_DIALOG dlg( this, _( "Group name / pattern:" ), _( "New Group" ), newGroupName );
1237 wxStaticText* help = new wxStaticText( &dlg, wxID_ANY, _( "(Use /.../ to indicate a regular expression.)" ) );
1238 help->SetFont( KIUI::GetInfoFont( this ).Italic() );
1239 dlg.m_ContentSizer->Add( help, 0, wxALL|wxEXPAND, 5 );
1240 dlg.SetTextValidator( validator );
1241 dlg.GetSizer()->SetSizeHints( &dlg );
1242
1243 if( dlg.ShowModal() != wxID_OK || dlg.GetValue().IsEmpty() )
1244 return; //Aborted by user
1245
1246 newGroupName = UnescapeString( dlg.GetValue() );
1247
1248 if( newGroupName == "" )
1249 return;
1250
1251 if( std::ranges::find_if( m_custom_group_rules,
1252 [&]( std::unique_ptr<EDA_COMBINED_MATCHER>& rule )
1253 {
1254 return rule->GetPattern() == newGroupName;
1255 } )
1256 == m_custom_group_rules.end() )
1257 {
1258 m_custom_group_rules.push_back( std::make_unique<EDA_COMBINED_MATCHER>( newGroupName, CTX_NET ) );
1259 SaveSettings();
1260 }
1261
1262 buildNetsList();
1263}
1264
1265
1267{
1268 m_highlightingNets = true;
1269
1270 m_frame->GetCanvas()->GetView()->GetPainter()->GetSettings()->SetHighlight( false );
1271 m_frame->GetCanvas()->GetView()->UpdateAllLayersColor();
1272 m_frame->GetCanvas()->Refresh();
1273
1274 m_highlightingNets = false;
1275}
1276
1277
1279{
1280 if( !m_rowExpanding )
1281 SaveSettings();
1282}
1283
1284
1286{
1287 m_contextMenuColumn = event.GetDataViewColumn();
1288
1289 wxMenu menu;
1290
1291 menu.Append( ID_AUTOFIT_COLUMN, _( "Auto-fit Column" ) );
1292 menu.Append( ID_AUTOFIT_ALL_COLUMNS, _( "Auto-fit All Columns" ) );
1293 menu.AppendSeparator();
1294
1296 menu.Bind( wxEVT_COMMAND_MENU_SELECTED, &PCB_NET_INSPECTOR_PANEL::onContextMenuSelection, this );
1297 PopupMenu( &menu );
1298}
1299
1300
1301void PCB_NET_INSPECTOR_PANEL::OnConfigButton( wxCommandEvent& event )
1302{
1304 auto& cfg = localSettings.m_NetInspectorPanel;
1305
1306 const LIST_ITEM* selItem = nullptr;
1307
1308 if( m_netsList->GetSelectedItemsCount() == 1 )
1309 {
1310 selItem = static_cast<const LIST_ITEM*>( m_netsList->GetSelection().GetID() );
1311 }
1312
1313 wxMenu menu;
1314
1315 // Filtering menu items
1316 wxMenuItem* filterByNetName = new wxMenuItem( &menu, ID_FILTER_BY_NET_NAME, _( "Filter by Net Name" ),
1317 wxEmptyString, wxITEM_CHECK );
1318 menu.Append( filterByNetName );
1319 filterByNetName->Check( cfg.filter_by_net_name );
1320
1321 wxMenuItem* filterByNetclass = new wxMenuItem( &menu, ID_FILTER_BY_NETCLASS, _( "Filter by Netclass" ),
1322 wxEmptyString, wxITEM_CHECK );
1323 menu.Append( filterByNetclass );
1324 filterByNetclass->Check( cfg.filter_by_netclass );
1325
1326 menu.AppendSeparator();
1327
1328 // Grouping menu items
1329 //wxMenuItem* groupConstraint =
1330 // new wxMenuItem( &menu, ID_GROUP_BY_CONSTRAINT, _( "Group by DRC Constraint" ),
1331 // wxEmptyString, wxITEM_CHECK );
1332 //groupConstraint->Check( m_group_by_constraint );
1333 //menu.Append( groupConstraint );
1334
1335 wxMenuItem* groupNetclass = new wxMenuItem( &menu, ID_GROUP_BY_NETCLASS, _( "Group by Netclass" ),
1336 wxEmptyString, wxITEM_CHECK );
1337 menu.Append( groupNetclass );
1338 groupNetclass->Check( m_groupByNetclass );
1339
1340 wxMenuItem* groupSignal = new wxMenuItem( &menu, ID_GROUP_BY_NET_CHAIN,
1341 _( "Group by Net Chain" ),
1342 wxEmptyString, wxITEM_CHECK );
1343 menu.Append( groupSignal );
1344 groupSignal->Check( m_groupByNetChain );
1345
1346 menu.AppendSeparator();
1347
1348 wxMenuItem* addGroup = new wxMenuItem( &menu, ID_ADD_GROUP, _( "Add Custom Group..." ),
1349 wxEmptyString, wxITEM_NORMAL );
1350 menu.Append( addGroup );
1351
1352 wxMenuItem* removeSelectedGroup = new wxMenuItem( &menu, ID_REMOVE_SELECTED_GROUP,
1353 _( "Remove Selected Custom Group" ),
1354 wxEmptyString, wxITEM_NORMAL );
1355 menu.Append( removeSelectedGroup );
1356
1357 if( !selItem || !selItem->GetIsGroup() )
1358 removeSelectedGroup->Enable( false );
1359
1360 wxMenuItem* removeCustomGroups = new wxMenuItem( &menu, ID_REMOVE_GROUPS, _( "Remove All Custom Groups" ),
1361 wxEmptyString, wxITEM_NORMAL );
1362 menu.Append( removeCustomGroups );
1363 removeCustomGroups->Enable( m_custom_group_rules.size() != 0 );
1364
1365 menu.AppendSeparator();
1366
1367 wxMenuItem* showZeroNetPads = new wxMenuItem( &menu, ID_SHOW_ZERO_NET_PADS, _( "Show Zero Pad Nets" ),
1368 wxEmptyString, wxITEM_CHECK );
1369 menu.Append( showZeroNetPads );
1370 showZeroNetPads->Check( m_showZeroPadNets );
1371
1372 wxMenuItem* showUnconnectedNets = new wxMenuItem( &menu, ID_SHOW_UNCONNECTED_NETS, _( "Show Unconnected Nets" ),
1373 wxEmptyString, wxITEM_CHECK );
1374 menu.Append( showUnconnectedNets );
1375 showUnconnectedNets->Check( m_showUnconnectedNets );
1376
1377 menu.AppendSeparator();
1378
1379 wxMenuItem* showTimeDomainDetails = new wxMenuItem( &menu, ID_SHOW_TIME_DOMAIN_DETAILS,
1380 _( "Show Time Domain Details" ),
1381 wxEmptyString, wxITEM_CHECK );
1382 menu.Append( showTimeDomainDetails );
1383 showTimeDomainDetails->Check( m_showTimeDomainDetails );
1384
1385 menu.AppendSeparator();
1386
1387 // Report generation
1388 wxMenuItem* generateReport = new wxMenuItem( &menu, ID_GENERATE_REPORT, _( "Save Net Inspector Report..." ),
1389 wxEmptyString, wxITEM_NORMAL );
1390 menu.Append( generateReport );
1391
1392 menu.AppendSeparator();
1393
1394 // Show / hide columns menu items
1395 wxMenu* colsMenu = new wxMenu();
1396 generateShowHideColumnMenu( colsMenu );
1397 menu.AppendSubMenu( colsMenu, _( "Show / Hide Columns" ) );
1398
1399 menu.Bind( wxEVT_COMMAND_MENU_SELECTED, &PCB_NET_INSPECTOR_PANEL::onContextMenuSelection, this );
1400
1401 PopupMenu( &menu );
1402}
1403
1404
1406{
1407 for( int i = 1; i <= COLUMN_LAST_STATIC_COL; ++i )
1408 {
1409 wxMenuItem* opt = new wxMenuItem( target, ID_HIDE_COLUMN + i, m_columns[i].display_name,
1410 wxEmptyString, wxITEM_CHECK );
1411 wxDataViewColumn* col = getDisplayedColumnForModelField( i );
1412 target->Append( opt );
1413 opt->Check( !col->IsHidden() );
1414 }
1415
1416 target->AppendSeparator();
1417
1418 for( std::size_t i = COLUMN_LAST_STATIC_COL + 1; i < m_columns.size(); ++i )
1419 {
1420 wxMenuItem* opt = new wxMenuItem( target, ID_HIDE_COLUMN + i, m_columns[i].display_name,
1421 wxEmptyString, wxITEM_CHECK );
1422 wxDataViewColumn* col = getDisplayedColumnForModelField( i );
1423 target->Append( opt );
1424 opt->Check( !col->IsHidden() );
1425 }
1426}
1427
1428
1430{
1431 bool saveAndRebuild = true;
1432
1433 switch( event.GetId() )
1434 {
1435 case ID_ADD_NET:
1436 onAddNet();
1437 break;
1438
1439 case ID_RENAME_NET:
1441 break;
1442
1443 case ID_DELETE_NET:
1445 break;
1446
1447 case ID_ADD_GROUP:
1448 onAddGroup();
1449 break;
1450
1453 break;
1454
1457 break;
1458
1461 break;
1462
1465 break;
1466
1469 break;
1470
1473 break;
1474
1475 case ID_REMOVE_GROUPS:
1476 m_custom_group_rules.clear();
1477 break;
1478
1481 break;
1482
1485 break;
1486
1489 break;
1490
1491 case ID_GENERATE_REPORT:
1493 saveAndRebuild = false;
1494 break;
1495
1498 saveAndRebuild = false;
1499 break;
1500
1503 saveAndRebuild = false;
1504 break;
1505
1506 case ID_AUTOFIT_COLUMN:
1509
1510 saveAndRebuild = false;
1511 break;
1512
1514 for( unsigned int i = 0; i < m_netsList->GetColumnCount(); ++i )
1515 autosizeColumn( m_netsList->GetColumn( i ) );
1516
1517 saveAndRebuild = false;
1518 break;
1519
1520 default:
1521 if( event.GetId() >= ID_HIDE_COLUMN )
1522 {
1523 const int columnId = event.GetId() - ID_HIDE_COLUMN;
1524 wxDataViewColumn* col = getDisplayedColumnForModelField( columnId );
1525 // Make sure we end up with something non-zero so we can resize it
1526 col->SetWidth( std::max( col->GetWidth(), 10 ) );
1527 col->SetHidden( !col->IsHidden() );
1528 }
1529 break;
1530 }
1531
1532 if( saveAndRebuild )
1533 {
1534 SaveSettings();
1535 buildNetsList();
1536 }
1537}
1538
1539
1541{
1542 if( m_netsList->GetSelectedItemsCount() == 1 )
1543 {
1544 auto* selItem = static_cast<const LIST_ITEM*>( m_netsList->GetSelection().GetID() );
1545
1546 if( selItem->GetIsGroup() )
1547 {
1548 const wxString groupName = selItem->GetGroupName();
1549 const auto groupIter = std::ranges::find_if( m_custom_group_rules,
1550 [&]( std::unique_ptr<EDA_COMBINED_MATCHER>& rule )
1551 {
1552 return rule->GetPattern() == groupName;
1553 } );
1554
1555 if( groupIter != m_custom_group_rules.end() )
1556 {
1557 m_custom_group_rules.erase( groupIter );
1558 SaveSettings();
1559 buildNetsList();
1560 }
1561 }
1562 }
1563}
1564
1565
1567{
1568 wxFileDialog dlg( this, _( "Save Net Inspector Report File" ), "", "",
1569 _( "Report file" ) + AddFileExtListToFilter( { "csv" } ),
1570 wxFD_SAVE | wxFD_OVERWRITE_PROMPT );
1571
1573
1574 if( dlg.ShowModal() == wxID_CANCEL )
1575 return;
1576
1577 wxTextFile f( dlg.GetPath() );
1578
1579 f.Create();
1580
1581 wxString txt;
1582
1583 m_inReporting = true;
1584
1585 // Print Header:
1586 for( auto&& col : m_columns )
1587 {
1588 txt += '"';
1589
1590 if( col.has_units )
1591 {
1592 txt += wxString::Format( _( "%s (%s)" ),
1593 col.csv_name,
1594 EDA_UNIT_UTILS::GetLabel( m_frame->GetUserUnits() ) );
1595 }
1596 else
1597 {
1598 txt += col.csv_name;
1599 }
1600
1601 txt += wxT( "\";" );
1602 }
1603
1604 f.AddLine( txt );
1605
1606 // Print list of nets:
1607 const unsigned int num_rows = m_dataModel->itemCount();
1608
1609 for( unsigned int row = 0; row < num_rows; row++ )
1610 {
1611 auto& i = m_dataModel->itemAt( row );
1612
1613 if( i.GetIsGroup() || i.GetNetCode() == 0 )
1614 continue;
1615
1616 txt = "";
1617
1618 for( auto&& col : m_columns )
1619 {
1620 if( static_cast<int>( col.csv_flags ) & static_cast<int>( CSV_COLUMN_DESC::CSV_QUOTE ) )
1621 txt += '"' + m_dataModel->valueAt( col.num, row ).GetString() + wxT( "\";" );
1622 else
1623 txt += m_dataModel->valueAt( col.num, row ).GetString() + ';';
1624 }
1625
1626 f.AddLine( txt );
1627 }
1628
1629 m_inReporting = false;
1630
1631 f.Write();
1632 f.Close();
1633}
1634
1635
1637{
1639}
1640
1641
1643{
1644 // ignore selection changes while the whole list is being rebuilt.
1645 if( m_inBuildNetsList )
1646 return;
1647
1648 m_highlightingNets = true;
1649
1650 RENDER_SETTINGS* renderSettings = m_frame->GetCanvas()->GetView()->GetPainter()->GetSettings();
1651
1652 if( m_netsList->HasSelection() )
1653 {
1654 wxDataViewItemArray sel;
1655 m_netsList->GetSelections( sel );
1656
1657 renderSettings->SetHighlight( false );
1658
1659 for( unsigned int i = 0; i < sel.GetCount(); ++i )
1660 {
1661 const LIST_ITEM* ii = static_cast<const LIST_ITEM*>( sel.Item( i ).GetID() );
1662
1663 if( ii->GetIsGroup() )
1664 {
1665 for( auto c = ii->ChildrenBegin(), end = ii->ChildrenEnd(); c != end; ++c )
1666 renderSettings->SetHighlight( true, ( *c )->GetNetCode(), true );
1667 }
1668 else
1669 {
1670 renderSettings->SetHighlight( true, ii->GetNetCode(), true );
1671 }
1672 }
1673 }
1674 else
1675 {
1676 renderSettings->SetHighlight( false );
1677 }
1678
1679 m_frame->GetCanvas()->GetView()->UpdateAllLayersColor();
1680 m_frame->GetCanvas()->Refresh();
1681
1682 m_highlightingNets = false;
1683}
1684
1685
1686void PCB_NET_INSPECTOR_PANEL::OnColumnSorted( wxDataViewEvent& event )
1687{
1688 if( !m_inBuildNetsList )
1689 SaveSettings();
1690}
1691
1692
1694{
1695 // Rebuilt the nets list, and force rebuild of columns in case the stackup has changed
1696 buildNetsList( true );
1697}
1698
1699
1701{
1702 wxString newNetName;
1703 NETNAME_VALIDATOR validator( &newNetName );
1704
1705 WX_TEXT_ENTRY_DIALOG dlg( this, _( "Net name:" ), _( "New Net" ), newNetName );
1706 dlg.SetTextValidator( validator );
1707
1708 while( true )
1709 {
1710 if( dlg.ShowModal() != wxID_OK || dlg.GetValue().IsEmpty() )
1711 return; //Aborted by user
1712
1713 newNetName = dlg.GetValue();
1714
1715 if( m_board->FindNet( newNetName ) )
1716 {
1717 DisplayError( this, wxString::Format( _( "Net name '%s' is already in use." ), newNetName ) );
1718 newNetName = wxEmptyString;
1719 }
1720 else
1721 {
1722 break;
1723 }
1724 }
1725
1726 NETINFO_ITEM* newnet = new NETINFO_ITEM( m_board, dlg.GetValue(), 0 );
1727
1728 m_board->Add( newnet );
1729
1730 // We'll get an OnBoardItemAdded callback from this to update our listbox
1731 m_frame->OnModify();
1732}
1733
1734
1736{
1737 if( m_netsList->GetSelectedItemsCount() == 1 )
1738 {
1739 const LIST_ITEM* sel = static_cast<const LIST_ITEM*>( m_netsList->GetSelection().GetID() );
1740
1741 if( sel->GetIsGroup() )
1742 return;
1743
1744 NETINFO_ITEM* net = sel->GetNet();
1745 wxString fullNetName = net->GetNetname();
1746 wxString netPath;
1747 wxString shortNetName;
1748
1749 if( fullNetName.Contains( wxT( "/" ) ) )
1750 {
1751 netPath = fullNetName.BeforeLast( '/' ) + '/';
1752 shortNetName = fullNetName.AfterLast( '/' );
1753 }
1754 else
1755 {
1756 shortNetName = fullNetName;
1757 }
1758
1759 wxString unescapedShortName = UnescapeString( shortNetName );
1760
1761 WX_TEXT_ENTRY_DIALOG dlg( this, _( "Net name:" ), _( "Rename Net" ), unescapedShortName );
1762 NETNAME_VALIDATOR validator( &unescapedShortName );
1763 dlg.SetTextValidator( validator );
1764
1765 while( true )
1766 {
1767 if( dlg.ShowModal() != wxID_OK || dlg.GetValue() == unescapedShortName )
1768 return;
1769
1770 unescapedShortName = dlg.GetValue();
1771
1772 if( unescapedShortName.IsEmpty() )
1773 {
1774 DisplayError( this, _( "Net name cannot be empty." ) );
1775 continue;
1776 }
1777
1778 shortNetName = EscapeString( unescapedShortName, CTX_NETNAME );
1779 fullNetName = netPath + shortNetName;
1780
1781 if( m_board->FindNet( shortNetName ) || m_board->FindNet( fullNetName ) )
1782 {
1783 DisplayError( this, wxString::Format( _( "Net name '%s' is already in use." ), unescapedShortName ) );
1784 unescapedShortName = wxEmptyString;
1785 }
1786 else
1787 {
1788 break;
1789 }
1790 }
1791
1792 for( BOARD_CONNECTED_ITEM* boardItem : m_frame->GetBoard()->AllConnectedItems() )
1793 {
1794 if( boardItem->GetNet() == net )
1795 boardItem->SetFlags( CANDIDATE );
1796 else
1797 boardItem->ClearFlags( CANDIDATE );
1798 }
1799
1800 // the changed name might require re-grouping. remove/re-insert is easier.
1801 auto removed_item = m_dataModel->deleteItem( m_dataModel->findItem( net ) );
1802
1803 m_board->Remove( net );
1804 net->SetNetname( fullNetName );
1805 m_board->Add( net );
1806
1807 for( BOARD_CONNECTED_ITEM* boardItem : m_frame->GetBoard()->AllConnectedItems() )
1808 {
1809 if( boardItem->GetFlags() & CANDIDATE )
1810 boardItem->SetNet( net );
1811 }
1812
1813 buildNetsList();
1814
1815 if( std::optional<LIST_ITEM_ITER> r = m_dataModel->findItem( net ) )
1816 m_netsList->Select( wxDataViewItem( r.value()->get() ) );
1817
1818 m_frame->OnModify();
1819
1820 // Currently only tracks and pads have netname annotations and need to be redrawn,
1821 // but zones are likely to follow. Since we don't have a way to ask what is current,
1822 // just refresh all items.
1823 m_frame->GetCanvas()->GetView()->UpdateAllItems( KIGFX::REPAINT );
1824 m_frame->GetCanvas()->Refresh();
1825 }
1826}
1827
1828
1830{
1831 if( !m_netsList->HasSelection() )
1832 return;
1833
1834 wxDataViewItemArray sel;
1835 m_netsList->GetSelections( sel );
1836
1837 auto delete_one = [this]( const LIST_ITEM* i )
1838 {
1839 if( i->GetPadCount() == 0
1840 || IsOK( this, wxString::Format( _( "Net '%s' is in use. Delete anyway?" ), i->GetNetName() ) ) )
1841 {
1842 // This is a bit hacky, but it will do for now, since this is the only path
1843 // outside the netlist updater where you can remove a net from a BOARD.
1844 int removedCode = i->GetNetCode();
1845
1846 m_frame->GetCanvas()->GetView()->UpdateAllItemsConditionally(
1847 [removedCode]( KIGFX::VIEW_ITEM* aItem ) -> int
1848 {
1849 auto boardItem = dynamic_cast<BOARD_CONNECTED_ITEM*>( aItem );
1850
1851 if( boardItem && boardItem->GetNetCode() == removedCode )
1852 return KIGFX::REPAINT;
1853
1854 EDA_TEXT* text = dynamic_cast<EDA_TEXT*>( aItem );
1855
1856 if( text && text->HasTextVars() )
1857 {
1858 text->ClearRenderCache();
1859 text->ClearBoundingBoxCache();
1861 }
1862
1863 return 0;
1864 } );
1865
1866 m_board->Remove( i->GetNet() );
1867 m_frame->OnModify();
1868
1869 // We'll get an OnBoardItemRemoved callback from this to update our listbox
1870 }
1871 };
1872
1873 for( unsigned int i = 0; i < sel.GetCount(); ++i )
1874 {
1875 const LIST_ITEM* ii = static_cast<const LIST_ITEM*>( sel.Item( i ).GetID() );
1876
1877 if( ii->GetIsGroup() )
1878 {
1879 if( ii->ChildrenCount() != 0
1880 && IsOK( this, wxString::Format( _( "Delete all nets in group '%s'?" ), ii->GetGroupName() ) ) )
1881 {
1882 // we can't be iterating the children container and deleting items from
1883 // it at the same time. thus take a copy of it first.
1884 std::vector<const LIST_ITEM*> children;
1885 children.reserve( ii->ChildrenCount() );
1886 std::copy( ii->ChildrenBegin(), ii->ChildrenEnd(), std::back_inserter( children ) );
1887
1888 for( const LIST_ITEM* c : children )
1889 delete_one( c );
1890 }
1891 }
1892 else
1893 {
1894 delete_one( ii );
1895 }
1896 }
1897}
1898
1899/*****************************************************************************************
1900 *
1901 * Application-generated event handling
1902 *
1903 * ***************************************************************************************/
1904
1905
1907{
1908 SaveSettings();
1909 buildNetsList( true );
1910 m_dataModel->updateAllItems();
1911}
1912
1913
1914void PCB_NET_INSPECTOR_PANEL::onUnitsChanged( wxCommandEvent& event )
1915{
1916 m_dataModel->updateAllItems();
1917 event.Skip();
1918}
1919
1920
1921/*****************************************************************************************
1922 *
1923 * Settings persistence
1924 *
1925 * ***************************************************************************************/
1926
1927
1929{
1930 // Don't save settings if a board has not yet been loaded or the panel hasn't been displayed.
1931 // Events fire while we set up the panel which overwrite the settings we haven't yet loaded.
1932 bool displayed = false;
1933
1934 for( unsigned int ii = 0; ii < m_dataModel->columnCount() && !displayed; ++ii )
1935 {
1936 if( m_netsList->GetColumn( ii )->GetWidth() > 0 )
1937 displayed = true;
1938 }
1939
1940 if( !displayed || !m_boardLoaded || m_boardLoading )
1941 return;
1942
1944 auto& cfg = localSettings.m_NetInspectorPanel;
1945
1946 // User-defined filters / grouping
1947 cfg.filter_text = m_searchCtrl->GetValue();
1948 cfg.filter_by_net_name = m_filterByNetName;
1949 cfg.filter_by_netclass = m_filterByNetclass;
1950 cfg.group_by_netclass = m_groupByNetclass;
1951 cfg.group_by_net_chain = m_groupByNetChain;
1952 cfg.group_by_constraint = m_groupByConstraint;
1953 cfg.show_zero_pad_nets = m_showZeroPadNets;
1954 cfg.show_unconnected_nets = m_showUnconnectedNets;
1955 cfg.show_time_domain_details = m_showTimeDomainDetails;
1956
1957 // Grid sorting
1958 wxDataViewColumn* sortingCol = m_netsList->GetSortingColumn();
1959 cfg.sorting_column = sortingCol ? static_cast<int>( sortingCol->GetModelColumn() ) : -1;
1960 cfg.sort_order_asc = sortingCol ? sortingCol->IsSortOrderAscending() : true;
1961
1962 // Column arrangement / sizes
1963 cfg.col_order.resize( m_dataModel->columnCount() );
1964 cfg.col_widths.resize( m_dataModel->columnCount() );
1965 cfg.col_hidden.resize( m_dataModel->columnCount() );
1966
1967 for( unsigned int ii = 0; ii < m_dataModel->columnCount(); ++ii )
1968 {
1969 cfg.col_order[ii] = (int) m_netsList->GetColumn( ii )->GetModelColumn();
1970 cfg.col_widths[ii] = m_netsList->GetColumn( ii )->GetWidth();
1971 cfg.col_hidden[ii] = m_netsList->GetColumn( ii )->IsHidden();
1972 }
1973
1974 // Expanded rows
1975 cfg.expanded_rows.clear();
1976 std::vector<std::pair<wxString, wxDataViewItem>> groupItems = m_dataModel->getGroupDataViewItems();
1977
1978 for( std::pair<wxString, wxDataViewItem>& item : groupItems )
1979 {
1980 if( m_netsList->IsExpanded( item.second ) )
1981 cfg.expanded_rows.push_back( item.first );
1982 }
1983
1984 // Customer group rules
1985 cfg.custom_group_rules.clear();
1986
1987 for( const std::unique_ptr<EDA_COMBINED_MATCHER>& rule : m_custom_group_rules )
1988 cfg.custom_group_rules.push_back( rule->GetPattern() );
1989}
constexpr BOX2I KiROUND(const BOX2D &aBoxD)
Definition box2.h:990
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,...
A base class for any item which can be embedded within the BOARD container class, and therefore insta...
Definition board_item.h:84
Information pertinent to a Pcbnew printed circuit board.
Definition board.h:323
CN_ITEM represents a BOARD_CONNETED_ITEM in the connectivity system (ie: a pad, track/arc/via,...
int Net() const
int ShowModal() override
A mix-in class (via multiple inheritance) that handles texts such as labels, parts,...
Definition eda_text.h:93
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
Lightweight class which holds a pad, via, or a routed trace outline.
Class which calculates lengths (and associated routing statistics) in a BOARD context.
LENGTH_DELAY_CALCULATION_ITEM GetLengthCalculationItem(const BOARD_CONNECTED_ITEM *aBoardItem) const
Return a LENGTH_CALCULATION_ITEM constructed from the given BOARD_CONNECTED_ITEM.
LENGTH_DELAY_STATS CalculateLengthDetails(std::vector< LENGTH_DELAY_CALCULATION_ITEM > &aItems, PATH_OPTIMISATIONS aOptimisations, const PAD *aStartPad=nullptr, const PAD *aEndPad=nullptr, LENGTH_DELAY_LAYER_OPT aLayerOpt=LENGTH_DELAY_LAYER_OPT::NO_LAYER_DETAIL, LENGTH_DELAY_DOMAIN_OPT aDomain=LENGTH_DELAY_DOMAIN_OPT::NO_DELAY_DETAIL) const
Calculates the electrical length of the given items.
A collection of nets and the parameters used to route or test these nets.
Definition netclass.h:42
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:328
Handle the data for a net.
Definition netinfo.h:50
const wxString & GetNetChain() const
Definition netinfo.h:115
void SetNetname(const wxString &aNewName)
Set the long netname to aNetName, the short netname to the last token in the long netname's path,...
const wxString & GetNetname() const
Definition netinfo.h:103
NETCLASS * GetNetClass()
Definition netinfo.h:95
int GetNetCode() const
Definition netinfo.h:97
NET_INSPECTOR_PANEL(wxWindow *parent, EDA_BASE_FRAME *aFrame, wxWindowID id=wxID_ANY, const wxPoint &pos=wxDefaultPosition, const wxSize &size=wxSize(-1, -1), long style=wxTAB_TRAVERSAL, const wxString &name=wxEmptyString)
wxDataViewCtrl * m_netsList
wxSearchCtrl * m_searchCtrl
Definition pad.h:55
The main frame for Pcbnew.
Data model for display in the Net Inspector panel.
Primary data item for entries in the Net Inspector list.
void OnBoardItemRemoved(BOARD &aBoard, BOARD_ITEM *aBoardItem) override
void OnBoardHighlightNetChanged(BOARD &aBoard) override
void generateReport()
Generates a CSV report from currently disaplyed data.
PCB_NET_INSPECTOR_PANEL(wxWindow *parent, PCB_EDIT_FRAME *aFrame)
int getMinColumnWidth(int aModelColumn) const
Computes the minimum display width for a column based on its header text.
void onDeleteSelectedNet()
Deletes a selected net.
bool restoreSortColumn(int sortingColumnId, bool sortOrderAsc) const
Sets the sort column in the grid to that showing the given model ID column.
void OnBoardItemsChanged(BOARD &aBoard, std::vector< BOARD_ITEM * > &aBoardItems) override
void adjustListColumnSizes(PANEL_NET_INSPECTOR_SETTINGS *cfg) const
Adjust the sizing of list columns.
void OnSearchTextChanged(wxCommandEvent &event) override
void updateDisplayedRowValues(const std::optional< LIST_ITEM_ITER > &aRow) const
Refreshes displayed data for the given rows.
void onAddNet()
Adds a new user-specified net to the board.
PCB_EDIT_FRAME * m_frame
Owning edit frame.
void OnBoardItemsRemoved(BOARD &aBoard, std::vector< BOARD_ITEM * > &aBoardItems) override
void onClearHighlighting()
Clears highlighting from nets.
void onContextMenuSelection(wxCommandEvent &event)
Handle a net row(s) context menu selection.
static wxString formatNetCode(const NETINFO_ITEM *aNet)
void OnBoardChanged() override
Update panel when board is changed.
void generateShowHideColumnMenu(wxMenu *target)
Generates a sub-menu for the show / hide columns submenu.
std::vector< std::unique_ptr< LIST_ITEM > > calculateNets(const std::vector< NETINFO_ITEM * > &aNetCodes, bool aIncludeZeroPadNets) const
Calculates the length statistics for each given netcode.
void autosizeColumn(wxDataViewColumn *aCol)
Auto-sizes a column to fit both its header text and content.
wxDataViewColumn * m_contextMenuColumn
Tracks which column the header context menu was opened for.
static wxString formatCount(unsigned int aValue)
std::vector< std::unique_ptr< EDA_COMBINED_MATCHER > > m_custom_group_rules
Custom net grouping rules.
std::vector< CN_ITEM * > relevantConnectivityItems() const
Fetches an ordered (by NetCode) list of all board connectivity items.
void highlightSelectedNets()
Highlight the currently selected net.
void updateNets(const std::vector< NETINFO_ITEM * > &aNets) const
Updates displayed statistics for the given nets.
void OnHeaderContextMenu(wxDataViewEvent &event)
void OnBoardItemsAdded(BOARD &aBoard, std::vector< BOARD_ITEM * > &aBoardItems) override
void OnLanguageChangedImpl() override
Reloads strings on an application language change.
void onAddGroup()
Adds a custom display grouping of nets.
void OnNetsListContextMenu(wxDataViewEvent &event)
void OnBoardNetSettingsChanged(BOARD &aBoard) override
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 onRemoveSelectedGroup()
Removes a custom display grouping.
void buildColumns()
Build the required columns in the net inspector grid.
void OnBoardItemAdded(BOARD &aBoard, BOARD_ITEM *aBoardItem) override
void OnParentSetupChanged() override
Updates the netlist based on global board changes (e.g.
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.
void OnConfigButton(wxCommandEvent &event) override
void buildNetsList(bool rebuildColumns=false)
Rebuilds the net inspector list, removing all previous entries.
wxString formatLength(int64_t aValue) const
void SaveSettings() override
Persist the net inspector configuration to project / global settings.
void onRenameSelectedNet()
Renames a selected net.
void onUnitsChanged(wxCommandEvent &event)
Handle an application-level change of units.
void OnExpandCollapseRow(wxCommandEvent &event)
void updateBoardItems(const std::vector< BOARD_ITEM * > &aBoardItems)
Unified handling of added / deleted / modified board items.
wxString formatDelay(int64_t aValue) const
wxObjectDataPtr< DATA_MODEL > m_dataModel
The bound data model to display.
wxDataViewColumn * getDisplayedColumnForModelField(int columnId) const
Fetches the displayed grid view column for the given model column ID.
static wxString formatNetName(const NETINFO_ITEM *aNet)
void OnBoardItemChanged(BOARD &aBoard, BOARD_ITEM *aBoardItem) override
std::vector< COLUMN_DESC > m_columns
All displayed (or hidden) columns.
void OnShowPanel() override
Prepare the panel when shown in the editor.
virtual SETTINGS_MANAGER & GetSettingsManager() const
Definition pgm_base.h:130
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:210
PROJECT & Prj() const
A helper while we are not MDI-capable – return the one and only project.
wxBoxSizer * m_ContentSizer
A KICAD version of wxTextEntryDialog which supports the various improvements/work-arounds from DIALOG...
wxString GetValue() const
void SetTextValidator(const wxTextValidator &validator)
bool IsOK(wxWindow *aParent, const wxString &aMessage)
Display a yes/no dialog with aMessage and returns the user response.
Definition confirm.cpp:278
void DisplayError(wxWindow *aParent, const wxString &aText)
Display an error or warning message box with aMessage.
Definition confirm.cpp:196
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
bool IsCopperLayer(int aLayerId)
Test whether a layer is a copper layer.
Definition layer_ids.h:679
PCB_LAYER_ID
A quick note on layer IDs:
Definition layer_ids.h:60
@ UNDEFINED_LAYER
Definition layer_ids.h:61
KICOMMON_API wxString GetLabel(EDA_UNITS aUnits, EDA_DATA_TYPE aType=EDA_DATA_TYPE::DISTANCE)
Get the units string for a given units type.
@ REPAINT
Item needs to be redrawn.
Definition view_item.h:58
@ GEOMETRY
Position or shape has changed.
Definition view_item.h:55
void AllowNetworkFileSystems(wxDialog *aDialog)
Configure a file dialog to show network and virtual file systems.
Definition wxgtk/ui.cpp:435
KICOMMON_API wxFont GetInfoFont(wxWindow *aWindow)
PGM_BASE & Pgm()
The global program "get" accessor.
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
Holds length measurement result details and statistics.
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
KIBIS_MODEL * model
VECTOR2I end
thread_pool & GetKiCadThreadPool()
Get a reference to the current thread pool.
static thread_pool * tp
BS::priority_thread_pool thread_pool
Definition thread_pool.h:31
@ PCB_VIA_T
class PCB_VIA, a via (like a track segment on a copper layer)
Definition typeinfo.h:94
@ PCB_PAD_T
class PAD, a pad in a footprint
Definition typeinfo.h:84
@ PCB_ARC_T
class PCB_ARC, an arc track segment on a copper layer
Definition typeinfo.h:95
@ PCB_TRACE_T
class PCB_TRACK, a track segment (segment on a copper layer)
Definition typeinfo.h:93
Custom text control validator definitions.
VECTOR2< int32_t > VECTOR2I
Definition vector2d.h:687
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.