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-2020 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>
28 #include <class_board.h>
29 #include <class_track.h>
31 #include <eda_pattern_match.h>
33 #include <view/view_controls.h>
34 #include <pcb_painter.h>
37 #include <validators.h>
38 #include <bitmaps.h>
39 
41 {
42  int col_num;
43  wxString display_name;
44 
45  operator int() const
46  {
47  return col_num;
48  }
49 };
50 
51 #define def_col( c, num, name ) \
52  const DIALOG_SELECT_NET_FROM_LIST::COLUMN_ID DIALOG_SELECT_NET_FROM_LIST::c = { num, name }
53 
54 def_col( COLUMN_NET, 0, _( "Net" ) );
55 def_col( COLUMN_NAME, 1, _( "Name" ) );
56 def_col( COLUMN_PAD_COUNT, 2, _( "Pad Count" ) );
57 def_col( COLUMN_VIA_COUNT, 3, _( "Via Count" ) );
58 def_col( COLUMN_BOARD_LENGTH, 4, _( "Board Length" ) );
59 def_col( COLUMN_CHIP_LENGTH, 5, _( "Die Length" ) );
60 def_col( COLUMN_TOTAL_LENGTH, 6, _( "Length" ) );
61 
62 #undef def_col
63 
64 
66 {
67  LIST_ITEM( NETINFO_ITEM* aNet ) : m_net( aNet )
68  {
69  }
70 
72  int m_pad_count = 0;
73  int m_via_count = 0;
76  int m_total_length = 0;
77 };
78 
79 
81 {
83 
84  LIST_ITEM_NET_CMP_LESS( const std::vector<LIST_ITEM>& container )
85  : m_base_ptr( container.data() )
86  {
87  }
88 
89  bool operator()( unsigned int a, unsigned int b ) const
90  {
91  return m_base_ptr[a].m_net < m_base_ptr[b].m_net;
92  }
93 
94  bool operator()( unsigned int a, NETINFO_ITEM* b ) const
95  {
96  return m_base_ptr[a].m_net < b;
97  }
98 
99  bool operator()( NETINFO_ITEM* a, unsigned int b ) const
100  {
101  return a < m_base_ptr[b].m_net;
102  }
103 };
104 
105 
107 {
108  int row_num = -1;
111 
112  bool valid() const
113  {
114  return row_num != -1;
115  }
116 
117  explicit operator bool() const
118  {
119  return valid();
120  }
121 };
122 
123 
125  const SETTINGS& aSettings ) :
127  m_frame( aParent )
128 {
129  m_brd = aParent->GetBoard();
130  m_wasSelected = false;
131 
132 #define ADD_COL( name, flag, align ) m_netsList->AppendTextColumn( name, flag, 0, align, \
133  wxDATAVIEW_COL_RESIZABLE );
134 
135  ADD_COL( COLUMN_NET.display_name, wxDATAVIEW_CELL_INERT, wxALIGN_LEFT );
136  ADD_COL( COLUMN_NAME.display_name, wxDATAVIEW_CELL_INERT, wxALIGN_LEFT );
137  ADD_COL( COLUMN_PAD_COUNT.display_name, wxDATAVIEW_CELL_INERT, wxALIGN_CENTER );
138  ADD_COL( COLUMN_VIA_COUNT.display_name, wxDATAVIEW_CELL_INERT, wxALIGN_CENTER );
139  ADD_COL( COLUMN_BOARD_LENGTH.display_name, wxDATAVIEW_CELL_INERT, wxALIGN_CENTER );
140  ADD_COL( COLUMN_CHIP_LENGTH.display_name, wxDATAVIEW_CELL_INERT, wxALIGN_CENTER );
141  ADD_COL( COLUMN_TOTAL_LENGTH.display_name, wxDATAVIEW_CELL_INERT, wxALIGN_CENTER );
142 
143  // The fact that we're a list should keep the control from reserving space for the
144  // expander buttons... but it doesn't. Fix by forcing the indent to 0.
145  m_netsList->SetIndent( 0 );
146 
147  m_textCtrlFilter->SetValue( aSettings.filter_string );
148  m_cbShowZeroPad->SetValue( aSettings.show_zero_pad_nets );
149 
150  buildNetsList();
151 
153 
154  m_addNet->SetBitmap( KiBitmap( small_plus_xpm ) );
155  m_renameNet->SetBitmap( KiBitmap( small_edit_xpm ) );
156  m_deleteNet->SetBitmap( KiBitmap( trash_xpm ) );
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  m_frame->GetCanvas()->SetFocus();
191 }
192 
193 
195 {
196  return { m_textCtrlFilter->GetValue(), m_cbShowZeroPad->IsChecked() };
197 }
198 
199 
201 {
202  Close();
203  event.Skip();
204 }
205 
206 
207 void DIALOG_SELECT_NET_FROM_LIST::onUnitsChanged( wxCommandEvent& event )
208 {
209  this->m_units = m_frame->GetUserUnits();
210 
211  buildNetsList();
212  m_netsList->Refresh();
213 
214  event.Skip();
215 }
216 
217 
218 void DIALOG_SELECT_NET_FROM_LIST::onBoardChanged( wxCommandEvent& event )
219 {
220  if( m_brd != nullptr )
221  m_brd->RemoveListener( this );
222 
223  m_brd = m_frame->GetBoard();
224 
225  if( m_brd != nullptr )
226  m_brd->AddListener( this );
227 
228  m_wasSelected = false;
229 
230  buildNetsList();
231  m_netsList->Refresh();
232 
233  event.Skip();
234 }
235 
236 
238 {
239  // Note: the filtering is case insensitive.
240 
241  if( m_netFilter.GetPattern().IsEmpty() )
242  return true;
243 
244  return m_netFilter.Find( UnescapeString( aNet->GetNetname() ).Upper() )
246 }
247 
248 
250 {
251  bool operator()( const CN_ITEM* a, const CN_ITEM* b ) const
252  {
253  return a->Net() < b->Net();
254  }
255 
256  bool operator()( const CN_ITEM* a, int b ) const
257  {
258  return a->Net() < b;
259  }
260 
261  bool operator()( int a, const CN_ITEM* b ) const
262  {
263  return a < b->Net();
264  }
265 };
266 
267 
269 {
270  // pre-filter the connectivity items and sort them by netcode.
271  // this avoids quadratic runtime when building the whole net list and
272  // calculating the total length for each net.
273 
274  const auto type_bits = std::bitset<MAX_STRUCT_TYPE_ID>()
275  .set( PCB_TRACE_T )
276  .set( PCB_VIA_T )
277  .set( PCB_PAD_T );
278 
279  std::vector<CN_ITEM*> cn_items;
280  cn_items.reserve( 1024 );
281 
282  for( CN_ITEM* cn_item : m_brd->GetConnectivity()->GetConnectivityAlgo()->ItemList() )
283  {
284  if( cn_item->Valid() && type_bits[cn_item->Parent()->Type()] )
285  cn_items.push_back( cn_item );
286  }
287 
288  std::sort( cn_items.begin(), cn_items.end(), NETCODE_CMP_LESS() );
289 
290  return cn_items;
291 }
292 
293 
295 {
296  return findRow( m_brd->FindNet( aNetCode ) );
297 }
298 
299 
301 {
302  auto i = std::lower_bound( m_list_items_by_net.begin(), m_list_items_by_net.end(), aNet,
304 
305  if( i != m_list_items_by_net.end() && m_list_items[*i].m_net == aNet )
306  return { static_cast<int>( *i ), m_list_items.begin() + *i, i };
307  else
308  return {};
309 }
310 
311 
313 {
314  if( !aRow )
315  return;
316 
317  m_netsList->DeleteItem( aRow.row_num );
318  m_list_items.erase( aRow.by_row );
319 
320  std::iter_swap( aRow.by_net, m_list_items_by_net.end() - 1 );
321  m_list_items_by_net.pop_back();
322 
323  std::sort( m_list_items_by_net.begin(), m_list_items_by_net.end(),
325 }
326 
327 
329  wxString aVal )
330 {
331  if( aRow )
332  m_netsList->SetValue( aVal, aRow.row_num, aCol.col_num );
333 }
334 
335 
337 {
338  return wxString::Format( "%.3d", aNet->GetNet() );
339 }
340 
341 
343 {
344  return UnescapeString( aNet->GetNetname() );
345 }
346 
347 
348 wxString DIALOG_SELECT_NET_FROM_LIST::formatCount( unsigned int aValue ) const
349 {
350  return wxString::Format( "%u", aValue );
351 }
352 
353 
354 wxString DIALOG_SELECT_NET_FROM_LIST::formatLength( int aValue ) const
355 {
356  return MessageTextFromValue( GetUserUnits(), aValue );
357 }
358 
359 
361 {
362  if( NETINFO_ITEM* net = dynamic_cast<NETINFO_ITEM*>( aBoardItem ) )
363  {
364  // a new net has been added to the board. add it to our list if it
365  // passes the netname filter test.
366  if( netFilterMatches( net ) )
367  {
368  m_list_items.emplace_back( net );
369  m_list_items_by_net.push_back( m_list_items.size() - 1 );
370 
371  std::sort( m_list_items_by_net.begin(), m_list_items_by_net.end(),
373 
374  LIST_ITEM& new_i = m_list_items.back();
375  new_i.m_pad_count = m_brd->GetNodesCount( net->GetNet() );
376 
377  wxVector<wxVariant> new_row( 7 );
378  new_row[COLUMN_NET] = formatNetCode( net );
379  new_row[COLUMN_NAME] = formatNetName( net );
380  new_row[COLUMN_PAD_COUNT] = formatCount( new_i.m_pad_count );
381  new_row[COLUMN_VIA_COUNT] = formatCount( new_i.m_via_count );
382  new_row[COLUMN_BOARD_LENGTH] = formatLength( new_i.m_board_wire_length );
383  new_row[COLUMN_CHIP_LENGTH] = formatLength( new_i.m_chip_wire_length );
384  new_row[COLUMN_TOTAL_LENGTH] = formatLength( new_i.m_total_length );
385 
386  m_netsList->AppendItem( new_row );
387  }
388 
389  return;
390  }
391  else if( BOARD_CONNECTED_ITEM* i = dynamic_cast<BOARD_CONNECTED_ITEM*>( aBoardItem ) )
392  {
393  const ROW_DESC& r = findRow( i->GetNet() );
394 
395  if( r )
396  {
397  // try to handle frequent operations quickly.
398  if( TRACK* track = dynamic_cast<TRACK*>( i ) )
399  {
400  int len = track->GetLength();
401  r.by_row->m_board_wire_length += len;
402  r.by_row->m_total_length += len;
403 
404  setValue( r, COLUMN_BOARD_LENGTH, formatLength( r.by_row->m_board_wire_length ) );
405  setValue( r, COLUMN_TOTAL_LENGTH, formatLength( r.by_row->m_total_length ) );
406 
407  if( track->Type() == PCB_VIA_T )
408  {
409  r.by_row->m_via_count += 1;
410  setValue( r, COLUMN_VIA_COUNT, formatCount( r.by_row->m_via_count ) );
411  }
412 
413  return;
414  }
415  }
416 
417  // resort to generic slower net update otherwise.
418  updateNet( i->GetNet() );
419  }
420 }
421 
422 
424 {
425  if( NETINFO_ITEM* net = dynamic_cast<NETINFO_ITEM*>( aBoardItem ) )
426  {
427  deleteRow( findRow( net ) );
428  return;
429  }
430  else if( MODULE* mod = dynamic_cast<MODULE*>( aBoardItem ) )
431  {
432  for( const D_PAD* pad : mod->Pads() )
433  {
434  const ROW_DESC& r = findRow( pad->GetNet() );
435 
436  if( r )
437  {
438  r.by_row->m_pad_count -= 1;
439 
440  if( r.by_row->m_pad_count == 0 && !m_cbShowZeroPad->IsChecked() )
441  deleteRow( r );
442  else
443  setValue( r, COLUMN_PAD_COUNT, formatCount( r.by_row->m_pad_count ) );
444  }
445  }
446  }
447  else if( BOARD_CONNECTED_ITEM* i = dynamic_cast<BOARD_CONNECTED_ITEM*>( aBoardItem ) )
448  {
449  const ROW_DESC& r = findRow( i->GetNet() );
450 
451  if( r )
452  {
453  // try to handle frequent operations quickly.
454  if( TRACK* track = dynamic_cast<TRACK*>( i ) )
455  {
456  int len = track->GetLength();
457  r.by_row->m_board_wire_length -= len;
458  r.by_row->m_total_length -= len;
459 
460  setValue( r, COLUMN_BOARD_LENGTH, formatLength( r.by_row->m_board_wire_length ) );
461  setValue( r, COLUMN_TOTAL_LENGTH, formatLength( r.by_row->m_total_length ) );
462 
463  if( track->Type() == PCB_VIA_T )
464  {
465  r.by_row->m_via_count -= 1;
466  setValue( r, COLUMN_VIA_COUNT, formatCount( r.by_row->m_via_count ) );
467  }
468 
469  return;
470  }
471 
472  // resort to generic slower net update otherwise.
473  updateNet( i->GetNet() );
474  }
475  }
476 }
477 
478 
480 {
481  if( dynamic_cast<BOARD_CONNECTED_ITEM*>( aBoardItem ) != nullptr
482  || dynamic_cast<MODULE*>( aBoardItem ) != nullptr )
483  {
484  buildNetsList();
485  m_netsList->Refresh();
486  }
487 }
488 
489 
491 {
492  if( !m_brd->IsHighLightNetON() )
493  m_netsList->UnselectAll();
494  else if( !m_brd->GetHighLightNetCodes().empty() )
496 }
497 
498 
500 {
501  buildNetsList();
502  m_netsList->Refresh();
503 }
504 
505 
507 {
508  // something for the specified net has changed, update that row.
509  if( !netFilterMatches( aNet ) )
510  return;
511 
512  // if the net had no pads before, it might not be in the displayed list yet.
513  // if it had pads and now doesn't anymore, we might need to remove it from the list.
514 
515  auto cur_net_row = findRow( aNet );
516 
517  const unsigned int node_count = m_brd->GetNodesCount( aNet->GetNet() );
518 
519  if( node_count == 0 && !m_cbShowZeroPad->IsChecked() )
520  {
521  deleteRow( cur_net_row );
522  return;
523  }
524 
525  std::vector<CN_ITEM*> all_cn_items = relevantConnectivityItems();
526 
527  LIST_ITEM list_item( aNet );
528  list_item.m_pad_count = node_count;
529 
530  const auto cn_items = std::equal_range( all_cn_items.begin(), all_cn_items.end(),
531  aNet->GetNet(), NETCODE_CMP_LESS() );
532 
533  for( auto i = cn_items.first; i != cn_items.second; ++i )
534  {
535  BOARD_CONNECTED_ITEM* item = ( *i )->Parent();
536 
537  if( item->Type() == PCB_PAD_T )
538  list_item.m_chip_wire_length += static_cast<D_PAD*>( item )->GetPadToDieLength();
539 
540  else if( TRACK* track = dynamic_cast<TRACK*>( item ) )
541  {
542  list_item.m_board_wire_length += track->GetLength();
543 
544  if( item->Type() == PCB_VIA_T )
545  list_item.m_via_count += 1;
546  }
547  }
548 
549  list_item.m_total_length = list_item.m_board_wire_length + list_item.m_chip_wire_length;
550 
551  if( !cur_net_row )
552  {
553  m_list_items.push_back( list_item );
554  m_list_items_by_net.push_back( m_list_items.size() - 1 );
555  std::sort( m_list_items_by_net.begin(), m_list_items_by_net.end(),
557 
558  wxVector<wxVariant> new_row( 7 );
559  new_row[COLUMN_NET] = formatNetCode( aNet );
560  new_row[COLUMN_NAME] = formatNetName( aNet );
561  new_row[COLUMN_PAD_COUNT] = formatCount( list_item.m_pad_count );
562  new_row[COLUMN_VIA_COUNT] = formatCount( list_item.m_via_count );
563  new_row[COLUMN_BOARD_LENGTH] = formatLength( list_item.m_board_wire_length );
564  new_row[COLUMN_CHIP_LENGTH] = formatLength( list_item.m_chip_wire_length );
565  new_row[COLUMN_TOTAL_LENGTH] = formatLength( list_item.m_total_length );
566 
567  m_netsList->AppendItem( new_row );
568  }
569  else
570  {
571  *cur_net_row.by_row = list_item;
572 
573  setValue( cur_net_row, COLUMN_PAD_COUNT, formatCount( list_item.m_pad_count ) );
574  setValue( cur_net_row, COLUMN_VIA_COUNT, formatCount( list_item.m_via_count ) );
575  setValue( cur_net_row, COLUMN_BOARD_LENGTH, formatLength( list_item.m_board_wire_length ) );
576  setValue( cur_net_row, COLUMN_CHIP_LENGTH, formatLength( list_item.m_chip_wire_length ) );
577  setValue( cur_net_row, COLUMN_TOTAL_LENGTH, formatLength( list_item.m_total_length ) );
578  }
579 }
580 
581 
583 {
584  // when rebuilding the netlist, try to keep the row selection
585  const int prev_selected_row = m_netsList->GetSelectedRow();
586  const int prev_selected_netcode =
587  prev_selected_row >= 0 ? m_list_items[prev_selected_row].m_net->GetNet() : -1;
588 
589  m_netsList->DeleteAllItems();
590  m_list_items.clear();
591 
592  std::vector<CN_ITEM*> prefiltered_cn_items = relevantConnectivityItems();
593 
594  // collect all nets which pass the filter string.
595 
596  struct NET_INFO
597  {
598  int netcode;
599  NETINFO_ITEM* net;
600  unsigned int pad_count;
601  };
602 
603  struct NET_INFO_CMP_LESS
604  {
605  bool operator()( const NET_INFO& a, const NET_INFO& b ) const
606  {
607  return a.netcode < b.netcode;
608  }
609  bool operator()( const NET_INFO& a, int b ) const
610  {
611  return a.netcode < b;
612  }
613  bool operator()( int a, const NET_INFO& b ) const
614  {
615  return a < b.netcode;
616  }
617  };
618 
619  std::vector<NET_INFO> nets;
620  nets.reserve( m_brd->GetNetInfo().NetsByNetcode().size() );
621 
622  for( const std::pair<const int, NETINFO_ITEM*>& ni : m_brd->GetNetInfo().NetsByNetcode() )
623  {
624  if( netFilterMatches( ni.second ) )
625  nets.emplace_back( NET_INFO{ ni.first, ni.second, 0 } );
626  }
627 
628  // count the pads for each net. since the nets are sorted by netcode
629  // this way around is faster than using counting pads for each net.
630 
631  for( MODULE* mod : m_brd->Modules() )
632  {
633  for( D_PAD* pad : mod->Pads() )
634  {
635  auto i = std::lower_bound( nets.begin(), nets.end(), pad->GetNetCode(),
636  NET_INFO_CMP_LESS() );
637 
638  if( i != nets.end() && i->netcode == pad->GetNetCode() )
639  i->pad_count += 1;
640  }
641  }
642 
643  for( NET_INFO& ni : nets )
644  {
645  if( !m_cbShowZeroPad->IsChecked() && ni.pad_count == 0 )
646  continue;
647 
648  m_list_items.emplace_back( ni.net );
649  LIST_ITEM& list_item = m_list_items.back();
650 
651  const auto cn_items = std::equal_range( prefiltered_cn_items.begin(),
652  prefiltered_cn_items.end(), ni.netcode, NETCODE_CMP_LESS() );
653 
654  for( auto i = cn_items.first; i != cn_items.second; ++i )
655  {
656  BOARD_CONNECTED_ITEM* item = ( *i )->Parent();
657 
658  if( item->Type() == PCB_PAD_T )
659  list_item.m_chip_wire_length += static_cast<D_PAD*>( item )->GetPadToDieLength();
660 
661  else if( TRACK* track = dynamic_cast<TRACK*>( item ) )
662  {
663  list_item.m_board_wire_length += track->GetLength();
664 
665  if( track->Type() == PCB_VIA_T )
666  list_item.m_via_count += 1;
667  }
668  }
669 
670  list_item.m_pad_count = ni.pad_count;
671  list_item.m_total_length = list_item.m_board_wire_length + list_item.m_chip_wire_length;
672  }
673 
674  wxVector<wxVariant> dataLine;
675  dataLine.resize( 7 );
676 
677  for( LIST_ITEM& i : m_list_items )
678  {
679  dataLine[COLUMN_NET] = formatNetCode( i.m_net );
680  dataLine[COLUMN_NAME] = formatNetName( i.m_net );
681  dataLine[COLUMN_PAD_COUNT] = formatCount( i.m_pad_count );
682  dataLine[COLUMN_VIA_COUNT] = formatCount( i.m_via_count );
683  dataLine[COLUMN_BOARD_LENGTH] = formatLength( i.m_board_wire_length );
684  dataLine[COLUMN_CHIP_LENGTH] = formatLength( i.m_chip_wire_length );
685  dataLine[COLUMN_TOTAL_LENGTH] = formatLength( i.m_total_length );
686 
687  m_netsList->AppendItem( dataLine );
688  }
689 
690  m_list_items_by_net.clear();
691  m_list_items_by_net.reserve( m_list_items.size() );
692 
693  for( unsigned int i = 0; i < m_list_items.size(); ++i )
694  m_list_items_by_net.push_back( i );
695 
696  std::sort( m_list_items_by_net.begin(), m_list_items_by_net.end(),
698 
699  if( prev_selected_netcode == -1 )
700  m_wasSelected = false;
701  else
702  {
703  const ROW_DESC& r = findRow( prev_selected_netcode );
704 
705  if( r )
706  {
707  m_selection = r.by_row->m_net->GetNetname();
708  m_wasSelected = true;
709 
710  wxDataViewItem i = m_netsList->RowToItem( r.row_num );
711  m_netsList->Select( i );
712  m_netsList->EnsureVisible( i );
713  }
714  }
715 }
716 
717 
719 {
720  const ROW_DESC& r = findRow( aNet );
721 
722  if( r )
723  {
724  wxDataViewItem i = m_netsList->RowToItem( r.row_num );
725  m_netsList->Select( i );
726  m_netsList->EnsureVisible( i );
727  }
728  else
729  m_netsList->UnselectAll();
730 }
731 
732 
734 {
735  int netCode = aNet != nullptr ? aNet->GetNet() : -1;
736 
738  render->SetHighlight( netCode >= 0, netCode );
739 
741  m_frame->GetCanvas()->Refresh();
742 }
743 
744 
745 void DIALOG_SELECT_NET_FROM_LIST::onFilterChange( wxCommandEvent& event )
746 {
747  m_netFilter.SetPattern( m_textCtrlFilter->GetValue().Upper() );
748  buildNetsList();
749 }
750 
751 
753 {
754  int selected_row = m_netsList->GetSelectedRow();
755 
756  if( selected_row >= 0 && selected_row < static_cast<int>( m_list_items.size() ) )
757  {
758  NETINFO_ITEM* net = m_list_items[selected_row].m_net;
759 
760  m_selection = net->GetNetname();
761  m_wasSelected = true;
762  highlightNetOnBoard( net );
763  return;
764  }
765 
766  highlightNetOnBoard( nullptr );
767  m_wasSelected = false;
768 }
769 
770 
772 {
773  int w0, w1, w2, w3, w4, w5, w6;
774 
781  wxClientDC dc( GetParent() );
782  int h, minw, minw_col0;
783 
784  dc.GetTextExtent( COLUMN_NET.display_name, &w0, &h );
785  dc.GetTextExtent( COLUMN_PAD_COUNT.display_name, &w2, &h );
786  dc.GetTextExtent( COLUMN_VIA_COUNT.display_name, &w3, &h );
787  dc.GetTextExtent( COLUMN_BOARD_LENGTH.display_name, &w4, &h );
788  dc.GetTextExtent( COLUMN_CHIP_LENGTH.display_name, &w5, &h );
789  dc.GetTextExtent( COLUMN_TOTAL_LENGTH.display_name, &w6, &h );
790  dc.GetTextExtent( "00000,000 mm", &minw, &h );
791  dc.GetTextExtent( "00000", &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 = w2 + 10;
797  w3 = w3 + 10;
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 - 24;
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( "MMMMMMMMMMMMMMMM", &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::onAddNet( wxCommandEvent& aEvent )
838 {
839  wxString newNetName;
840  NETNAME_VALIDATOR validator( &newNetName );
841 
842  WX_TEXT_ENTRY_DIALOG dlg( this, _( "Net name:" ), _( "New Net" ), newNetName );
843  dlg.SetTextValidator( validator );
844 
845  while( true )
846  {
847  if( dlg.ShowModal() != wxID_OK || dlg.GetValue().IsEmpty() )
848  return; //Aborted by user
849 
850  newNetName = dlg.GetValue();
851 
852  if( m_brd->FindNet( newNetName ) )
853  {
854  DisplayError( this, wxString::Format( _( "Net name '%s' is already in use." ),
855  newNetName ) );
856  newNetName = wxEmptyString;
857  }
858  else
859  {
860  break;
861  }
862  }
863 
864  NETINFO_ITEM *newnet = new NETINFO_ITEM( m_brd, dlg.GetValue(), 0 );
865 
866  m_brd->Add( newnet );
867  m_frame->OnModify();
868 
869  // We'll get an OnBoardItemChanged callback from this to update our listbox
870 }
871 
872 
873 void DIALOG_SELECT_NET_FROM_LIST::onRenameNet( wxCommandEvent& aEvent )
874 {
875  int selected_row = m_netsList->GetSelectedRow();
876 
877  if( selected_row >= 0 && selected_row < static_cast<int>( m_list_items.size() ) )
878  {
879  NETINFO_ITEM* net = m_list_items[selected_row].m_net;
880  wxString fullNetName = net->GetNetname();
881  wxString netPath;
882  wxString shortNetName;
883 
884  if( fullNetName.Contains( "/" ) )
885  {
886  netPath = fullNetName.BeforeLast( '/' ) + '/';
887  shortNetName = fullNetName.AfterLast( '/' );
888  }
889  else
890  {
891  shortNetName = fullNetName;
892  }
893 
894  wxString unescapedShortName = UnescapeString( shortNetName );
895 
896  WX_TEXT_ENTRY_DIALOG dlg( this, _( "Net name:" ), _( "Rename Net" ), unescapedShortName );
897  NETNAME_VALIDATOR validator( &unescapedShortName );
898  dlg.SetTextValidator( validator );
899 
900  while( true )
901  {
902  if( dlg.ShowModal() != wxID_OK || dlg.GetValue() == unescapedShortName )
903  return;
904 
905  unescapedShortName = dlg.GetValue();
906 
907  if( unescapedShortName.IsEmpty() )
908  {
909  DisplayError( this, wxString::Format( _( "Net name cannot be empty." ),
910  unescapedShortName ) );
911  continue;
912  }
913 
914  shortNetName = EscapeString( unescapedShortName, CTX_NETNAME );
915  fullNetName = netPath + shortNetName;
916 
917  if( m_brd->FindNet( shortNetName ) || m_brd->FindNet( fullNetName ) )
918  {
919  DisplayError( this, wxString::Format( _( "Net name '%s' is already in use." ),
920  unescapedShortName ) );
921  unescapedShortName = wxEmptyString;
922  }
923  else
924  {
925  break;
926  }
927  }
928 
929  net->SetNetname( fullNetName );
930  m_frame->OnModify();
931 
932  buildNetsList();
933  m_netsList->Refresh();
934 
935  // Currently only tracks and pads have netname annotations and need to be redrawn,
936  // but zones are likely to follow. Since we don't have a way to ask what is current,
937  // just refresh all items.
939  m_frame->GetCanvas()->Refresh();
940  }
941 }
942 
943 
944 void DIALOG_SELECT_NET_FROM_LIST::onDeleteNet( wxCommandEvent& aEvent )
945 {
946  int selected_row = m_netsList->GetSelectedRow();
947 
948  if( selected_row >= 0 && selected_row < static_cast<int>( m_list_items.size() ) )
949  {
950  NETINFO_ITEM* net = m_list_items[selected_row].m_net;
951 
952  if( m_list_items[selected_row].m_pad_count > 0 )
953  {
954  if( !IsOK( this, _( "Net is in use. Delete anyway?" ) ) )
955  return;
956  }
957 
958  m_brd->Remove( net );
959  m_frame->OnModify();
960 
961  // We'll get an OnBoardItemChanged callback from this to update our listbox
962  }
963 }
964 
965 
966 void DIALOG_SELECT_NET_FROM_LIST::onReport( wxCommandEvent& aEvent )
967 {
968  wxFileDialog dlg( this, _( "Report file" ), "", "",
969  _( "Report file" ) + AddFileExtListToFilter( { "csv" } ),
970  wxFD_SAVE );
971 
972  if( dlg.ShowModal() == wxID_CANCEL )
973  return;
974 
975  wxTextFile f( dlg.GetPath() );
976 
977  f.Create();
978 
979  int rows = m_netsList->GetItemCount();
980  wxString txt;
981 
982  // Print Header:
983  txt.Printf( "\"%s\";\"%s\";\"%s\";\"%s\";\"%s\";\"%s\";\"%s\";",
984  _( "Net Id" ), _( "Net name" ),
985  _( "Pad count" ), _( "Via count" ),
986  _( "Board length" ), _( "Die length" ), _( "Net length" ) );
987  f.AddLine( txt );
988 
989  // Print list of nets:
990  for( int row = 1; row < rows; row++ )
991  {
992  txt.Printf( "%s;\"%s\";%s;%s;%s;%s;%s;",
993  m_netsList->GetTextValue( row, COLUMN_NET ),
994  m_netsList->GetTextValue( row, COLUMN_NAME ),
995  m_netsList->GetTextValue( row, COLUMN_PAD_COUNT ),
996  m_netsList->GetTextValue( row, COLUMN_VIA_COUNT ),
997  m_netsList->GetTextValue( row, COLUMN_BOARD_LENGTH ),
998  m_netsList->GetTextValue( row, COLUMN_CHIP_LENGTH ),
999  m_netsList->GetTextValue( row, COLUMN_TOTAL_LENGTH ) );
1000 
1001  f.AddLine( txt );
1002  }
1003 
1004  f.Write();
1005  f.Close();
1006 }
decltype(DIALOG_SELECT_NET_FROM_LIST::m_list_items_by_net) ::iterator by_net
#define connect_event(e, f)
void DisplayError(wxWindow *aParent, const wxString &aText, int aDisplayTime)
Display an error or warning message box with aMessage.
Definition: confirm.cpp:239
const BITMAP_OPAQUE trash_xpm[1]
Definition: trash.cpp:46
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.
void OnModify() override
Function OnModify must be called after a board change to set the modified flag.
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:474
VIEW_CONTROLS class definition.
virtual void OnBoardItemAdded(BOARD &aBoard, BOARD_ITEM *aBoardItem) override
bool IsHighLightNetON() const
Function IsHighLightNetON.
Definition: class_board.h:400
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 SetTextValidator(wxTextValidatorStyle style)
void FinishDialogSettings()
In all dialogs, we must call the same functions to fix minimal dlg size, the default position and per...
void UpdateAllItems(int aUpdateFlags)
Updates all items in the view according to the given flags.
Definition: view.cpp:1435
virtual void OnBoardItemRemoved(BOARD &aBoard, BOARD_ITEM *aBoardItem) override
const NETINFO_LIST & GetNetInfo() const
Definition: class_board.h:713
class D_PAD, a pad in a footprint
Definition: typeinfo.h:90
void onListSize(wxSizeEvent &event) override
void onAddNet(wxCommandEvent &event) override
virtual wxString const & GetPattern() const override
Return the pattern passed to SetPattern().
BOARD_CONNECTED_ITEM is a base class derived from BOARD_ITEM for items that can be connected and have...
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)
wxBitmap KiBitmap(BITMAP_DEF aBitmap)
Construct a wxBitmap from a memory record, held in a BITMAP_DEF.
Definition: bitmap.cpp:80
void onDeleteNet(wxCommandEvent &event) override
wxString formatCount(unsigned int aValue) const
void Add(BOARD_ITEM *aItem, ADD_MODE aMode=ADD_MODE::INSERT) override
Adds an item to the container.
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)
Item is being added to the view.
Definition: view_item.h:62
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:249
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:345
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
virtual void SetFocus() override
void onRenameNet(wxCommandEvent &event) override
static const int EDA_PATTERN_NOT_FOUND
void SetNetname(const wxString &aNewName)
Function SetNetname Sets the long netname to aNetName, and the short netname to the last token in the...
Definition: netinfo.h:244
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:383
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.
#define ADD_COL(name, flag, align)
bool GetNetName(wxString &aName) const
virtual void OnBoardNetSettingsChanged(BOARD &aBoard) override
const BITMAP_OPAQUE small_edit_xpm[1]
Definition: small_edit.cpp:26
NETINFO_ITEM handles the data for a net.
Definition: netinfo.h:65
wxString GetValue()
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:201
int GetNet() const
Function GetNet.
Definition: netinfo.h:223
BOARD holds information pertinent to a Pcbnew printed circuit board.
Definition: class_board.h:178
void highlightNetOnBoard(NETINFO_ITEM *aNet) const
#define _(s)
Definition: 3d_actions.cpp:33
wxString UnescapeString(const wxString &aSource)
Definition: string.cpp:152
wxString EscapeString(const wxString &aSource, ESCAPE_CONTEXT aContext)
These Escape/Unescape routines use HTML-entity-reference-style encoding to handle characters which ar...
Definition: string.cpp:77
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:794
void onReport(wxCommandEvent &event) override
bool IsOK(wxWindow *aParent, const wxString &aMessage)
Display a yes/no dialog with aMessage and returns the user response.
Definition: confirm.cpp:283
const BITMAP_OPAQUE small_plus_xpm[1]
Definition: small_plus.cpp:20
Custom text control validator definitions.
bool operator()(unsigned int a, NETINFO_ITEM *b) const
void Remove(BOARD_ITEM *aBoardItem) override
Removes an item from the container.
EDA_UNITS GetUserUnits() const
Return the user units currently in use.
KICAD_T Type() const
Function Type()
Definition: base_struct.h:193
wxString AddFileExtListToFilter(const std::vector< std::string > &aExts)
Build the wildcard extension file dialog wildcard filter to add to the base message dialog.