[hdf-compass] 138/295: Implementation of frames to visualize Text and Xml nodes

Ghislain Vaillant ghisvail-guest at moszumanska.debian.org
Sun May 8 10:35:36 UTC 2016


This is an automated email from the git hooks/post-receive script.

ghisvail-guest pushed a commit to branch debian/master
in repository hdf-compass.

commit 86507704b251c96e614d78f51134207e726d9892
Author: giumas <giumas at yahoo.it>
Date:   Sat Oct 10 00:06:04 2015 -0400

    Implementation of frames to visualize Text and Xml nodes
---
 hdf_compass/bag_model/model.py                     |  19 ++
 hdf_compass/compass_model/model.py                 |   9 +
 hdf_compass/compass_viewer/__init__.py             |  23 ++-
 hdf_compass/compass_viewer/icons/save_24.png       | Bin 0 -> 1121 bytes
 .../compass_viewer/icons/xml_validate_24.png       | Bin 0 -> 896 bytes
 hdf_compass/compass_viewer/text/__init__.py        |   7 +
 hdf_compass/compass_viewer/text/frame.py           | 181 ++++++++++++++++
 hdf_compass/compass_viewer/text/text_ctrl.py       | 230 +++++++++++++++++++++
 8 files changed, 463 insertions(+), 6 deletions(-)

diff --git a/hdf_compass/bag_model/model.py b/hdf_compass/bag_model/model.py
index 78d73a1..078f6f3 100644
--- a/hdf_compass/bag_model/model.py
+++ b/hdf_compass/bag_model/model.py
@@ -437,6 +437,11 @@ class BAGMetadataXml(compass_model.Xml):
     def can_handle(store, key):
         return (key == "/BAG_root/metadata") and (key in store) and (isinstance(store.f[key], h5py.Dataset))
 
+    @staticmethod
+    def has_validation():
+        """For BAG data there is a known validation mechanism based on XSD and Schematron"""
+        return True
+
     def __init__(self, store, key):
         self._store = store
         self._key = key
@@ -466,6 +471,20 @@ class BAGMetadataXml(compass_model.Xml):
     def text(self):
         return self._dset
 
+    @property
+    def validation(self):
+        """ Collect a message string with the result of the validation """
+        msg = str()
+
+        msg += "XML input source: %s\nValidation output: " % self.key
+        if self.store.f.validate_metadata():
+            msg += "VALID"
+        else:
+            msg += "INVALID\nReasons:\n"
+            for err_msg in self.store.f.meta_errors:
+                msg += " - %s\n" % err_msg
+        return msg
+
 
 class BAGUncertainty(compass_model.Array):
     """ Represents a BAG uncertainty. """
diff --git a/hdf_compass/compass_model/model.py b/hdf_compass/compass_model/model.py
index dd6c7cb..f5ba4b7 100644
--- a/hdf_compass/compass_model/model.py
+++ b/hdf_compass/compass_model/model.py
@@ -451,6 +451,15 @@ class Xml(Text):
     icons = {16:    os.path.join(icon_folder, "xml_16.png"),
              64:    os.path.join(icon_folder, "xml_64.png")}
 
