KiCad PCB EDA Suite
Loading...
Searching...
No Matches
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 GetViaDelay() const { return m_via_delay; }
187
188 void SetViaDelay( unsigned int aValue )
189 {
190 if( m_parent )
192
194 m_via_delay = aValue;
195 }
196
197 void AddViaDelay( unsigned int aValue )
198 {
199 if( m_parent )
200 m_parent->AddViaDelay( aValue );
201
202 m_column_changed[COLUMN_VIA_LENGTH] |= ( aValue != 0 );
203 m_via_delay += aValue;
204 }
205
206 void SubViaDelay( int64_t aValue )
207 {
208 if( m_parent )
209 m_parent->SubViaDelay( aValue );
210
211 m_column_changed[COLUMN_VIA_LENGTH] |= ( aValue != 0 );
212 m_via_delay -= aValue;
213 }
214
215 int64_t GetBoardWireLength() const
216 {
217 int64_t retval = 0;
218
219 for( auto& [layer, length] : m_layer_wire_length )
220 retval += length;
221
222 return retval;
223 }
224
225 int64_t GetBoardWireDelay() const
226 {
227 int64_t retval = 0;
228
229 for( auto& [layer, delay] : m_layer_wire_delay )
230 retval += delay;
231
232 return retval;
233 }
234
235 int64_t GetLayerWireLength( PCB_LAYER_ID aLayer ) const
236 {
237 auto it = m_layer_wire_length.find( aLayer );
238 return it != m_layer_wire_length.end() ? it->second : 0;
239 }
240
241 int64_t GetLayerWireDelay( PCB_LAYER_ID aLayer ) const
242 {
243 auto it = m_layer_wire_delay.find( aLayer );
244 return it != m_layer_wire_delay.end() ? it->second : 0;
245 }
246
248
249 void SetLayerWireLength( const int64_t aValue, PCB_LAYER_ID aLayer )
250 {
251 auto it = m_layer_wire_length.find( aLayer );
252
253 wxCHECK_RET( it != m_layer_wire_length.end(), wxT( "Invalid layer specified" ) );
254
255 auto& [_, length] = *it;
256
257 if( m_parent )
258 {
260 aLayer );
261 }
262
263 m_column_changed[COLUMN_BOARD_LENGTH] |= ( length != aValue );
264 length = aValue;
265 }
266
267 std::map<PCB_LAYER_ID, int64_t> GetLayerWireLengths() const { return m_layer_wire_length; }
268
269 std::map<PCB_LAYER_ID, int64_t> GetLayerWireDelays() const { return m_layer_wire_delay; }
270
271 void SetLayerWireLengths( const std::map<PCB_LAYER_ID, int64_t>& aValue )
272 {
273 if( m_parent )
274 {
275 for( auto& [oldLayer, oldLength] : m_layer_wire_length )
276 m_parent->SubLayerWireLength( oldLength, oldLayer );
277
278 for( auto& [newLayer, newLength] : aValue )
279 m_parent->AddLayerWireLength( newLength, newLayer );
280 }
281
282 m_layer_wire_length = aValue;
283 }
284
285 void AddLayerWireLength( const int64_t aValue, PCB_LAYER_ID aLayer )
286 {
287 if( m_parent )
288 m_parent->AddLayerWireLength( aValue, aLayer );
289
291 m_layer_wire_length[aLayer] += aValue;
292 }
293
294 void SubLayerWireLength( const int64_t aValue, PCB_LAYER_ID aLayer )
295 {
296 if( m_parent )
297 m_parent->SubLayerWireLength( aValue, aLayer );
298
300 m_layer_wire_length[aLayer] -= aValue;
301 }
302
303 void SetLayerWireDelays( const std::map<PCB_LAYER_ID, int64_t>& aValue )
304 {
305 if( m_parent )
306 {
307 for( auto& [oldLayer, oldLength] : m_layer_wire_delay )
308 m_parent->SubLayerWireDelay( oldLength, oldLayer );
309
310 for( auto& [newLayer, newLength] : aValue )
311 m_parent->AddLayerWireDelay( newLength, newLayer );
312 }
313
314 m_layer_wire_delay = aValue;
315 }
316
317 void AddLayerWireDelay( const int64_t aValue, PCB_LAYER_ID aLayer )
318 {
319 if( m_parent )
320 m_parent->AddLayerWireDelay( aValue, aLayer );
321
323 m_layer_wire_delay[aLayer] += aValue;
324 }
325
326 void SubLayerWireDelay( const int64_t aValue, PCB_LAYER_ID aLayer )
327 {
328 if( m_parent )
329 m_parent->SubLayerWireDelay( aValue, aLayer );
330
332 m_layer_wire_delay[aLayer] -= aValue;
333 }
334
335 int64_t GetPadDieLength() const { return m_pad_die_length; }
336
338
339 void SetPadDieLength( int64_t aValue )
340 {
341 if( m_parent )
343
345 m_pad_die_length = aValue;
346 }
347
348 void AddPadDieLength( int64_t aValue )
349 {
350 if( m_parent )
351 m_parent->AddPadDieLength( aValue );
352
353 m_column_changed[COLUMN_PAD_DIE_LENGTH] |= ( aValue != 0 );
354 m_pad_die_length += aValue;
355 }
356
357 void SubPadDieLength( int64_t aValue )
358 {
359 if( m_parent )
360 m_parent->SubPadDieLength( aValue );
361
362 m_column_changed[COLUMN_PAD_DIE_LENGTH] |= ( aValue != 0 );
363 m_pad_die_length -= aValue;
364 }
365
366 int64_t GetPadDieDelay() const { return m_pad_die_delay; }
367
368 void SetPadDieDelay( int64_t aValue )
369 {
370 if( m_parent )
372
374 m_pad_die_delay = aValue;
375 }
376
377 void AddPadDieDelay( int64_t aValue )
378 {
379 if( m_parent )
380 m_parent->AddPadDieDelay( aValue );
381
382 m_column_changed[COLUMN_PAD_DIE_LENGTH] |= ( aValue != 0 );
383 m_pad_die_delay += aValue;
384 }
385
386 void SubPadDieDelay( int64_t aValue )
387 {
388 if( m_parent )
389 m_parent->SubPadDieDelay( aValue );
390
391 m_column_changed[COLUMN_PAD_DIE_LENGTH] |= ( aValue != 0 );
392 m_pad_die_delay -= aValue;
393 }
394
395 // the total length column is always computed, never stored.
396 unsigned long long int GetTotalLength() const
397 {
399 }
400
401 unsigned long long int GetTotalDelay() const { return GetBoardWireDelay() + GetViaDelay() + GetPadDieDelay(); }
402
404 {
406 }
407
408 LIST_ITEM* Parent() const { return m_parent; }
409
410 void SetParent( LIST_ITEM* aParent )
411 {
412 if( m_parent == aParent )
413 return;
414
415 if( m_parent != nullptr )
416 {
421
422 for( auto& [layer, length] : m_layer_wire_length )
423 m_parent->SubLayerWireLength( length, layer );
424
425 for( auto& [layer, delay] : m_layer_wire_delay )
426 m_parent->SubLayerWireDelay( delay, layer );
427
430
431 m_parent->m_children.erase( std::find( m_parent->m_children.begin(),
432 m_parent->m_children.end(), this ) );
433 }
434
435 m_parent = aParent;
436
437 if( m_parent != nullptr )
438 {
443
444 for( auto& [layer, length] : m_layer_wire_length )
445 m_parent->AddLayerWireLength( length, layer );
446
447 for( auto& [layer, delay] : m_layer_wire_delay )
448 m_parent->AddLayerWireDelay( delay, layer );
449
452
453 m_parent->m_children.push_back( this );
454 }
455 }
456
457private:
458 LIST_ITEM* m_parent = nullptr;
459 std::vector<LIST_ITEM*> m_children;
460
462 unsigned int m_group_number = 0;
463 NETINFO_ITEM* m_net = nullptr;
464 unsigned int m_pad_count = 0;
465 unsigned int m_via_count = 0;
466 int64_t m_via_length = 0;
467 int64_t m_via_delay = 0;
468 int64_t m_pad_die_length = 0;
469 int64_t m_pad_die_delay = 0;
470
471 std::map<PCB_LAYER_ID, int64_t> m_layer_wire_length{};
472 std::map<PCB_LAYER_ID, int64_t> m_layer_wire_delay{};
473
474 // Dirty bits to record when some attribute has changed, in order to avoid unnecessary sort
475 // operations.
476 // The values are semantically bools, but STL auto-promotes a std::vector<bool> to a bitset,
477 // and then operator|= doesn't work.
478 std::vector<int> m_column_changed;
479
480 // cached formatted names for faster display sorting
481 wxString m_net_name;
482 wxString m_net_class;
483 wxString m_group_name;
484};
485
486
488{
489 template <typename T>
490 bool operator()( const T& a, const T& b ) const
491 {
492 return a->GetNetCode() < b->GetNetCode();
493 }
494
495 template <typename T>
496 bool operator()( const T& a, int b ) const
497 {
498 return a->GetNetCode() < b;
499 }
500
501 template <typename T>
502 bool operator()( int a, const T& b ) const
503 {
504 return a < b->GetNetCode();
505 }
506};
507
508
510{
511 template <typename T>
512 bool operator()( const T& a, const T& b ) const
513 {
514 return a->GetGroupNumber() < b->GetGroupNumber();
515 }
516
517 template <typename T>
518 bool operator()( const T& a, int b ) const
519 {
520 return a->GetGroupNumber() < b;
521 }
522
523 template <typename T>
524 bool operator()( int a, const T& b ) const
525 {
526 return a < b->GetGroupNumber();
527 }
528};
529
530
534class PCB_NET_INSPECTOR_PANEL::DATA_MODEL : public wxDataViewModel
535{
536public:
538
539 unsigned int columnCount() const { return m_parent.m_columns.size(); }
540
541 unsigned int itemCount() const { return m_items.size(); }
542
543 wxVariant valueAt( unsigned int aCol, unsigned int aRow ) const
544 {
545 wxVariant r;
546 GetValue( r, wxDataViewItem( const_cast<LIST_ITEM*>( &*( m_items[aRow] ) ) ), aCol );
547 return r;
548 }
549
550 const LIST_ITEM& itemAt( unsigned int aRow ) const { return *m_items.at( aRow ); }
551
552 std::vector<std::pair<wxString, wxDataViewItem>> getGroupDataViewItems()
553 {
554 std::vector<std::pair<wxString, wxDataViewItem>> ret;
555
556 for( std::unique_ptr<LIST_ITEM>& item : m_items )
557 {
558 if( item->GetIsGroup() )
559 {
560 ret.push_back( std::make_pair( item->GetGroupName(),
561 wxDataViewItem( item.get() ) ) );
562 }
563 }
564
565 return ret;
566 }
567
568
569 std::optional<LIST_ITEM_ITER> findItem( int aNetCode )
570 {
571 auto i = std::lower_bound( m_items.begin(), m_items.end(), aNetCode,
573
574 if( i == m_items.end() || ( *i )->GetNetCode() != aNetCode )
575 return std::nullopt;
576
577 return { i };
578 }
579
580
581 std::optional<LIST_ITEM_ITER> findItem( NETINFO_ITEM* aNet )
582 {
583 if( aNet != nullptr )
584 return findItem( aNet->GetNetCode() );
585 else
586 return std::nullopt;
587 }
588
589
590 std::optional<LIST_ITEM_ITER> findGroupItem( int aGroupNumber )
591 {
592 auto i = std::lower_bound( m_items.begin(), m_items.end(), aGroupNumber,
594
595 if( i == m_items.end() || ( *i )->GetGroupNumber() != aGroupNumber )
596 return std::nullopt;
597
598 return { i };
599 }
600
601
603 wxString groupName, LIST_ITEM::GROUP_TYPE groupType )
604 {
605 LIST_ITEM_ITER group = std::find_if( groupsBegin, groupsEnd,
606 [&]( const std::unique_ptr<LIST_ITEM>& x )
607 {
608 return x->GetGroupName() == groupName
609 && x->GetGroupType() == groupType;
610 } );
611
612 if( group == groupsEnd )
613 {
614 int dist = std::distance( groupsBegin, groupsEnd );
615 std::unique_ptr<LIST_ITEM> groupItem = std::make_unique<LIST_ITEM>( dist, groupName, groupType );
616
617 group = m_items.insert( groupsEnd, std::move( groupItem ) );
618 ItemAdded( wxDataViewItem( ( *group )->Parent() ), wxDataViewItem( ( *group ).get() ) );
619 }
620
621 return ( *group ).get();
622 }
623
624
625 std::optional<LIST_ITEM_ITER> addItem( std::unique_ptr<LIST_ITEM> aItem )
626 {
627 if( aItem == nullptr )
628 return {};
629
630 bool groupMatched = false;
631
632 // First see if item matches a group-by rule
633 if( m_parent.m_custom_group_rules.size() > 0 )
634 {
635 wxString searchName = aItem->GetNetName();
636
637 for( const std::unique_ptr<EDA_COMBINED_MATCHER>& rule : m_parent.m_custom_group_rules )
638 {
639 if( rule->Find( searchName ) )
640 {
641 aItem->SetParent( m_custom_group_map[ rule->GetPattern() ] );
642 groupMatched = true;
643 break;
644 }
645 }
646 }
647
648 // Then add any netclass groups required by this item
649 if( m_parent.m_groupByNetclass && !groupMatched )
650 {
651 LIST_ITEM_ITER groups_begin = m_items.begin();
652 LIST_ITEM_ITER groups_end = std::find_if_not( m_items.begin(), m_items.end(),
653 []( const std::unique_ptr<LIST_ITEM>& x )
654 {
655 return x->GetIsGroup();
656 } );
657
658 wxString match_str = aItem->GetNetclassName();
659 LIST_ITEM* group = addGroup( groups_begin, groups_end, match_str,
661 aItem->SetParent( group );
662 }
663
664 // Now add the item itself. Usually when new nets are added,
665 // they always get a higher netcode number than the already existing ones.
666 // however, if we've got filtering enabled, we might not have all the nets in
667 // our list, so do a sorted insertion.
668 auto new_iter = std::lower_bound( m_items.begin(), m_items.end(), aItem->GetNetCode(),
670
671 new_iter = m_items.insert( new_iter, std::move( aItem ) );
672 const std::unique_ptr<LIST_ITEM>& new_item = *new_iter;
673
674 ItemAdded( wxDataViewItem( new_item->Parent() ), wxDataViewItem( new_item.get() ) );
675
676 return { new_iter };
677 }
678
679 void addItems( std::vector<std::unique_ptr<LIST_ITEM>>& aItems )
680 {
681 m_items.reserve( m_items.size() + aItems.size() );
682
683 for( std::unique_ptr<LIST_ITEM>& i : aItems )
684 addItem( std::move( i ) );
685 }
686
687 std::unique_ptr<LIST_ITEM> deleteItem( const std::optional<LIST_ITEM_ITER>& aRow )
688 {
689 if( !aRow )
690 return {};
691
692 std::unique_ptr<LIST_ITEM> i = std::move( **aRow );
693
694 LIST_ITEM* parent = i->Parent();
695 i->SetParent( nullptr );
696
697 m_items.erase( *aRow );
698 ItemDeleted( wxDataViewItem( parent ), wxDataViewItem( &*i ) );
699
700 if( parent )
701 {
702 ItemChanged( wxDataViewItem( parent ) );
703
704 if( m_parent.m_groupByNetclass && parent != nullptr && parent->ChildrenCount() == 0 )
705 {
706 auto p = std::find_if( m_items.begin(), m_items.end(),
707 [&]( std::unique_ptr<LIST_ITEM>& x )
708 {
709 return x.get() == parent;
710 } );
711
712 wxASSERT( p != m_items.end() );
713 m_items.erase( p );
714
715 ItemDeleted( wxDataViewItem( parent->Parent() ), wxDataViewItem( parent ) );
716 }
717 }
718
719 Resort();
720 return i;
721 }
722
723
730 {
731 m_custom_group_map.clear();
732 int groupId = 0;
733
734 for( const std::unique_ptr<EDA_COMBINED_MATCHER>& rule : m_parent.m_custom_group_rules )
735 {
736 std::unique_ptr<LIST_ITEM>& group = m_items.emplace_back( std::make_unique<LIST_ITEM>(
737 groupId, rule->GetPattern(), LIST_ITEM::GROUP_TYPE::USER_DEFINED ) );
738 m_custom_group_map[ rule->GetPattern() ] = group.get();
739 group->SetLayerCount( m_parent.m_board->GetCopperLayerCount() );
740 ItemAdded( wxDataViewItem( group->Parent() ), wxDataViewItem( group.get() ) );
741 ++groupId;
742 }
743 }
744
745
747 {
748 BeforeReset();
749 m_items.clear();
750 AfterReset();
751 }
752
753 void updateItem( const std::optional<LIST_ITEM_ITER>& aRow )
754 {
755 if( aRow )
756 {
757 const std::unique_ptr<LIST_ITEM>& listItem = *aRow.value();
758
759 if( listItem->Parent() )
760 ItemChanged( wxDataViewItem( listItem->Parent() ) );
761
762 ItemChanged( wxDataViewItem( listItem.get() ) );
763 resortIfChanged( listItem.get() );
764 }
765 }
766
768 {
769 for( std::unique_ptr<LIST_ITEM>& i : m_items )
770 ItemChanged( wxDataViewItem( i.get() ) );
771 }
772
774 {
775 if( wxDataViewColumn* column = m_parent.m_netsList->GetSortingColumn() )
776 {
777 bool changed = false;
778
779 for( const LIST_ITEM* i = aItem; i != nullptr; i = i->Parent() )
780 changed |= itemColumnChanged( i, column->GetModelColumn() );
781
782 for( LIST_ITEM* i = aItem; i != nullptr; i = i->Parent() )
783 i->ResetColumnChangedBits();
784
785 if( changed )
786 Resort();
787 }
788 }
789
790 bool itemColumnChanged( const LIST_ITEM* aItem, unsigned int aCol ) const
791 {
792 if( aItem == nullptr || aCol >= m_parent.m_columns.size() )
793 return false;
794
795 if( aCol == COLUMN_PAD_COUNT )
796 return aItem->PadCountChanged();
797
798 else if( aCol == COLUMN_VIA_COUNT )
799 return aItem->ViaCountChanged();
800
801 else if( aCol == COLUMN_VIA_LENGTH )
802 return aItem->ViaLengthChanged();
803
804 else if( aCol == COLUMN_BOARD_LENGTH )
805 return aItem->BoardWireLengthChanged();
806
807 else if( aCol == COLUMN_PAD_DIE_LENGTH )
808 return aItem->PadDieLengthChanged();
809
810 else if( aCol == COLUMN_TOTAL_LENGTH )
811 return aItem->TotalLengthChanged();
812
813 else if( aCol > COLUMN_LAST_STATIC_COL )
814 return aItem->BoardWireLengthChanged();
815
816
817 return false;
818 }
819
820 void SetIsTimeDomain( const bool aIsTimeDomain ) { m_show_time_domain_details = aIsTimeDomain; }
821
822 // implementation of wxDataViewModel interface
823 // these are used to query the data model by the GUI view implementation.
824 // these are not supposed to be used to modify the data model. for that
825 // use the public functions above.
826
827protected:
828 unsigned int GetColumnCount() const override { return columnCount(); }
829
830 void GetValue( wxVariant& aOutValue, const wxDataViewItem& aItem,
831 unsigned int aCol ) const override
832 {
833 if( LIST_ITEM* i = static_cast<LIST_ITEM*>( aItem.GetID() ) )
834 {
835 if( aCol == COLUMN_NAME )
836 {
837 if( i->GetIsGroup() )
838 {
839 switch( i->GetGroupType() )
840 {
842 aOutValue = _( "Netclass" ) + ": " + i->GetGroupName();
843 break;
845 aOutValue = _( "Custom" ) + ": " + i->GetGroupName();
846 break;
847 default:
848 aOutValue = i->GetGroupName();
849 break;
850 }
851 }
852 else
853 {
854 aOutValue = i->GetNetName();
855 }
856 }
857
858 else if( aCol == COLUMN_NETCLASS )
859 aOutValue = i->GetNetclassName();
860
861 else if( aCol == COLUMN_PAD_COUNT )
862 aOutValue = m_parent.formatCount( i->GetPadCount() );
863
864 else if( aCol == COLUMN_VIA_COUNT )
865 aOutValue = m_parent.formatCount( i->GetViaCount() );
866
867 else if( aCol == COLUMN_VIA_LENGTH )
868 {
870 aOutValue = m_parent.formatDelay( i->GetViaDelay() );
871 else
872 aOutValue = m_parent.formatLength( i->GetViaLength() );
873 }
874
875 else if( aCol == COLUMN_BOARD_LENGTH )
876 {
878 aOutValue = m_parent.formatDelay( i->GetBoardWireDelay() );
879 else
880 aOutValue = m_parent.formatLength( i->GetBoardWireLength() );
881 }
882
883 else if( aCol == COLUMN_PAD_DIE_LENGTH )
884 {
886 aOutValue = m_parent.formatDelay( i->GetPadDieDelay() );
887 else
888 aOutValue = m_parent.formatLength( i->GetPadDieLength() );
889 }
890
891 else if( aCol == COLUMN_TOTAL_LENGTH )
892 {
894 aOutValue = m_parent.formatDelay( i->GetTotalDelay() );
895 else
896 aOutValue = m_parent.formatLength( i->GetTotalLength() );
897 }
898
899 else if( aCol > COLUMN_LAST_STATIC_COL && aCol <= m_parent.m_columns.size() )
900 {
902 aOutValue = m_parent.formatDelay( i->GetLayerWireDelay( m_parent.m_columns[aCol].layer ) );
903 else
904 aOutValue = m_parent.formatLength( i->GetLayerWireLength( m_parent.m_columns[aCol].layer ) );
905 }
906
907 else
908 aOutValue = "";
909 }
910 }
911
912 static int compareUInt( int64_t aValue1, int64_t aValue2, bool aAsc )
913 {
914 if( aAsc )
915 return aValue1 < aValue2 ? -1 : 1;
916 else
917 return aValue2 < aValue1 ? -1 : 1;
918 }
919
920 int Compare( const wxDataViewItem& aItem1, const wxDataViewItem& aItem2, unsigned int aCol,
921 bool aAsc ) const override
922 {
923 const LIST_ITEM& i1 = *static_cast<const LIST_ITEM*>( aItem1.GetID() );
924 const LIST_ITEM& i2 = *static_cast<const LIST_ITEM*>( aItem2.GetID() );
925
926 if( i1.GetIsGroup() && !i2.GetIsGroup() )
927 return -1;
928
929 if( i2.GetIsGroup() && !i1.GetIsGroup() )
930 return 1;
931
932 if( aCol == COLUMN_NAME )
933 {
934 const wxString& s1 = i1.GetNetName();
935 const wxString& s2 = i2.GetNetName();
936
937 int res = aAsc ? ValueStringCompare( s1, s2 ) : ValueStringCompare( s2, s1 );
938
939 if( res != 0 )
940 return res;
941 }
942
943 else if( aCol == COLUMN_PAD_COUNT && i1.GetPadCount() != i2.GetPadCount() )
944 return compareUInt( i1.GetPadCount(), i2.GetPadCount(), aAsc );
945
946 else if( aCol == COLUMN_VIA_COUNT && i1.GetViaCount() != i2.GetViaCount() )
947 return compareUInt( i1.GetViaCount(), i2.GetViaCount(), aAsc );
948
949 else if( aCol == COLUMN_VIA_LENGTH )
950 {
952 return compareUInt( i1.GetViaDelay(), i2.GetViaDelay(), aAsc );
953
955 return compareUInt( i1.GetViaLength(), i2.GetViaLength(), aAsc );
956 }
957
958 else if( aCol == COLUMN_BOARD_LENGTH )
959 {
961 return compareUInt( i1.GetBoardWireDelay(), i2.GetBoardWireDelay(), aAsc );
962
964 return compareUInt( i1.GetBoardWireLength(), i2.GetBoardWireLength(), aAsc );
965 }
966
967 else if( aCol == COLUMN_PAD_DIE_LENGTH )
968 {
970 return compareUInt( i1.GetPadDieDelay(), i2.GetPadDieDelay(), aAsc );
971
973 return compareUInt( i1.GetPadDieLength(), i2.GetPadDieLength(), aAsc );
974 }
975
976 else if( aCol == COLUMN_TOTAL_LENGTH )
977 {
979 return compareUInt( i1.GetTotalDelay(), i2.GetTotalDelay(), aAsc );
980
982 return compareUInt( i1.GetTotalLength(), i2.GetTotalLength(), aAsc );
983 }
984
985 else if( aCol > COLUMN_LAST_STATIC_COL && aCol < m_parent.m_columns.size() )
986 {
988 && i1.GetLayerWireDelay( m_parent.m_columns[aCol].layer )
989 != i2.GetLayerWireDelay( m_parent.m_columns[aCol].layer ) )
990 {
991 return compareUInt( i1.GetLayerWireDelay( m_parent.m_columns[aCol].layer ),
992 i2.GetLayerWireDelay( m_parent.m_columns[aCol].layer ), aAsc );
993 }
994
996 && i1.GetLayerWireLength( m_parent.m_columns[aCol].layer )
997 != i2.GetLayerWireLength( m_parent.m_columns[aCol].layer ) )
998 {
999 return compareUInt( i1.GetLayerWireLength( m_parent.m_columns[aCol].layer ),
1000 i2.GetLayerWireLength( m_parent.m_columns[aCol].layer ), aAsc );
1001 }
1002 }
1003
1004 // when the item values compare equal resort to pointer comparison.
1005 wxUIntPtr id1 = wxPtrToUInt( aItem1.GetID() );
1006 wxUIntPtr id2 = wxPtrToUInt( aItem2.GetID() );
1007
1008 return aAsc ? id1 - id2 : id2 - id1;
1009 }
1010
1011 bool SetValue( const wxVariant& aInValue, const wxDataViewItem& aItem,
1012 unsigned int aCol ) override
1013 {
1014 return false;
1015 }
1016
1017 wxDataViewItem GetParent( const wxDataViewItem& aItem ) const override
1018 {
1019 if( !aItem.IsOk() )
1020 return wxDataViewItem();
1021
1022 return wxDataViewItem( static_cast<const LIST_ITEM*>( aItem.GetID() )->Parent() );
1023 }
1024
1025 bool IsContainer( const wxDataViewItem& aItem ) const override
1026 {
1027 if( !aItem.IsOk() )
1028 return true;
1029
1030 return static_cast<const LIST_ITEM*>( aItem.GetID() )->GetIsGroup();
1031 }
1032
1033 bool HasContainerColumns( const wxDataViewItem& aItem ) const override
1034 {
1035 return IsContainer( aItem );
1036 }
1037
1038 unsigned int GetChildren( const wxDataViewItem& aParent,
1039 wxDataViewItemArray& aChildren ) const override
1040 {
1041 const LIST_ITEM* p = static_cast<const LIST_ITEM*>( aParent.GetID() );
1042
1043 if( !aParent.IsOk() )
1044 {
1045 aChildren.Alloc( m_items.size() );
1046
1047 for( const std::unique_ptr<LIST_ITEM>& i : m_items )
1048 {
1049 if( i->Parent() == nullptr )
1050 aChildren.Add( wxDataViewItem( &*i ) );
1051 }
1052
1053 return aChildren.GetCount();
1054 }
1055 else if( p->GetIsGroup() )
1056 {
1057 const int count = p->ChildrenCount();
1058
1059 if( count == 0 )
1060 return 0;
1061
1062 aChildren.Alloc( count );
1063
1064 for( auto i = p->ChildrenBegin(), end = p->ChildrenEnd(); i != end; ++i )
1065 aChildren.Add( wxDataViewItem( *i ) );
1066
1067 return aChildren.GetCount();
1068 }
1069
1070 return 0;
1071 }
1072
1073 wxString GetColumnType( unsigned int /* aCol */ ) const override { return wxS( "string" ); }
1074
1075private:
1077
1078 // primary container, sorted by netcode number.
1079 // groups have netcode < 0, so they always come first, in the order
1080 // of the filter strings as input by the user
1081 std::vector<std::unique_ptr<LIST_ITEM>> m_items;
1082
1084 std::map<wxString, LIST_ITEM*> m_custom_group_map;
1085
1087};
1088
1089#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:288
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 * 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 AddLayerWireDelay(const int64_t aValue, PCB_LAYER_ID aLayer)
void SetLayerWireLengths(const std::map< PCB_LAYER_ID, int64_t > &aValue)
void AddLayerWireLength(const int64_t aValue, PCB_LAYER_ID aLayer)
std::map< PCB_LAYER_ID, int64_t > m_layer_wire_delay
LIST_ITEM & operator=(const LIST_ITEM &)=delete
int64_t GetLayerWireDelay(PCB_LAYER_ID aLayer) const
std::map< PCB_LAYER_ID, int64_t > GetLayerWireDelays() const
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 SubLayerWireDelay(const int64_t aValue, PCB_LAYER_ID aLayer)
void SetLayerWireDelays(const std::map< PCB_LAYER_ID, int64_t > &aValue)
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
wxString formatDelay(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