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