+    @staticmethod
+    def has_validation():
+        """To be overriden in case that the xml has a known mechanism to be validated"""
+        return False
+
+    @property
+    def validation(self):
+        """ Validation info """
+
 
 class Unknown(Node):
     """
diff --git a/hdf_compass/compass_viewer/__init__.py b/hdf_compass/compass_viewer/__init__.py
index a4ee57e..bc6d483 100644
--- a/hdf_compass/compass_viewer/__init__.py
+++ b/hdf_compass/compass_viewer/__init__.py
@@ -31,7 +31,7 @@ from hdf_compass import compass_model
 from hdf_compass import utils
 
 from .events import ID_COMPASS_OPEN
-from . import container, array, keyvalue, image, frame
+from . import container, array, keyvalue, image, frame, text
 
 __version__ = utils.__version__
 
@@ -113,21 +113,32 @@ def open_node(node, pos=None):
     if pos is not None:
         # The thing we get from GetPosition isn't really a tuple, so
         # you have to manually cast entries to int or it silently fails.
-        newpos =(int(pos[0])+40, int(pos[1])+40)
+        new_pos =(int(pos[0])+40, int(pos[1])+40)
     else:
-        newpos = None
+        new_pos = None
 
     log.debug("Top-level open called for %s" % node)
 
     if isinstance(node, compass_model.Container):
-        f = container.ContainerFrame(node, pos=newpos)
+        f = container.ContainerFrame(node, pos=new_pos)
         f.Show()
+
     elif isinstance(node, compass_model.Array):
-        f = array.ArrayFrame(node, pos=newpos)
+        f = array.ArrayFrame(node, pos=new_pos)
+        f.Show()
+
+    elif isinstance(node, compass_model.Xml):
+        f = text.XmlFrame(node, pos=new_pos)
         f.Show()
+
+    elif isinstance(node, compass_model.Text):
+        f = text.TextFrame(node, pos=new_pos)
+        f.Show()
+
     elif isinstance(node, compass_model.KeyValue):
-        f = keyvalue.KeyValueFrame(node, pos=newpos)
+        f = keyvalue.KeyValueFrame(node, pos=new_pos)
         f.Show()
+
     elif isinstance(node, compass_model.Image):
         f = image.ImageFrame(node, pos=pos)
         f.Show()
diff --git a/hdf_compass/compass_viewer/icons/save_24.png b/hdf_compass/compass_viewer/icons/save_24.png
new file mode 100644
index 0000000..fa6c180
Binary files /dev/null and b/hdf_compass/compass_viewer/icons/save_24.png differ
diff --git a/hdf_compass/compass_viewer/icons/xml_validate_24.png b/hdf_compass/compass_viewer/icons/xml_validate_24.png
new file mode 100644
index 0000000..1ca0560
Binary files /dev/null and b/hdf_compass/compass_viewer/icons/xml_validate_24.png differ
diff --git a/hdf_compass/compass_viewer/text/__init__.py b/hdf_compass/compass_viewer/text/__init__.py
new file mode 100644
index 0000000..cab49fe
--- /dev/null
+++ b/hdf_compass/compass_viewer/text/__init__.py
@@ -0,0 +1,7 @@
+from __future__ import absolute_import, division, print_function, unicode_literals
+
+from .frame import TextFrame, XmlFrame
+
+import logging
+log = logging.getLogger(__name__)
+log.addHandler(logging.NullHandler())
diff --git a/hdf_compass/compass_viewer/text/frame.py b/hdf_compass/compass_viewer/text/frame.py
new file mode 100644
index 0000000..aa65acf
--- /dev/null
+++ b/hdf_compass/compass_viewer/text/frame.py
@@ -0,0 +1,181 @@
+##############################################################################
+# Copyright by The HDF Group.                                                #
+# All rights reserved.                                                       #
+#                                                                            #
+# This file is part of the HDF Compass Viewer. The full HDF Compass          #
+# copyright notice, including terms governing use, modification, and         #
+# terms governing use, modification, and redistribution, is contained in     #
+# the file COPYING, which can be found at the root of the source code        #
+# distribution tree.  If you do not have access to this file, you may        #
+# request a copy from help at hdfgroup.org.                                     #
+##############################################################################
+
+"""
+Implements a viewer frame for compass_model.Array.
+"""
+from __future__ import absolute_import, division, print_function, unicode_literals
+
+import os
+import logging
+
+import wx
+
+log = logging.getLogger(__name__)
+
+from .text_ctrl import TextViewerFrame, XmlStc
+from ..frame import NodeFrame
+
+
+# Menu and button IDs
+ID_SAVE_TEXT_MENU = wx.NewId()
+ID_VALIDATE_XML_MENU = wx.NewId()
+ID_SAVE_XML_MENU = wx.NewId()
+
+
+class TextFrame(NodeFrame):
+    icon_folder = os.path.abspath(os.path.join(os.path.dirname(__file__), os.pardir, 'icons'))
+
+    """
+    Top-level frame displaying objects of type compass_model.Text.
+
+    From top to bottom, has:
+
+    1. Toolbar (see TextFrame.init_toolbar)
+    2. A TextCtrl, which displays the text.
+    """
+
+    def __init__(self, node, pos=None):
+        """ Create a new array viewer, to display *node*. """
+        super(TextFrame, self).__init__(node, size=(800, 400), title=node.display_name, pos=pos)
+        log.debug("init")
+
+        self.node = node
+
+        self.txt = wx.TextCtrl(self, 1, style=wx.TE_MULTILINE | wx.TE_READONLY)
+        self.txt.SetValue(node.text)
+
+        save_menu = wx.Menu()
+        save_menu.Append(ID_SAVE_TEXT_MENU, "Save Text\tCtrl-T")
+        self.add_menu(save_menu, "Save")
+
+        self.toolbar = None
+        self.init_toolbar()
+
+        gridsizer = wx.BoxSizer(wx.VERTICAL)
+        gridsizer.Add(self.txt, 1, wx.EXPAND)
+
+        self.view = gridsizer
+
+        self.Bind(wx.EVT_MENU, self.on_save, id=ID_SAVE_TEXT_MENU)
+
+    def init_toolbar(self):
+        """ Set up the toolbar at the top of the window. """
+        t_size = (24, 24)
+        plot_bmp = wx.Bitmap(os.path.join(self.icon_folder, "save_24.png"), wx.BITMAP_TYPE_ANY)
+
+        self.toolbar = self.CreateToolBar(wx.TB_HORIZONTAL | wx.NO_BORDER | wx.TB_FLAT | wx.TB_TEXT)
+
+        self.toolbar.SetToolBitmapSize(t_size)
+        self.toolbar.AddStretchableSpace()
+        self.toolbar.AddLabelTool(ID_SAVE_TEXT_MENU, "Save", plot_bmp,
+                                  shortHelp="Save Text", longHelp="Extract and save Text on disk")
+        self.toolbar.Realize()
+
+    def on_save(self, evt):
+        """ User has chosen to save the current Text """
+        log.debug("saving: %s" % self.node.key)
+
+        save_file_dialog = wx.FileDialog(self, "Save XML file", "", "text.txt",
+                                         "Text files (*.txt)|*.txt", wx.FD_SAVE | wx.FD_OVERWRITE_PROMPT)
+        if save_file_dialog.ShowModal() == wx.ID_CANCEL:
+            return     # the user changed idea...
+
+        # save the current contents in the file
+        # this can be done with e.g. wxPython output streams:
+        with open(save_file_dialog.GetPath(), 'w') as fod:
+            fod.write(self.node.text)
+
+
+class XmlFrame(NodeFrame):
+    icon_folder = os.path.abspath(os.path.join(os.path.dirname(__file__), os.pardir, 'icons'))
+
+    """
+    Top-level frame displaying objects of type compass_model.Text.
+
+    From top to bottom, has:
+
+    1. Toolbar (see ArrayFrame.init_toolbar)
+    2. A TextCtrl, which displays the text.
+    """
+
+    def __init__(self, node, pos=None):
+        """ Create a new array viewer, to display *node*. """
+        super(XmlFrame, self).__init__(node, size=(800, 400), title=node.display_name, pos=pos)
+        log.debug("init")
+
+        self.node = node
+
+        self.xml = XmlStc(self, xml_string=self.node.text)
+
+        self.text_viewer = None
+
+        save_menu = wx.Menu()
+        save_menu.Append(ID_SAVE_XML_MENU, "Save xml\tCtrl-X")
+        self.add_menu(save_menu, "Save")
+
+        if self.node.has_validation():
+            val_menu = wx.Menu()
+            val_menu.Append(ID_VALIDATE_XML_MENU, "Validate xml\tCtrl-V")
+            self.add_menu(val_menu, "Validate")
+
+        self.toolbar = None
+        self.init_toolbar()
+
+        gridsizer = wx.BoxSizer(wx.VERTICAL)
+        gridsizer.Add(self.xml, 1, wx.EXPAND)
+        self.view = gridsizer
+
+        self.Bind(wx.EVT_MENU, self.on_save, id=ID_SAVE_XML_MENU)
+        if self.node.has_validation():
+            self.Bind(wx.EVT_MENU, self.on_validate, id=ID_VALIDATE_XML_MENU)
+
+    def init_toolbar(self):
+        """ Set up the toolbar at the top of the window. """
+        t_size = (24, 24)
+        save_bmp = wx.Bitmap(os.path.join(self.icon_folder, "save_24.png"), wx.BITMAP_TYPE_ANY)
+        if self.node.has_validation():
+            validate_bmp = wx.Bitmap(os.path.join(self.icon_folder, "xml_validate_24.png"), wx.BITMAP_TYPE_ANY)
+
+        self.toolbar = self.CreateToolBar(wx.TB_HORIZONTAL | wx.NO_BORDER | wx.TB_FLAT | wx.TB_TEXT)
+
+        self.toolbar.SetToolBitmapSize(t_size)
+        self.toolbar.AddStretchableSpace()
+        self.toolbar.AddLabelTool(ID_SAVE_XML_MENU, "Save", save_bmp,
+                                  shortHelp="Save XML", longHelp="Extract and save XML on disk")
+        if self.node.has_validation():
+            self.toolbar.AddLabelTool(ID_VALIDATE_XML_MENU, "Validate", validate_bmp,
+                                      shortHelp="Validate XML", longHelp="Validate XML in a popup window")
+        self.toolbar.Realize()
+
+    def on_validate(self, evt):
+        """ User has chosen to validate the current XML """
+        if self.node.has_validation():
+            log.debug("validating: %s" % self.node.key)
+            self.text_viewer = TextViewerFrame(self.node.validation)
+            self.text_viewer.Show()
+        else:
+            log.warning("this node type has not validation: %s" % self.node)
+
+    def on_save(self, evt):
+        """ User has chosen to save the current XML """
+        log.debug("saving: %s" % self.node.key)
+
+        save_file_dialog = wx.FileDialog(self, "Save XML file", "", "text.xml",
+                                         "Xml files (*.xml)|*.xml", wx.FD_SAVE | wx.FD_OVERWRITE_PROMPT)
+        if save_file_dialog.ShowModal() == wx.ID_CANCEL:
+            return     # the user changed idea...
+
+        # save the current contents in the file
+        # this can be done with e.g. wxPython output streams:
+        with open(save_file_dialog.GetPath(), 'w') as fod:
+            fod.write(self.node.text)
diff --git a/hdf_compass/compass_viewer/text/text_ctrl.py b/hdf_compass/compass_viewer/text/text_ctrl.py
new file mode 100644
index 0000000..e7c9c61
--- /dev/null
+++ b/hdf_compass/compass_viewer/text/text_ctrl.py
@@ -0,0 +1,230 @@
+##############################################################################
+# Copyright by The HDF Group.                                                #
+# All rights reserved.                                                       #
+#                                                                            #
+# This file is part of the HDF Compass Viewer. The full HDF Compass          #
+# copyright notice, including terms governing use, modification, and         #
+# terms governing use, modification, and redistribution, is contained in     #
+# the file COPYING, which can be found at the root of the source code        #
+# distribution tree.  If you do not have access to this file, you may        #
+# request a copy from help at hdfgroup.org.                                     #
+##############################################################################
+
+"""
+Implements a viewer frame for compass_model.Array.
+"""
+from __future__ import absolute_import, division, print_function, unicode_literals
+
+import logging
+
+import wx
+import wx.stc as stc
+
+log = logging.getLogger(__name__)
+
+from ..frame import BaseFrame
+
+
+if wx.Platform == '__WXMSW__':
+    faces = {'times': 'Times New Roman',
+             'mono': 'Courier New',
+             'helv': 'Arial',
+             'other': 'Comic Sans MS',
+             'size': 10,
+             'size2': 8,
+             }
+else:
+    faces = {'times': 'Times',
+             'mono': 'Courier',
+             'helv': 'Helvetica',
+             'other': 'new century schoolbook',
+             'size': 13,
+             'size2': 11,
+             }
+
+
+class TextViewerFrame(BaseFrame):
+
+    """
+    Base class for Matplotlib plot windows.
+
+    Override draw_figure() to plot your figure on the provided axes.
+    """
+
+    def __init__(self, data, title="Validation"):
+        """ Create a new Matplotlib plotting window for a 1D line plot """
+        BaseFrame.__init__(self, id=wx.ID_ANY, title=title, size=(800, 400))
+
+        self.data = data
+
+        self.txt = wx.TextCtrl(self, 1, style=wx.TE_MULTILINE | wx.TE_READONLY)
+        self.txt.SetValue(self.data)
+
+        gridsizer = wx.BoxSizer(wx.VERTICAL)
+        gridsizer.Add(self.txt, 1, wx.LEFT | wx.TOP | wx.GROW)
+
+        self.view = gridsizer
+
+
+class XmlStc(stc.StyledTextCtrl):
+    def __init__(self, parent, xml_string, keywords=None):
+        stc.StyledTextCtrl.__init__(self, parent, -1)
+        self.SetLexer(stc.STC_LEX_XML)
+        if keywords is not None:
+            self.SetKeyWords(0, keywords)
+
+        # Global default styles for all languages
+        self.StyleSetSpec(stc.STC_STYLE_DEFAULT, "face:%(mono)s,size:%(size)d" % faces)
+        self.StyleClearAll()  # Reset all to be like the default
+
+        # Global default styles for all languages
+        self.StyleSetSpec(stc.STC_STYLE_DEFAULT, "face:%(mono)s,size:%(size)d" % faces)
+        self.StyleSetSpec(stc.STC_STYLE_LINENUMBER, "back:#C0C0C0,face:%(helv)s,size:%(size2)d" % faces)
+        self.StyleSetSpec(stc.STC_STYLE_CONTROLCHAR, "face:%(other)s" % faces)
+        self.StyleSetSpec(stc.STC_STYLE_BRACELIGHT, "fore:#FFFFFF,back:#0000FF,bold")
+        self.StyleSetSpec(stc.STC_STYLE_BRACEBAD, "fore:#000000,back:#FF0000,bold")
+
+        self.StyleSetSpec(stc.STC_H_VALUE, "fore:#0000cc,face:%(helv)s,size:%(size)d" % faces)
+        self.StyleSetSpec(stc.STC_H_DEFAULT, "fore:#0000cc,face:%(helv)s,size:%(size)d" % faces)
+        self.StyleSetSpec(stc.STC_H_ENTITY, "fore:#0000cc,face:%(helv)s,size:%(size)d" % faces)
+        # initial XML tag
+        self.StyleSetSpec(stc.STC_H_XMLSTART, "fore:#ffcccc,bold,face:%(helv)s,size:%(size)d" % faces)
+        self.StyleSetSpec(stc.STC_H_XMLEND, "fore:#ffcccc,bold,face:%(helv)s,size:%(size)d" % faces)
+        # XML tags
+        self.StyleSetSpec(stc.STC_H_TAG, "fore:#555555,face:%(helv)s,size:%(size)d" % faces)
+        self.StyleSetSpec(stc.STC_H_TAGEND, "fore:#555555,face:%(helv)s,size:%(size)d" % faces)
+        self.StyleSetSpec(stc.STC_H_TAGUNKNOWN, "fore:#555555,face:%(helv)s,size:%(size)d" % faces)
+        # XML attributes
+        self.StyleSetSpec(stc.STC_H_ATTRIBUTE, "fore:#BDB76B,face:%(helv)s,size:%(size)d" % faces)
+        self.StyleSetSpec(stc.STC_H_ATTRIBUTEUNKNOWN, "fore:#BDB76B,face:%(helv)s,size:%(size)d" % faces)
+        # XML comments and quotes
+        self.StyleSetSpec(stc.STC_H_COMMENT, "fore:#888888,face:%(helv)s,size:%(size)d" % faces)
+        self.StyleSetSpec(stc.STC_H_SINGLESTRING, "fore:#aa2222,face:%(helv)s,size:%(size)d" % faces)
+        self.StyleSetSpec(stc.STC_H_DOUBLESTRING, "fore:#aa2222,face:%(helv)s,size:%(size)d" % faces)
+        self.StyleSetSpec(stc.STC_H_SGML_SIMPLESTRING, "fore:#aa2222,face:%(helv)s,size:%(size)d" % faces)
+        self.StyleSetSpec(stc.STC_H_SGML_DOUBLESTRING, "fore:#aa2222,face:%(helv)s,size:%(size)d" % faces)
+
+        # Keyword
+        self.StyleSetSpec(stc.STC_P_WORD, "fore:#990000,size:%(size)d" % faces)
+
+        # Caret color
+        self.SetCaretForeground("BLUE")
+        # Selection background
+        self.SetSelBackground(1, '#66CCFF')
+
+        self.SetSelBackground(True, wx.SystemSettings_GetColour(wx.SYS_COLOUR_HIGHLIGHT))
+        self.SetSelForeground(True, wx.SystemSettings_GetColour(wx.SYS_COLOUR_HIGHLIGHTTEXT))
+
+        self.SetProperty("fold", "1")  # Enable folding
+        self.SetProperty("fold.html", "1")  # Enable folding
+        self.SetProperty("tab.timmy.whinge.level", "1")  # Highlight tab/space mixing (shouldn't be any)
+        self.SetMargins(3, 3)  # Set left and right margins
+        self.SetMarginType(1, stc.STC_MARGIN_NUMBER)  # Set up the numbers in the margin for margin #1
+        self.SetMarginWidth(1, 40)  # Reasonable value for, say, 4-5 digits using a mono font (40 pix)
+        # self.SetViewWhiteSpace(False)
+        self.SetWrapMode(stc.STC_WRAP_WORD)
+        self.SetUseVerticalScrollBar(True)
+        self.SetUseHorizontalScrollBar(True)
+
+        # Setup a margin to hold fold markers
+        self.SetMarginType(2, stc.STC_MARGIN_SYMBOL)
+        self.SetMarginMask(2, stc.STC_MASK_FOLDERS)
+        self.SetMarginSensitive(2, True)
+        self.SetMarginWidth(2, 15)
+        # marker style
+        self.MarkerDefine(stc.STC_MARKNUM_FOLDEREND, stc.STC_MARK_BOXPLUSCONNECTED, "white", "black")
+        self.MarkerDefine(stc.STC_MARKNUM_FOLDEROPENMID, stc.STC_MARK_BOXMINUSCONNECTED, "white", "black")
+        self.MarkerDefine(stc.STC_MARKNUM_FOLDERMIDTAIL, stc.STC_MARK_TCORNER, "white", "black")
+        self.MarkerDefine(stc.STC_MARKNUM_FOLDERTAIL, stc.STC_MARK_LCORNER, "white", "black")
+        self.MarkerDefine(stc.STC_MARKNUM_FOLDERSUB, stc.STC_MARK_VLINE, "white", "black")
+        self.MarkerDefine(stc.STC_MARKNUM_FOLDER, stc.STC_MARK_BOXPLUS, "white", "#cccccc")
+        self.MarkerDefine(stc.STC_MARKNUM_FOLDEROPEN, stc.STC_MARK_BOXMINUS, "white", "black")
+        stc.EVT_STC_MARGINCLICK(self, -1, self.on_margin_click)
+
+        self.SetText(xml_string)
+        self.SetEditable(False)
+
+    def on_margin_click(self, evt):
+        """ Folds and unfolds as needed """
+
+        if evt.GetMargin() == 2:
+            if evt.GetShift() and evt.GetControl():
+                self.fold_all()
+
+            else:
+                line_clicked = self.LineFromPosition(evt.GetPosition())
+                if self.GetFoldLevel(line_clicked) & stc.STC_FOLDLEVELHEADERFLAG:
+                    if evt.GetShift():
+                        self.SetFoldExpanded(line_clicked, True)
+                        self.expand_item(line_clicked, True, True, 1)
+                    elif evt.GetControl():
+                        if self.GetFoldExpanded(line_clicked):
+                            self.SetFoldExpanded(line_clicked, False)
+                            self.expand_item(line_clicked, False, True, 0)
+                        else:
+                            self.SetFoldExpanded(line_clicked, True)
+                            self.expand_item(line_clicked, True, True, 100)
+                    else:
+                        self.ToggleFold(line_clicked)
+
+    def fold_all(self):
+        line_count = self.GetLineCount()
+        expanding = True
+
+        # find out if we are folding or unfolding
+        for line_num in range(line_count):
+            if self.GetFoldLevel(line_num) & stc.STC_FOLDLEVELHEADERFLAG:
+                expanding = not self.GetFoldExpanded(line_num)
+                break
+
+        line_num = 0
+        while line_num < line_count:
+            level = self.GetFoldLevel(line_num)
+            if level & stc.STC_FOLDLEVELHEADERFLAG and (level & stc.STC_FOLDLEVELNUMBERMASK) == stc.STC_FOLDLEVELBASE:
+
+                if expanding:
+                    self.SetFoldExpanded(line_num, True)
+                    line_num = self.expand_item(line_num, True)
+                    line_num -= 1
+                else:
+                    last_child = self.GetLastChild(line_num, -1)
+                    self.SetFoldExpanded(line_num, False)
+                    if last_child > line_num:
+                        self.HideLines(line_num + 1, last_child)
+
+            line_num += 1
+
+    def expand_item(self, line, do_expand, force=False, vis_levels=0, level=-1):
+        last_child = self.GetLastChild(line, level)
+        line += 1
+        while line <= last_child:
+            if force:
+                if vis_levels > 0:
+                    self.ShowLines(line, line)
+                else:
+                    self.HideLines(line, line)
+            else:
+                if do_expand:
+                    self.ShowLines(line, line)
+
+            if level == -1:
+                level = self.GetFoldLevel(line)
+
+            if level & stc.STC_FOLDLEVELHEADERFLAG:
+                if force:
+                    if vis_levels > 1:
+                        self.SetFoldExpanded(line, True)
+                    else:
+                        self.SetFoldExpanded(line, False)
+                    line = self.expand_item(line, do_expand, force, vis_levels - 1)
+
+                else:
+                    if do_expand and self.GetFoldExpanded(line):
+                        line = self.expand_item(line=line, do_expand=True, force=force, vis_levels=(vis_levels - 1))
+                    else:
+                        line = self.expand_item(line=line, do_expand=False, force=force, vis_levels=(vis_levels - 1))
+            else:
+                line += 1
+
+        return line
+

-- 
Alioth's /usr/local/bin/git-commit-notice on /srv/git.debian.org/git/debian-science/packages/hdf-compass.git



More information about the debian-science-commits mailing list