@@ -532,102 +532,227 @@ def highlight_item(self, item):
532
532
self .setCurrentItem (item , 0 , QItemSelectionModel .SelectionFlag .ClearAndSelect )
533
533
self .scrollToItem (item )
534
534
535
- def check_multi_selection (self ):
536
- if len (self .selectedItems ()) > 1 :
537
- info_dialog (self , _ ('Multiple items selected' ), _ (
538
- 'You are trying to move multiple items at once, this is not supported. Instead use'
539
- ' Drag and Drop to move multiple items' ), show = True )
540
- return False
541
- return True
535
+ def _sort_items_by_index (self , items , reverse = False ):
536
+ def get_index (item ):
537
+ result = []
542
538
543
- def move_left (self ):
544
- if not self .check_multi_selection ():
539
+ parent = item .parent ()
540
+ while parent is not None :
541
+ result .append (parent .indexOfChild (item ))
542
+ item , parent = parent , parent .parent ()
543
+
544
+ result .reverse ()
545
+ return result
546
+
547
+ items .sort (key = get_index , reverse = reverse )
548
+
549
+ def _get_root_items (self , items ):
550
+ items_ = []
551
+ for item in items :
552
+ if item is None :
553
+ continue
554
+
555
+ parent = item
556
+ while (parent := parent .parent ()) is not None :
557
+ if parent in items :
558
+ break
559
+ else :
560
+ items_ .append (item )
561
+
562
+ return items_
563
+
564
+ def _move_indent_left (self , items ):
565
+ self ._sort_items_by_index (items )
566
+
567
+ for item in items :
568
+ old_parent = item .parent ()
569
+ if old_parent is None :
570
+ return
571
+
572
+ old_index = old_parent .indexOfChild (item )
573
+ was_expanded = item .isExpanded () or item .childCount () == 0
574
+
575
+ new_parent = old_parent .parent () or self .invisibleRootItem ()
576
+ new_index = new_parent .indexOfChild (old_parent ) + 1
577
+
578
+ # all former lower siblings become children of indented item
579
+ for _ in range (old_parent .childCount () - old_index - 1 ):
580
+ lower_sibling = old_parent .child (old_index + 1 )
581
+ old_parent .removeChild (lower_sibling )
582
+ item .addChild (lower_sibling )
583
+
584
+ if lower_sibling not in items :
585
+ was_expanded = True
586
+
587
+ old_parent .removeChild (item )
588
+ new_parent .insertChild (new_index , item )
589
+
590
+ self .expandItem (new_parent )
591
+ if was_expanded :
592
+ self .expandItem (item )
593
+
594
+ def _move_indent_right (self , items ):
595
+ self ._sort_items_by_index (items )
596
+
597
+ failed_parent = None
598
+ for item in items :
599
+ # indent right == become child of upper sibling
600
+ old_parent = item .parent () or self .invisibleRootItem ()
601
+ old_idx = old_parent .indexOfChild (item )
602
+ was_expanded = item .isExpanded ()
603
+
604
+ if old_idx <= 0 :
605
+ # no upper sibling exists; cannot become child
606
+ failed_parent = old_parent
607
+ continue
608
+ elif failed_parent and old_parent is failed_parent :
609
+ # this prevents siblings at the same level from
610
+ # nesting into each other forming a "staircase"
611
+ continue
612
+ else :
613
+ failed_parent = None
614
+
615
+ new_parent = old_parent .child (old_idx - 1 )
616
+ old_parent .removeChild (item )
617
+ new_parent .addChild (item )
618
+
619
+ self .expandItem (new_parent )
620
+ if was_expanded :
621
+ self .expandItem (item )
622
+
623
+ def _move_indent (self , items , indent ):
624
+ if not items or indent == 0 :
545
625
return
626
+
627
+ # indent offsets are absolute (as opposed to relative to parent)
628
+ # child indented with parent automatically, no need for manual
629
+ items_ = self ._get_root_items (items )
630
+ if len (items_ ) <= 0 or indent == 0 :
631
+ return
632
+
633
+ focus_item = self .currentItem ()
634
+
546
635
self .push_history ()
547
- item = self .currentItem ()
548
- if item is not None :
549
- parent = item .parent ()
550
- if parent is not None :
551
- is_expanded = item .isExpanded () or item .childCount () == 0
552
- gp = parent .parent () or self .invisibleRootItem ()
553
- idx = gp .indexOfChild (parent )
554
- for gc in [parent .child (i ) for i in range (parent .indexOfChild (item )+ 1 , parent .childCount ())]:
555
- parent .removeChild (gc )
556
- item .addChild (gc )
557
- parent .removeChild (item )
558
- gp .insertChild (idx + 1 , item )
559
- if is_expanded :
560
- self .expandItem (item )
561
- self .highlight_item (item )
636
+ if indent < 0 :
637
+ self ._move_indent_left (items_ )
638
+ elif indent > 0 :
639
+ self ._move_indent_right (items_ )
640
+
641
+ # restore previous focused item
642
+ if focus_item is None and items_ :
643
+ focus_item = items_ [0 ]
644
+
645
+ if focus_item :
646
+ self .setCurrentItem (
647
+ focus_item ,
648
+ 0 ,
649
+ QItemSelectionModel .SelectionFlag .ClearAndSelect
650
+ )
651
+
652
+ for item in items :
653
+ item .setSelected (True )
654
+
655
+ def move_left (self ):
656
+ selected_items = self .selectedItems ()
657
+ if len (selected_items ) <= 0 :
658
+ return
659
+
660
+ self ._move_indent (selected_items , - 1 )
562
661
563
662
def move_right (self ):
564
- if not self .check_multi_selection ():
663
+ selected_items = self .selectedItems ()
664
+ if len (selected_items ) <= 0 :
565
665
return
566
- self .push_history ()
567
- item = self .currentItem ()
568
- if item is not None :
569
- parent = item .parent () or self .invisibleRootItem ()
570
- idx = parent .indexOfChild (item )
571
- if idx > 0 :
572
- is_expanded = item .isExpanded ()
573
- np = parent .child (idx - 1 )
574
- parent .removeChild (item )
575
- np .addChild (item )
576
- if is_expanded :
577
- self .expandItem (item )
578
- self .highlight_item (item )
666
+
667
+ self ._move_indent (selected_items , 1 )
579
668
580
669
def move_down (self ):
581
- if not self .check_multi_selection ():
670
+ selected_items = self .selectedItems ()
671
+ if len (selected_items ) <= 0 :
582
672
return
673
+
583
674
self .push_history ()
584
- item = self .currentItem ()
585
- if item is None :
586
- if self .root .childCount () == 0 :
587
- return
588
- item = self .root .child (0 )
589
- self .highlight_item (item )
590
- return
591
- parent = item .parent () or self .root
592
- idx = parent .indexOfChild (item )
593
- if idx == parent .childCount () - 1 :
594
- # At end of parent, need to become sibling of parent
595
- if parent is self .root :
596
- return
597
- gp = parent .parent () or self .root
598
- parent .removeChild (item )
599
- gp .insertChild (gp .indexOfChild (parent )+ 1 , item )
600
- else :
601
- sibling = parent .child (idx + 1 )
602
- parent .removeChild (item )
603
- sibling .insertChild (0 , item )
604
- self .highlight_item (item )
675
+
676
+ items_ = self ._get_root_items (selected_items )
677
+ self ._sort_items_by_index (items_ )
678
+
679
+ focus_item = self .currentItem ()
680
+
681
+ for item in reversed (items_ ):
682
+ old_parent = item .parent () or self .invisibleRootItem ()
683
+ old_index = old_parent .indexOfChild (item )
684
+ was_expanded = item .isExpanded () or item .childCount () == 0
685
+
686
+ new_parent = None
687
+ if old_index + 1 < old_parent .childCount ():
688
+ # there is still space in parent; move down in same parent
689
+ old_parent .removeChild (item )
690
+ old_parent .insertChild (old_index + 1 , item )
691
+ elif old_parent is not self .invisibleRootItem ():
692
+ # move down past bottom of parent, become child of grandparent
693
+ new_parent = old_parent .parent () or self .invisibleRootItem ()
694
+ old_parent .removeChild (item )
695
+ new_index = new_parent .indexOfChild (old_parent ) + 1
696
+ new_parent .insertChild (new_index , item )
697
+ self .expandItem (new_parent )
698
+
699
+ self .expandItem (new_parent or old_parent )
700
+ if was_expanded :
701
+ self .expandItem (item )
702
+
703
+ if focus_item :
704
+ self .setCurrentItem (
705
+ focus_item ,
706
+ 0 ,
707
+ QItemSelectionModel .SelectionFlag .ClearAndSelect
708
+ )
709
+
710
+ for item in selected_items :
711
+ item .setSelected (True )
605
712
606
713
def move_up (self ):
607
- if not self .check_multi_selection ():
714
+ selected_items = self .selectedItems ()
715
+ if len (selected_items ) <= 0 :
608
716
return
717
+
609
718
self .push_history ()
610
- item = self .currentItem ()
611
- if item is None :
612
- if self .root .childCount () == 0 :
613
- return
614
- item = self .root .child (self .root .childCount ()- 1 )
615
- self .highlight_item (item )
616
- return
617
- parent = item .parent () or self .root
618
- idx = parent .indexOfChild (item )
619
- if idx == 0 :
620
- # At end of parent, need to become sibling of parent
621
- if parent is self .root :
622
- return
623
- gp = parent .parent () or self .root
624
- parent .removeChild (item )
625
- gp .insertChild (gp .indexOfChild (parent ), item )
626
- else :
627
- sibling = parent .child (idx - 1 )
628
- parent .removeChild (item )
629
- sibling .addChild (item )
630
- self .highlight_item (item )
719
+
720
+ items_ = self ._get_root_items (selected_items )
721
+ self ._sort_items_by_index (items_ )
722
+
723
+ focus_item = self .currentItem ()
724
+
725
+ for item in items_ :
726
+ old_parent = item .parent () or self .invisibleRootItem ()
727
+ old_index = old_parent .indexOfChild (item )
728
+ was_expanded = item .isExpanded () or item .childCount () == 0
729
+
730
+ new_parent = None
731
+ if old_index - 1 >= 0 :
732
+ # there is still space in parent; move up within parent
733
+ old_parent .removeChild (item )
734
+ old_parent .insertChild (old_index - 1 , item )
735
+ elif old_parent is not self .invisibleRootItem ():
736
+ # move up past top of parent, become upper sibling of parent
737
+ new_parent = old_parent .parent () or self .invisibleRootItem ()
738
+ old_parent .removeChild (item )
739
+ new_index = new_parent .indexOfChild (old_parent )
740
+ new_parent .insertChild (new_index , item )
741
+ self .expandItem (new_parent )
742
+
743
+ self .expandItem (new_parent or old_parent )
744
+ if was_expanded :
745
+ self .expandItem (item )
746
+
747
+ if focus_item :
748
+ self .setCurrentItem (
749
+ focus_item ,
750
+ 0 ,
751
+ QItemSelectionModel .SelectionFlag .ClearAndSelect
752
+ )
753
+
754
+ for item in selected_items :
755
+ item .setSelected (True )
631
756
632
757
def del_items (self ):
633
758
self .push_history ()
0 commit comments