KiCad PCB EDA Suite
All Classes Namespaces Files Functions Variables Typedefs Enumerations Enumerator Friends Macros Modules Pages Concepts
pcb_net_inspector_panel_data_model.h
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#ifndef PCB_NET_INSPECTOR_PANEL_DATA_MODEL
21#define PCB_NET_INSPECTOR_PANEL_DATA_MODEL
22
23#include <eda_pattern_match.h>
24
25
32{
33public:
34 enum class GROUP_TYPE
35 {
36 NONE,
39 };
40
41 LIST_ITEM( unsigned int aGroupNumber, const wxString& aGroupName, GROUP_TYPE aGroupType ) :
42 m_group_type( aGroupType ),
43 m_group_number( aGroupNumber ),
44 m_net_name( aGroupName )
45 {
46 m_group_name = aGroupName;
47 m_column_changed.resize( COLUMN_LAST_STATIC_COL + 1 + 2, 0 ); // 2 for default layer count
48 }
49
52 m_net( aNet )
53 {
54 wxASSERT( aNet );
57 m_column_changed.resize( COLUMN_LAST_STATIC_COL + 1 + 2, 0 );
58 }
59
61
62 LIST_ITEM& operator=( const LIST_ITEM& ) = delete;
63
64 bool GetIsGroup() const { return m_group_type != GROUP_TYPE::NONE; }
65 const wxString& GetGroupName() const { return m_group_name; }
67 int GetGroupNumber() const { return m_group_number; }
68
69 auto ChildrenBegin() const { return m_children.begin(); }
70 auto ChildrenEnd() const { return m_children.end(); }
71 unsigned int ChildrenCount() const { return m_children.size(); }
72
73 void SetLayerCount( unsigned int aValue )
74 {
75 m_column_changed.resize( COLUMN_LAST_STATIC_COL + 1 + aValue, 0 );
76 }
77
78 NETINFO_ITEM* GetNet() const { return m_net; }
79
80 int GetNetCode() const
81 {
82 return GetIsGroup() ? ( 0 - int( m_group_number ) - 1 ) : m_net->GetNetCode();
83 }
84
85 const wxString& GetNetName() const { return m_net_name; }
86 const wxString& GetNetclassName() const { return m_net_class; }
87
89 {
90 std::fill( m_column_changed.begin(), m_column_changed.end(), 0 );
91 }
92
93 unsigned int GetPadCount() const { return m_pad_count; }
94
96
97 void SetPadCount( unsigned int aValue )
98 {
99 if( m_parent )
101
103 m_pad_count = aValue;
104 }
105
106 void AddPadCount( unsigned int aValue )
107 {
108 if( m_parent )
109 m_parent->AddPadCount( aValue );
110
111 m_column_changed[COLUMN_PAD_COUNT] |= ( aValue != 0 );
112 m_pad_count += aValue;
113 }
114
115 void SubPadCount( unsigned int aValue )
116 {
117 if( m_parent )
118 m_parent->SubPadCount( aValue );
119
120 m_column_changed[COLUMN_PAD_COUNT] |= ( aValue != 0 );
121 m_pad_count -= aValue;
122 }
123
124 unsigned GetViaCount() const { return m_via_count; }
125
127
128 void SetViaCount( unsigned int aValue )
129 {
130 if( m_parent )
132
134 m_via_count = aValue;
135 }
136
137 void AddViaCount( unsigned int aValue )
138 {
139 if( m_parent )
140 m_parent->AddViaCount( aValue );
141
142 m_column_changed[COLUMN_VIA_COUNT] |= ( aValue != 0 );
143 m_via_count += aValue;
144 }
145
146 void SubViaCount( unsigned int aValue )
147 {
148 if( m_parent )
149 m_parent->SubViaCount( aValue );
150
151 m_column_changed[COLUMN_VIA_COUNT] |= ( aValue != 0 );
152 m_via_count -= aValue;
153 }
154
155 int64_t GetViaLength() const { return m_via_length; }
156
158
159 void SetViaLength( unsigned int aValue )
160 {
161 if( m_parent )
163
165 m_via_length = aValue;
166 }
167
168 void AddViaLength( unsigned int aValue )
169 {
170 if( m_parent )
171 m_parent->AddViaLength( aValue );
172
173 m_column_changed[COLUMN_VIA_LENGTH] |= ( aValue != 0 );
174 m_via_length += aValue;
175 }
176
177 void SubViaLength( int64_t aValue )
178 {
179 if( m_parent )
180 m_parent->SubViaLength( aValue );
181
182 m_column_changed[COLUMN_VIA_LENGTH] |= ( aValue != 0 );
183 m_via_length -= aValue;
184 }
185
186 int64_t GetBoardWireLength() const
187 {
188 int64_t retval = 0;
189
190 for( auto& [layer, length] : m_layer_wire_length )
191 retval += length;
192
193 return retval;
194 }
195
196 int64_t GetLayerWireLength( PCB_LAYER_ID aLayer ) const
197 {
198 auto it = m_layer_wire_length.find( aLayer );
199 return it != m_layer_wire_length.end() ? it->second : 0;
200 }
201
203
204 void SetLayerWireLength( const int64_t aValue, PCB_LAYER_ID aLayer )
205 {
206 auto it = m_layer_wire_length.find( aLayer );
207
208 wxCHECK_RET( it != m_layer_wire_length.end(), wxT( "Invalid layer specified" ) );
209
210 auto& [_, length] = *it;
211
212 if( m_parent )
213 {
215 aLayer );
216 }
217
218 m_column_changed[COLUMN_BOARD_LENGTH] |= ( length != aValue );
219 length = aValue;
220 }
221
222 std::map<PCB_LAYER_ID, int64_t> GetLayerWireLengths() const { return m_layer_wire_length; }
223
224 void SetLayerWireLengths( const std::map<PCB_LAYER_ID, int64_t>& aValue )
225 {
226 if( m_parent )
227 {
228 for( auto& [oldLayer, oldLength] : m_layer_wire_length )
229 m_parent->SubLayerWireLength( oldLength, oldLayer );
230
231 for( auto& [newLayer, newLength] : aValue )
232 m_parent->AddLayerWireLength( newLength, newLayer );
233 }
234
235 m_layer_wire_length = aValue;
236 }
237
238 void AddLayerWireLength( const int64_t aValue, PCB_LAYER_ID aLayer )
239 {
240 if( m_parent )
241 m_parent->AddLayerWireLength( aValue, aLayer );
242
244 m_layer_wire_length[aLayer] += aValue;
245 }
246
247 void SubLayerWireLength( const int64_t aValue, PCB_LAYER_ID aLayer )
248 {
249 if( m_parent )
250 m_parent->SubLayerWireLength( aValue, aLayer );
251
253 m_layer_wire_length[aLayer] -= aValue;
254 }
255
256 int64_t GetPadDieLength() const { return m_pad_die_length; }
257
259
260 void SetPadDieLength( int64_t aValue )
261 {
262 if( m_parent )
264
266 m_pad_die_length = aValue;
267 }
268
269 void AddPadDieLength( int64_t aValue )
270 {
271 if( m_parent )
272 m_parent->AddPadDieLength( aValue );
273
274 m_column_changed[COLUMN_PAD_DIE_LENGTH] |= ( aValue != 0 );
275 m_pad_die_length += aValue;
276 }
277
278 void SubPadDieLength( int64_t aValue )
279 {
280 if( m_parent )
281 m_parent->SubPadDieLength( aValue );
282
283 m_column_changed[COLUMN_PAD_DIE_LENGTH] |= ( aValue != 0 );
284 m_pad_die_length -= aValue;
285 }
286
287 // the total length column is always computed, never stored.
288 unsigned long long int GetTotalLength() const
289 {
291 }
292
294 {
296 }
297
298 LIST_ITEM* Parent() const { return m_parent; }
299
300 void SetParent( LIST_ITEM* aParent )
301 {
302 if( m_parent == aParent )
303 return;
304
305 if( m_parent != nullptr )
306 {
310
311 for( auto& [layer, length] : m_layer_wire_length )
312 m_parent->SubLayerWireLength( length, layer );
313
315
316 m_parent->m_children.erase( std::find( m_parent->m_children.begin(),
317 m_parent->m_children.end(), this ) );
318 }
319
320 m_parent = aParent;
321
322 if( m_parent != nullptr )
323 {
327
328 for( auto& [layer, length] : m_layer_wire_length )
329 m_parent->AddLayerWireLength( length, layer );
330
332
333 m_parent->m_children.push_back( this );
334 }
335 }
336
337private:
338 LIST_ITEM* m_parent = nullptr;
339 std::vector<LIST_ITEM*> m_children;
340
342 unsigned int m_group_number = 0;
343 NETINFO_ITEM* m_net = nullptr;
344 unsigned int m_pad_count = 0;
345 unsigned int m_via_count = 0;
346 int64_t m_via_length = 0;
347 int64_t m_pad_die_length = 0;
348
349 std::map<PCB_LAYER_ID, int64_t> m_layer_wire_length{};
350
351 // Dirty bits to record when some attribute has changed, in order to avoid unnecessary sort
352 // operations.
353 // The values are semantically bools, but STL auto-promotes a std::vector<bool> to a bitset,
354 // and then operator|= doesn't work.
355 std::vector<int> m_column_changed;
356
357 // cached formatted names for faster display sorting
358 wxString m_net_name;
359 wxString m_net_class;
360 wxString m_group_name;
361};
362
363
365{
366 template <typename T>
367 bool operator()( const T& a, const T& b ) const
368 {
369 return a->GetNetCode() < b->GetNetCode();
370 }
371
372 template <typename T>
373 bool operator()( const T& a, int b ) const
374 {
375 return a->GetNetCode() < b;
376 }
377
378 template <typename T>
379 bool operator()( int a, const T& b ) const
380 {
381 return a < b->GetNetCode();
382 }
383};
384
385
387{
388 template <typename T>
389 bool operator()( const T& a, const T& b ) const
390 {
391 return a->GetGroupNumber() < b->GetGroupNumber();
392 }
393
394 template <typename T>
395 bool operator()( const T& a, int b ) const
396 {
397 return a->GetGroupNumber() < b;
398 }
399
400 template <typename T>
401 bool operator()( int a, const T& b ) const
402 {
403 return a < b->GetGroupNumber();
404 }
405};
406
407
411class PCB_NET_INSPECTOR_PANEL::DATA_MODEL : public wxDataViewModel
412{
413public:
415
416 unsigned int columnCount() const { return m_parent.m_columns.size(); }
417
418 unsigned int itemCount() const { return m_items.size(); }
419
420 wxVariant valueAt( unsigned int aCol, unsigned int aRow ) const
421 {
422 wxVariant r;
423 GetValue( r, wxDataViewItem( const_cast<LIST_ITEM*>( &*( m_items[aRow] ) ) ), aCol );
424 return r;
425 }
426
427 const LIST_ITEM& itemAt( unsigned int aRow ) const { return *m_items.at( aRow ); }
428
429 std::vector<std::pair<wxString, wxDataViewItem>> getGroupDataViewItems()
430 {
431 std::vector<std::pair<wxString, wxDataViewItem>> ret;
432
433 for( std::unique_ptr<LIST_ITEM>& item : m_items )
434 {
435 if( item->GetIsGroup() )
436 {
437 ret.push_back( std::make_pair( item->GetGroupName(),
438 wxDataViewItem( item.get() ) ) );
439 }
440 }
441
442 return ret;
443 }
444
445
446 std::optional<LIST_ITEM_ITER> findItem( int aNetCode )
447 {
448 auto i = std::lower_bound( m_items.begin(), m_items.end(), aNetCode,
450
451 if( i == m_items.end() || ( *i )->GetNetCode() != aNetCode )
452 return std::nullopt;
453
454 return { i };
455 }
456
457
458 std::optional<LIST_ITEM_ITER> findItem( NETINFO_ITEM* aNet )
459 {
460 if( aNet != nullptr )
461 return findItem( aNet->GetNetCode() );
462 else
463 return std::nullopt;
464 }
465
466
467 std::optional<LIST_ITEM_ITER> findGroupItem( int aGroupNumber )
468 {
469 auto i = std::lower_bound( m_items.begin(), m_items.end(), aGroupNumber,
471
472 if( i == m_items.end() || ( *i )->GetGroupNumber() != aGroupNumber )
473 return std::nullopt;
474
475 return { i };
476 }
477
478
480 wxString groupName, LIST_ITEM::GROUP_TYPE groupType )
481 {
482 LIST_ITEM_ITER group = std::find_if( groupsBegin, groupsEnd,
483 [&]( const std::unique_ptr<LIST_ITEM>& x )
484 {
485 return x->GetGroupName() == groupName
486 && x->GetGroupType() == groupType;
487 } );
488
489 if( group == groupsEnd )
490 {
491 int dist = std::distance( groupsBegin, groupsEnd );
492 std::unique_ptr<LIST_ITEM> groupItem = std::make_unique<LIST_ITEM>( dist, groupName,
493 groupType );
494 group = m_items.insert( groupsEnd, std::move( groupItem ) );
495 ItemAdded( wxDataViewItem( ( *group )->Parent() ), wxDataViewItem( &**group ) );
496 }
497
498 return group;
499 }
500
501
502 std::optional<LIST_ITEM_ITER> addItem( std::unique_ptr<LIST_ITEM> aItem )
503 {
504 if( aItem == nullptr )
505 return {};
506
507 bool groupMatched = false;
508
509 // First see if item matches a group-by rule
510 if( m_parent.m_custom_group_rules.size() > 0 )
511 {
512 wxString searchName = aItem->GetNetName();
513
514 for( const std::unique_ptr<EDA_COMBINED_MATCHER>& rule : m_parent.m_custom_group_rules )
515 {
516 if( rule->Find( searchName ) )
517 {
518 aItem->SetParent( m_custom_group_map[ rule->GetPattern() ] );
519 groupMatched = true;
520 break;
521 }
522 }
523 }
524
525 // Then add any netclass groups required by this item
526 if( m_parent.m_groupByNetclass && !groupMatched )
527 {
528 LIST_ITEM_ITER groups_begin = m_items.begin();
529 LIST_ITEM_ITER groups_end = std::find_if_not( m_items.begin(), m_items.end(),
530 []( const std::unique_ptr<LIST_ITEM>& x )
531 {
532 return x->GetIsGroup();
533 } );
534
535 wxString match_str = aItem->GetNetclassName();
536 LIST_ITEM_ITER group = addGroup( groups_begin, groups_end, match_str,
538 aItem->SetParent( &**group );
539 }
540
541 // Now add the item itself. Usually when new nets are added,
542 // they always get a higher netcode number than the already existing ones.
543 // however, if we've got filtering enabled, we might not have all the nets in
544 // our list, so do a sorted insertion.
545 auto new_iter = std::lower_bound( m_items.begin(), m_items.end(), aItem->GetNetCode(),
547
548 new_iter = m_items.insert( new_iter, std::move( aItem ) );
549 const std::unique_ptr<LIST_ITEM>& new_item = *new_iter;
550
551 ItemAdded( wxDataViewItem( new_item->Parent() ), wxDataViewItem( new_item.get() ) );
552
553 return { new_iter };
554 }
555
556 void addItems( std::vector<std::unique_ptr<LIST_ITEM>>& aItems )
557 {
558 m_items.reserve( m_items.size() + aItems.size() );
559
560 for( std::unique_ptr<LIST_ITEM>& i : aItems )
561 addItem( std::move( i ) );
562 }
563
564 std::unique_ptr<LIST_ITEM> deleteItem( const std::optional<LIST_ITEM_ITER>& aRow )
565 {
566 if( !aRow )
567 return {};
568
569 std::unique_ptr<LIST_ITEM> i = std::move( **aRow );
570
571 LIST_ITEM* parent = i->Parent();
572 i->SetParent( nullptr );
573
574 m_items.erase( *aRow );
575 ItemDeleted( wxDataViewItem( parent ), wxDataViewItem( &*i ) );
576
577 if( parent )
578 {
579 ItemChanged( wxDataViewItem( parent ) );
580
581 if( m_parent.m_groupByNetclass && parent != nullptr && parent->ChildrenCount() == 0 )
582 {
583 auto p = std::find_if( m_items.begin(), m_items.end(),
584 [&]( std::unique_ptr<LIST_ITEM>& x )
585 {
586 return x.get() == parent;
587 } );
588
589 wxASSERT( p != m_items.end() );
590 m_items.erase( p );
591
592 ItemDeleted( wxDataViewItem( parent->Parent() ), wxDataViewItem( parent ) );
593 }
594 }
595
596 Resort();
597 return i;
598 }
599
600
607 {
608 m_custom_group_map.clear();
609 int groupId = 0;
610
611 for( const std::unique_ptr<EDA_COMBINED_MATCHER>& rule : m_parent.m_custom_group_rules )
612 {
613 std::unique_ptr<LIST_ITEM>& group = m_items.emplace_back( std::make_unique<LIST_ITEM>(
614 groupId, rule->GetPattern(), LIST_ITEM::GROUP_TYPE::USER_DEFINED ) );
615 m_custom_group_map[ rule->GetPattern() ] = group.get();
616 group->SetLayerCount( m_parent.m_board->GetCopperLayerCount() );
617 ItemAdded( wxDataViewItem( group->Parent() ), wxDataViewItem( group.get() ) );
618 ++groupId;
619 }
620 }
621
622
624 {
625 BeforeReset();
626 m_items.clear();
627 AfterReset();
628 }
629
630 void updateItem( const std::optional<LIST_ITEM_ITER>& aRow )
631 {
632 if( aRow )
633 {
634 const std::unique_ptr<LIST_ITEM>& listItem = *aRow.value();
635
636 if( listItem->Parent() )
637 ItemChanged( wxDataViewItem( listItem->Parent() ) );
638
639 ItemChanged( wxDataViewItem( listItem.get() ) );
640 resortIfChanged( listItem.get() );
641 }
642 }
643
645 {
646 for( std::unique_ptr<LIST_ITEM>& i : m_items )
647 ItemChanged( wxDataViewItem( i.get() ) );
648 }
649
651 {
652 if( wxDataViewColumn* column = m_parent.m_netsList->GetSortingColumn() )
653 {
654 bool changed = false;
655
656 for( const LIST_ITEM* i = aItem; i != nullptr; i = i->Parent() )
657 changed |= itemColumnChanged( i, column->GetModelColumn() );
658
659 for( LIST_ITEM* i = aItem; i != nullptr; i = i->Parent() )
660 i->ResetColumnChangedBits();
661
662 if( changed )
663 Resort();
664 }
665 }
666
667 bool itemColumnChanged( const LIST_ITEM* aItem, unsigned int aCol ) const
668 {
669 if( aItem == nullptr || aCol >= m_parent.m_columns.size() )
670 return false;
671
672 if( aCol == COLUMN_PAD_COUNT )
673 return aItem->PadCountChanged();
674
675 else if( aCol == COLUMN_VIA_COUNT )
676 return aItem->ViaCountChanged();
677
678 else if( aCol == COLUMN_VIA_LENGTH )
679 return aItem->ViaLengthChanged();
680
681 else if( aCol == COLUMN_BOARD_LENGTH )
682 return aItem->BoardWireLengthChanged();
683
684 else if( aCol == COLUMN_PAD_DIE_LENGTH )
685 return aItem->PadDieLengthChanged();
686
687 else if( aCol == COLUMN_TOTAL_LENGTH )
688 return aItem->TotalLengthChanged();
689
690 else if( aCol > COLUMN_LAST_STATIC_COL )
691 return aItem->BoardWireLengthChanged();
692
693
694 return false;
695 }
696
697 // implementation of wxDataViewModel interface
698 // these are used to query the data model by the GUI view implementation.
699 // these are not supposed to be used to modify the data model. for that
700 // use the public functions above.
701
702protected:
703 unsigned int GetColumnCount() const override { return columnCount(); }
704
705 void GetValue( wxVariant& aOutValue, const wxDataViewItem& aItem,
706 unsigned int aCol ) const override
707 {
708 if( LIST_ITEM* i = static_cast<LIST_ITEM*>( aItem.GetID() ) )
709 {
710 if( aCol == COLUMN_NAME )
711 {
712 if( i->GetIsGroup() )
713 {
714 switch( i->GetGroupType() )
715 {
717 aOutValue = _( "Netclass" ) + ": " + i->GetGroupName();
718 break;
720 aOutValue = _( "Custom" ) + ": " + i->GetGroupName();
721 break;
722 default:
723 aOutValue = i->GetGroupName();
724 break;
725 }
726 }
727 else
728 {
729 aOutValue = i->GetNetName();
730 }
731 }
732
733 else if( aCol == COLUMN_NETCLASS )
734 aOutValue = i->GetNetclassName();
735
736 else if( aCol == COLUMN_PAD_COUNT )
737 aOutValue = m_parent.formatCount( i->GetPadCount() );
738
739 else if( aCol == COLUMN_VIA_COUNT )
740 aOutValue = m_parent.formatCount( i->GetViaCount() );
741
742 else if( aCol == COLUMN_VIA_LENGTH )
743 aOutValue = m_parent.formatLength( i->GetViaLength() );
744
745 else if( aCol == COLUMN_BOARD_LENGTH )
746 aOutValue = m_parent.formatLength( i->GetBoardWireLength() );
747
748 else if( aCol == COLUMN_PAD_DIE_LENGTH )
749 aOutValue = m_parent.formatLength( i->GetPadDieLength() );
750
751 else if( aCol == COLUMN_TOTAL_LENGTH )
752 aOutValue = m_parent.formatLength( i->GetTotalLength() );
753
754 else if( aCol > COLUMN_LAST_STATIC_COL && aCol <= m_parent.m_columns.size() )
755 aOutValue = m_parent.formatLength( i->GetLayerWireLength( m_parent.m_columns[aCol].layer ) );
756
757 else
758 aOutValue = "";
759 }
760 }
761
762 static int compareUInt( int64_t aValue1, int64_t aValue2, bool aAsc )
763 {
764 if( aAsc )
765 return aValue1 < aValue2 ? -1 : 1;
766 else
767 return aValue2 < aValue1 ? -1 : 1;
768 }
769
770 int Compare( const wxDataViewItem& aItem1, const wxDataViewItem& aItem2, unsigned int aCol,
771 bool aAsc ) const override
772 {
773 const LIST_ITEM& i1 = *static_cast<const LIST_ITEM*>( aItem1.GetID() );
774 const LIST_ITEM& i2 = *static_cast<const LIST_ITEM*>( aItem2.GetID() );
775
776 if( i1.GetIsGroup() && !i2.GetIsGroup() )
777 return -1;
778
779 if( i2.GetIsGroup() && !i1.GetIsGroup() )
780 return 1;
781
782 if( aCol == COLUMN_NAME )
783 {
784 const wxString& s1 = i1.GetNetName();
785 const wxString& s2 = i2.GetNetName();
786
787 int res = aAsc ? ValueStringCompare( s1, s2 ) : ValueStringCompare( s2, s1 );
788
789 if( res != 0 )
790 return res;
791 }
792
793 else if( aCol == COLUMN_PAD_COUNT && i1.GetPadCount() != i2.GetPadCount() )
794 return compareUInt( i1.GetPadCount(), i2.GetPadCount(), aAsc );
795
796 else if( aCol == COLUMN_VIA_COUNT && i1.GetViaCount() != i2.GetViaCount() )
797 return compareUInt( i1.GetViaCount(), i2.GetViaCount(), aAsc );
798
799 else if( aCol == COLUMN_VIA_LENGTH && i1.GetViaLength() != i2.GetViaLength() )
800 return compareUInt( i1.GetViaLength(), i2.GetViaLength(), aAsc );
801
802 else if( aCol == COLUMN_BOARD_LENGTH && i1.GetBoardWireLength() != i2.GetBoardWireLength() )
803 return compareUInt( i1.GetBoardWireLength(), i2.GetBoardWireLength(), aAsc );
804
805 else if( aCol == COLUMN_PAD_DIE_LENGTH && i1.GetPadDieLength() != i2.GetPadDieLength() )
806 return compareUInt( i1.GetPadDieLength(), i2.GetPadDieLength(), aAsc );
807
808 else if( aCol == COLUMN_TOTAL_LENGTH && i1.GetTotalLength() != i2.GetTotalLength() )
809 return compareUInt( i1.GetTotalLength(), i2.GetTotalLength(), aAsc );
810
811 else if( aCol > COLUMN_LAST_STATIC_COL && aCol < m_parent.m_columns.size()
812 && i1.GetLayerWireLength( m_parent.m_columns[aCol].layer )
813 != i2.GetLayerWireLength( m_parent.m_columns[aCol].layer ) )
814 {
815 return compareUInt( i1.GetLayerWireLength( m_parent.m_columns[aCol].layer ),
816 i2.GetLayerWireLength( m_parent.m_columns[aCol].layer ), aAsc );
817 }
818
819 // when the item values compare equal resort to pointer comparison.
820 wxUIntPtr id1 = wxPtrToUInt( aItem1.GetID() );
821 wxUIntPtr id2 = wxPtrToUInt( aItem2.GetID() );
822
823 return aAsc ? id1 - id2 : id2 - id1;
824 }
825
826 bool SetValue( const wxVariant& aInValue, const wxDataViewItem& aItem,
827 unsigned int aCol ) override
828 {
829 return false;
830 }
831
832 wxDataViewItem GetParent( const wxDataViewItem& aItem ) const override
833 {
834 if( !aItem.IsOk() )
835 return wxDataViewItem();
836
837 return wxDataViewItem( static_cast<const LIST_ITEM*>( aItem.GetID() )->Parent() );
838 }
839
840 bool IsContainer( const wxDataViewItem& aItem ) const override
841 {
842 if( !aItem.IsOk() )
843 return true;
844
845 return static_cast<const LIST_ITEM*>( aItem.GetID() )->GetIsGroup();
846 }
847
848 bool HasContainerColumns( const wxDataViewItem& aItem ) const override
849 {
850 return IsContainer( aItem );
851 }
852
853 unsigned int GetChildren( const wxDataViewItem& aParent,
854 wxDataViewItemArray& aChildren ) const override
855 {
856 const LIST_ITEM* p = static_cast<const LIST_ITEM*>( aParent.GetID() );
857
858 if( !aParent.IsOk() )
859 {
860 aChildren.Alloc( m_items.size() );
861
862 for( const std::unique_ptr<LIST_ITEM>& i : m_items )
863 {
864 if( i->Parent() == nullptr )
865 aChildren.Add( wxDataViewItem( &*i ) );
866 }
867
868 return aChildren.GetCount();
869 }
870 else if( p->GetIsGroup() )
871 {
872 const int count = p->ChildrenCount();
873
874 if( count == 0 )
875 return 0;
876
877 aChildren.Alloc( count );
878
879 for( auto i = p->ChildrenBegin(), end = p->ChildrenEnd(); i != end; ++i )
880 aChildren.Add( wxDataViewItem( *i ) );
881
882 return aChildren.GetCount();
883 }
884
885 return 0;
886 }
887
888 wxString GetColumnType( unsigned int /* aCol */ ) const override { return wxS( "string" ); }
889
890private:
892
893 // primary container, sorted by netcode number.
894 // groups have netcode < 0, so they always come first, in the order
895 // of the filter strings as input by the user
896 std::vector<std::unique_ptr<LIST_ITEM>> m_items;
897
899 std::map<wxString, LIST_ITEM*> m_custom_group_map;
900};
901
902#endif
int GetCopperLayerCount() const
Definition: board.cpp:781
A collection of nets and the parameters used to route or test these nets.
Definition: netclass.h:45
const wxString GetHumanReadableName() const
Gets the consolidated name of this netclass (which may be an aggregate).
Definition: netclass.cpp:286
Handle the data for a net.
Definition: netinfo.h:56
const wxString & GetNetname() const
Definition: netinfo.h:114
NETCLASS * GetNetClass()
Definition: netinfo.h:101
int GetNetCode() const
Definition: netinfo.h:108
wxDataViewCtrl * m_netsList
Data model for display in the Net Inspector panel.
std::unique_ptr< LIST_ITEM > deleteItem(const std::optional< LIST_ITEM_ITER > &aRow)
bool IsContainer(const wxDataViewItem &aItem) const override
bool itemColumnChanged(const LIST_ITEM *aItem, unsigned int aCol) const
static int compareUInt(int64_t aValue1, int64_t aValue2, bool aAsc)
void addCustomGroups()
Adds all custom group-by entries to the items table.
wxString GetColumnType(unsigned int) const override
wxDataViewItem GetParent(const wxDataViewItem &aItem) const override
bool HasContainerColumns(const wxDataViewItem &aItem) const override
bool SetValue(const wxVariant &aInValue, const wxDataViewItem &aItem, unsigned int aCol) override
void GetValue(wxVariant &aOutValue, const wxDataViewItem &aItem, unsigned int aCol) const override
std::vector< std::pair< wxString, wxDataViewItem > > getGroupDataViewItems()
std::optional< LIST_ITEM_ITER > findItem(NETINFO_ITEM *aNet)
unsigned int GetChildren(const wxDataViewItem &aParent, wxDataViewItemArray &aChildren) const override
std::optional< LIST_ITEM_ITER > findItem(int aNetCode)
std::map< wxString, LIST_ITEM * > m_custom_group_map
Map of custom group names to their representative list item.
wxVariant valueAt(unsigned int aCol, unsigned int aRow) const
void addItems(std::vector< std::unique_ptr< LIST_ITEM > > &aItems)
int Compare(const wxDataViewItem &aItem1, const wxDataViewItem &aItem2, unsigned int aCol, bool aAsc) const override
std::optional< LIST_ITEM_ITER > findGroupItem(int aGroupNumber)
std::vector< std::unique_ptr< LIST_ITEM > > m_items
const LIST_ITEM & itemAt(unsigned int aRow) const
void updateItem(const std::optional< LIST_ITEM_ITER > &aRow)
LIST_ITEM_ITER addGroup(LIST_ITEM_ITER groupsBegin, LIST_ITEM_ITER groupsEnd, wxString groupName, LIST_ITEM::GROUP_TYPE groupType)
std::optional< LIST_ITEM_ITER > addItem(std::unique_ptr< LIST_ITEM > aItem)
Primary data item for entries in the Net Inspector list.
LIST_ITEM(unsigned int aGroupNumber, const wxString &aGroupName, GROUP_TYPE aGroupType)
std::map< PCB_LAYER_ID, int64_t > m_layer_wire_length
void SetLayerWireLengths(const std::map< PCB_LAYER_ID, int64_t > &aValue)
void AddLayerWireLength(const int64_t aValue, PCB_LAYER_ID aLayer)
LIST_ITEM & operator=(const LIST_ITEM &)=delete
std::map< PCB_LAYER_ID, int64_t > GetLayerWireLengths() const
int64_t GetLayerWireLength(PCB_LAYER_ID aLayer) const
void SetLayerWireLength(const int64_t aValue, PCB_LAYER_ID aLayer)
void SubLayerWireLength(const int64_t aValue, PCB_LAYER_ID aLayer)
PCB net inspection panel.
std::vector< std::unique_ptr< LIST_ITEM > >::iterator LIST_ITEM_ITER
static wxString formatCount(unsigned int aValue)
std::vector< std::unique_ptr< EDA_COMBINED_MATCHER > > m_custom_group_rules
Custom net grouping rules.
wxString formatLength(int64_t aValue) const
std::vector< COLUMN_DESC > m_columns
All displayed (or hidden) columns.
#define _(s)
Abstract pattern-matching tool and implementations.
PCB_LAYER_ID
A quick note on layer IDs:
Definition: layer_ids.h:60
wxString UnescapeString(const wxString &aSource)
int ValueStringCompare(const wxString &strFWord, const wxString &strSWord)
Compare strings like the strcmp function but handle numbers and modifiers within the string text corr...
VECTOR3I res
VECTOR2I end