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