1111using System . Text ;
1212using System . Windows . Forms ;
1313using System . Xml ;
14- using SIL . LCModel . Core . Cellar ;
1514using SIL . FieldWorks . Common . Controls ;
1615using SIL . FieldWorks . Common . Framework . DetailControls . Resources ;
17- using SIL . LCModel . Core . KernelInterfaces ;
1816using SIL . FieldWorks . Common . FwUtils ;
1917using SIL . FieldWorks . Common . RootSites ;
20- using SIL . LCModel ;
21- using SIL . LCModel . Infrastructure ;
2218using SIL . FieldWorks . FdoUi ;
2319using SIL . FieldWorks . LexText . Controls ;
20+ using SIL . LCModel ;
21+ using SIL . LCModel . Core . Cellar ;
22+ using SIL . LCModel . Core . KernelInterfaces ;
23+ using SIL . LCModel . Infrastructure ;
2424using SIL . LCModel . Utils ;
2525using SIL . PlatformUtilities ;
2626using SIL . Utils ;
@@ -2800,42 +2800,90 @@ internal protected virtual bool UpdateDisplayIfNeeded(int hvo, int tag)
28002800 private void MoveField ( Direction dir )
28012801 {
28022802 CheckDisposed ( ) ;
2803- if ( ContainingDataTree . ShowingAllFields )
2803+ XmlNode swapWith ;
2804+ XmlNode fieldRef = MoveableFieldReferenceForSlice ( ) ;
2805+
2806+ if ( fieldRef == null )
28042807 {
2805- XmlNode swapWith ;
2806- XmlNode fieldRef = FieldReferenceForSlice ( ) ;
2808+ Debug . Fail ( "Could not identify field to move on slice." ) ;
2809+ return ;
2810+ }
28072811
2808- if ( fieldRef == null )
2809- {
2810- Debug . Fail ( "Could not identify field to move on slice." ) ;
2811- return ;
2812- }
2812+ if ( dir == Direction . Up )
2813+ {
2814+ swapWith = PrevSliceSiblingPart ( fieldRef ) ;
2815+ }
2816+ else
2817+ {
2818+ swapWith = NextSliceSiblingPart ( fieldRef ) ;
2819+ }
28132820
2821+ var parent = fieldRef . ParentNode ;
2822+ // Reorder in the parent node in the xml
2823+ if ( parent != null )
2824+ {
2825+ parent . RemoveChild ( fieldRef ) ;
28142826 if ( dir == Direction . Up )
2815- {
2816- swapWith = PrevPartSibling ( fieldRef ) ;
2817- }
2827+ parent . InsertBefore ( fieldRef , swapWith ) ;
28182828 else
2829+ parent . InsertAfter ( fieldRef , swapWith ) ;
2830+ }
2831+
2832+ // Persist in the parent part (might not be the immediate parent node)
2833+ Inventory . GetInventory ( "layouts" , m_cache . ProjectId . Name )
2834+ . PersistOverrideElement ( PartParent ( fieldRef ) ) ;
2835+ ContainingDataTree . RefreshList ( true ) ;
2836+ }
2837+
2838+ /// <summary>
2839+ /// Get the sibling for the current slice in the given dir.
2840+ /// </summary>
2841+ internal Slice GetSibling ( Direction dir )
2842+ {
2843+ int islice = IndexInContainer ;
2844+ int cslice = ContainingDataTree . Slices . Count ;
2845+ int increment = ( dir == Direction . Down ? 1 : - 1 ) ;
2846+ int depth = GetMoveableDepth ( ) ;
2847+ XmlNode fieldRef = MoveableFieldReferenceForSlice ( ) ;
2848+ while ( true )
2849+ {
2850+ islice += increment ;
2851+ if ( dir == Direction . Down )
28192852 {
2820- swapWith = NextPartSibling ( fieldRef ) ;
2853+ if ( islice >= cslice ) break ;
28212854 }
2822-
2823- var parent = fieldRef . ParentNode ;
2824- // Reorder in the parent node in the xml
2825- if ( parent != null )
2855+ else
28262856 {
2827- parent . RemoveChild ( fieldRef ) ;
2828- if ( dir == Direction . Up )
2829- parent . InsertBefore ( fieldRef , swapWith ) ;
2830- else
2831- parent . InsertAfter ( fieldRef , swapWith ) ;
2857+ if ( islice < 0 ) break ;
28322858 }
2859+ var slice = ContainingDataTree . Slices [ islice ] ;
2860+ int sliceDepth = slice . GetMoveableDepth ( ) ;
2861+ // Skip over our children.
2862+ if ( sliceDepth > depth )
2863+ continue ;
2864+ // Stop if we get past the children of our parent.
2865+ if ( sliceDepth < depth )
2866+ break ;
2867+ XmlNode sliceFieldRef = slice . MoveableFieldReferenceForSlice ( ) ;
2868+ if ( sliceFieldRef == fieldRef )
2869+ // Skip slices with the same fieldRef as self.
2870+ // This happens with nested headers.
2871+ continue ;
2872+ return slice ;
2873+ }
2874+ return null ;
2875+ }
28332876
2834- // Persist in the parent part (might not be the immediate parent node)
2835- Inventory . GetInventory ( "layouts" , m_cache . ProjectId . Name )
2836- . PersistOverrideElement ( PartParent ( fieldRef ) ) ;
2837- ContainingDataTree . RefreshList ( true ) ;
2877+ private int GetMoveableDepth ( )
2878+ {
2879+ int count = 0 ;
2880+ foreach ( object obj in Key )
2881+ {
2882+ var node = obj as XmlNode ;
2883+ if ( IsMoveableNode ( node ) )
2884+ count ++ ;
28382885 }
2886+ return count ;
28392887 }
28402888
28412889 /// <summary>
@@ -2854,13 +2902,79 @@ private XmlNode FieldReferenceForSlice()
28542902 {
28552903 continue ;
28562904 }
2857-
28582905 fieldRef = node ;
28592906 }
28602907
28612908 return fieldRef ;
28622909 }
28632910
2911+ /// <summary>
2912+ /// Get the last moveable field reference for slice.
2913+ /// </summary>
2914+ private XmlNode MoveableFieldReferenceForSlice ( )
2915+ {
2916+ XmlNode fieldRef = null ;
2917+ foreach ( object obj in Key )
2918+ {
2919+ var node = obj as XmlNode ;
2920+ if ( IsMoveableNode ( node ) )
2921+ {
2922+ fieldRef = node ;
2923+ }
2924+ }
2925+
2926+ return fieldRef ;
2927+ }
2928+
2929+ /// <summary>
2930+ /// Can this node be moved?
2931+ /// </summary>
2932+ private bool IsMoveableNode ( XmlNode node )
2933+ {
2934+ if ( ! IsRefPartNode ( node ) )
2935+ return false ;
2936+ if ( node . PreviousSibling != null )
2937+ // node has siblings, so it can be moved.
2938+ return true ;
2939+ // This is the first node in a (possibly singleton) sequence.
2940+ // Sometimes the first node represents the sequence as a whole (e.g. "Variant Type").
2941+ // In this case, it is not moveable at this level, but where it is invoked (e.g. ref="EntryRefs").
2942+ // Other times, the sequence as a whole is represented by a header (e.g. "Category Info." is represented by "Grammatical Info. Details").
2943+ // In this case, the first node is moveable.
2944+ // We look at the reference part nodes above node to determine whether the node is moveable.
2945+ bool found = false ;
2946+ for ( int i = Key . Length - 1 ; i >= 0 ; i -- )
2947+ {
2948+ XmlNode keyNode = Key [ i ] as XmlNode ;
2949+ if ( ! IsRefPartNode ( keyNode ) ) continue ;
2950+ if ( keyNode == node )
2951+ {
2952+ found = true ;
2953+ continue ;
2954+ }
2955+ if ( ! found ) continue ;
2956+ // keyNode is a ref part node above node.
2957+ string keyNodeLabel = XmlUtils . GetOptionalAttributeValue ( keyNode , "label" , null ) ;
2958+ if ( keyNodeLabel != null )
2959+ // keyNode represents the sequence as a whole.
2960+ // So node represents itself and can be moved at this level.
2961+ // Example: node label="Category Info.", keyNodeLabel="Grammatical Info. Details".
2962+ return true ;
2963+ if ( keyNode . PreviousSibling != null || keyNode . NextSibling != null )
2964+ // node represents the sequence as a whole.
2965+ // So it does not represent itself and cannot be moved at this level.
2966+ // Example: node label="Variant Type", keyNode ref="EntryRefs".
2967+ return false ;
2968+ }
2969+ return true ;
2970+ }
2971+
2972+ private bool IsRefPartNode ( XmlNode node )
2973+ {
2974+ return node != null && node . Name == "part"
2975+ && XmlUtils . GetOptionalAttributeValue ( node , "ref" , null ) != null ;
2976+ }
2977+
28642978 protected void SetFieldVisibility ( string visibility )
28652979 {
28662980 CheckDisposed ( ) ;
@@ -2976,13 +3090,47 @@ protected bool IsVisibilityItemChecked(string visibility)
29763090
29773091 private bool CheckValidMove ( UIItemDisplayProperties display , Direction dir )
29783092 {
2979- XmlNode lastPartRef = FieldReferenceForSlice ( ) ;
3093+ XmlNode lastPartRef = MoveableFieldReferenceForSlice ( ) ;
29803094
29813095 if ( lastPartRef == null )
29823096 return false ;
29833097 return dir == Direction . Up
2984- ? PrevPartSibling ( lastPartRef ) != null
2985- : NextPartSibling ( lastPartRef ) != null ;
3098+ ? PrevSliceSiblingPart ( lastPartRef ) != null
3099+ : NextSliceSiblingPart ( lastPartRef ) != null ;
3100+ }
3101+
3102+ private XmlNode PrevSliceSiblingPart ( XmlNode partRef )
3103+ {
3104+ Slice targetSlice = GetSibling ( Direction . Up ) ;
3105+ XmlNode targetNode = targetSlice ? . MoveableFieldReferenceForSlice ( ) ;
3106+ if ( targetNode == null )
3107+ return null ;
3108+
3109+ XmlNode prev = PrevPartSibling ( partRef ) ;
3110+ while ( prev != null )
3111+ {
3112+ if ( prev == targetNode )
3113+ return prev ;
3114+ prev = PrevPartSibling ( prev ) ;
3115+ }
3116+ return null ;
3117+ }
3118+
3119+ private XmlNode NextSliceSiblingPart ( XmlNode partRef )
3120+ {
3121+ Slice targetSlice = GetSibling ( Direction . Down ) ;
3122+ XmlNode targetNode = targetSlice ? . MoveableFieldReferenceForSlice ( ) ;
3123+ if ( targetNode == null )
3124+ return null ;
3125+
3126+ XmlNode next = NextPartSibling ( partRef ) ;
3127+ while ( next != null )
3128+ {
3129+ if ( next == targetNode )
3130+ return next ;
3131+ next = NextPartSibling ( next ) ;
3132+ }
3133+ return null ;
29863134 }
29873135
29883136 private XmlNode PrevPartSibling ( XmlNode partRef )
@@ -3024,7 +3172,7 @@ private XmlNode PartParent(XmlNode partRef)
30243172 public bool OnDisplayMoveFieldUp ( object args , ref UIItemDisplayProperties display )
30253173 {
30263174 CheckDisposed ( ) ;
3027- display . Enabled = ContainingDataTree . ShowingAllFields && CheckValidMove ( display , Direction . Up ) ;
3175+ display . Enabled = CheckValidMove ( display , Direction . Up ) ;
30283176
30293177 return true ;
30303178 }
@@ -3033,7 +3181,7 @@ public bool OnDisplayMoveFieldUp(object args, ref UIItemDisplayProperties displa
30333181 public bool OnDisplayMoveFieldDown ( object args , ref UIItemDisplayProperties display )
30343182 {
30353183 CheckDisposed ( ) ;
3036- display . Enabled = ContainingDataTree . ShowingAllFields && CheckValidMove ( display , Direction . Down ) ;
3184+ display . Enabled = CheckValidMove ( display , Direction . Down ) ;
30373185 return true ;
30383186 }
30393187
0 commit comments