KiCad PCB EDA Suite
dialog_select_net_from_list.cpp
Go to the documentation of this file.
1 /*
2  * This program source code file is part of KiCad, a free EDA CAD application.
3  *
4  * Copyright (C) 2020 Oleg Endo <olegendo@gcc.gnu.org>
5  * Copyright (C) 2019 Jean-Pierre Charras, jp.charras at wanadoo.fr
6  * Copyright (C) 1992-2019 KiCad Developers, see AUTHORS.txt for contributors.
7  *
8  * This program is free software; you can redistribute it and/or
9  * modify it under the terms of the GNU General Public License
10  * as published by the Free Software Foundation; either version 2
11  * of the License, or (at your option) any later version.
12  *
13  * This program is distributed in the hope that it will be useful,
14  * but WITHOUT ANY WARRANTY; without even the implied warranty of
15  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
16  * GNU General Public License for more details.
17  *
18  * You should have received a copy of the GNU General Public License
19  * along with this program; if not, you may find one here:
20  * http://www.gnu.org/licenses/old-licenses/gpl-2.0.html
21  * or you may search the http://www.gnu.org website for the version 2 license,
22  * or you may write to the Free Software Foundation, Inc.,
23  * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA
24  */
25 
26 #include <fctsys.h>
27 #include <kicad_string.h>
28 #include <pcbnew.h>
30 #include <class_board.h>
31 #include <class_track.h>
33 #include <eda_pattern_match.h>
35 #include <view/view.h>
36 #include <view/view_controls.h>
37 #include <pcb_painter.h>
40 
42 {
43  int col_num;
44  wxString display_name;
45 
46  operator int() const
47  {
48  return col_num;
49  }
50 };
51 
52 #define def_col( c, num, name ) \
53  const DIALOG_SELECT_NET_FROM_LIST::COLUMN_ID DIALOG_SELECT_NET_FROM_LIST::c = { num, name }
54 
55 def_col( COLUMN_NET, 0, _( "Net" ) );
56 def_col( COLUMN_NAME, 1, _( "Name" ) );
57 def_col( COLUMN_PAD_COUNT, 2, _( "Pad Count" ) );
58 def_col( COLUMN_VIA_COUNT, 3, _( "Via Count" ) );
59 def_col( COLUMN_BOARD_LENGTH, 4, _( "Board Length" ) );
60 def_col( COLUMN_CHIP_LENGTH, 5, _( "Die Length" ) );
61 def_col( COLUMN_TOTAL_LENGTH, 6, _( "Length" ) );
62 
63 #undef def_col
64 
65 
67 {
68  LIST_ITEM( NETINFO_ITEM* aNet ) : m_net( aNet )
69  {
70  }
71 
73  int m_pad_count = 0;
74  int m_via_count = 0;
77  int m_total_length = 0;
78 };
79 
80 
82 {
84 
85  LIST_ITEM_NET_CMP_LESS( const std::vector<LIST_ITEM>& container )
86  : m_base_ptr( container.data() )
87  {
88  }
89 
90  bool operator()( unsigned int a, unsigned int b ) const
91  {
92  return m_base_ptr[a].m_net < m_base_ptr[b].m_net;
93  }
94 
95  bool operator()( unsigned int a, NETINFO_ITEM* b ) const
96  {
97  return m_base_ptr[a].m_net < b;
98  }
99 
100  bool operator()( NETINFO_ITEM* a, unsigned int b ) const
101  {
102  return a < m_base_ptr[b].m_net;
103  }
104 };
105 
106 
108 {
109  int row_num = -1;
112 
113  bool valid() const
114  {
115  return row_num != -1;
116  }
117 
118  explicit operator bool() const
119  {
120  return valid();
121  }
122 };
123 
124 
126  PCB_EDIT_FRAME* aParent, const SETTINGS& aSettings )
127  : DIALOG_SELECT_NET_FROM_LIST_BASE( aParent ), m_frame( aParent )
128 {
129  m_brd = aParent->GetBoard();
130  m_wasSelected = false;
131 
132  m_netsList->AppendTextColumn(
133  COLUMN_NET.display_name, wxDATAVIEW_CELL_INERT, 0, wxALIGN_LEFT, 0 );
134  m_netsList->AppendTextColumn(
135  COLUMN_NAME.display_name, wxDATAVIEW_CELL_INERT, 0, wxALIGN_LEFT, 0 );
136  m_netsList->AppendTextColumn(
137  COLUMN_PAD_COUNT.display_name, wxDATAVIEW_CELL_INERT, 0, wxALIGN_CENTER, 0 );
138  m_netsList->AppendTextColumn(
139  COLUMN_VIA_COUNT.display_name, wxDATAVIEW_CELL_INERT, 0, wxALIGN_CENTER, 0 );
140  m_netsList->AppendTextColumn(
141  COLUMN_BOARD_LENGTH.display_name, wxDATAVIEW_CELL_INERT, 0, wxALIGN_CENTER, 0 );
142  m_netsList->AppendTextColumn(
143  COLUMN_CHIP_LENGTH.display_name, wxDATAVIEW_CELL_INERT, 0, wxALIGN_CENTER, 0 );
144  m_netsList->AppendTextColumn(
145  COLUMN_TOTAL_LENGTH.display_name, wxDATAVIEW_CELL_INERT, 0, wxALIGN_CENTER, 0 );
146 
147  // The fact that we're a list should keep the control from reserving space for the
148  // expander buttons... but it doesn't. Fix by forcing the indent to 0.
149  m_netsList->SetIndent( 0 );
150 
151  m_textCtrlFilter->SetValue( aSettings.filter_string );
152  m_cbShowZeroPad->SetValue( aSettings.show_zero_pad_nets );
153 
154  buildNetsList();
155 
157 
158  m_sdbSizerOK->SetDefault();
159 
161 
162 #define connect_event( e, f ) \
163  m_frame->Connect( e, wxCommandEventHandler( DIALOG_SELECT_NET_FROM_LIST::f ), nullptr, this )
164 
165  connect_event( wxEVT_CLOSE_WINDOW, onParentWindowClosed );
166  connect_event( UNITS_CHANGED, onUnitsChanged );
167  connect_event( BOARD_CHANGED, onBoardChanged );
168 
169 #undef connect_event
170 
171  if( m_brd != nullptr )
172  m_brd->AddListener( this );
173 }
174 
175 
177 {
178 #define disconnect_event( e, f ) \
179  m_frame->Disconnect( e, wxCommandEventHandler( DIALOG_SELECT_NET_FROM_LIST::f ), nullptr, this )
180 
181  disconnect_event( wxEVT_CLOSE_WINDOW, onParentWindowClosed );
182  disconnect_event( UNITS_CHANGED, onUnitsChanged );
183  disconnect_event( BOARD_CHANGED, onBoardChanged );
184 
185 #undef disconnect_event
186 
187  if( m_brd != nullptr )
188  m_brd->RemoveListener( this );
189 }
190 
191 
193 {
194  return { m_textCtrlFilter->GetValue(), m_cbShowZeroPad->IsChecked() };
195 }
196 
197 
199 {
200  Close();
201  event.Skip();
202 }
203 
204 
205 void DIALOG_SELECT_NET_FROM_LIST::onUnitsChanged( wxCommandEvent& event )
206 {
207  this->m_units = m_frame->GetUserUnits();
208 
209  buildNetsList();
210  m_netsList->Refresh();
211 
212  event.Skip();
213 }
214 
215 
216 void DIALOG_SELECT_NET_FROM_LIST::onBoardChanged( wxCommandEvent& event )
217 {
218  if( m_brd != nullptr )
219  m_brd->RemoveListener( this );
220 
221  m_brd = m_frame->GetBoard();
222 
223  if( m_brd != nullptr )
224  m_brd->AddListener( this );
225 
226  m_wasSelected = false;
227 
228  buildNetsList();
229  m_netsList->Refresh();
230 
231  event.Skip();
232 }
233 
234 
236 {
237  // Note: the filtering is case insensitive.
238 
239  if( m_netFilter.GetPattern().IsEmpty() )
240  return true;
241 
242  return m_netFilter.Find( UnescapeString( aNet->GetNetname() ).Upper() )
244 }
245 
246 
248 {
249  bool operator()( const CN_ITEM* a, const CN_ITEM* b ) const
250  {
251  return a->Net() < b->Net();
252  }
253 
254  bool operator()( const CN_ITEM* a, int b ) const
255  {
256  return a->Net() < b;
257  }
258 
259  bool operator()( int a, const CN_ITEM* b ) const
260  {
261  return a < b->Net();
262  }
263 };
264 
265 
267 {
268  // pre-filter the connectivity items and sort them by netcode.
269  // this avoids quadratic runtime when building the whole net list and
270  // calculating the total length for each net.
271 
272  const auto type_bits = std::bitset<MAX_STRUCT_TYPE_ID>()
273  .set( PCB_TRACE_T )
274  .set( PCB_VIA_T )
275  .set( PCB_PAD_T );
276 
277  std::vector<CN_ITEM*> cn_items;
278  cn_items.reserve( 1024 );
279 
280  for( auto& cn_item : m_brd->GetConnectivity()->GetConnectivityAlgo()->ItemList() )
281  {
282  if( cn_item->Valid() && type_bits[cn_item->Parent()->Type()] )
283  cn_items.push_back( cn_item );
284  }
285 
286  std::sort( cn_items.begin(), cn_items.end(), NETCODE_CMP_LESS() );
287 
288  return cn_items;
289 }
290 
291 
293 {
294  return findRow( m_brd->FindNet( aNetCode ) );
295 }
296 
297 
299 {
300  auto i = std::lower_bound( m_list_items_by_net.begin(), m_list_items_by_net.end(), aNet,
302 
303  if( i != m_list_items_by_net.end() && m_list_items[*i].m_net == aNet )
304  return { static_cast<int>( *i ), m_list_items.begin() + *i, i };
305  else
306  return {};
307 }
308 
309 
311 {
312  if( !aRow )
313  return;
314 
315  m_netsList->DeleteItem( aRow.row_num );
316  m_list_items.erase( aRow.by_row );
317 
318  std::iter_swap( aRow.by_net, m_list_items_by_net.end() - 1 );
319  m_list_items_by_net.pop_back();
320 
321  std::sort( m_list_items_by_net.begin(), m_list_items_by_net.end(),
323 }
324 
325 
327  const ROW_DESC& aRow, const COLUMN_ID& aCol, wxString aVal )
328 {
329  if( aRow )
330  m_netsList->SetValue( aVal, aRow.row_num, aCol.col_num );
331 }
332 
333 
335 {
336  return wxString::Format( "%.3d", aNet->GetNet() );
337 }
338 
339 
341 {
342  return UnescapeString( aNet->GetNetname() );
343 }
344 
345 
346 wxString DIALOG_SELECT_NET_FROM_LIST::formatCount( unsigned int aValue ) const
347 {
348  return wxString::Format( "%u", aValue );
349 }
350 
351 
352 wxString DIALOG_SELECT_NET_FROM_LIST::formatLength( int aValue ) const
353 {
354  return MessageTextFromValue( GetUserUnits(), aValue );
355 }
356 
357 
359 {
360  if( NETINFO_ITEM* net = dynamic_cast<NETINFO_ITEM*>( aBoardItem ) )
361  {
362  // a new net has been added to the board. add it to our list if it
363  // passes the netname filter test.
364  if( netFilterMatches( net ) )
365  {
366  m_list_items.emplace_back( net );
367  m_list_items_by_net.push_back( m_list_items.size() - 1 );
368 
369  std::sort( m_list_items_by_net.begin(), m_list_items_by_net.end(),
371 
372  auto& new_i = m_list_items.back();
373  new_i.m_pad_count = m_brd->GetNodesCount( net->GetNet() );
374 
375  wxVector<wxVariant> new_row( 7 );
376  new_row[COLUMN_NET] = formatNetCode( net );
377  new_row[COLUMN_NAME] = formatNetName( net );
378  new_row[COLUMN_PAD_COUNT] = formatCount( new_i.m_pad_count );
379  new_row[COLUMN_VIA_COUNT] = formatCount( new_i.m_via_count );
380  new_row[COLUMN_BOARD_LENGTH] = formatLength( new_i.m_board_wire_length );
381  new_row[COLUMN_CHIP_LENGTH] = formatLength( new_i.m_chip_wire_length );
382  new_row[COLUMN_TOTAL_LENGTH] = formatLength( new_i.m_total_length );
383 
384  m_netsList->AppendItem( new_row );
385  }
386 
387  return;
388  }
389  else if( auto* i = dynamic_cast<BOARD_CONNECTED_ITEM*>( aBoardItem ) )
390  {
391  auto r = findRow( i->GetNet() );
392 
393  if( r )
394  {
395  // try to handle frequent operations quickly.
396  if( auto* track = dynamic_cast<TRACK*>( i ) )
397  {
398  int len = track->GetLength();
399  r.by_row->m_board_wire_length += len;
400  r.by_row->m_total_length += len;
401 
402  setValue( r, COLUMN_BOARD_LENGTH, formatLength( r.by_row->m_board_wire_length ) );
403  setValue( r, COLUMN_TOTAL_LENGTH, formatLength( r.by_row->m_total_length ) );
404 
405  if( track->Type() == PCB_VIA_T )
406  {
407  r.by_row->m_via_count += 1;
408  setValue( r, COLUMN_VIA_COUNT, formatCount( r.by_row->m_via_count ) );
409  }
410 
411  return;
412  }
413  }
414 
415  // resort to generic slower net update otherwise.
416  updateNet( i->GetNet() );
417  }
418 }
419 
420 
422 {
423  if( auto* net = dynamic_cast<NETINFO_ITEM*>( aBoardItem ) )
424  {
425  deleteRow( findRow( net ) );
426  return;
427  }
428  else if( auto* mod = dynamic_cast<MODULE*>( aBoardItem ) )
429  {
430  for( const D_PAD* pad : mod->Pads() )
431  {
432  auto r = findRow( pad->GetNet() );
433 
434  if( r )
435  {
436  r.by_row->m_pad_count -= 1;
437 
438  if( r.by_row->m_pad_count == 0 && !m_cbShowZeroPad->IsChecked() )
439  deleteRow( r );
440  else
441  setValue( r, COLUMN_PAD_COUNT, formatCount( r.by_row->m_pad_count ) );
442  }
443  }
444  }
445  else if( auto* i = dynamic_cast<BOARD_CONNECTED_ITEM*>( aBoardItem ) )
446  {
447  auto r = findRow( i->GetNet() );
448 
449  if( r )
450  {
451  // try to handle frequent operations quickly.
452  if( auto* track = dynamic_cast<TRACK*>( i ) )
453  {
454  int len = track->GetLength();
455  r.by_row->m_board_wire_length -= len;
456  r.by_row->m_total_length -= len;
457 
458  setValue( r, COLUMN_BOARD_LENGTH, formatLength( r.by_row->m_board_wire_length ) );
459  setValue( r, COLUMN_TOTAL_LENGTH, formatLength( r.by_row->m_total_length ) );
460 
461  if( track->Type() == PCB_VIA_T )
462  {
463  r.by_row->m_via_count -= 1;
464  setValue( r, COLUMN_VIA_COUNT, formatCount( r.by_row->m_via_count ) );
465  }
466 
467  return;
468  }
469 
470  // resort to generic slower net update otherwise.
471  updateNet( i->GetNet() );
472  }
473  }
474 }
475 
476 
478 {
479  if( dynamic_cast<BOARD_CONNECTED_ITEM*>( aBoardItem ) != nullptr
480  || dynamic_cast<MODULE*>( aBoardItem ) != nullptr )
481  {
482  buildNetsList();
483  m_netsList->Refresh();
484  }
485 }
486 
487 
489 {
490  if( !m_brd->IsHighLightNetON() )
491  m_netsList->UnselectAll();
492  else if( !m_brd->GetHighLightNetCodes().empty() )
494 }
495 
496 
498 {
499  buildNetsList();
500  m_netsList->Refresh();
501 }
502 
503 
505 {
506  // something for the specified net has changed, update that row.
507  if( !netFilterMatches( aNet ) )
508  return;
509 
510  // if the net had no pads before, it might not be in the displayed list yet.
511  // if it had pads and now doesn't anymore, we might need to remove it from the list.
512 
513  auto cur_net_row = findRow( aNet );
514 
515  const unsigned int node_count = m_brd->GetNodesCount( aNet->GetNet() );
516 
517  if( node_count == 0 && !m_cbShowZeroPad->IsChecked() )
518  {
519  deleteRow( cur_net_row );
520  return;
521  }
522 
523  auto all_cn_items = relevantConnectivityItems();
524 
525  LIST_ITEM list_item( aNet );
526  list_item.m_pad_count = node_count;
527 
528  const auto cn_items = std::equal_range(
529  all_cn_items.begin(), all_cn_items.end(), aNet->GetNet(), NETCODE_CMP_LESS() );
530 
531  for( auto i = cn_items.first; i != cn_items.second; ++i )
532  {
533  auto item = ( *i )->Parent();
534 
535  if( item->Type() == PCB_PAD_T )
536  list_item.m_chip_wire_length += static_cast<D_PAD*>( item )->GetPadToDieLength();
537 
538  else if( auto* track = dynamic_cast<TRACK*>( item ) )
539  {
540  list_item.m_board_wire_length += track->GetLength();
541 
542  if( item->Type() == PCB_VIA_T )
543  list_item.m_via_count += 1;
544  }
545  }
546 
547  list_item.m_total_length = list_item.m_board_wire_length + list_item.m_chip_wire_length;
548 
549  if( !cur_net_row )
550  {
551  m_list_items.push_back( list_item );
552  m_list_items_by_net.push_back( m_list_items.size() - 1 );
553  std::sort( m_list_items_by_net.begin(), m_list_items_by_net.end(),
555 
556  wxVector<wxVariant> new_row( 7 );
557  new_row[COLUMN_NET] = formatNetCode( aNet );
558  new_row[COLUMN_NAME] = formatNetName( aNet );
559  new_row[COLUMN_PAD_COUNT] = formatCount( list_item.m_pad_count );
560  new_row[COLUMN_VIA_COUNT] = formatCount( list_item.m_via_count );
561  new_row[COLUMN_BOARD_LENGTH] = formatLength( list_item.m_board_wire_length );
562  new_row[COLUMN_CHIP_LENGTH] = formatLength( list_item.m_chip_wire_length );
563  new_row[COLUMN_TOTAL_LENGTH] = formatLength( list_item.m_total_length );
564 
565  m_netsList->AppendItem( new_row );
566  }
567  else
568  {
569  *cur_net_row.by_row = list_item;
570 
571  setValue( cur_net_row, COLUMN_PAD_COUNT, formatCount( list_item.m_pad_count ) );
572  setValue( cur_net_row, COLUMN_VIA_COUNT, formatCount( list_item.m_via_count ) );
573  setValue( cur_net_row, COLUMN_BOARD_LENGTH, formatLength( list_item.m_board_wire_length ) );
574  setValue( cur_net_row, COLUMN_CHIP_LENGTH, formatLength( list_item.m_chip_wire_length ) );
575  setValue( cur_net_row, COLUMN_TOTAL_LENGTH, formatLength( list_item.m_total_length ) );
576  }
577 }
578 
579 
581 {
582  // when rebuilding the netlist, try to keep the row selection
583  const int prev_selected_row = m_netsList->GetSelectedRow();
584  const int prev_selected_netcode =
585  prev_selected_row >= 0 ? m_list_items[prev_selected_row].m_net->GetNet() : -1;
586 
587  m_netsList->DeleteAllItems();
588  m_list_items.clear();
589 
590  std::vector<CN_ITEM*> prefiltered_cn_items = relevantConnectivityItems();
591 
592 
593  // collect all nets which pass the filter string.
594 
595  struct NET_INFO
596  {
597  int netcode;
598  NETINFO_ITEM* net;
599  unsigned int pad_count;
600  };
601 
602  struct NET_INFO_CMP_LESS
603  {
604  bool operator()( const NET_INFO& a, const NET_INFO& b ) const
605  {
606  return a.netcode < b.netcode;
607  }
608  bool operator()( const NET_INFO& a, int b ) const
609  {
610  return a.netcode < b;
611  }
612  bool operator()( int a, const NET_INFO& b ) const
613  {
614  return a < b.netcode;
615  }
616  };
617 
618  std::vector<NET_INFO> nets;
619  nets.reserve( m_brd->GetNetInfo().NetsByNetcode().size() );
620 
621  for( auto&& ni : m_brd->GetNetInfo().NetsByNetcode() )
622  {
623  if( netFilterMatches( ni.second ) )
624  nets.emplace_back( NET_INFO{ ni.first, ni.second, 0 } );
625  }
626 
627  // count the pads for each net. since the nets are sorted by netcode
628  // this way around is faster than using counting pads for each net.
629 
630  for( auto&& mod : m_brd->Modules() )
631  {
632  for( auto&& pad : mod->Pads() )
633  {
634  auto i = std::lower_bound(
635  nets.begin(), nets.end(), pad->GetNetCode(), NET_INFO_CMP_LESS() );
636 
637  if( i != nets.end() && i->netcode == pad->GetNetCode() )
638  i->pad_count += 1;
639  }
640  }
641 
642  for( auto&& ni : nets )
643  {
644  if( !m_cbShowZeroPad->IsChecked() && ni.pad_count == 0 )
645  continue;
646 
647  m_list_items.emplace_back( ni.net );
648  auto& list_item = m_list_items.back();
649 
650  const auto cn_items = std::equal_range( prefiltered_cn_items.begin(),
651  prefiltered_cn_items.end(), ni.netcode, NETCODE_CMP_LESS() );
652 
653  for( auto i = cn_items.first; i != cn_items.second; ++i )
654  {
655  auto item = ( *i )->Parent();
656 
657  if( item->Type() == PCB_PAD_T )
658  list_item.m_chip_wire_length += static_cast<D_PAD*>( item )->GetPadToDieLength();
659 
660  else if( auto* track = dynamic_cast<TRACK*>( item ) )
661  {
662  list_item.m_board_wire_length += track->GetLength();
663 
664  if( track->Type() == PCB_VIA_T )
665  list_item.m_via_count += 1;
666  }
667  }
668 
669  list_item.m_pad_count = ni.pad_count;
670  list_item.m_total_length = list_item.m_board_wire_length + list_item.m_chip_wire_length;
671  }
672 
673  wxVector<wxVariant> dataLine;
674  dataLine.resize( 7 );
675 
676  for( auto& i : m_list_items )
677  {
678  dataLine[COLUMN_NET] = formatNetCode( i.m_net );
679  dataLine[COLUMN_NAME] = formatNetName( i.m_net );
680  dataLine[COLUMN_PAD_COUNT] = formatCount( i.m_pad_count );
681  dataLine[COLUMN_VIA_COUNT] = formatCount( i.m_via_count );
682  dataLine[COLUMN_BOARD_LENGTH] = formatLength( i.m_board_wire_length );
683  dataLine[COLUMN_CHIP_LENGTH] = formatLength( i.m_chip_wire_length );
684  dataLine[COLUMN_TOTAL_LENGTH] = formatLength( i.m_total_length );
685 
686  m_netsList->AppendItem( dataLine );
687  }
688 
689  m_list_items_by_net.clear();
690  m_list_items_by_net.reserve( m_list_items.size() );
691 
692  for( unsigned int i = 0; i < m_list_items.size(); ++i )
693  m_list_items_by_net.push_back( i );
694 
695  std::sort( m_list_items_by_net.begin(), m_list_items_by_net.end(),
697 
698  if( prev_selected_netcode == -1 )
699  m_wasSelected = false;
700  else
701  {
702  auto r = findRow( prev_selected_netcode );
703 
704  if( r )
705  {
706  m_selection = r.by_row->m_net->GetNetname();
707  m_wasSelected = true;
708 
709  auto i = m_netsList->RowToItem( r.row_num );
710  m_netsList->Select( i );
711  m_netsList->EnsureVisible( i );
712  }
713  }
714 }
715 
716 
718 {
719  const auto r = findRow( aNet );
720 
721  if( r )
722  {
723  auto i = m_netsList->RowToItem( r.row_num );
724  m_netsList->Select( i );
725  m_netsList->EnsureVisible( i );
726  }
727  else
728  m_netsList->UnselectAll();
729 }
730 
731 
733 {
734  int netCode = aNet != nullptr ? aNet->GetNet() : -1;
735 
737  render->SetHighlight( netCode >= 0, netCode );
738 
740  m_frame->GetCanvas()->Refresh();
741 }
742 
743 
744 void DIALOG_SELECT_NET_FROM_LIST::onFilterChange( wxCommandEvent& event )
745 {
746  m_netFilter.SetPattern( m_textCtrlFilter->GetValue().Upper() );
747  buildNetsList();
748 }
749 
750 
752 {
753  int selected_row = m_netsList->GetSelectedRow();
754 
755  if( selected_row >= 0 && selected_row < static_cast<int>( m_list_items.size() ) )
756  {
757  auto* net = m_list_items[selected_row].m_net;
758 
759  m_selection = net->GetNetname();
760  m_wasSelected = true;
761  highlightNetOnBoard( net );
762  return;
763  }
764 
765  highlightNetOnBoard( nullptr );
766  m_wasSelected = false;
767 }
768 
769 
771 {
772  int w0, w1, w2, w3, w4, w5, w6;
773 
781  wxClientDC dc( GetParent() );
782  int h, minw, minw_col0;
783 
784  dc.GetTextExtent( COLUMN_NET.display_name + "MM", &w0, &h );
785  dc.GetTextExtent( COLUMN_PAD_COUNT.display_name + "MM", &w2, &h );
786  dc.GetTextExtent( COLUMN_VIA_COUNT.display_name + "MM", &w3, &h );
787  dc.GetTextExtent( COLUMN_BOARD_LENGTH.display_name + "MM", &w4, &h );
788  dc.GetTextExtent( COLUMN_CHIP_LENGTH.display_name + "MM", &w5, &h );
789  dc.GetTextExtent( COLUMN_TOTAL_LENGTH.display_name + "MM", &w6, &h );
790  dc.GetTextExtent( "M00000,000 mmM", &minw, &h );
791  dc.GetTextExtent( "M00000M", &minw_col0, &h );
792 
793  // Considering left and right margins.
794  // For wxRenderGeneric it is 5px.
795  w0 = std::max( w0+10, minw_col0);
796  w2 = std::max( w2+10, minw);
797  w3 = std::max( w3+10, minw);
798  w4 = std::max( w4+10, minw);
799  w5 = std::max( w5+10, minw);
800  w6 = std::max( w6+10, minw);
801 
802  m_netsList->GetColumn( 0 )->SetWidth( w0 );
803  m_netsList->GetColumn( 2 )->SetWidth( w2 );
804  m_netsList->GetColumn( 3 )->SetWidth( w3 );
805  m_netsList->GetColumn( 4 )->SetWidth( w4 );
806  m_netsList->GetColumn( 5 )->SetWidth( w5 );
807  m_netsList->GetColumn( 6 )->SetWidth( w6 );
808 
809  // At resizing of the list the width of middle column (Net Names) changes only.
810  int width = m_netsList->GetClientSize().x;
811  w1 = width - w0 - w2 - w3 - w4 - w5 - w6;
812 
813  // Column 1 (net names) need a minimal width to display net names
814  dc.GetTextExtent( "MMMMMMMMMMMMMMMMMMMM", &minw, &h );
815  w1 = std::max( w1, minw );
816 
817  m_netsList->GetColumn( 1 )->SetWidth( w1 );
818 
819  m_netsList->Refresh();
820 }
821 
822 
823 void DIALOG_SELECT_NET_FROM_LIST::onListSize( wxSizeEvent& aEvent )
824 {
825  aEvent.Skip();
827 }
828 
829 
830 bool DIALOG_SELECT_NET_FROM_LIST::GetNetName( wxString& aName ) const
831 {
832  aName = m_selection;
833  return m_wasSelected;
834 }
835 
836 
837 void DIALOG_SELECT_NET_FROM_LIST::onReport( wxCommandEvent& aEvent )
838 {
839  wxFileDialog dlg( this, _( "Report file" ), "", "",
840  _( "Report file" ) + AddFileExtListToFilter( { "csv" } ),
841  wxFD_SAVE );
842 
843  if( dlg.ShowModal() == wxID_CANCEL )
844  return;
845 
846  wxTextFile f( dlg.GetPath() );
847 
848  f.Create();
849 
850  int rows = m_netsList->GetItemCount();
851  wxString txt;
852 
853  // Print Header:
854  txt.Printf( "\"%s\";\"%s\";\"%s\";\"%s\";\"%s\";\"%s\";\"%s\";",
855  _( "Net Id" ), _( "Net name" ),
856  _( "Pad count" ), _( "Via count" ),
857  _( "Board length" ), _( "Die length" ), _( "Net length" ) );
858  f.AddLine( txt );
859 
860  // Print list of nets:
861  for( int row = 1; row < rows; row++ )
862  {
863  txt.Printf( "%s;\"%s\";%s;%s;%s;%s;%s;", m_netsList->GetTextValue( row, COLUMN_NET ),
864  m_netsList->GetTextValue( row, COLUMN_NAME ),
865  m_netsList->GetTextValue( row, COLUMN_PAD_COUNT ),
866  m_netsList->GetTextValue( row, COLUMN_VIA_COUNT ),
867  m_netsList->GetTextValue( row, COLUMN_BOARD_LENGTH ),
868  m_netsList->GetTextValue( row, COLUMN_CHIP_LENGTH ),
869  m_netsList->GetTextValue( row, COLUMN_TOTAL_LENGTH ) );
870 
871  f.AddLine( txt );
872  }
873 
874  f.Write();
875  f.Close();
876 }
877 
decltype(DIALOG_SELECT_NET_FROM_LIST::m_list_items_by_net) ::iterator by_net
#define connect_event(e, f)
void AddListener(BOARD_LISTENER *aListener)
Add a listener to the board to receive calls whenever something on the board has been modified.
decltype(DIALOG_SELECT_NET_FROM_LIST::m_list_items) ::iterator by_row
NETINFO_ITEM * FindNet(int aNetcode) const
Function FindNet searches for a net with the given netcode.
bool operator()(unsigned int a, unsigned int b) const
RENDER_SETTINGS Contains all the knowledge about how graphical objects are drawn on any output surfac...
DIALOG_SELECT_NET_FROM_LIST(PCB_EDIT_FRAME *aParent, const SETTINGS &aSettings)
BOARD_ITEM is a base class for any item which can be embedded within the BOARD container class,...
const NETCODES_MAP & NetsByNetcode() const
Return the netcode map, at least for python.
Definition: netinfo.h:457
VIEW_CONTROLS class definition.
virtual void OnBoardItemAdded(BOARD &aBoard, BOARD_ITEM *aBoardItem) override
bool IsHighLightNetON() const
Function IsHighLightNetON.
Definition: class_board.h:414
PCB_DRAW_PANEL_GAL * GetCanvas() const override
Return a pointer to GAL-based canvas of given EDA draw frame.
bool operator()(int a, const CN_ITEM *b) const
std::vector< unsigned int > m_list_items_by_net
void FinishDialogSettings()
In all dialogs, we must call the same functions to fix minimal dlg size, the default position and per...
virtual void OnBoardItemRemoved(BOARD &aBoard, BOARD_ITEM *aBoardItem) override
class D_PAD, a pad in a footprint
Definition: typeinfo.h:90
void onListSize(wxSizeEvent &event) override
virtual wxString const & GetPattern() const override
Return the pattern passed to SetPattern().
int Net() const
PAINTER * GetPainter() const
Function GetPainter() Returns the painter object used by the view for drawing VIEW_ITEMS.
Definition: view.h:199
A single base class (TRACK) represents both tracks and vias, with subclasses for curved tracks (ARC) ...
class TRACK, a track segment (segment on a copper layer)
Definition: typeinfo.h:96
virtual bool SetPattern(const wxString &aPattern) override
Set the pattern against which candidates will be matched.
Abstract pattern-matching tool and implementations.
EDA_PATTERN_MATCH_WILDCARD m_netFilter
EDA_UNITS GetUserUnits() const
Definition: dialog_shim.h:131
static const COLUMN_ID COLUMN_BOARD_LENGTH
#define def_col(c, num, name)
wxString formatCount(unsigned int aValue) const
std::vector< CN_ITEM * > relevantConnectivityItems() const
void HighlightNet(NETINFO_ITEM *aNet)
Visually highlights a net in the list view.
void setValue(const ROW_DESC &aRow, const COLUMN_ID &aCol, wxString aVal)
void onBoardChanged(wxCommandEvent &event)
void onParentWindowClosed(wxCommandEvent &event)
wxString formatNetName(const NETINFO_ITEM *aNet) const
void onSelChanged(wxDataViewEvent &event) override
unsigned GetNodesCount(int aNet=-1)
Function GetNodesCount.
void RemoveListener(BOARD_LISTENER *aListener)
Remove the specified listener.
MODULES & Modules()
Definition: class_board.h:266
Class DIALOG_SELECT_NET_FROM_LIST_BASE.
void onFilterChange(wxCommandEvent &event) override
wxString formatNetCode(const NETINFO_ITEM *aNet) const
bool netFilterMatches(NETINFO_ITEM *aNet) const
std::shared_ptr< CONNECTIVITY_DATA > GetConnectivity() const
Function GetConnectivity() returns list of missing connections between components/tracks.
Definition: class_board.h:355
wxString formatLength(int aValue) const
Definition of file extensions used in Kicad.
const wxString & GetNetname() const
Function GetNetname.
Definition: netinfo.h:231
virtual void OnBoardItemChanged(BOARD &aBoard, BOARD_ITEM *aBoardItem) override
static const int EDA_PATTERN_NOT_FOUND
NETINFO_LIST & GetNetInfo()
Definition: class_board.h:739
virtual KIGFX::PCB_VIEW * GetView() const override
Function GetView() Returns a pointer to the VIEW instance used in the panel.
virtual void Refresh(bool aEraseBackground=true, const wxRect *aRect=NULL) override
Update the board display after modifying it by a python script (note: it is automatically called by a...
static const COLUMN_ID COLUMN_TOTAL_LENGTH
bool operator()(NETINFO_ITEM *a, unsigned int b) const
virtual void OnBoardHighlightNetChanged(BOARD &aBoard) override
const std::set< int > & GetHighLightNetCodes() const
Function GetHighLightNetCode.
Definition: class_board.h:397
bool operator()(const CN_ITEM *a, const CN_ITEM *b) const
#define disconnect_event(e, f)
wxString MessageTextFromValue(EDA_UNITS aUnits, int aValue, bool aUseMils, EDA_DATA_TYPE aType)
Definition: base_units.cpp:124
EDA_UNITS m_units
Definition: dialog_shim.h:197
ROW_DESC findRow(NETINFO_ITEM *aNet)
virtual RENDER_SETTINGS * GetSettings()=0
Function GetAdapter Returns pointer to current settings that are going to be used when drawing items.
bool GetNetName(wxString &aName) const
virtual void OnBoardNetSettingsChanged(BOARD &aBoard) override
NETINFO_ITEM handles the data for a net.
Definition: netinfo.h:65
LIST_ITEM_NET_CMP_LESS(const std::vector< LIST_ITEM > &container)
void SetHighlight(bool aEnabled, int aNetcode=-1, bool aMulti=false)
Function SetHighlight Turns on/off highlighting - it may be done for the active layer or the specifie...
void Format(OUTPUTFORMATTER *out, int aNestLevel, int aCtl, CPTREE &aTree)
Function Format outputs a PTREE into s-expression format via an OUTPUTFORMATTER derivative.
Definition: ptree.cpp:205
int GetNet() const
Function GetNet.
Definition: netinfo.h:223
BOARD holds information pertinent to a Pcbnew printed circuit board.
Definition: class_board.h:180
void highlightNetOnBoard(NETINFO_ITEM *aNet) const
#define _(s)
Definition: 3d_actions.cpp:33
wxString UnescapeString(const wxString &aSource)
Definition: string.cpp:131
PCB_EDIT_FRAME is the main frame for Pcbnew.
virtual int Find(const wxString &aCandidate) const override
Return the location of a match iff a given candidate string matches the set pattern.
class VIA, a via (like a track segment on a copper layer)
Definition: typeinfo.h:97
BOARD * GetBoard() const
bool operator()(const CN_ITEM *a, int b) const
void onUnitsChanged(wxCommandEvent &event)
static const COLUMN_ID COLUMN_CHIP_LENGTH
void UpdateAllLayersColor()
Function UpdateAllLayersColor() Applies the new coloring scheme to all layers.
Definition: view.cpp:798
void onReport(wxCommandEvent &event) override
bool operator()(unsigned int a, NETINFO_ITEM *b) const
EDA_UNITS GetUserUnits() const
Return the user units currently in use.
wxString AddFileExtListToFilter(const std::vector< std::string > &aExts)
Build the wildcard extension file dialog wildcard filter to add to the base message dialog.