KiCad PCB EDA Suite
dialog_lib_edit_pin_table.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) 1992-2016 KiCad Developers, see AUTHORS.txt for contributors.
5  *
6  * This program is free software; you can redistribute it and/or
7  * modify it under the terms of the GNU General Public License
8  * as published by the Free Software Foundation; either version 2
9  * of the License, or (at your option) any later version.
10  *
11  * This program is distributed in the hope that it will be useful,
12  * but WITHOUT ANY WARRANTY; without even the implied warranty of
13  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
14  * GNU General Public License for more details.
15  *
16  * You should have received a copy of the GNU General Public License
17  * along with this program; if not, you may find one here:
18  * http://www.gnu.org/licenses/old-licenses/gpl-2.0.html
19  * or you may search the http://www.gnu.org website for the version 2 license,
20  * or you may write to the Free Software Foundation, Inc.,
21  * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA
22  */
23 
25 #include "lib_pin.h"
26 #include "pin_number.h"
27 
28 #include <boost/algorithm/string/join.hpp>
29 #include <queue>
30 #include <list>
31 #include <map>
32 
33 /* Avoid wxWidgets bug #16906 -- http://trac.wxwidgets.org/ticket/16906
34  *
35  * If multiple elements live in the root of a wxDataViewCtrl, using
36  * ItemsAdded() can run into an assertion failure. To avoid this, we avoid
37  * notifying the widget of changes, but rather reinitialize it.
38  *
39  * When a fix for this exists in wxWidgets, this is the place to turn it
40  * off.
41  */
42 #define REASSOCIATE_HACK
43 
45  public wxDataViewModel
46 {
47 public:
48  DataViewModel( LIB_PART& aPart );
49 
50  // wxDataViewModel
51  virtual unsigned int GetColumnCount() const override;
52  virtual wxString GetColumnType( unsigned int col ) const override;
53  virtual void GetValue( wxVariant&, const wxDataViewItem&, unsigned int ) const override;
54  virtual bool SetValue( const wxVariant&, const wxDataViewItem&, unsigned int ) override;
55  virtual wxDataViewItem GetParent( const wxDataViewItem& ) const override;
56  virtual bool IsContainer( const wxDataViewItem& ) const override;
57  virtual bool HasContainerColumns( const wxDataViewItem& ) const override;
58  virtual unsigned int GetChildren( const wxDataViewItem&, wxDataViewItemArray& ) const override;
59 
60  virtual int Compare( const wxDataViewItem& lhs,
61  const wxDataViewItem& rhs,
62  unsigned int col,
63  bool ascending ) const override;
64 
65  void SetGroupingColumn( int aCol );
66  void CalculateGrouping();
67  void Refresh();
68 
70 
71 #ifdef REASSOCIATE_HACK
72  void SetWidget( wxDataViewCtrl* aWidget ) { m_Widget = aWidget; }
73 #endif
74 
75  enum
76  {
77  NONE = -1,
79  PIN_NAME = 1,
80  PIN_TYPE = 2,
82  };
83 
84 private:
89 
90  class Item;
91  class Group;
92  class Pin;
93 
94  mutable std::list<Pin> m_Pins;
95  mutable std::map<wxString, Group> m_Groups;
96 
97  // like GetValue, but always returns a string
98  wxString GetString( const wxDataViewItem&, unsigned int ) const;
99 
100 #ifdef REASSOCIATE_HACK
101  wxDataViewCtrl* m_Widget;
102 #endif
103 };
104 
106 {
107 public:
108  virtual void GetValue( wxVariant& aValue, unsigned int aCol ) const = 0;
109  virtual wxString GetString( unsigned int aCol ) const = 0;
110  virtual wxDataViewItem GetParent() const = 0;
111  virtual bool IsContainer() const = 0;
112  virtual unsigned int GetChildren( wxDataViewItemArray& ) const = 0;
113 };
114 
116  public Item
117 {
118 public:
119  Group( unsigned int aGroupingColumn ) : m_GroupingColumn( aGroupingColumn ) {}
120 
121  virtual void GetValue( wxVariant& aValue, unsigned int aCol ) const override;
122  virtual wxString GetString( unsigned int aCol ) const override;
123  virtual wxDataViewItem GetParent() const override { return wxDataViewItem(); }
124  virtual bool IsContainer() const override { return true; }
125  virtual unsigned int GetChildren( wxDataViewItemArray& aItems ) const override
126  {
128  for( std::list<Pin*>::const_iterator i = m_Members.begin(); i != m_Members.end(); ++i )
129  aItems.push_back( wxDataViewItem( *i ) );
130 
131  return aItems.size();
132  }
133 
134  unsigned int GetCount() const { return m_Members.size(); }
135  void Add( Pin* aPin );
136 
137 private:
138  std::list<Pin*> m_Members;
139  unsigned int m_GroupingColumn;
140 };
141 
143  public Item
144 {
145 public:
146  Pin( DataViewModel& aModel,
147  LIB_PIN* aBacking ) : m_Model( aModel ), m_Backing( aBacking ), m_Group( 0 ) {}
148 
149  virtual void GetValue( wxVariant& aValue, unsigned int aCol ) const override;
150  virtual wxString GetString( unsigned int aCol ) const override;
151  virtual wxDataViewItem GetParent() const override { return wxDataViewItem( m_Group ); }
152  virtual bool IsContainer() const override { return false; }
153  virtual unsigned int GetChildren( wxDataViewItemArray& ) const override { return 0; }
154 
155  void SetGroup( Group* aGroup ) { m_Group = aGroup; }
156 
157  static bool Compare( const Pin& lhs, const Pin& rhs )
158  {
159  return PinNumbers::Compare( lhs.m_Backing->GetNumber(), rhs.m_Backing->GetNumber() ) < 0;
160  }
161 
162 private:
166 };
167 
169  LIB_PART& aPart ) :
171  m_Model( new DataViewModel( aPart ) )
172 {
173 #ifdef REASSOCIATE_HACK
174  m_Model->SetWidget( m_Pins );
175 #endif
176  m_Pins->AssociateModel( m_Model.get() );
177 
179  wxDataViewTextRenderer* rend0 = new wxDataViewTextRenderer( wxT( "string" ), wxDATAVIEW_CELL_INERT );
180  wxDataViewColumn* col0 = new wxDataViewColumn( _( "Number" ),
181  rend0,
183  100,
184  wxAlignment( wxALIGN_LEFT | wxALIGN_TOP ),
185  wxDATAVIEW_COL_RESIZABLE | wxDATAVIEW_COL_SORTABLE );
186  wxDataViewTextRenderer* rend1 = new wxDataViewTextRenderer( wxT( "string" ), wxDATAVIEW_CELL_INERT );
187  wxDataViewColumn* col1 = new wxDataViewColumn( _( "Name" ),
188  rend1,
190  100,
191  wxAlignment( wxALIGN_LEFT | wxALIGN_TOP ),
192  wxDATAVIEW_COL_RESIZABLE | wxDATAVIEW_COL_SORTABLE );
193  wxDataViewIconTextRenderer* rend2 = new wxDataViewIconTextRenderer( wxT( "wxDataViewIconText" ), wxDATAVIEW_CELL_INERT );
194  wxDataViewColumn* col2 = new wxDataViewColumn( _( "Type" ),
195  rend2,
197  100,
198  wxAlignment( wxALIGN_LEFT | wxALIGN_TOP ),
199  wxDATAVIEW_COL_RESIZABLE | wxDATAVIEW_COL_SORTABLE );
200  wxDataViewTextRenderer* rend3 = new wxDataViewTextRenderer( wxT( "string" ), wxDATAVIEW_CELL_INERT );
201  wxDataViewColumn* col3 = new wxDataViewColumn( _( "Position" ),
202  rend3,
204  100,
205  wxAlignment( wxALIGN_LEFT | wxALIGN_TOP ),
206  wxDATAVIEW_COL_RESIZABLE | wxDATAVIEW_COL_SORTABLE );
207  m_Pins->AppendColumn( col0 );
208  m_Pins->SetExpanderColumn( col0 );
209  m_Pins->AppendColumn( col1 );
210  m_Pins->AppendColumn( col2 );
211  m_Pins->AppendColumn( col3 );
212 
213  UpdateSummary();
214 
215  GetSizer()->SetSizeHints(this);
216  Centre();
217 }
218 
219 
221 {
222 }
223 
224 
226 {
227  PinNumbers pins = m_Model->GetAllPinNumbers();
228 
229  m_Summary->SetValue( pins.GetSummary() );
230 }
231 
232 
234 {
235  m_Model->SetGroupingColumn( event.GetDataViewColumn()->GetModelColumn() );
236  event.Skip();
237 }
238 
239 
241  m_Part( aPart ),
242  m_GroupingColumn( 1 ),
243  m_UnitCount( m_Part.GetUnitCount() )
244 {
245 #ifdef REASSOCIATE_HACK
246  m_Widget = NULL;
247 #endif
248  aPart.GetPins( m_Backing );
250  for( LIB_PINS::const_iterator i = m_Backing.begin(); i != m_Backing.end(); ++i )
251  m_Pins.push_back( Pin( *this, *i ) );
252 
253  m_Pins.sort(Pin::Compare);
254 
256 }
257 
258 
260 {
261  return 4;
262 }
263 
264 
266 {
267  switch( aCol )
268  {
269  case PIN_NUMBER:
270  return wxT( "string" );
271 
272  case PIN_NAME:
273  return wxT( "string" );
274 
275  case PIN_TYPE:
276  return wxT( "wxDataViewIconText" );
277 
278  case PIN_POSITION:
279  return wxT( "string" );
280  }
281 
282  assert( ! "Unhandled column" );
283  return wxT( "" );
284 }
285 
286 
288  const wxDataViewItem& aItem,
289  unsigned int aCol ) const
290 {
291  assert( aItem.IsOk() );
292 
293  reinterpret_cast<Item const*>( aItem.GetID() )->GetValue( aVal, aCol );
294 }
295 
296 
298  const wxDataViewItem&,
299  unsigned int )
300 {
301  return false;
302 }
303 
304 
305 wxDataViewItem DIALOG_LIB_EDIT_PIN_TABLE::DataViewModel::GetParent( const wxDataViewItem& aItem )
306 const
307 {
308  assert( aItem.IsOk() );
309 
310  return reinterpret_cast<Item const*>( aItem.GetID() )->GetParent();
311 }
312 
313 
314 bool DIALOG_LIB_EDIT_PIN_TABLE::DataViewModel::IsContainer( const wxDataViewItem& aItem ) const
315 {
316  if( aItem.IsOk() )
317  return reinterpret_cast<Item const*>( aItem.GetID() )->IsContainer();
318  else
319  return true;
320 }
321 
322 
324 {
325  return true;
326 }
327 
328 
329 unsigned int DIALOG_LIB_EDIT_PIN_TABLE::DataViewModel::GetChildren( const wxDataViewItem& aItem,
330  wxDataViewItemArray& aItems ) const
331 {
332  if( !aItem.IsOk() )
333  {
334  for( std::map<wxString, Group>::iterator i = m_Groups.begin(); i != m_Groups.end(); ++i )
335  if( i->second.GetCount() > 1 )
336  aItems.push_back( wxDataViewItem( &i->second ) );
337 
338  for( std::list<Pin>::iterator i = m_Pins.begin(); i != m_Pins.end(); ++i )
339  if( !i->GetParent().IsOk() )
340  aItems.push_back( wxDataViewItem( &*i ) );
341 
342  return aItems.size();
343  }
344  else
345  return reinterpret_cast<Item const*>( aItem.GetID() )->GetChildren( aItems );
346 }
347 
348 
349 int DIALOG_LIB_EDIT_PIN_TABLE::DataViewModel::Compare( const wxDataViewItem& aItem1,
350  const wxDataViewItem& aItem2,
351  unsigned int aCol,
352  bool aAscending ) const
353 {
354  wxString str1 = GetString( aItem1, aCol );
355  wxString str2 = GetString( aItem2, aCol );
356  int res = PinNumbers::Compare( str1, str2 );
357 
358  if( res == 0 )
359  res = ( aItem1.GetID() < aItem2.GetID() ) ? -1 : 1;
360 
361  return res * ( aAscending ? 1 : -1 );
362 }
363 
364 
366 {
367  if( m_GroupingColumn == aCol )
369  else
370  m_GroupingColumn = aCol;
371 
372  Cleared();
374  Refresh();
375 }
376 
377 
379 {
380  m_Groups.clear();
381 
382  if( m_GroupingColumn != -1 )
383  {
384  wxVariant value;
385 
386  for( std::list<Pin>::iterator i = m_Pins.begin(); i != m_Pins.end(); ++i )
387  {
388  wxString str = i->GetString( m_GroupingColumn );
389  std::map<wxString, Group>::iterator j = m_Groups.find( str );
390 
391  if( j == m_Groups.end() )
392  j = m_Groups.insert( std::make_pair( str, m_GroupingColumn ) ).first;
393 
394  j->second.Add( &*i );
395  }
396  }
397  else
398  {
399  for( std::list<Pin>::iterator i = m_Pins.begin(); i != m_Pins.end(); ++i )
400  i->SetGroup( 0 );
401  }
402 }
403 
404 
406 {
407 #ifdef REASSOCIATE_HACK
408  m_Widget->AssociateModel( this );
409 #else
410  std::queue<wxDataViewItem> todo;
411  todo.push( wxDataViewItem() );
412 
413  while( !todo.empty() )
414  {
415  wxDataViewItem current = todo.front();
416  wxDataViewItemArray items;
417 
418  GetChildren( current, items );
419  ItemsAdded( current, items );
420 
421  for( wxDataViewItemArray::const_iterator i = items.begin(); i != items.end(); ++i )
422  {
423  if( IsContainer( *i ) )
424  todo.push( *i );
425  }
426 
427  todo.pop();
428  }
429 
430 #endif
431 }
432 
433 
435 {
436  PinNumbers ret;
437 
438  for( std::list<Pin>::const_iterator i = m_Pins.begin(); i != m_Pins.end(); ++i )
439  ret.insert( i->GetString( PIN_NUMBER ) );
440 
441  return ret;
442 }
443 
444 
445 wxString DIALOG_LIB_EDIT_PIN_TABLE::DataViewModel::GetString( const wxDataViewItem& aItem, unsigned int aCol ) const
446 {
447  assert( aItem.IsOk() );
448 
449  return reinterpret_cast<Item const*>( aItem.GetID() )->GetString( aCol );
450 }
451 
452 
454  unsigned int aCol ) const
455 {
456  if( aCol == m_GroupingColumn )
457  // shortcut
458  m_Members.front()->GetValue( aValue, aCol );
459  else if( aCol != PIN_TYPE )
460  aValue = GetString( aCol );
461  else
462  {
463  PinNumbers values;
464 
465  for( std::list<Pin*>::const_iterator i = m_Members.begin(); i != m_Members.end(); ++i )
466  values.insert( (*i)->GetString( aCol ) );
467 
468  if( values.size() > 1 )
469  {
470  // when multiple pins are grouped, thes have not necessary the same electrical type
471  // therefore use a neutral icon to show a type.
472  // Do Not use a null icon, because on some OS (Linux), for an obscure reason,
473  // if a null icon is used somewhere, no other icon is displayed
474  wxIcon icon_notype;
475  icon_notype.CopyFromBitmap( KiBitmap ( pintype_notspecif_xpm ) ); // could be tree_nosel_xpm
476  aValue << wxDataViewIconText( boost::algorithm::join( values, "," ), icon_notype );
477  }
478  else
479  m_Members.front()->GetValue( aValue, aCol );
480  }
481 }
482 
483 
485 {
486  if( aCol == m_GroupingColumn )
487  return m_Members.front()->GetString( aCol );
488 
489  PinNumbers values;
490 
491  for( std::list<Pin*>::const_iterator i = m_Members.begin(); i != m_Members.end(); ++i )
492  values.insert( (*i)->GetString( aCol ) );
493 
494  if( values.size() > 1 )
495  return boost::algorithm::join( values, "," );
496  else
497  return m_Members.front()->GetString( aCol );
498 }
499 
500 
502 {
503  switch( GetCount() )
504  {
505  case 0:
506  aPin->SetGroup( 0 );
507  break;
508 
509  case 1:
510  m_Members.front()->SetGroup( this );
511  // fall through
512 
513  default:
514  aPin->SetGroup( this );
515  }
516 
517  m_Members.push_back( aPin );
518 }
519 
520 
522  unsigned int aCol ) const
523 {
524  switch( aCol )
525  {
526  case PIN_NUMBER:
527  case PIN_NAME:
528  case PIN_POSITION:
529  aValue = GetString( aCol );
530  break;
531 
532  case PIN_TYPE:
533  {
534  wxIcon icon;
535  icon.CopyFromBitmap( KiBitmap ( GetBitmap( m_Backing->GetType() ) ) );
536  aValue << wxDataViewIconText( m_Backing->GetElectricalTypeName(), icon );
537  }
538  break;
539  }
540 }
541 
542 
544 {
545  switch( aCol )
546  {
547  case PIN_NUMBER:
548  return m_Backing->GetNumber();
549 
550  case PIN_NAME:
551  if( m_Model.m_UnitCount > 1 )
552  {
553  wxString name;
554  int unit = m_Backing->GetPartNumber();
555 
556  if( unit )
557  name << unit;
558  else
559  name << "com";
560 
561  name << ':';
562  name << m_Backing->GetName();
563  return name;
564  }
565  else
566  {
567  return m_Backing->GetName();
568  }
569 
570  case PIN_TYPE:
571  return m_Backing->GetElectricalTypeName();
572 
573  case PIN_POSITION:
574  {
575  wxPoint position = m_Backing->GetPosition();
576  wxString value;
577  value << "(" << position.x << "," << position.y << ")";
578  return value;
579  }
580  }
581 
582  return wxEmptyString;
583 }
static int Compare(PinNumber const &lhs, PinNumber const &rhs)
Definition: pin_number.cpp:110
static bool Compare(const Pin &lhs, const Pin &rhs)
virtual void GetValue(wxVariant &aValue, unsigned int aCol) const override
virtual void GetValue(wxVariant &, const wxDataViewItem &, unsigned int) const override
virtual wxString GetString(unsigned int aCol) const override
virtual void GetValue(wxVariant &aValue, unsigned int aCol) const =0
virtual void OnColumnHeaderRightClicked(wxDataViewEvent &aEvent) override
virtual void GetValue(wxVariant &aValue, unsigned int aCol) const override
virtual wxDataViewItem GetParent() const override
const string & str
Definition: json11.cpp:596
virtual wxDataViewItem GetParent() const =0
void insert(value_type const &v)
Definition: pin_number.h:57
const wxString & GetNumber() const
Definition: lib_pin.h:193
virtual unsigned int GetChildren(const wxDataViewItem &, wxDataViewItemArray &) const override
void GetPins(LIB_PINS &aList, int aUnit=0, int aConvert=0)
Return a list of pin object pointers from the draw item list.
virtual wxString GetString(unsigned int aCol) const =0
wxBitmap KiBitmap(BITMAP_DEF aBitmap)
Function KiBitmap constructs a wxBitmap from a memory record, held in a BITMAP_DEF.
Definition: bitmap.cpp:78
wxObjectDataPtr< DataViewModel > m_Model
wxString GetSummary() const
Definition: pin_number.cpp:70
virtual wxDataViewItem GetParent() const override
virtual bool IsContainer(const wxDataViewItem &) const override
Define a library symbol object.
virtual wxString GetString(unsigned int aCol) const override
DIALOG_LIB_EDIT_PIN_TABLE(wxWindow *parent, LIB_PART &aPart)
virtual unsigned int GetColumnCount() const override
YYCODETYPE lhs
Class DIALOG_LIB_EDIT_PIN_TABLE_BASE.
std::vector< LIB_PIN * > LIB_PINS
Helper for defining a list of pin object pointers.
Definition: lib_draw_item.h:60
virtual unsigned int GetChildren(wxDataViewItemArray &) const =0
const char * name
Definition: DXF_plotter.cpp:61
virtual int Compare(const wxDataViewItem &lhs, const wxDataViewItem &rhs, unsigned int col, bool ascending) const override
virtual unsigned int GetChildren(wxDataViewItemArray &) const override
virtual bool HasContainerColumns(const wxDataViewItem &) const override
size_t i
Definition: json11.cpp:597
virtual wxString GetColumnType(unsigned int col) const override
Pin(DataViewModel &aModel, LIB_PIN *aBacking)
virtual unsigned int GetChildren(wxDataViewItemArray &aItems) const override
BITMAP_DEF GetBitmap(GRAPHIC_PINSHAPE shape)
Definition: pin_shape.cpp:70
container_type::size_type size() const
Definition: pin_number.h:58
virtual wxDataViewItem GetParent(const wxDataViewItem &) const override
virtual bool SetValue(const wxVariant &, const wxDataViewItem &, unsigned int) override
wxString GetString(const wxDataViewItem &, unsigned int) const