[latexila] Structure action: shift right



commit 48948a3fe9bce9b89e109f2f7ad1097db140835b
Author: SÃbastien Wilmet <swilmet src gnome org>
Date:   Tue Jul 5 01:52:08 2011 +0200

    Structure action: shift right
    
    For example we have a chapter with sections, and we want to shift it to
    the right: the chapter becomes a section, and the sections become
    sub-sections.
    
    What still need to be done:
    - show a warning if a subparagraph already exists
    - show a warning if the action failed (and undo the changes, if any)

 src/document_structure.vala |  102 ++++++++++++++++++++++++++++++++-
 src/structure_model.vala    |  131 +++++++++++++++++++++++++++++++++----------
 2 files changed, 202 insertions(+), 31 deletions(-)
---
diff --git a/src/document_structure.vala b/src/document_structure.vala
index b603e41..44aead1 100644
--- a/src/document_structure.vala
+++ b/src/document_structure.vala
@@ -73,6 +73,8 @@ public class DocumentStructure : GLib.Object
     private static const bool _measure_parsing_time = false;
     private Timer _timer = null;
 
+    private static string[] _section_names = null;
+
     public bool parsing_done { get; private set; default = false; }
 
     public DocumentStructure (Document doc)
@@ -568,9 +570,18 @@ public class DocumentStructure : GLib.Object
             return;
         }
 
-        if (action_type == StructAction.SHIFT_LEFT
-            || action_type == StructAction.SHIFT_RIGHT)
+        if (action_type == StructAction.SHIFT_LEFT)
+            return;
+
+        if (action_type == StructAction.SHIFT_RIGHT)
+        {
+            _doc.begin_user_action ();
+            shift_right (tree_iter);
+            _doc.end_user_action ();
+
+            _model.shift_right (tree_iter);
             return;
+        }
 
         TextIter? start_iter;
         TextIter? end_iter;
@@ -893,4 +904,91 @@ public class DocumentStructure : GLib.Object
         if (text_between.strip () == "")
             iter = begin_line_iter;
     }
+
+    private bool shift_right (TreeIter tree_iter)
+    {
+        /* Get some data about the item */
+        StructType type;
+        TextMark mark;
+        _model.get (tree_iter,
+            StructColumn.TYPE, out type,
+            StructColumn.START_MARK, out mark,
+            -1);
+
+        return_val_if_fail (type != StructType.SUBPARAGRAPH, false);
+
+        if (! Structure.is_section (type))
+            return true;
+
+        /* Get the markup name, do some checks, etc. */
+        TextIter text_iter;
+        _doc.get_iter_at_mark (out text_iter, mark);
+
+        int line_num = text_iter.get_line ();
+        string? line = get_document_line_contents (line_num);
+        return_val_if_fail (line != null, false);
+
+        int backslash_index = text_iter.get_line_index ();
+        if (line[backslash_index] != '\\')
+            return false;
+
+        int after_backslash_index = backslash_index + 1;
+        string? markup_name = get_markup_name (line, after_backslash_index);
+        if (markup_name == null)
+            return false;
+
+        /* Get the new markup name */
+        bool with_star = markup_name.has_suffix ("*");
+
+        string? new_markup_name = get_section_name_from_type (type + 1);
+        return_val_if_fail (new_markup_name != null, false);
+
+        if (with_star)
+            new_markup_name += "*";
+
+        /* Replace the markup name */
+        TextIter begin_markup_name_iter;
+        _doc.get_iter_at_line_index (out begin_markup_name_iter, line_num,
+            after_backslash_index);
+
+        TextIter end_markup_name_iter;
+        _doc.get_iter_at_line_index (out end_markup_name_iter, line_num,
+            after_backslash_index + markup_name.length);
+
+        _doc.delete (begin_markup_name_iter, end_markup_name_iter);
+        _doc.insert (begin_markup_name_iter, new_markup_name, -1);
+
+        /* Do the same for all the children */
+        int nb_children = _model.iter_n_children (tree_iter);
+        for (int child_num = 0 ; child_num < nb_children ; child_num++)
+        {
+            TreeIter child_iter;
+            if (! _model.iter_nth_child (out child_iter, tree_iter, child_num))
+                continue;
+
+            if (! shift_right (child_iter))
+                return false;
+        }
+
+        return true;
+    }
+
+    private string? get_section_name_from_type (StructType type)
+    {
+        if (_section_names == null)
+        {
+            _section_names = new string[7];
+            _section_names[StructType.PART]             = "part";
+            _section_names[StructType.CHAPTER]          = "chapter";
+            _section_names[StructType.SECTION]          = "section";
+            _section_names[StructType.SUBSECTION]       = "subsection";
+            _section_names[StructType.SUBSUBSECTION]    = "subsubsection";
+            _section_names[StructType.PARAGRAPH]        = "paragraph";
+            _section_names[StructType.SUBPARAGRAPH]     = "subparagraph";
+        }
+
+        return_val_if_fail (Structure.is_section (type), null);
+
+        return _section_names[type];
+    }
 }
