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#include <string_utils.h>
25#include <board.h>
28
29
36{
37public:
45
46 LIST_ITEM( unsigned int aGroupNumber, const wxString& aGroupName, GROUP_TYPE aGroupType ) :
47 m_group_type( aGroupType ),
48 m_group_number( aGroupNumber ),
49 m_net_name( aGroupName )
50 {
51 m_group_name = aGroupName;
52 m_column_changed.resize( COLUMN_LAST_STATIC_COL + 1 + 2, 0 ); // 2 for default layer count
53 }
54
57 m_net( aNet )
58 {
59 wxASSERT( aNet );
63 m_column_changed.resize( COLUMN_LAST_STATIC_COL + 1 + 2, 0 );
64 }
65
67 {
68 m_column_changed.resize( COLUMN_LAST_STATIC_COL + 1 + 2, 0 );
69 }
70
71 LIST_ITEM& operator=( const LIST_ITEM& ) = delete;
72
73 bool GetIsGroup() const { return m_group_type != GROUP_TYPE::NONE; }
74 const wxString& GetGroupName() const { return m_group_name; }
76 int GetGroupNumber() const { return m_group_number; }
77
78 auto ChildrenBegin() const { return m_children.begin(); }
79 auto ChildrenEnd() const { return m_children.end(); }
80 unsigned int ChildrenCount() const { return m_children.size(); }
81
82 void SetLayerCount( unsigned int aValue )
83 {
84 m_column_changed.resize( COLUMN_LAST_STATIC_COL + 1 + aValue, 0 );
85 }
86
87 NETINFO_ITEM* GetNet() const { return m_net; }
88
89 int GetNetCode() const
90 {
91 return GetIsGroup() ? ( 0 - int( m_group_number ) - 1 ) : m_net->GetNetCode();
92 }
93
94 const wxString& GetNetName() const { return m_net_name; }
95 const wxString& GetNetclassName() const { return m_net_class; }
96 const wxString& GetNetChainName() const { return m_netChainName; }
97
99 {
100 std::fill( m_column_changed.begin(), m_column_changed.end(), 0 );
101 }
102
103 unsigned int GetPadCount() const { return m_pad_count; }
104
106
107 void SetPadCount( unsigned int aValue )
108 {
109 if( m_parent )
110 m_parent->SetPadCount( m_parent->GetPadCount() - m_pad_count + aValue );
111
113 m_pad_count = aValue;
114 }
115
117
118 void SetNetChainName( const wxString& aValue )
119 {
121 m_netChainName = aValue;
122 }
123
124 void AddPadCount( unsigned int aValue )
125 {
126 if( m_parent )
127 m_parent->AddPadCount( aValue );
128
129 m_column_changed[COLUMN_PAD_COUNT] |= ( aValue != 0 );
130 m_pad_count += aValue;
131 }
132
133 void SubPadCount( unsigned int aValue )
134 {
135 if( m_parent )
136 m_parent->SubPadCount( aValue );
137
138 m_column_changed[COLUMN_PAD_COUNT] |= ( aValue != 0 );
139 m_pad_count -= aValue;
140 }
141
142 unsigned GetViaCount() const { return m_via_count; }
143
145
146 void SetViaCount( unsigned int aValue )
147 {
148 if( m_parent )
149 m_parent->SetViaCount( m_parent->GetViaCount() - m_via_count + aValue );
150
152 m_via_count = aValue;
153 }
154
155 void AddViaCount( unsigned int aValue )
156 {
157 if( m_parent )
158 m_parent->AddViaCount( aValue );
159
160 m_column_changed[COLUMN_VIA_COUNT] |= ( aValue != 0 );
161 m_via_count += aValue;
162 }
163
164 void SubViaCount( unsigned int aValue )
165 {
166 if( m_parent )
167 m_parent->SubViaCount( aValue );
168
169 m_column_changed[COLUMN_VIA_COUNT] |= ( aValue != 0 );
170 m_via_count -= aValue;
171 }
172
173 int64_t GetViaLength() const { return m_via_length; }
174
176
177 void SetViaLength( unsigned int aValue )
178 {
179 if( m_parent )
180 m_parent->SetViaLength( m_parent->GetViaLength() - m_via_length + aValue );
181
183 m_via_length = aValue;
184 }
185
186 void AddViaLength( unsigned int aValue )
187 {
188 if( m_parent )
189 m_parent->AddViaLength( aValue );
190
191 m_column_changed[COLUMN_VIA_LENGTH] |= ( aValue != 0 );
192 m_via_length += aValue;
193 }
194
195 void SubViaLength( int64_t aValue )
196 {
197 if( m_parent )
198 m_parent->SubViaLength( aValue );
199
200 m_column_changed[COLUMN_VIA_LENGTH] |= ( aValue != 0 );
201 m_via_length -= aValue;
202 }
203
204 int64_t GetViaDelay() const { return m_via_delay; }
205
206 void SetViaDelay( unsigned int aValue )
207 {
208 if( m_parent )
209 m_parent->SetViaDelay( m_parent->GetViaDelay() - m_via_delay + aValue );
210
212 m_via_delay = aValue;
213 }
214
215 void AddViaDelay( unsigned int aValue )
216 {
217 if( m_parent )
218 m_parent->AddViaDelay( aValue );
219
220 m_column_changed[COLUMN_VIA_LENGTH] |= ( aValue != 0 );
221 m_via_delay += aValue;
222 }
223
224 void SubViaDelay( int64_t aValue )
225 {
226 if( m_parent )
227 m_parent->SubViaDelay( aValue );
228
229 m_column_changed[COLUMN_VIA_LENGTH] |= ( aValue != 0 );
230 m_via_delay -= aValue;
231 }
232
233 int64_t GetBoardWireLength() const
234 {
235 int64_t retval = 0;
236
237 for( auto& [layer, length] : m_layer_wire_length )
238 retval += length;
239
240 return retval;
241 }
242
243 int64_t GetBoardWireDelay() const
244 {
245 int64_t retval = 0;
246
247 for( auto& [layer, delay] : m_layer_wire_delay )
248 retval += delay;
249
250 return retval;
251 }
252
253 int64_t GetLayerWireLength( PCB_LAYER_ID aLayer ) const
254 {
255 auto it = m_layer_wire_length.find( aLayer );
256 return it != m_layer_wire_length.end() ? it->second : 0;
257 }
258
259 int64_t GetLayerWireDelay( PCB_LAYER_ID aLayer ) const
260 {
261 auto it = m_layer_wire_delay.find( aLayer );
262 return it != m_layer_wire_delay.end() ? it->second : 0;
263 }
264
266
267 void SetLayerWireLength( const int64_t aValue, PCB_LAYER_ID aLayer )
268 {
269 auto it = m_layer_wire_length.find( aLayer );
270
271 wxCHECK_RET( it != m_layer_wire_length.end(), wxT( "Invalid layer specified" ) );
272
273 auto& [_, length] = *it;
274
275 if( m_parent )
276 {
277 m_parent->SetLayerWireLength( m_parent->GetBoardWireLength() - length + aValue,
278 aLayer );
279 }
280
281 m_column_changed[COLUMN_BOARD_LENGTH] |= ( length != aValue );
282 length = aValue;
283 }
284
285 std::map<PCB_LAYER_ID, int64_t> GetLayerWireLengths() const { return m_layer_wire_length; }
286
287 std::map<PCB_LAYER_ID, int64_t> GetLayerWireDelays() const { return m_layer_wire_delay; }
288
289 void SetLayerWireLengths( const std::map<PCB_LAYER_ID, int64_t>& aValue )
290 {
291 if( m_parent )
292 {
293 for( auto& [oldLayer, oldLength] : m_layer_wire_length )
294 m_parent->SubLayerWireLength( oldLength, oldLayer );
295
296 for( auto& [newLayer, newLength] : aValue )
297 m_parent->AddLayerWireLength( newLength, newLayer );
298 }
299
300 m_layer_wire_length = aValue;
301 }
302
303 void AddLayerWireLength( const int64_t aValue, PCB_LAYER_ID aLayer )
304 {
305 if( m_parent )
306 m_parent->AddLayerWireLength( aValue, aLayer );
307
309 m_layer_wire_length[aLayer] += aValue;
310 }
311
312 void SubLayerWireLength( const int64_t aValue, PCB_LAYER_ID aLayer )
313 {
314 if( m_parent )
315 m_parent->SubLayerWireLength( aValue, aLayer );
316
318 m_layer_wire_length[aLayer] -= aValue;
319 }
320
321 void SetLayerWireDelays( const std::map<PCB_LAYER_ID, int64_t>& aValue )
322 {
323 if( m_parent )
324 {
325 for( auto& [oldLayer, oldLength] : m_layer_wire_delay )
326 m_parent->SubLayerWireDelay( oldLength, oldLayer );
327
328 for( auto& [newLayer, newLength] : aValue )
329 m_parent->AddLayerWireDelay( newLength, newLayer );
330 }
331
332 m_layer_wire_delay = aValue;
333 }
334
335 void AddLayerWireDelay( const int64_t aValue, PCB_LAYER_ID aLayer )
336 {
337 if( m_parent )
338 m_parent->AddLayerWireDelay( aValue, aLayer );
339
341 m_layer_wire_delay[aLayer] += aValue;
342 }
343
344 void SubLayerWireDelay( const int64_t aValue, PCB_LAYER_ID aLayer )
345 {
346 if( m_parent )
347 m_parent->SubLayerWireDelay( aValue, aLayer );
348
350 m_layer_wire_delay[aLayer] -= aValue;
351 }
352
353 int64_t GetPadDieLength() const { return m_pad_die_length; }
354
356
357 void SetPadDieLength( int64_t aValue )
358 {
359 if( m_parent )
360 m_parent->SetPadDieLength( m_parent->GetPadDieLength() - m_pad_die_length + aValue );
361
363 m_pad_die_length = aValue;
364 }
365
366 void AddPadDieLength( int64_t aValue )
367 {
368 if( m_parent )
369 m_parent->AddPadDieLength( aValue );
370
371 m_column_changed[COLUMN_PAD_DIE_LENGTH] |= ( aValue != 0 );
372 m_pad_die_length += aValue;
373 }
374
375 void SubPadDieLength( int64_t aValue )
376 {
377 if( m_parent )
378 m_parent->SubPadDieLength( aValue );
379
380 m_column_changed[COLUMN_PAD_DIE_LENGTH] |= ( aValue != 0 );
381 m_pad_die_length -= aValue;
382 }
383
384 int64_t GetNetChainLength() const { return m_netChainLength; }
385
387
388 void SetNetChainLength( int64_t aValue )
389 {
391 m_netChainLength = aValue;
392 }
393
394 int64_t GetNetChainDelay() const { return m_netChainDelay; }
395
396 void SetNetChainDelay( int64_t aValue )
397 {
399 m_netChainDelay = aValue;
400 }
401
402 int64_t GetPadDieDelay() const { return m_pad_die_delay; }
403
404 void SetPadDieDelay( int64_t aValue )
405 {
406 if( m_parent )
407 m_parent->SetPadDieDelay( m_parent->GetPadDieDelay() - m_pad_die_delay + aValue );
408
410 m_pad_die_delay = aValue;
411 }
412
413 void AddPadDieDelay( int64_t aValue )
414 {
415 if( m_parent )
416 m_parent->AddPadDieDelay( aValue );
417
418 m_column_changed[COLUMN_PAD_DIE_LENGTH] |= ( aValue != 0 );
419 m_pad_die_delay += aValue;
420 }
421
422 void SubPadDieDelay( int64_t aValue )
423 {
424 if( m_parent )
425 m_parent->SubPadDieDelay( aValue );
426
427 m_column_changed[COLUMN_PAD_DIE_LENGTH] |= ( aValue != 0 );
428 m_pad_die_delay -= aValue;
429 }
430
431 // the total length column is always computed, never stored.
432 unsigned long long int GetTotalLength() const
433 {
435 }
436
437 unsigned long long int GetTotalDelay() const { return GetBoardWireDelay() + GetViaDelay() + GetPadDieDelay(); }
438
440 {
442 }
443
444 LIST_ITEM* Parent() const { return m_parent; }
445
446 void SetParent( LIST_ITEM* aParent )
447 {
448 if( m_parent == aParent )
449 return;
450
451 if( m_parent != nullptr )
452 {
453 m_parent->SubPadCount( GetPadCount() );
454 m_parent->SubViaCount( GetViaCount() );
455 m_parent->SubViaLength( GetViaLength() );
456 m_parent->SubViaDelay( GetViaDelay() );
457
458 for( auto& [layer, length] : m_layer_wire_length )
459 m_parent->SubLayerWireLength( length, layer );
460
461 for( auto& [layer, delay] : m_layer_wire_delay )
462 m_parent->SubLayerWireDelay( delay, layer );
463
464 m_parent->SubPadDieLength( GetPadDieLength() );
465 m_parent->SubPadDieDelay( GetPadDieDelay() );
466
467 m_parent->m_children.erase( std::find( m_parent->m_children.begin(),
468 m_parent->m_children.end(), this ) );
469 }
470
471 m_parent = aParent;
472
473 if( m_parent != nullptr )
474 {
475 m_parent->AddPadCount( GetPadCount() );
476 m_parent->AddViaCount( GetViaCount() );
477 m_parent->AddViaLength( GetViaLength() );
478 m_parent->AddViaDelay( GetViaDelay() );
479
480 for( auto& [layer, length] : m_layer_wire_length )
481 m_parent->AddLayerWireLength( length, layer );
482
483 for( auto& [layer, delay] : m_layer_wire_delay )
484 m_parent->AddLayerWireDelay( delay, layer );
485
486 m_parent->AddPadDieLength( GetPadDieLength() );
487 m_parent->AddPadDieDelay( GetPadDieDelay() );
488
489 m_parent->m_children.push_back( this );
490 }
491 }
492
493private:
494 LIST_ITEM* m_parent = nullptr;
495 std::vector<LIST_ITEM*> m_children;
496
498 unsigned int m_group_number = 0;
499 NETINFO_ITEM* m_net = nullptr;
500 unsigned int m_pad_count = 0;
501 unsigned int m_via_count = 0;
502 int64_t m_via_length = 0;
503 int64_t m_via_delay = 0;
504 int64_t m_pad_die_length = 0;
505 int64_t m_pad_die_delay = 0;
506 int64_t m_netChainLength = 0;
507 int64_t m_netChainDelay = 0;
508
509 std::map<PCB_LAYER_ID, int64_t> m_layer_wire_length{};
510 std::map<PCB_LAYER_ID, int64_t> m_layer_wire_delay{};
511
512 // Dirty bits to record when some attribute has changed, in order to avoid unnecessary sort
513 // operations.
514 // The values are semantically bools, but STL auto-promotes a std::vector<bool> to a bitset,
515 // and then operator|= doesn't work.
516 std::vector<int> m_column_changed;
517
518 // cached formatted names for faster display sorting
519 wxString m_net_name;
520 wxString m_net_class;
522 wxString m_group_name;
523};
524
525
527{
528 template <typename T>
529 bool operator()( const T& a, const T& b ) const
530 {
531 return a->GetNetCode() < b->GetNetCode();
532 }
533
534 template <typename T>
535 bool operator()( const T& a, int b ) const
536 {
537 return a->GetNetCode() < b;
538 }
539
540 template <typename T>
541 bool operator()( int a, const T& b ) const
542 {
543 return a < b->GetNetCode();
544 }
545};
546
547
549{
550 template <typename T>
551 bool operator()( const T& a, const T& b ) const
552 {
553 return a->GetGroupNumber() < b->GetGroupNumber();
554 }
555
556 template <typename T>
557 bool operator()( const T& a, int b ) const
558 {
559 return a->GetGroupNumber() < b;
560 }
561
562 template <typename T>
563 bool operator()( int a, const T& b ) const
564 {
565 return a < b->GetGroupNumber();
566 }
567};
568
569
573class PCB_NET_INSPECTOR_PANEL::DATA_MODEL : public wxDataViewModel
574{
575public:
577 m_parent( parent )
578 {}
579
580 unsigned int columnCount() const { return m_parent.m_columns.size(); }
581
582 unsigned int itemCount() const { return m_items.size(); }
583
584 wxVariant valueAt( unsigned int aCol, unsigned int aRow ) const
585 {
586 wxVariant r;
587 GetValue( r, wxDataViewItem( const_cast<LIST_ITEM*>( &*( m_items[aRow] ) ) ), aCol );
588 return r;
589 }
590
591 const LIST_ITEM& itemAt( unsigned int aRow ) const { return *m_items.at( aRow ); }
592
593 wxVariant valueForItem( const LIST_ITEM* aItem, unsigned int aCol ) const
594 {
595 wxVariant r;
596 GetValue( r, wxDataViewItem( const_cast<LIST_ITEM*>( aItem ) ), aCol );
597 return r;
598 }
599
600 std::vector<std::pair<wxString, wxDataViewItem>> getGroupDataViewItems()
601 {
602 std::vector<std::pair<wxString, wxDataViewItem>> ret;
603
604 for( std::unique_ptr<LIST_ITEM>& item : m_items )
605 {
606 if( item->GetIsGroup() )
607 ret.push_back( std::make_pair( item->GetGroupName(), wxDataViewItem( item.get() ) ) );
608 }
609
610 return ret;
611 }
612
613 std::optional<LIST_ITEM_ITER> findItem( int aNetCode )
614 {
615 auto i = std::lower_bound( m_items.begin(), m_items.end(), aNetCode,
617
618 if( i == m_items.end() || ( *i )->GetNetCode() != aNetCode )
619 return std::nullopt;
620
621 return { i };
622 }
623
624 std::optional<LIST_ITEM_ITER> findItem( NETINFO_ITEM* aNet )
625 {
626 if( aNet != nullptr )
627 return findItem( aNet->GetNetCode() );
628 else
629 return std::nullopt;
630 }
631
632 std::optional<LIST_ITEM_ITER> findGroupItem( int aGroupNumber )
633 {
634 auto i = std::lower_bound( m_items.begin(), m_items.end(), aGroupNumber,
636
637 if( i == m_items.end() || ( *i )->GetGroupNumber() != aGroupNumber )
638 return std::nullopt;
639
640 return { i };
641 }
642
644 wxString groupName, LIST_ITEM::GROUP_TYPE groupType )
645 {
646 LIST_ITEM_ITER group = std::find_if( groupsBegin, groupsEnd,
647 [&]( const std::unique_ptr<LIST_ITEM>& x )
648 {
649 return x->GetGroupName() == groupName
650 && x->GetGroupType() == groupType;
651 } );
652
653 if( group == groupsEnd )
654 {
655 int dist = std::distance( groupsBegin, groupsEnd );
656 std::unique_ptr<LIST_ITEM> groupItem = std::make_unique<LIST_ITEM>( dist, groupName, groupType );
657
658 group = m_items.insert( groupsEnd, std::move( groupItem ) );
659 ItemAdded( wxDataViewItem( ( *group )->Parent() ), wxDataViewItem( ( *group ).get() ) );
660 }
661
662 return ( *group ).get();
663 }
664
665 std::optional<LIST_ITEM_ITER> addItem( std::unique_ptr<LIST_ITEM> aItem )
666 {
667 if( aItem == nullptr )
668 return {};
669
670 bool groupMatched = false;
671
672 // First see if item matches a group-by rule
673 if( m_parent.m_custom_group_rules.size() > 0 )
674 {
675 wxString searchName = aItem->GetNetName();
676
677 for( const std::unique_ptr<EDA_COMBINED_MATCHER>& rule : m_parent.m_custom_group_rules )
678 {
679 if( rule->Find( searchName ) )
680 {
681 aItem->SetParent( m_custom_group_map[ rule->GetPattern() ] );
682 groupMatched = true;
683 break;
684 }
685 }
686 }
687
688 // Then add any chain groups required by this item
689 if( m_parent.m_groupByNetChain && !groupMatched )
690 {
691 LIST_ITEM_ITER groups_begin = m_items.begin();
692 LIST_ITEM_ITER groups_end = std::find_if_not( m_items.begin(), m_items.end(),
693 []( const std::unique_ptr<LIST_ITEM>& x )
694 {
695 return x->GetIsGroup();
696 } );
697
698 wxString match_str = aItem->GetNetChainName();
699 LIST_ITEM* group = addGroup( groups_begin, groups_end, match_str,
701 aItem->SetParent( group );
702 groupMatched = true;
703 }
704
705 // Then add any netclass groups required by this item
706 if( m_parent.m_groupByNetclass && !groupMatched )
707 {
708 LIST_ITEM_ITER groups_begin = m_items.begin();
709 LIST_ITEM_ITER groups_end = std::find_if_not( m_items.begin(), m_items.end(),
710 []( const std::unique_ptr<LIST_ITEM>& x )
711 {
712 return x->GetIsGroup();
713 } );
714
715 wxString match_str = aItem->GetNetclassName();
716 LIST_ITEM* group = addGroup( groups_begin, groups_end, match_str, LIST_ITEM::GROUP_TYPE::NETCLASS );
717 aItem->SetParent( group );
718 groupMatched = true;
719 }
720
721 // Now add the item itself. Usually when new nets are added,
722 // they always get a higher netcode number than the already existing ones.
723 // however, if we've got filtering enabled, we might not have all the nets in
724 // our list, so do a sorted insertion.
725 auto new_iter = std::lower_bound( m_items.begin(), m_items.end(), aItem->GetNetCode(),
727
728 new_iter = m_items.insert( new_iter, std::move( aItem ) );
729 const std::unique_ptr<LIST_ITEM>& new_item = *new_iter;
730
731 ItemAdded( wxDataViewItem( new_item->Parent() ), wxDataViewItem( new_item.get() ) );
732
733 return { new_iter };
734 }
735
736 void addItems( std::vector<std::unique_ptr<LIST_ITEM>>& aItems )
737 {
738 m_items.reserve( m_items.size() + aItems.size() );
739
740 for( std::unique_ptr<LIST_ITEM>& i : aItems )
741 addItem( std::move( i ) );
742 }
743
744 std::unique_ptr<LIST_ITEM> deleteItem( const std::optional<LIST_ITEM_ITER>& aRow )
745 {
746 if( !aRow )
747 return {};
748
749 std::unique_ptr<LIST_ITEM> i = std::move( **aRow );
750
751 LIST_ITEM* parent = i->Parent();
752 i->SetParent( nullptr );
753
754 m_items.erase( *aRow );
755 ItemDeleted( wxDataViewItem( parent ), wxDataViewItem( &*i ) );
756
757 if( parent )
758 {
759 ItemChanged( wxDataViewItem( parent ) );
760
761 if( parent != nullptr && parent->ChildrenCount() == 0
762 && ( ( m_parent.m_groupByNetclass && parent->GetGroupType() == LIST_ITEM::GROUP_TYPE::NETCLASS )
763 || ( m_parent.m_groupByNetChain && parent->GetGroupType() == LIST_ITEM::GROUP_TYPE::NET_CHAIN ) ) )
764 {
765 auto p = std::find_if( m_items.begin(), m_items.end(),
766 [&]( std::unique_ptr<LIST_ITEM>& x )
767 {
768 return x.get() == parent;
769 } );
770
771 wxASSERT( p != m_items.end() );
772 m_items.erase( p );
773
774 ItemDeleted( wxDataViewItem( parent->Parent() ), wxDataViewItem( parent ) );
775 }
776 }
777
778 Resort();
779 return i;
780 }
781
788 {
789 m_custom_group_map.clear();
790 int groupId = 0;
791
792 for( const std::unique_ptr<EDA_COMBINED_MATCHER>& rule : m_parent.m_custom_group_rules )
793 {
794 std::unique_ptr<LIST_ITEM>& group = m_items.emplace_back( std::make_unique<LIST_ITEM>(
795 groupId, rule->GetPattern(), LIST_ITEM::GROUP_TYPE::USER_DEFINED ) );
796 m_custom_group_map[ rule->GetPattern() ] = group.get();
797 group->SetLayerCount( m_parent.m_board->GetCopperLayerCount() );
798 ItemAdded( wxDataViewItem( group->Parent() ), wxDataViewItem( group.get() ) );
799 ++groupId;
800 }
801 }
802
804 {
805 BeforeReset();
806 m_items.clear();
807 AfterReset();
808 }
809
810 void updateItem( const std::optional<LIST_ITEM_ITER>& aRow )
811 {
812 if( aRow )
813 {
814 const std::unique_ptr<LIST_ITEM>& listItem = *aRow.value();
815
816 if( listItem->Parent() )
817 ItemChanged( wxDataViewItem( listItem->Parent() ) );
818
819 ItemChanged( wxDataViewItem( listItem.get() ) );
820 resortIfChanged( listItem.get() );
821 }
822 }
823
825 {
826 for( std::unique_ptr<LIST_ITEM>& i : m_items )
827 ItemChanged( wxDataViewItem( i.get() ) );
828 }
829
831 {
832 if( wxDataViewColumn* column = m_parent.m_netsList->GetSortingColumn() )
833 {
834 bool changed = false;
835
836 for( const LIST_ITEM* i = aItem; i != nullptr; i = i->Parent() )
837 changed |= itemColumnChanged( i, column->GetModelColumn() );
838
839 for( LIST_ITEM* i = aItem; i != nullptr; i = i->Parent() )
840 i->ResetColumnChangedBits();
841
842 if( changed )
843 Resort();
844 }
845 }
846
847 bool itemColumnChanged( const LIST_ITEM* aItem, unsigned int aCol ) const
848 {
849 if( aItem == nullptr || aCol >= m_parent.m_columns.size() )
850 return false;
851
852 if( aCol == COLUMN_PAD_COUNT )
853 return aItem->PadCountChanged();
854
855 else if( aCol == COLUMN_VIA_COUNT )
856 return aItem->ViaCountChanged();
857
858 else if( aCol == COLUMN_VIA_LENGTH )
859 return aItem->ViaLengthChanged();
860
861 else if( aCol == COLUMN_BOARD_LENGTH )
862 return aItem->BoardWireLengthChanged();
863
864 else if( aCol == COLUMN_PAD_DIE_LENGTH )
865 return aItem->PadDieLengthChanged();
866
867 else if( aCol == COLUMN_TOTAL_LENGTH )
868 return aItem->TotalLengthChanged();
869
870 else if( aCol > COLUMN_LAST_STATIC_COL )
871 return aItem->BoardWireLengthChanged();
872
873
874 return false;
875 }
876
877 void SetIsTimeDomain( const bool aIsTimeDomain ) { m_show_time_domain_details = aIsTimeDomain; }
878
879 // implementation of wxDataViewModel interface
880 // these are used to query the data model by the GUI view implementation.
881 // these are not supposed to be used to modify the data model. for that
882 // use the public functions above.
883
884protected:
885 unsigned int GetColumnCount() const override { return columnCount(); }
886
887 void GetValue( wxVariant& aOutValue, const wxDataViewItem& aItem,
888 unsigned int aCol ) const override
889 {
890 if( LIST_ITEM* i = static_cast<LIST_ITEM*>( aItem.GetID() ) )
891 {
892 if( aCol == COLUMN_NAME )
893 {
894 if( i->GetIsGroup() )
895 {
896 switch( i->GetGroupType() )
897 {
899 aOutValue = _( "Netclass" ) + ": " + i->GetGroupName();
900 break;
902 aOutValue = _( "Custom" ) + ": " + i->GetGroupName();
903 break;
904 default:
905 aOutValue = i->GetGroupName();
906 break;
907 }
908 }
909 else
910 {
911 aOutValue = i->GetNetName();
912 }
913 }
914 else if( aCol == COLUMN_NET_CHAIN )
915 {
916 wxString chainName = i->GetNetChainName();
917
918 // If the chain is assigned to a class, append it for visibility:
919 // "DDR_DQ0 [DDR_DATA]"
920 if( !chainName.IsEmpty() && m_parent.m_board )
921 {
922 if( const std::shared_ptr<NET_SETTINGS>& ns =
923 m_parent.m_board->GetDesignSettings().m_NetSettings )
924 {
925 wxString className = ns->GetNetChainClass( chainName );
926
927 if( !className.IsEmpty() )
928 chainName += wxString::Format( wxT( " [%s]" ), className );
929 }
930 }
931
932 aOutValue = chainName;
933 }
934 else if( aCol == COLUMN_NETCLASS )
935 {
936 aOutValue = i->GetNetclassName();
937 }
938 else if( aCol == COLUMN_PAD_COUNT )
939 {
940 aOutValue = m_parent.formatCount( i->GetPadCount() );
941 }
942 else if( aCol == COLUMN_VIA_COUNT )
943 {
944 aOutValue = m_parent.formatCount( i->GetViaCount() );
945 }
946 else if( aCol == COLUMN_VIA_LENGTH )
947 {
949 aOutValue = m_parent.formatDelay( i->GetViaDelay() );
950 else
951 aOutValue = m_parent.formatLength( i->GetViaLength() );
952 }
953 else if( aCol == COLUMN_BOARD_LENGTH )
954 {
956 aOutValue = m_parent.formatDelay( i->GetBoardWireDelay() );
957 else
958 aOutValue = m_parent.formatLength( i->GetBoardWireLength() );
959 }
960 else if( aCol == COLUMN_PAD_DIE_LENGTH )
961 {
963 aOutValue = m_parent.formatDelay( i->GetPadDieDelay() );
964 else
965 aOutValue = m_parent.formatLength( i->GetPadDieLength() );
966 }
967 else if( aCol == COLUMN_TOTAL_LENGTH )
968 {
970 aOutValue = m_parent.formatDelay( i->GetTotalDelay() );
971 else
972 aOutValue = m_parent.formatLength( i->GetTotalLength() );
973 }
974 else if( aCol == COLUMN_NET_CHAIN_LENGTH )
975 {
977 aOutValue = m_parent.formatDelay( i->GetNetChainDelay() );
978 else
979 aOutValue = m_parent.formatLength( i->GetNetChainLength() );
980 }
981 else if( aCol > COLUMN_LAST_STATIC_COL && aCol <= m_parent.m_columns.size() )
982 {
984 aOutValue = m_parent.formatDelay( i->GetLayerWireDelay( m_parent.m_columns[aCol].layer ) );
985 else
986 aOutValue = m_parent.formatLength( i->GetLayerWireLength( m_parent.m_columns[aCol].layer ) );
987 }
988 else
989 {
990 aOutValue = "";
991 }
992 }
993 }
994
995 static int compareUInt( int64_t aValue1, int64_t aValue2, bool aAsc )
996 {
997 if( aAsc )
998 return aValue1 < aValue2 ? -1 : 1;
999 else
1000 return aValue2 < aValue1 ? -1 : 1;
1001 }
1002
1003 int Compare( const wxDataViewItem& aItem1, const wxDataViewItem& aItem2, unsigned int aCol,
1004 bool aAsc ) const override
1005 {
1006 const LIST_ITEM& i1 = *static_cast<const LIST_ITEM*>( aItem1.GetID() );
1007 const LIST_ITEM& i2 = *static_cast<const LIST_ITEM*>( aItem2.GetID() );
1008
1009 if( i1.GetIsGroup() && !i2.GetIsGroup() )
1010 return -1;
1011
1012 if( i2.GetIsGroup() && !i1.GetIsGroup() )
1013 return 1;
1014
1015 if( aCol == COLUMN_NAME )
1016 {
1017 const wxString& s1 = i1.GetNetName();
1018 const wxString& s2 = i2.GetNetName();
1019
1020 int res = aAsc ? ValueStringCompare( s1, s2 ) : ValueStringCompare( s2, s1 );
1021
1022 if( res != 0 )
1023 return res;
1024 }
1025 else if( aCol == COLUMN_NETCLASS )
1026 {
1027 const wxString& s1 = i1.GetNetclassName();
1028 const wxString& s2 = i2.GetNetclassName();
1029
1030 int res = aAsc ? ValueStringCompare( s1, s2 ) : ValueStringCompare( s2, s1 );
1031
1032 if( res != 0 )
1033 return res;
1034 }
1035 else if( aCol == COLUMN_NET_CHAIN )
1036 {
1037 const wxString& s1 = i1.GetNetChainName();
1038 const wxString& s2 = i2.GetNetChainName();
1039
1040 int res = aAsc ? ValueStringCompare( s1, s2 ) : ValueStringCompare( s2, s1 );
1041
1042 if( res != 0 )
1043 return res;
1044 }
1045 else if( aCol == COLUMN_PAD_COUNT && i1.GetPadCount() != i2.GetPadCount() )
1046 {
1047 return compareUInt( i1.GetPadCount(), i2.GetPadCount(), aAsc );
1048 }
1049 else if( aCol == COLUMN_VIA_COUNT && i1.GetViaCount() != i2.GetViaCount() )
1050 {
1051 return compareUInt( i1.GetViaCount(), i2.GetViaCount(), aAsc );
1052 }
1053 else if( aCol == COLUMN_VIA_LENGTH )
1054 {
1056 return compareUInt( i1.GetViaDelay(), i2.GetViaDelay(), aAsc );
1057
1059 return compareUInt( i1.GetViaLength(), i2.GetViaLength(), aAsc );
1060 }
1061 else if( aCol == COLUMN_BOARD_LENGTH )
1062 {
1064 return compareUInt( i1.GetBoardWireDelay(), i2.GetBoardWireDelay(), aAsc );
1065
1067 return compareUInt( i1.GetBoardWireLength(), i2.GetBoardWireLength(), aAsc );
1068 }
1069 else if( aCol == COLUMN_PAD_DIE_LENGTH )
1070 {
1072 return compareUInt( i1.GetPadDieDelay(), i2.GetPadDieDelay(), aAsc );
1073
1075 return compareUInt( i1.GetPadDieLength(), i2.GetPadDieLength(), aAsc );
1076 }
1077 else if( aCol == COLUMN_TOTAL_LENGTH )
1078 {
1080 return compareUInt( i1.GetTotalDelay(), i2.GetTotalDelay(), aAsc );
1081
1083 return compareUInt( i1.GetTotalLength(), i2.GetTotalLength(), aAsc );
1084 }
1085 else if( aCol == COLUMN_NET_CHAIN_LENGTH )
1086 {
1088 return compareUInt( i1.GetNetChainDelay(), i2.GetNetChainDelay(), aAsc );
1089
1091 return compareUInt( i1.GetNetChainLength(), i2.GetNetChainLength(), aAsc );
1092 }
1093 else if( aCol > COLUMN_LAST_STATIC_COL && aCol < m_parent.m_columns.size() )
1094 {
1096 && i1.GetLayerWireDelay( m_parent.m_columns[aCol].layer )
1097 != i2.GetLayerWireDelay( m_parent.m_columns[aCol].layer ) )
1098 {
1099 return compareUInt( i1.GetLayerWireDelay( m_parent.m_columns[aCol].layer ),
1100 i2.GetLayerWireDelay( m_parent.m_columns[aCol].layer ), aAsc );
1101 }
1102
1104 && i1.GetLayerWireLength( m_parent.m_columns[aCol].layer )
1105 != i2.GetLayerWireLength( m_parent.m_columns[aCol].layer ) )
1106 {
1107 return compareUInt( i1.GetLayerWireLength( m_parent.m_columns[aCol].layer ),
1108 i2.GetLayerWireLength( m_parent.m_columns[aCol].layer ), aAsc );
1109 }
1110 }
1111
1112 // when the item values compare equal resort to pointer comparison.
1113 wxUIntPtr id1 = wxPtrToUInt( aItem1.GetID() );
1114 wxUIntPtr id2 = wxPtrToUInt( aItem2.GetID() );
1115
1116 return aAsc ? id1 - id2 : id2 - id1;
1117 }
1118
1119 bool SetValue( const wxVariant& aInValue, const wxDataViewItem& aItem,
1120 unsigned int aCol ) override
1121 {
1122 return false;
1123 }
1124
1125 wxDataViewItem GetParent( const wxDataViewItem& aItem ) const override
1126 {
1127 if( !aItem.IsOk() )
1128 return wxDataViewItem();
1129
1130 return wxDataViewItem( static_cast<const LIST_ITEM*>( aItem.GetID() )->Parent() );
1131 }
1132
1133 bool IsContainer( const wxDataViewItem& aItem ) const override
1134 {
1135 if( !aItem.IsOk() )
1136 return true;
1137
1138 return static_cast<const LIST_ITEM*>( aItem.GetID() )->GetIsGroup();
1139 }
1140
1141 bool HasContainerColumns( const wxDataViewItem& aItem ) const override
1142 {
1143 return IsContainer( aItem );
1144 }
1145
1146 unsigned int GetChildren( const wxDataViewItem& aParent,
1147 wxDataViewItemArray& aChildren ) const override
1148 {
1149 const LIST_ITEM* p = static_cast<const LIST_ITEM*>( aParent.GetID() );
1150
1151 if( !aParent.IsOk() )
1152 {
1153 aChildren.Alloc( m_items.size() );
1154
1155 for( const std::unique_ptr<LIST_ITEM>& i : m_items )
1156 {
1157 if( i->Parent() == nullptr )
1158 aChildren.Add( wxDataViewItem( &*i ) );
1159 }
1160
1161 return aChildren.GetCount();
1162 }
1163 else if( p->GetIsGroup() )
1164 {
1165 const int count = p->ChildrenCount();
1166
1167 if( count == 0 )
1168 return 0;
1169
1170 aChildren.Alloc( count );
1171
1172 for( auto i = p->ChildrenBegin(), end = p->ChildrenEnd(); i != end; ++i )
1173 aChildren.Add( wxDataViewItem( *i ) );
1174
1175 return aChildren.GetCount();
1176 }
1177
1178 return 0;
1179 }
1180
1181 wxString GetColumnType( unsigned int /* aCol */ ) const override { return wxS( "string" ); }
1182
1183private:
1185
1186 // primary container, sorted by netcode number.
1187 // groups have netcode < 0, so they always come first, in the order
1188 // of the filter strings as input by the user
1189 std::vector<std::unique_ptr<LIST_ITEM>> m_items;
1190
1192 std::map<wxString, LIST_ITEM*> m_custom_group_map;
1193
1195};
1196
1197#endif
const wxString GetHumanReadableName() const
Gets the consolidated name of this netclass (which may be an aggregate).
Definition netclass.cpp:294
Handle the data for a net.
Definition netinfo.h:50
const wxString & GetNetChain() const
Definition netinfo.h:116
const wxString & GetNetname() const
Definition netinfo.h:104
NETCLASS * GetNetClass()
Definition netinfo.h:95
int GetNetCode() const
Definition netinfo.h:98
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
wxVariant valueForItem(const LIST_ITEM *aItem, unsigned int aCol) const
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_INSPECTOR_PANEL(wxWindow *parent, PCB_EDIT_FRAME *aFrame)
std::vector< std::unique_ptr< LIST_ITEM > >::iterator LIST_ITEM_ITER
#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