[latexila/structure-update: 1/2] Structure: shift items if needed when inserting a new item



commit cdd669cda49c8a3f0c1ad054c337d4a0510c6bef
Author: Sébastien Wilmet <sebastien wilmet gmail com>
Date:   Sun May 1 01:51:56 2011 +0200

    Structure: shift items if needed when inserting a new item
    
    The code is well documented.
    
    The glib-2.0.vapi contains some errors, see this bug report:
    https://bugzilla.gnome.org/show_bug.cgi?id=649052

 TODO                        |    1 -
 src/document_structure.vala |   85 ++++++++++++++++++++++++++++++++++++++++++-
 2 files changed, 83 insertions(+), 3 deletions(-)
---
diff --git a/TODO b/TODO
index e55a3e6..36391fe 100644
--- a/TODO
+++ b/TODO
@@ -8,7 +8,6 @@ LaTeXila 2.2
 
 - Structure (list of chapters, sections, etc.):
 	- different style (e.g. italic) for commented items
-	- improve insert_item_at_position() (shift items if needed)
 	- update on the fly the structure when the document is modified
 	- right click: cut, copy, paste below, select, delete, comment, shift left/right
 
diff --git a/src/document_structure.vala b/src/document_structure.vala
index 50f9c32..b2854e3 100644
--- a/src/document_structure.vala
+++ b/src/document_structure.vala
@@ -365,9 +365,90 @@ public class DocumentStructure : GLib.Object
         }
     }
 
-    private void insert_item_at_position (DataNode item, Node<DataNode?> parent, int pos)
+    private void insert_item_at_position (DataNode item, Node<DataNode?> direct_parent,
+        int pos)
     {
-        parent.insert_data (pos, item);
+        // If the item to insert is a simple element (not a section), simply insert it
+        // at the given position.
+        if (item.type > StructType.SUBPARAGRAPH)
+        {
+            direct_parent.insert_data (pos, item);
+            return;
+        }
+
+        bool shifted = false;
+
+        // Create the node, but for the moment it is not attached to the tree.
+        // If needed, some nodes from the tree will be removed and inserted as children
+        // of the new node.
+        Node<DataNode?> new_node = new Node<DataNode?> (item);
+
+        // This kind of algorithm is better understandable with an example and some
+        // documentation. So here we go.
+
+        // Example:
+        //_tree (last parent)      _tree
+        // 1    (third parent)      1
+        //  2                        2
+        //  2   (second parent)      2
+        //   3  (first parent)        3
+        //    4                        4
+        //    insert a 1 here  =>   1
+        //    4                      4
+        //    4                      4
+        //   3                       3
+        //   3                       3
+        //  2                        2
+
+        // 1 is e.g. a part, 2 a chapter, and so on.
+        // All the items above the item to insert must NOT move.
+
+        // We take the first parent (the one given as the function argument).
+
+        // For this parent, we inspect the children (only those that are below).
+        // If a child have a type higher than the type of the item to insert, then
+        // the child is removed from the _tree and added to the new node. In the example,
+        // the first parent is the '3', and the two children '4' are moved.
+
+        // When we have inspected all the below children, we check if the parent have
+        // a lower type. If it's the case, then we know the real parent and the real
+        // position. If it's not the case, then we have to take the grand-parent, and
+        // redo the same stuff with its children.
+        // In the example, the first parent ('3') have not a lower type than '1', so we
+        // take the grand-parent ('2').
+
+        unowned Node<DataNode?>? parent = direct_parent;
+        int cur_pos = pos;
+        while (true)
+        {
+            // Inspect the other children which are after 'cur_pos'. Indeed, the children
+            // which are before 'cur_pos' must not move.
+            unowned Node<DataNode?>? child = parent.nth_child (pos);
+            while (child != null)
+            {
+                unowned Node<DataNode?>? next_child = child.next_sibling ();
+
+                if (child.data.type <= item.type)
+                    break;
+
+                shifted = true;
+                new_node.append (child.unlink ());
+
+                child = next_child;
+            }
+
+            if (parent == _tree)
+                break;
+
+            if (parent.data.type < item.type)
+                break;
+
+            unowned Node<DataNode?> grand_parent = parent.parent;
+            cur_pos = grand_parent.child_position (parent) + 1;
+            parent = grand_parent;
+        }
+
+        parent.insert (cur_pos, (owned) new_node);
     }
 
     private static int get_position_from_mark (TextMark mark)



[Date Prev][Date Next]   [Thread Prev][Thread Next]   [Thread Index] [Date Index] [Author Index]