diff --git a/src/structure_model.vala b/src/structure_model.vala
index 91b21ba..0dc18f4 100644
--- a/src/structure_model.vala
+++ b/src/structure_model.vala
@@ -460,10 +460,107 @@ public class StructureModel : TreeModel, GLib.Object
     {
         return_if_fail (iter_is_valid (iter));
 
-        TreePath path = get_path (iter);
         unowned Node<StructData?> node = get_node_from_iter (iter);
-        node.unlink ();
+        delete_node (node);
+    }
+
+    public void shift_right (TreeIter iter)
+    {
+        return_if_fail (iter_is_valid (iter));
+
+        unowned Node<StructData?> node = get_node_from_iter (iter);
+        StructType type = node.data.type;
+        return_if_fail (type < StructType.SUBPARAGRAPH);
+
+        StructType new_type = type + 1;
+
+        unowned Node<StructData?>? new_parent = node.prev_sibling ();
+        int new_pos;
+
+        if (new_parent == null || new_type <= new_parent.data.type)
+        {
+            new_parent = node.parent;
+            new_pos = new_parent.child_position (node);
+        }
+        else
+            new_pos = -1; // append
+
+        Node<StructData?> node_unlinked = delete_node (node);
+
+        shift_node_right (node_unlinked);
+
+        node = new_parent.insert (new_pos, (owned) node_unlinked);
+        reinsert_node (node);
+    }
+
+    private void insert_node (Node<StructData?> node, bool force_first_child = false)
+    {
+        new_stamp ();
+
+        TreeIter item_iter = create_iter_at_node (node);
+        TreePath item_path = get_path (item_iter);
+        row_inserted (item_path, item_iter);
+
+        // Attention, the row-has-child-toggled signal must be emitted _after_,
+        // else there are strange errors.
+        unowned Node<StructData?> parent = node.parent;
+        bool first_child = parent != _tree && parent.n_children () == 1;
+        if (force_first_child || first_child)
+        {
+            TreeIter parent_iter = create_iter_at_node (parent);
+            TreePath parent_path = get_path (parent_iter);
+            row_has_child_toggled (parent_path, parent_iter);
+        }
+    }
+
+    private Node<StructData?>? delete_node (Node<StructData?> node)
+    {
+        new_stamp ();
+
+        TreeIter? iter = create_iter_at_node (node);
+        return_val_if_fail (iter != null, null);
+
+        TreePath path = get_path (iter);
+        unowned Node<StructData?> parent = node.parent;
+        Node<StructData?> node_unlinked = node.unlink ();
         row_deleted (path);
+
+        if (parent != _tree && parent.n_children () == 0)
+        {
+            TreeIter parent_iter = create_iter_at_node (parent);
+            TreePath parent_path = get_path (parent_iter);
+            row_has_child_toggled (parent_path, parent_iter);
+        }
+
+        return node_unlinked;
+    }
+
+    private void shift_node_right (Node<StructData?> node)
+    {
+        if (node.data.type < StructType.SUBPARAGRAPH)
+            node.data.type += 1;
+
+        unowned Node<StructData?>? child = node.first_child ();
+        while (child != null)
+        {
+            shift_node_right (child);
+            child = child.next_sibling ();
+        }
+    }
+
+    private void reinsert_node (Node<StructData?> node, bool force_first_child = false)
+    {
+        insert_node (node, force_first_child);
+
+        unowned Node<StructData?>? child = node.first_child ();
+        bool first_child = true;
+
+        while (child != null)
+        {
+            reinsert_node (child, first_child);
+            child = child.next_sibling ();
+            first_child = false;
+        }
     }
 
     private void insert_item_at_position (StructData item, Node<StructData?> parent,
@@ -518,22 +615,7 @@ public class StructureModel : TreeModel, GLib.Object
         return_if_fail (item.text != null);
 
         unowned Node<StructData?> new_node = parent.insert_data (pos, item);
-
-        new_stamp ();
-
-        TreeIter item_iter = create_iter_at_node (new_node);
-        TreePath item_path = get_path (item_iter);
-        row_inserted (item_path, item_iter);
-
-        // Attention, the row-has-child-toggled signal must be emitted _after_,
-        // else there are strange errors.
-        if (parent != _tree && parent.n_children () == 1)
-        {
-            TreeIter parent_iter = create_iter_at_node (parent);
-            TreePath parent_path = get_path (parent_iter);
-            row_has_child_toggled (parent_path, parent_iter);
-        }
-
+        insert_node (new_node);
 
         // Store the node to a list, if it's not a section
         bool append = pos == -1;
@@ -596,20 +678,11 @@ public class StructureModel : TreeModel, GLib.Object
                 break;
 
             // unlink the node
-            new_stamp ();
-            TreePath previous_path = get_path (create_iter_at_node (sibling));
-            Node<StructData?> sibling_unlinked = sibling.unlink ();
-            row_deleted (previous_path);
+            Node<StructData?> sibling_unlinked = delete_node (sibling);
 
             // append it as a child
-            new_stamp ();
             unowned Node<StructData?> new_child = node.append ((owned) sibling_unlinked);
-
-            TreeIter? new_iter = create_iter_at_node (new_child);
-            return_if_fail (new_iter != null);
-
-            TreePath new_path = get_path (new_iter);
-            row_inserted (new_path, new_iter);
+            insert_node (new_child);
 
             sibling = node.next_sibling ();
         }



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