bin/gla11y                              | 1145 ++++++++++++++++++++++++++++----
 solenv/gbuild/UIConfig.mk               |   67 +
 solenv/gbuild/platform/com_GCC_class.mk |    2 
 solenv/gbuild/platform/com_MSC_class.mk |    2 
 solenv/sanitizers/ui/cui.suppr          |   11 
 solenv/sanitizers/ui/svt.suppr          |    4 
 solenv/sanitizers/ui/svx.suppr          |   18 
 7 files changed, 1100 insertions(+), 149 deletions(-)

New commits:
commit d0f1a431eab9a7a503bf6487732eeaec0e881053
Author: Samuel Thibault <sthiba...@hypra.fr>
Date:   Mon Mar 12 18:28:06 2018 +0100

    gla11y: update heuristics but don't enable warnings yet
    
    This updates gla11y with all heuristics to detect orphan labels and widgets
    without too many false positives.
    
    This updates gbuild to tell gla11y to only emit errors about undefined
    targets and about orphan warnings for GtkScale (as was the case with
    previous versions). More errors and warnings will be enabled progressively
    later on.
    
    Change-Id: I96580eb0eb8eb327f0f54563d7976a5148e9531a
    Reviewed-on: https://gerrit.libreoffice.org/51161
    Tested-by: Jenkins <c...@libreoffice.org>
    Reviewed-by: Thorsten Behrens <thorsten.behr...@cib.de>

diff --git a/bin/gla11y b/bin/gla11y
index fa6e7281a0cd..e19e580d0d4f 100755
--- a/bin/gla11y
+++ b/bin/gla11y
@@ -36,23 +36,263 @@ try:
     lxml = True
 except ImportError:
     if sys.version_info < (2,7):
+        print("gla11y needs lxml or python >= 2.7")
         exit()
     import xml.etree.ElementTree as ET
     lxml = False
 
+# Toplevel widgets
+widgets_toplevel = [
+    'GtkWindow',
+    'GtkOffscreenWindow',
+    'GtkApplicationWindow',
+    'GtkDialog',
+    'GtkAboutDialog',
+    'GtkFileChooserDialog',
+    'GtkColorChooserDialog',
+    'GtkFontChooserDialog',
+    'GtkMessageDialog',
+    'GtkRecentChooserDialog',
+    'GtkAssistant',
+    'GtkAppChooserDialog',
+    'GtkPrintUnixDialog',
+    'GtkShortcutsWindow',
+]
+
+widgets_ignored = widgets_toplevel + [
+    # Containers
+    'GtkBox',
+    'GtkGrid',
+    'GtkNotebook',
+    'GtkFrame',
+    'GtkAspectFrame',
+    'GtkListBox',
+    'GtkFlowBox',
+    'GtkOverlay',
+    'GtkMenuBar',
+    'GtkToolbar',
+    'GtkToolpalette',
+    'GtkPaned',
+    'GtkHPaned',
+    'GtkVPaned',
+    'GtkButtonBox',
+    'GtkHButtonBox',
+    'GtkVButtonBox',
+    'GtkLayout',
+    'GtkFixed',
+    'GtkEventBox',
+    'GtkExpander',
+    'GtkViewport',
+    'GtkScrolledWindow',
+    'GtkAlignment',
+    'GtkRevealer',
+    'GtkSearchBar',
+    'GtkHeaderBar',
+    'GtkStack',
+    'GtkStackSwticher',
+    'GtkPopover',
+    'GtkPopoverMenu',
+    'GtkActionBar',
+    'GtkHandleBox',
+    'GtkShortcutsSection',
+    'GtkShortcutsGroup',
+    'GtkTable',
+
+    'GtkVBox',
+    'GtkHBox',
+    'GtkToolItem',
+    'GtkMenu',
+
+    # Invisible actions
+    'GtkSeparator',
+    'GtkHSeparator',
+    'GtkVSeparator',
+    'GtkAction',
+    'GtkToggleAction',
+    'GtkActionGroup',
+    'GtkCellRendererGraph',
+    'GtkCellRendererPixbuf',
+    'GtkCellRendererProgress',
+    'GtkCellRendererSpin',
+    'GtkCellRendererText',
+    'GtkCellRendererToggle',
+    'GtkSeparatorMenuItem',
+    'GtkSeparatorToolItem',
+
+    # Storage objects
+    'GtkListStore',
+    'GtkTreeStore',
+    'GtkTreeModelFilter',
+    'GtkTreeModelSort',
+
+    'GtkEntryBuffer',
+    'GtkTextBuffer',
+    'GtkTextTag',
+    'GtkTextTagTable',
+
+    'GtkSizeGroup',
+    'GtkWindowGroup',
+    'GtkAccelGroup',
+    'GtkAdjustment',
+    'GtkEntryCompletion',
+    'GtkIconFactory',
+    'GtkStatusIcon',
+    'GtkFileFilter',
+    'GtkRecentFilter',
+    'GtkRecentManager',
+    'GThemedIcon',
+
+    'GtkTreeSelection',
+
+    'GtkListBoxRow',
+
+    # Useless to label
+    'GtkScrollbar',
+    'GtkHScrollbar',
+    'GtkStatusbar',
+    'GtkInfoBar',
+
+    # These are actually labels
+    'GtkLinkButton',
+
+    # This precisely give a11y information :)
+    'AtkObject',
+]
+
+widgets_suffixignored = [
+]
+
+# These widgets always need a label
+widgets_needlabel = [
+    'GtkEntry',
+    'GtkSearchEntry',
+    'GtkScale',
+    'GtkHScale',
+    'GtkVScale',
+    'GtkSpinButton',
+    'GtkSwitch',
+]
+
+# These widgets normally have their own label
+widgets_buttons = [
+    'GtkButton',
+    'GtkToolButton',
+    'GtkToggleButton',
+    'GtkToggleToolButton',
+    'GtkRadioButton',
+    'GtkRadioToolButton',
+    'GtkCheckButton',
+    'GtkModelButton',
+    'GtkLockButton',
+    'GtkColorButton',
+    'GtkMenuButton',
+
+    'GtkMenuItem',
+    'GtkImageMenuItem',
+    'GtkMenuToolButton',
+    'GtkRadioMenuItem',
+    'GtkCheckMenuItem',
+]
+
+# These widgets are labels that can label other widgets
+widgets_labels = [
+    'GtkLabel',
+    'GtkAccelLabel',
+]
+
+# The rest should probably be labelled if there are orphan labels
+
+# GtkSpinner
+# GtkProgressBar
+# GtkLevelBar
+
+# GtkComboBox
+# GtkComboBoxText
+# GtkFileChooserButton
+# GtkAppChooserButton
+# GtkFontButton
+# GtkCalendar
+# GtkColorChooserWidget
+
+# GtkCellView
+# GtkTreeView
+# GtkTreeViewColumn
+# GtkTextView
+# GtkIconView
+
+# GtkImage
+# GtkArrow
+# GtkDrawingArea
+
+# GtkScaleButton
+# GtkVolumeButton
+
+
+# TODO:
+# GtkColorPlane ?
+# GtkColorScale ?
+# GtkColorSwatch ?
+# GtkFileChooserWidget ?
+# GtkFishbowl ?
+# GtkFontChooserWidget ?
+# GtkIcon ?
+# GtkInspector* ?
+# GtkMagnifier ?
+# GtkPathBar ?
+# GtkPlacesSidebar ?
+# GtkPlacesView ?
+# GtkPrinterOptionWidget ?
+# GtkStackCombo ?
+# GtkStackSidebar ?
+
 progname = os.path.basename(sys.argv[0])
+
 suppressions = {}
+ids = {}
+ids_dup = {}
+labelled_by_elm = {}
+label_for_elm = {}
+mnemonic_for_elm = {}
+
 gen_suppr = None
 gen_supprfile = None
 suppr_prefix = ""
 outfile = None
+
 pflag = False
-Werror = False
-Wnone = False
+
+warn_orphan_labels = True
+
 errors = 0
 errexists = 0
 warnings = 0
 warnexists = 0
+fatals = 0
+fatalexists = 0
+
+enables = [ ]
+dofatals = [ ]
+
+#
+# XML browsing and printing functions
+#
+
+def elm_parent(root, elm):
+    """
+    Return the parent of the element.
+    """
+    if lxml:
+        return elm.getparent()
+    else:
+        def find_parent(cur, elm):
+            for o in cur:
+                if o == elm:
+                    return cur
+                parent = find_parent(o, elm)
+                if parent is not None:
+                    return parent
+            return None
+        return find_parent(root, elm)
 
 def step_elm(elm):
     """
@@ -96,18 +336,23 @@ def errpath(filename, tree, elm):
     oid = elm.attrib.get('id')
     if oid is not None:
         oid = oid.encode('ascii','ignore').decode('ascii')
-        path += "[@id='%s']" % oid
-    if lxml:
-        elm = elm.getparent()
-        while elm is not None:
-            step = step_elm(elm)
-            path = step + path
-            elm = elm.getparent()
+        path = "//" + path + "[@id='%s']" % oid
     else:
-        path = find_elm(tree.getroot(), elm)[:-1]
+        if lxml:
+            elm = elm.getparent()
+            while elm is not None:
+                step = step_elm(elm)
+                path = step + path
+                elm = elm.getparent()
+        else:
+            path = find_elm(tree.getroot(), elm)[:-1]
     path = filename + ':' + path
     return path
 
+#
+# Warning/Error printing functions
+#
+
 def elm_prefix(filename, elm):
     """
     Return the display prefix of the element
@@ -128,10 +373,49 @@ def elm_name(elm):
         if 'id' in elm.attrib:
             id = elm.attrib['id'].encode('ascii','ignore').decode('ascii')
             name += "'%s' " % id
+        if not name:
+            name = "'" + elm.tag + "'"
+            if lxml:
+                name += " line " + str(elm.sourceline)
         return name
     return ""
 
-def elm_suppr(filename, tree, elm, msgtype):
+def elm_name_line(elm):
+    """
+    Return a display name of the element with line number
+    """
+    if elm is not None:
+        name = elm_name(elm)
+        if lxml and " line " not in name:
+            name += "line " + str(elm.sourceline) + " "
+        return name
+    return ""
+
+def elm_line(elm):
+    """
+    Return the line for the given element.
+    """
+    if lxml:
+        return " line " + str(elm.sourceline)
+    else:
+        return ""
+
+def elms_lines(elms):
+    """
+    Return the list of lines for the given elements.
+    """
+    if lxml:
+        return " lines " + ', '.join([str(l.sourceline) for l in elms])
+    else:
+        return ""
+
+def elms_names_lines(elms):
+    """
+    Return the list of names and lines for the given elements.
+    """
+    return ', '.join([elm_name_line(elm) for elm in elms])
+
+def elm_suppr(filename, tree, elm, msgtype, dogen):
     """
     Return the prefix to be displayed to the user and the suppression line for
     the warning type "msgtype" for element "elm"
@@ -146,7 +430,7 @@ def elm_suppr(filename, tree, elm, msgtype):
     if suppressions or gen_suppr is not None:
         suppr = '%s %s' % (prefix, msgtype)
 
-        if gen_suppr is not None and msgtype is not None:
+        if gen_suppr is not None and msgtype is not None and dogen:
             if gen_supprfile is None:
                 gen_supprfile = open(gen_suppr, 'w')
             print(suppr, file=gen_supprfile)
@@ -161,90 +445,458 @@ def elm_suppr(filename, tree, elm, msgtype):
 
     return (prefix, suppr)
 
-def err(filename, tree, elm, msgtype, msg):
+def is_enabled(elm, msgtype, l, default):
     """
-    Emit an error for an element
+    Test whether warning type msgtype is enabled for elm in l
     """
-    global errors, errexists
-
-    (prefix, suppr) = elm_suppr(filename, tree, elm, msgtype)
-
-    if suppr in suppressions:
-        # Suppressed
-        errexists += 1
-        return
-
-    errors += 1
-    msg = "%s ERROR: %s%s" % (prefix, elm_name(elm), msg)
-    print(msg)
-    if outfile is not None:
-        print(msg, file=outfile)
-
+    enabled = default
+    for (enable, thetype, klass) in l:
+        # Match warning type
+        if thetype is not None:
+            if thetype != msgtype:
+                continue
+        # Match elm class
+        if klass is not None and elm is not None:
+            if klass != elm.attrib.get('class'):
+                continue
+        enabled = enable
+    return enabled
 
-def warn(filename, tree, elm, msgtype, msg):
+def err(filename, tree, elm, msgtype, msg, error = True):
     """
-    Emit a warning for an element
+    Emit a warning or error for an element
     """
-    global Werror, Wnone, errors, errexists, warnings, warnexists
+    global errors, errexists, warnings, warnexists, fatals, fatalexists
 
-    if Wnone:
+    # Let user tune whether a warning or error
+    fatal = is_enabled(elm, msgtype, dofatals, error)
+
+    # By default warnings and errors are enabled, but let user tune it
+    if not is_enabled(elm, msgtype, enables, True):
         return
 
-    (prefix, suppr) = elm_suppr(filename, tree, elm, msgtype)
+    (prefix, suppr) = elm_suppr(filename, tree, elm, msgtype, True)
     if suppr in suppressions:
         # Suppressed
-        if Werror:
+        suppressions[suppr] = False
+        if fatal:
+            fatalexists += 1
+        if error:
             errexists += 1
         else:
             warnexists += 1
         return
 
-    if Werror:
+    if error:
         errors += 1
     else:
         warnings += 1
+    if fatal:
+        fatals += 1
 
-    msg = "%s WARNING: %s%s" % (prefix, elm_name(elm), msg)
+    msg = "%s %s%s: %s%s" % (prefix,
+            "FATAL " if fatal else "",
+            "ERROR" if error else "WARNING",
+            elm_name(elm), msg)
     print(msg)
     if outfile is not None:
         print(msg, file=outfile)
 
+def warn(filename, tree, elm, msgtype, msg):
+    """
+    Emit a warning for an element
+    """
+    err(filename, tree, elm, msgtype, msg, False)
+
+#
+# Labelling testing functions
+#
 
-def check_objects(filename, tree, elm, objects, target):
+def find_button_parent(root, elm):
     """
-    Check that objects contains exactly one object
+    Find a parent which is a button
     """
-    length = len(list(objects))
-    if length == 0:
-        err(filename, tree, elm, "undeclared-target", "uses undeclared target 
'%s'" % target)
-    elif length > 1:
-        err(filename, tree, elm, "multiple-target", "several targets are named 
'%s'" % target)
+    if lxml:
+        parent = elm.getparent()
+        if parent is not None:
+            if parent.attrib.get('class') in widgets_buttons:
+                return parent
+            return find_button_parent(root, parent)
+    else:
+        def find_parent(cur, elm):
+            for o in cur:
+                if o == elm:
+                    if cur.attrib.get('class') in widgets_buttons:
+                        # we are the button, immediately above the target
+                        return cur
+                    else:
+                        # we aren't the button, but target is over there
+                        return True
+                parent = find_parent(o, elm)
+                if parent == True:
+                    # It is over there, but didn't find a button yet
+                    if cur.attrib.get('class') in widgets_buttons:
+                        # we are the button
+                        return cur
+                    else:
+                        return True
+                if parent is not None:
+                    # we have the button parent over there
+                    return parent
+            return None
+        parent = find_parent(root, elm)
+        if parent == True:
+            parent = None
+        return parent
+
 
-def check_props(filename, tree, root, elm, props):
+def is_labelled_parent(elm):
     """
-    Check the given list of relation properties
+    Return whether this element is a labelled parent
     """
-    for prop in props:
-        objects = root.iterfind(".//object[@id='%s']" % prop.text)
-        check_objects(filename, tree, elm, objects, prop.text)
+    klass = elm.attrib.get('class')
+    if klass in widgets_toplevel:
+        return True
+    if klass == 'GtkShortcutsGroup':
+        children = elm.findall("property[@name='title']")
+        if len(children) >= 1:
+            return True
+    if klass == 'GtkFrame' or klass == 'GtkNotebook':
+        children = elm.findall("child[@type='tab']") + 
elm.findall("child[@type='label']") 
+        if len(children) >= 1:
+            return True
+    return False
 
-def check_rels(filename, tree, root, elm, rels):
+def elm_labelled_parent(root, elm):
     """
-    Check the given list of relations
+    Return the first labelled parent of the element, which can thus be used as
+    the root of widgets with common labelled context
     """
-    for rel in rels:
+
+    if lxml:
+        def find_labelled_parent(elm):
+            if is_labelled_parent(elm):
+                return elm
+            parent = elm.getparent()
+            if parent is None:
+                return None
+            return find_labelled_parent(parent)
+        parent = elm.getparent()
+        if parent is None:
+            return None
+        return find_labelled_parent(elm.getparent())
+    else:
+        def find_labelled_parent(cur, elm):
+            if cur == elm:
+                # the target element is over there
+                return True
+            for o in cur:
+                parent = find_labelled_parent(o, elm)
+                if parent == True:
+                    # target element is over there, check ourself
+                    if is_labelled_parent(cur):
+                        # yes, and we are the first ancestor of the target 
element
+                        return cur
+                    else:
+                        # no, but target element is over there.
+                        return True
+                if parent != None:
+                    # the first ancestor of the target element was over there
+                    return parent
+            return None
+        parent = find_labelled_parent(root, elm)
+        if parent == True:
+            parent = None
+        return parent
+
+def is_orphan_label(filename, tree, root, obj, orphan_root, doprint = False):
+    """
+    Check whether this label has no accessibility relation, or doubtful 
relation
+    because another label labels the same target
+    """
+    global label_for_elm, labelled_by_elm, mnemonic_for_elm, warnexists
+
+    # label-for
+    label_for = obj.findall("accessibility/relation[@type='label-for']")
+    for rel in label_for:
         target = rel.attrib['target']
-        targets = root.iterfind(".//object[@id='%s']" % target)
-        check_objects(filename, tree, elm, targets, target)
+        l = label_for_elm[target]
+        if len(l) > 1:
+            return True
 
-def elms_lines(elms):
+    # mnemonic_widget
+    mnemonic_for = obj.findall("property[@name='mnemonic_widget']")
+    for rel in mnemonic_for:
+        target = rel.text
+        l = mnemonic_for_elm[target]
+        if len(l) > 1:
+            return True
+
+    if len(label_for) > 0:
+        # At least one label-for, we are not orphan.
+        return False
+
+    if len(mnemonic_for) > 0:
+        # At least one mnemonic_widget, we are not orphan.
+        return False
+
+    labelled_by = obj.findall("accessibility/relation[@type='labelled-by']")
+    if len(labelled_by) > 0:
+        # Oh, a labelled label, probably not to be labelling anything
+        return False
+
+    parent = elm_parent(root, obj)
+    if parent is not None:
+        childtype = parent.attrib.get('type')
+        if childtype is None:
+            childtype = parent.attrib.get('internal-child')
+        if parent.tag == 'child' and childtype == 'label' \
+                                  or childtype == 'tab':
+            # This is a frame or a notebook label, not orphan.
+            return False
+
+    if find_button_parent(root, obj) is not None:
+        # This label is part of a button
+        return False
+
+    oid = obj.attrib.get('oid')
+    if oid is not None:
+        if oid in labelled_by_elm:
+            # Some widget is labelled by us, we are not orphan.
+            # We should have had a label-for, will warn about it later.
+            return False
+
+    # No label-for, no mnemonic-for, no labelled-by, we are orphan.
+    (_, suppr) = elm_suppr(filename, tree, obj, "orphan-label", False)
+    if suppr in suppressions:
+        # Warning suppressed for this label
+        if suppressions[suppr]:
+            warnexists += 1
+        suppressions[suppr] = False
+        return False
+
+    if doprint:
+        context = elm_name(orphan_root)
+        if context:
+            context = " within " + context
+        warn(filename, tree, obj, "orphan-label", "does not specify what it 
labels" + context)
+    return True
+
+def is_orphan_widget(filename, tree, root, obj, orphan, orphan_root, doprint = 
False):
     """
-    Return the list of lines for the given elements.
+    Check whether this widget has no accessibility relation.
     """
-    if lxml:
-        return ": lines " + ', '.join([str(l.sourceline) for l in elms])
+    global warnexists
+    if obj.tag != 'object':
+        return False
+
+    oid = obj.attrib.get('id')
+    klass = obj.attrib.get('class')
+
+    # "Don't care" special case
+    if klass in widgets_ignored:
+        return False
+    for suffix in widgets_suffixignored:
+        if klass[-len(suffix):] == suffix:
+            return False
+
+    # Widgets usual do not strictly require a label, i.e. a labelled parent
+    # is enough for context, but some do always need one.
+    requires_label = klass in widgets_needlabel
+
+    labelled_by = obj.findall("accessibility/relation[@type='labelled-by']")
+
+    # Labels special case
+    if klass in widgets_labels:
+        return False
+
+    # Case 1: has an explicit <child internal-child="accessible"> sub-element
+    children = obj.findall("child[@internal-child='accessible']")
+    if len(children) > 1 and doprint:
+        err(filename, tree, obj, "multiple-accessible", "has multiple <child 
internal-child='accessible'>"
+            "%s" % elms_lines(children))
+    if len(children) >= 1:
+        return False
+
+    # Case 2: has an <accessibility> sub-element with a "labelled-by"
+    # <relation> pointing to an existing element.
+    if len(labelled_by) > 0:
+        return False
+
+    # Case 3: has a label-for
+    if oid in label_for_elm:
+        return False
+
+    # Case 4: has a mnemonic
+    if oid in mnemonic_for_elm:
+        return False
+
+    # Case 5: Has a <property name="tooltip_text">
+    tooltips = obj.findall("property[@name='tooltip_text']")
+    if len(tooltips) > 1 and doprint:
+        err(filename, tree, obj, "multiple-tooltip", "has multiple 
tooltip_text properties")
+    if len(tooltips) >= 1:
+        return False
+
+    # Case 6: Has a <property name="placeholder_text">
+    placeholders = obj.findall("property[@name='placeholder_text']")
+    if len(placeholders) > 1 and doprint:
+        err(filename, tree, obj, "multiple-placeholder", "has multiple 
placeholder_text properties")
+    if len(placeholders) >= 1:
+        return False
+
+    # Buttons usually don't need an external label, their own is enough, (but 
they do need one)
+    if klass in widgets_buttons:
+
+        labels = obj.findall("property[@name='label']")
+        if len(labels) > 1 and doprint:
+            err(filename, tree, obj, "multiple-label", "has multiple label 
properties")
+        if len(labels) >= 1:
+            # Has a <property name="label">
+            return False
+
+        actions = obj.findall("property[@name='action_name']")
+        if len(actions) > 1 and doprint:
+            err(filename, tree, obj, "multiple-action_name", "has multiple 
action_name properties")
+        if len(actions) >= 1:
+            # Has a <property name="action_name">
+            return False
+
+        gtklabels = obj.findall(".//object[@class='GtkLabel']") + 
obj.findall(".//object[@class='GtkAccelLabel']")
+        if len(gtklabels) >= 1:
+            # Has a custom label
+            return False
+
+        # no label for a button, warn
+        if doprint:
+            warn(filename, tree, obj, "button-no-label", "does not have its 
own label");
+        if not is_enabled(obj, "button-no-label", enables, True):
+            # Warnings disabled
+            return False
+        (_, suppr) = elm_suppr(filename, tree, obj, "button-no-label", False)
+        if suppr in suppressions:
+            # Warning suppressed for this widget
+            if suppressions[suppr]:
+                warnexists += 1
+            suppressions[suppr] = False
+            return False
+        return True
+
+    # GtkImages special case
+    if klass == "GtkImage":
+        uses = [u for u in tree.iterfind(".//object/property[@name='image']") 
if u.text == oid]
+        if len(uses) > 0:
+            # This image is just used by another element, don't warn
+            # about the image itself, we probably want the warning on
+            # the element instead.
+            return False
+
+        if find_button_parent(root, obj) is not None:
+            # This image is part of a button, we want the warning on the button
+            # instead, if any.
+            return False
+
+    # GtkEntry special case
+    if klass == 'GtkEntry' or klass == 'GtkSearchEntry':
+        parent = elm_parent(root, obj)
+        if parent is not None:
+            if parent.tag == 'child' and \
+                parent.attrib.get('internal-child') == "entry":
+                # This is an internal entry of another widget. Relations
+                # will be handled by that widget.
+                return False
+
+    # GtkShortcutsShortcut special case
+    if klass == 'GtkShortcutsShortcut':
+        children = obj.findall("property[@name='title']")
+        if len(children) >= 1:
+            return False
+
+
+    # Really no label, perhaps emit a warning
+    if not is_enabled(obj, "no-labelled-by", enables, True):
+        # Warnings disabled for this class of widgets
+        return False
+    (_, suppr) = elm_suppr(filename, tree, obj, "no-labelled-by", False)
+    if suppr in suppressions:
+        # Warning suppressed for this widget
+        if suppressions[suppr]:
+            warnexists += 1
+        suppressions[suppr] = False
+        return False
+
+    if not orphan:
+        # No orphan label, so probably the labelled parent provides enough
+        # context.
+        if requires_label:
+            # But these always need a label.
+            if doprint:
+                warn(filename, tree, obj, "no-labelled-by", "has no 
accessibility label")
+            return True
+        return False
+
+    if doprint:
+        context = elm_name(orphan_root)
+        if context:
+            context = " within " + context
+        warn(filename, tree, obj, "no-labelled-by", "has no accessibility 
label while there are orphan labels" + context)
+    return True
+
+def orphan_items(filename, tree, root, elm):
+    """
+    Check whether from some element there exists orphan labels and orphan 
widgets
+    """
+    orphan_labels = False
+    orphan_widgets = False
+    if elm.attrib.get('class') in widgets_labels:
+        orphan_labels = is_orphan_label(filename, tree, root, elm, None)
     else:
-        return ""
+        orphan_widgets = is_orphan_widget(filename, tree, root, elm, True, 
None)
+    for obj in elm:
+        # We are not interested in orphan labels under another labelled
+        # parent.  This also allows to keep linear complexity.
+        if not is_labelled_parent(obj):
+            label, widget = orphan_items(filename, tree, root, obj)
+            if label:
+                orphan_labels = True
+            if widget:
+                orphan_widgets = True
+            if orphan_labels and orphan_widgets:
+                # No need to look up more
+                break
+    return orphan_labels, orphan_widgets
+
+#
+# UI accessibility checks
+#
+
+def check_props(filename, tree, root, elm, forward):
+    """
+    Check the given list of relation properties
+    """
+    props = elm.findall("property[@name='mnemonic_widget']")
+    for prop in props:
+        if prop.text not in ids:
+            err(filename, tree, elm, "undeclared-target", forward + " uses 
undeclared target '%s'" % prop.text)
+    return props
+
+def check_rels(filename, tree, root, elm, forward, backward = None):
+    """
+    Check the relations given by forward
+    """
+    oid = elm.attrib.get('id')
+    rels = elm.findall("accessibility/relation[@type='" + forward + "']")
+    for rel in rels:
+        target = rel.attrib['target']
+        if target not in ids:
+            err(filename, tree, elm, "undeclared-target", forward + " uses 
undeclared target '%s'" % target)
+        elif backward is not None:
+            widget = ids[target]
+            backrels = widget.findall("accessibility/relation[@type='" + 
backward + "']")
+            if len([x for x in backrels if x.attrib['target'] == oid]) == 0:
+                err(filename, tree, elm, "missing-" + backward, "has " + 
forward + \
+                    ", but is not " + backward + " by " + 
elm_name_line(widget))
+    return rels
 
 def check_a11y_relation(filename, tree):
     """
@@ -252,111 +904,256 @@ def check_a11y_relation(filename, tree):
     document represented by `root' doesn't comply with Accessibility
     rules.
     """
-    root = tree.getroot()
+    global widgets_ignored, ids, label_for_elm, labelled_by_elm, 
mnemonic_for_elm
 
-    for obj in root.iter('object'):
+    def check_elm(orphan_root, obj, orphan_labels, orphan_widgets):
+        """
+        Check one element, knowing that orphan_labels/widgets tell whether
+        there are orphan labels and widgets within orphan_root
+        """
 
-        label_for = obj.findall("accessibility/relation[@type='label-for']")
-        check_rels(filename, tree, root, obj, label_for)
+        oid = obj.attrib.get('id')
+        klass = obj.attrib.get('class')
 
-        labelled_by = 
obj.findall("accessibility/relation[@type='labelled-by']")
-        check_rels(filename, tree, root, obj, labelled_by)
+        # "Don't care" special case
+        if klass in widgets_ignored:
+            return
+        for suffix in widgets_suffixignored:
+            if klass[-len(suffix):] == suffix:
+                return
 
-        member_of = obj.findall("accessibility/relation[@type='member-of']")
-        check_rels(filename, tree, root, obj, member_of)
+        # Widgets usual do not strictly require a label, i.e. a labelled parent
+        # is enough for context, but some do always need one.
+        requires_label = klass in widgets_needlabel
 
-        if obj.attrib['class'] == 'GtkLabel':
-            # Case 0: A 'GtkLabel' must contain one or more "label-for"
-            # pointing to existing elements or...
-            if len(label_for) > 0:
-                continue
+        if oid is not None:
+            # Check that ids are unique
+            if oid in ids_dup:
+                if ids[oid] == obj:
+                    # We are the first, warn
+                    duplicates = tree.findall(".//object[@id='" + oid + "']")
+                    err(filename, tree, obj, "duplicate-id", "has the same id 
as other elements " + elms_names_lines(duplicates))
+
+        # Check label-for and their dual labelled-by
+        label_for = check_rels(filename, tree, root, obj, "label-for", 
"labelled-by")
+
+        # Check labelled-by and its dual label-for
+        labelled_by = check_rels(filename, tree, root, obj, "labelled-by", 
"label-for")
 
-            # ...a single "mnemonic_widget"
-            properties = obj.findall("property[@name='mnemonic_widget']")
-            check_props(filename, tree, root, obj, properties)
+        # Should have only one label
+        if len(labelled_by) >= 1:
+            if oid in mnemonic_for_elm:
+                warn(filename, tree, obj, "labelled-by-and-mnemonic",
+                     "has both a mnemonic " + 
elm_name_line(mnemonic_for_elm[oid][0]) + "and labelled-by relation")
+            if len(labelled_by) > 1:
+                warn(filename, tree, obj, "multiple-labelled-by", "has 
multiple labelled-by relations")
+        if oid in label_for_elm:
+            if len(label_for_elm[oid]) > 1:
+                warn(filename, tree, obj, "duplicate-label-for", "is 
referenced by multiple label-for " + elms_names_lines(label_for_elm[oid]))
+        if oid in mnemonic_for_elm:
+            if len(mnemonic_for_elm[oid]) > 1:
+                warn(filename, tree, obj, "duplicate-mnemonic", "is referenced 
by multiple mnemonic_widget " + elms_names_lines(mnemonic_for_elm[oid]))
+
+        # Check member-of
+        member_of = check_rels(filename, tree, root, obj, "member-of")
+
+        # Labels special case
+        if klass in widgets_labels:
+            properties = check_props(filename, tree, root, obj, 
"mnemonic_widget")
             if len(properties) > 1:
-                # It does not make sense for a label to be a mnemonic for
-                # several actions.
-                err(filename, tree, obj, "multiple-mnemonic", "has too many 
sub-elements"
-                    ", expected single <property name='mnemonic_widgets'>"
+                err(filename, tree, obj, "multiple-mnemonic", "has multiple 
mnemonic_widgets properties"
                     "%s" % elms_lines(properties))
-                continue
-            if len(properties) == 1:
-                continue
-            # TODO: warn that it is a label for nothing
-            continue
 
-        # Case 1: has a <child internal-child="accessible"> sub-element
-        children = obj.findall("child[@internal-child='accessible']")
-        if children:
-            if len(children) > 1:
-                err(filename, tree, obj, "multiple-accessible", "has too many 
sub-elements"
-                    ", expected single <child internal-child='accessible'>"
-                    "%s" % elms_lines(children))
-            continue
+            # Emit orphaning warnings
+            if warn_orphan_labels or orphan_widgets:
+                is_orphan_label(filename, tree, root, obj, orphan_root, True)
 
-        # Case 2: has an <accessibility> sub-element with a "labelled-by"
-        # <relation> pointing to an existing element.
-        if len(labelled_by) > 0:
-            continue
+            # We are done with the label
+            return
 
-        # Case 3/4: has an ID...
+        # Not a label, will perhaps need one
+
+        # Emit orphaning warnings
+        is_orphan_widget(filename, tree, root, obj, orphan_labels, 
orphan_root, True)
+
+    root = tree.getroot()
+
+    # Flush ids and relations from previous files
+    ids = {}
+    ids_dup = {}
+    labelled_by_elm = {}
+    label_for_elm = {}
+    mnemonic_for_elm = {}
+
+    # First pass to get links into hash tables, no warning, just record 
duplicates
+    for obj in root.iter('object'):
         oid = obj.attrib.get('id')
         if oid is not None:
-            # ...referenced by a single "label-for" <relation>
-            rels = root.iterfind(".//relation[@target='%s']" % oid)
-            labelfor = [r for r in rels if r.attrib.get('type') == 'label-for']
-            if len(labelfor) == 1:
-                continue
-            if len(labelfor) > 1:
-                err(filename, tree, obj, "multiple-label-for", "has too many 
elements"
-                    ", expected single <relation type='label-for' target='%s'>"
-                    "%s" % (oid, elm_lines(labelfor)))
-                continue
+            if oid not in ids:
+                ids[oid] = obj
+            else:
+                ids_dup[oid] = True
 
-            # ...referenced by a single "mnemonic_widget"
-            props = root.iterfind(".//property[@name='mnemonic_widget']")
-            props = [p for p in props if p.text == oid]
-            # TODO: warn when more than one.
-            if len(props) >= 1:
-                continue
+        labelled_by = 
obj.findall("accessibility/relation[@type='labelled-by']")
+        for rel in labelled_by:
+            target = rel.attrib.get('target')
+            if target is not None:
+                if target not in labelled_by_elm:
+                    labelled_by_elm[target] = [ obj ]
+                else:
+                    labelled_by_elm[target].append(obj)
+
+        label_for = obj.findall("accessibility/relation[@type='label-for']")
+        for rel in label_for:
+            target = rel.attrib.get('target')
+            if target is not None:
+                if target not in label_for_elm:
+                    label_for_elm[target] = [ obj ]
+                else:
+                    label_for_elm[target].append(obj)
+
+        mnemonic_for = obj.findall("property[@name='mnemonic_widget']")
+        for rel in mnemonic_for:
+            target = rel.text
+            if target is not None:
+                if target not in mnemonic_for_elm:
+                    mnemonic_for_elm[target] = [ obj ]
+                else:
+                    mnemonic_for_elm[target].append(obj)
+
+    # Second pass, recursive depth-first, to be able to efficiently know 
whether
+    # there are orphan labels within a part of the tree.
+    def recurse(orphan_root, obj, orphan_labels, orphan_widgets):
+        if obj == root or is_labelled_parent(obj):
+            orphan_root = obj
+            orphan_labels, orphan_widgets = orphan_items(filename, tree, root, 
obj)
 
-        # TODO: after a few more checks and false-positives filtering, warn
-        # that this does not have a label
-        if obj.attrib['class'] == "GtkScale":
-            # GtkScale definitely needs a context
-            err(filename, tree, obj, "no-labelled-by", "has no accessibility 
label")
+        if obj.tag == 'object':
+            check_elm(orphan_root, obj, orphan_labels, orphan_widgets)
 
+        for o in obj:
+            recurse(orphan_root, o, orphan_labels, orphan_widgets)
+
+    recurse(root, root, False, False)
+
+#
+# Main
+#
 
 def usage():
-    print("%s [-W error|none] [-p] [-g SUPPR_FILE] [-s SUPPR_FILE] [-P 
SUPPR_PREFIX] [-o LOG_FILE] [file ... | -L filelist]" % progname,
+    print("%s [-p] [-g SUPPR_FILE] [-s SUPPR_FILE] [-i WIDGET1,WIDGET2[,...]] 
[-o LOG_FILE] [file ...]" % progname,
           file=sys.stderr)
-    print("  -p print XML class path instead of line number");
-    print("  -g Generate suppression file SUPPR_FILE");
-    print("  -s Suppress warnings given by file SUPPR_FILE");
-    print("  -P Suppress SUPPR_PREFIX from emitted warnings, e.g. absolute 
source directory");
-    print("  -o Also prints errors and warnings to given file");
+    print("")
+    print("  -p Print XML class path instead of line number")
+    print("  -g Generate suppression file SUPPR_FILE")
+    print("  -s Suppress warnings given by file SUPPR_FILE")
+    print("  -i Ignore warnings for widgets of a given class")
+    print("  -o Also prints errors and warnings to given file")
+    print("")
+    print("  --widgets-FOO [+][CLASS1[,CLASS2[,...]]]")
+    print("    Give or extend one of the lists of widget classes, where FOO 
can be:")
+    print("    - toplevel      : widgets to be considered toplevel windows")
+    print("    - ignored       : widgets which do not need labelling (e.g. 
GtkBox)")
+    print("    - suffixignored : suffixes of widget classes which do not need 
labelling")
+    print("    - needlabel     : widgets which always need labelling (e.g. 
GtkEntry)")
+    print("    - buttons       : widgets which need their own label but not 
more")
+    print("                      (e.g. GtkButton)")
+    print("    - labels        : widgets which provide labels (e.g. GtkLabel)")
+    print("  --widgets-print print default widgets lists")
+    print("")
+    print("  --enable-all         enable all warnings/dofatals (default)")
+    print("  --disable-all        disable all warnings/dofatals")
+    print("  --fatal-all          make all warnings dofatals")
+    print("  --not-fatal-all      do not make all warnings dofatals (default)")
+    print("")
+    print("  --enable-type=TYPE    enable warning/fatal type TYPE")
+    print("  --disable-type=TYPE   disable warning/fatal type TYPE")
+    print("  --fatal-type=TYPE     make warning type TYPE an fatal")
+    print("  --not-fatal-type=TYPE make warning type TYPE not an fatal")
+    print("")
+    print("  --enable-widgets=CLASS    enable warning/fatal type CLASS")
+    print("  --disable-widgets=CLASS   disable warning/fatal type CLASS")
+    print("  --fatal-widgets=CLASS     make warning type CLASS an fatal")
+    print("  --not-fatal-widgets=CLASS make warning type CLASS not an fatal")
+    print("")
+    print("  --enable-specific=TYPE.CLASS    enable warning/fatal type TYPE 
for widget")
+    print("                                  class CLASS")
+    print("  --disable-specific=TYPE.CLASS   disable warning/fatal type TYPE 
for widget")
+    print("                                  class CLASS")
+    print("  --fatal-specific=TYPE.CLASS     make warning type TYPE an fatal 
for widget")
+    print("                                  class CLASS")
+    print("  --not-fatal-specific=TYPE.CLASS make warning type TYPE not an 
fatal for widget")
+    print("                                  class CLASS")
+    print("")
+    print("  --disable-orphan-labels         only warn about orphan labels 
when there are")
+    print("                                  orphan widgets in the same 
context")
     sys.exit(2)
 
+def widgets_opt(widgets_list, arg):
+    """
+    Replace or extend `widgets_list' with the list of classes contained in 
`arg'
+    """
+    append = arg and arg[0] == '+'
+    if append:
+        arg = arg[1:]
+
+    if arg:
+        widgets = arg.split(',')
+    else:
+        widgets = []
+
+    if not append:
+        del widgets_list[:]
+
+    widgets_list.extend(widgets)
+
 
 def main():
-    global pflag, Werror, Wnone, gen_suppr, gen_supprfile, suppressions, 
suppr_prefix, errors, outfile
+    global pflag, gen_suppr, gen_supprfile, suppressions, suppr_prefix, 
dofatals, enables, dofatals, warn_orphan_labels
+    global widgets_toplevel, widgets_ignored, widgets_suffixignored, 
widgets_needlabel, widgets_buttons, widgets_labels
+    global outfile
 
     try:
-        opts, args = getopt.getopt(sys.argv[1:], "W:pg:s:P:o:L:")
+        opts, args = getopt.getopt(sys.argv[1:], "piIg:s:P:o:L:", [
+                "widgets-toplevel=",
+                "widgets-ignored=",
+                "widgets-suffixignored=",
+                "widgets-needlabel=",
+                "widgets-buttons=",
+                "widgets-labels=",
+                "widgets-print",
+
+                "enable-all",
+                "disable-all",
+                "fatal-all",
+                "not-fatal-all",
+
+                "enable-type=",
+                "disable-type=",
+                "fatal-type=",
+                "not-fatal-type=",
+
+                "enable-widgets=",
+                "disable-widgets=",
+                "fatal-widgets=",
+                "not-fatal-widgets=",
+
+                "enable-specific=",
+                "disable-specific=",
+                "fatal-specific=",
+                "not-fatal-specific=",
+
+                "disable-orphan-labels",
+            ] )
     except getopt.GetoptError:
         usage()
 
     suppr = None
     out = None
     filelist = None
+
     for o, a in opts:
-        if o == "-W":
-            if a == "error":
-                Werror = True
-            elif a == "none":
-                Wnone = True
-        elif o == "-p":
+        if o == "-p":
             pflag = True
         elif o == "-g":
             gen_suppr = a
@@ -369,6 +1166,70 @@ def main():
         elif o == "-L":
             filelist = a
 
+        elif o == "--widgets-toplevel":
+            widgets_opt(widgets_toplevel, a)
+        elif o == "--widgets-ignored":
+            widgets_opt(widgets_ignored, a)
+        elif o == "--widgets-suffixignored":
+            widgets_opt(widgets_suffixignored, a)
+        elif o == "--widgets-needlabel":
+            widgets_opt(widgets_needlabel, a)
+        elif o == "--widgets-buttons":
+            widgets_opt(widgets_buttons, a)
+        elif o == "--widgets-labels":
+            widgets_opt(widgets_labels, a)
+        elif o == "--widgets-print":
+            print("--widgets-toplevel '" + ','.join(widgets_toplevel) + "'")
+            print("--widgets-ignored '" + ','.join(widgets_ignored) + "'")
+            print("--widgets-suffixignored '" + 
','.join(widgets_suffixignored) + "'")
+            print("--widgets-needlabel '" + ','.join(widgets_needlabel) + "'")
+            print("--widgets-buttons '" + ','.join(widgets_buttons) + "'")
+            print("--widgets-labels '" + ','.join(widgets_labels) + "'")
+            sys.exit(0)
+
+        elif o == '--enable-all':
+            enables.append( (True, None, None) )
+        elif o == '--disable-all':
+            enables.append( (False, None, None) )
+        elif o == '--fatal-all':
+            dofatals.append( (True, None, None) )
+        elif o == '--not-fatal-all':
+            dofatals.append( (False, None, None) )
+
+        elif o == '--enable-type':
+            enables.append( (True, a, None) )
+        elif o == '--disable-type':
+            enables.append( (False, a, None) )
+        elif o == '--fatal-type':
+            dofatals.append( (True, a, None) )
+        elif o == '--not-fatal-type':
+            dofatals.append( (False, a, None) )
+
+        elif o == '--enable-widgets':
+            enables.append( (True, None, a) )
+        elif o == '--disable-widgets':
+            enables.append( (False, None, a) )
+        elif o == '--fatal-widgets':
+            dofatals.append( (True, None, a) )
+        elif o == '--not-fatal-widgets':
+            dofatals.append( (False, None, a) )
+
+        elif o == '--enable-specific':
+            (thetype, klass) = a.split('.', 1)
+            enables.append( (True, thetype, klass) )
+        elif o == '--disable-specific':
+            (thetype, klass) = a.split('.', 1)
+            enables.append( (False, thetype, klass) )
+        elif o == '--fatal-specific':
+            (thetype, klass) = a.split('.', 1)
+            dofatals.append( (True, thetype, klass) )
+        elif o == '--not-fatal-specific':
+            (thetype, klass) = a.split('.', 1)
+            dofatals.append( (False, thetype, klass) )
+
+        elif o == '--disable-orphan-labels':
+            warn_orphan_labels = False
+
     # Read suppression file before overwriting it
     if suppr is not None:
         try:
@@ -418,17 +1279,31 @@ def main():
         print(estr)
 
     if warnings > 0 or warnexists > 0:
-        wstr = "%s new warning%s" % (warnings,
-                                           's' if warnings > 1 else '')
+        wstr = "%s new warning%s" % (warnings, 's' if warnings > 1 else '')
         if warnexists > 0:
             wstr += " (%s suppressed by %s)" % (warnexists, suppr)
         print(wstr)
 
+    if fatals > 0 or fatalexists > 0:
+        wstr = "%s new fatal%s" % (fatals, 's' if fatals > 1 else '')
+        if fatalexists > 0:
+            wstr += " (%s suppressed by %s)" % (fatalexists, suppr)
+        print(wstr)
+
+    n = 0
+    for (suppr,unused) in suppressions.items():
+        if unused:
+            n += 1
+
+    if n > 0:
+        print("%s suppression%s unused" % (n, 's' if n > 1 else ''))
+
     if gen_supprfile is not None:
         gen_supprfile.close()
     if outfile is not None:
         outfile.close()
-    if errors > 0 and gen_suppr is None:
+    if fatals > 0 and gen_suppr is None:
+        print("Explanations are available on 
https://wiki.documentfoundation.org/Development/Accessibility";)
         sys.exit(1)
 
 
diff --git a/solenv/gbuild/UIConfig.mk b/solenv/gbuild/UIConfig.mk
index 9a88ffd44498..fb3d82d0b912 100644
--- a/solenv/gbuild/UIConfig.mk
+++ b/solenv/gbuild/UIConfig.mk
@@ -125,11 +125,76 @@ $(call gb_UIConfig_get_clean_target,%) :
        $(call gb_Output_announce,$*,$(false),UIA,2)
        rm -f $(call gb_UIConfig_get_a11yerrors_target,$*)
 
+gb_UIConfig_gla11y_PARAMETERS = -P $(SRCDIR)/
+
+# Disable this to see suppressed warnings
+ifeq (1,1)
+gb_UIConfig_gla11y_PARAMETERS += -s $(UI_A11YSUPPRS)
+endif
 # Enable this to regenerate suppression files
 ifeq (1,0)
-GEN_A11Y_SUPPRS = -g $(UI_A11YSUPPRS)
+gb_UIConfig_gla11y_PARAMETERS += -g $(UI_A11YSUPPRS)
 endif
 
+# Tell gla11y about LO-specific widgets
+# These are already automatically labelled Shrink/Expand
+gb_UIConfig_gla11y_PARAMETERS += --widgets-ignored +foruilo-RefButton
+# These, however, do need a label like a GtkEntry
+gb_UIConfig_gla11y_PARAMETERS += --widgets-needlabel +foruilo-RefEdit
+# These are storage, containers, or preview
+gb_UIConfig_gla11y_PARAMETERS += --widgets-suffixignored 
+ValueSet,HBox,VBox,ToolBox,Preview,PreviewWin,PreviewWindow,PrevWindow
+# These are buttons, thus already contain their label (but an image is not 
enough)
+gb_UIConfig_gla11y_PARAMETERS += --widgets-button 
+vcllo-SmallButton,cuilo-RubyRadioButton,chartcontrollerlo-LightButton,svtlo-ManagedMenuButton
+
+# All new warnings should be fatal except a few kinds which could be only 
doubtful
+gb_UIConfig_gla11y_PARAMETERS += --fatal-all --not-fatal-type 
duplicate-mnemonic --not-fatal-type labelled-by-and-mnemonic --not-fatal-type 
orphan-label
+
+# Disable all warnings types by default for now, to enable warnings types 
progressively
+gb_UIConfig_gla11y_PARAMETERS += --disable-all
+
+# For now, ignore orphan labels without an unlabelled widget
+gb_UIConfig_gla11y_PARAMETERS += --disable-orphan-labels
+# but do not ignore orphan labels with an unlabelled widget
+gb_UIConfig_gla11y_PARAMETERS += --enable-type orphan-label
+
+# The following are to be uncommented progressively
+
+# These are definite errors
+gb_UIConfig_gla11y_PARAMETERS += --enable-type undeclared-target
+#gb_UIConfig_gla11y_PARAMETERS += --enable-type missing-label-for
+#gb_UIConfig_gla11y_PARAMETERS += --enable-type missing-labelled-by
+
+# These are often buttons with only an image
+#gb_UIConfig_gla11y_PARAMETERS += --enable-type button-no-label
+# These are often doubtful
+#gb_UIConfig_gla11y_PARAMETERS += --enable-type duplicate-mnemonic 
--enable-type labelled-by-and-mnemonic
+
+# For now, disable warning about widgets without a label by default, to enable 
warnings for classes progressively
+# To be uncommented progressively
+gb_UIConfig_gla11y_PARAMETERS += --disable-type no-labelled-by
+# Clearly need labelling
+gb_UIConfig_gla11y_PARAMETERS += --enable-specific no-labelled-by.GtkScale
+#gb_UIConfig_gla11y_PARAMETERS += --enable-specific no-labelled-by.GtkEntry
+#gb_UIConfig_gla11y_PARAMETERS += --enable-specific 
no-labelled-by.GtkSpinButton
+#gb_UIConfig_gla11y_PARAMETERS += --enable-specific no-labelled-by.GtkSpinner
+#gb_UIConfig_gla11y_PARAMETERS += --enable-specific 
no-labelled-by.GtkProgressBar
+#gb_UIConfig_gla11y_PARAMETERS += --enable-specific 
no-labelled-by.svxcorelo-SvxColorListBox
+#gb_UIConfig_gla11y_PARAMETERS += --enable-specific 
no-labelled-by.svxcorelo-SvxLanguageBox
+#gb_UIConfig_gla11y_PARAMETERS += --enable-specific 
no-labelled-by.sfxlo-SvxCharView
+#gb_UIConfig_gla11y_PARAMETERS += --enable-specific 
no-labelled-by.foruilo-RefEdit
+#gb_UIConfig_gla11y_PARAMETERS += --enable-specific 
no-labelled-by.svxcorelo-PaperSizeListBox
+# Probably need labelling
+#gb_UIConfig_gla11y_PARAMETERS += --enable-specific no-labelled-by.GtkComboBox
+#gb_UIConfig_gla11y_PARAMETERS += --enable-specific 
no-labelled-by.GtkComboBoxText
+#gb_UIConfig_gla11y_PARAMETERS += --enable-specific no-labelled-by.GtkMenuItem
+# Possibly need labelling
+#gb_UIConfig_gla11y_PARAMETERS += --enable-specific no-labelled-by.GtkTreeView
+#gb_UIConfig_gla11y_PARAMETERS += --enable-specific 
no-labelled-by.GtkTreeViewColumn
+#gb_UIConfig_gla11y_PARAMETERS += --enable-specific no-labelled-by.GtkTextView
+#gb_UIConfig_gla11y_PARAMETERS += --enable-specific 
no-labelled-by.GtkDrawingArea
+# Perhaps need labelling
+#gb_UIConfig_gla11y_PARAMETERS += --enable-specific no-labelled-by.GtkImage
+
 define gb_UIConfig_a11yerrors__command
 $(call gb_Output_announce,$(2),$(true),UIA,1)
 $(call gb_UIConfig__gla11y_command)
diff --git a/solenv/gbuild/platform/com_GCC_class.mk 
b/solenv/gbuild/platform/com_GCC_class.mk
index 6d5393d2fad9..4c3531934d5e 100644
--- a/solenv/gbuild/platform/com_GCC_class.mk
+++ b/solenv/gbuild/platform/com_GCC_class.mk
@@ -159,7 +159,7 @@ define gb_UIConfig__gla11y_command
 $(call gb_Helper_abbreviate_dirs,\
        $(gb_UIConfig_LXML_PATH) $(gb_Helper_set_ld_path) \
        $(call gb_ExternalExecutable_get_command,python) \
-       $(gb_UIConfig_gla11y_SCRIPT) -s $(UI_A11YSUPPRS) $(GEN_A11Y_SUPPRS) -P 
$(SRCDIR)/ -o $@ $(UIFILES)
+       $(gb_UIConfig_gla11y_SCRIPT) $(gb_UIConfig_gla11y_PARAMETERS) -o $@ 
$(UIFILES)
 )
 
 endef
diff --git a/solenv/gbuild/platform/com_MSC_class.mk 
b/solenv/gbuild/platform/com_MSC_class.mk
index 0a1cdab314ac..8c0a23e9bf03 100644
--- a/solenv/gbuild/platform/com_MSC_class.mk
+++ b/solenv/gbuild/platform/com_MSC_class.mk
@@ -583,7 +583,7 @@ $(call gb_Helper_abbreviate_dirs,\
        FILES=$(call var2file,$(shell $(gb_MKTEMP)),100,$(UIFILES)) && \
        $(gb_UIConfig_LXML_PATH) $(gb_Helper_set_ld_path) \
        $(call gb_ExternalExecutable_get_command,python) \
-       $(gb_UIConfig_gla11y_SCRIPT) -s $(UI_A11YSUPPRS) $(GEN_A11Y_SUPPRS) -P 
$(SRCDIR)/ -o $@ -L $$FILES
+       $(gb_UIConfig_gla11y_SCRIPT) $(gb_UIConfig_gla11y_PARAMETERS) -o $@ -L 
$$FILES
 )
 
 endef
diff --git a/solenv/sanitizers/ui/cui.suppr b/solenv/sanitizers/ui/cui.suppr
index d9e0294f464f..598c7a600ae3 100644
--- a/solenv/sanitizers/ui/cui.suppr
+++ b/solenv/sanitizers/ui/cui.suppr
@@ -1,3 +1,8 @@
-cui/uiconfig/ui/gradientpage.ui:GtkBox[@id='GradientPage']/GtkFrame[@id='frame1']/GtkAlignment[@id='alignment1']/GtkBox[@id='box2']/GtkGrid[@id='grid6']/GtkScale[@id='incrementslider']
 no-labelled-by
-cui/uiconfig/ui/gradientpage.ui:GtkBox[@id='GradientPage']/GtkFrame[@id='frame1']/GtkAlignment[@id='alignment1']/GtkBox[@id='box2']/GtkGrid[@id='grid3']/GtkScale[@id='borderslider']
 no-labelled-by
-cui/uiconfig/ui/hatchpage.ui:GtkBox[@id='HatchPage']/GtkFrame[@id='frame1']/GtkAlignment[@id='alignment1']/GtkBox[@id='box3']/GtkBox[@id='box1']/GtkScale[@id='angleslider']
 no-labelled-by
+cui/uiconfig/ui/gradientpage.ui://GtkScale[@id='incrementslider'] 
no-labelled-by
+cui/uiconfig/ui/gradientpage.ui://GtkLabel[@id='centerft'] orphan-label
+cui/uiconfig/ui/gradientpage.ui://GtkScale[@id='borderslider'] no-labelled-by
+cui/uiconfig/ui/hatchpage.ui://GtkLabel[@id='distanceft'] orphan-label
+cui/uiconfig/ui/hatchpage.ui://GtkLabel[@id='angleft'] orphan-label
+cui/uiconfig/ui/hatchpage.ui://GtkScale[@id='angleslider'] no-labelled-by
+cui/uiconfig/ui/hatchpage.ui://GtkLabel[@id='linetypeft'] orphan-label
+cui/uiconfig/ui/hatchpage.ui://GtkLabel[@id='linecolorft'] orphan-label
diff --git a/solenv/sanitizers/ui/svt.suppr b/solenv/sanitizers/ui/svt.suppr
index 40ba68b7b93a..64325dcb38dd 100644
--- a/solenv/sanitizers/ui/svt.suppr
+++ b/solenv/sanitizers/ui/svt.suppr
@@ -1,2 +1,2 @@
-svtools/uiconfig/ui/graphicexport.ui:GtkDialog[@id='GraphicExportDialog']/GtkBox[@id='dialog-vbox1']/GtkBox[@id='box1']/GtkFrame[@id='jpgquality']/GtkAlignment[@id='alignment5']/GtkGrid[@id='grid2']/GtkScale[@id='compressionjpgsb']
 no-labelled-by
-svtools/uiconfig/ui/graphicexport.ui:GtkDialog[@id='GraphicExportDialog']/GtkBox[@id='dialog-vbox1']/GtkBox[@id='box1']/GtkFrame[@id='pngcompression']/GtkAlignment[@id='alignment13']/GtkGrid[@id='grid9']/GtkScale[@id='compressionpngsb']
 no-labelled-by
+svtools/uiconfig/ui/graphicexport.ui://GtkScale[@id='compressionjpgsb'] 
no-labelled-by
+svtools/uiconfig/ui/graphicexport.ui://GtkScale[@id='compressionpngsb'] 
no-labelled-by
diff --git a/solenv/sanitizers/ui/svx.suppr b/solenv/sanitizers/ui/svx.suppr
index 9179abb2dbd5..b9babb1171ab 100644
--- a/solenv/sanitizers/ui/svx.suppr
+++ b/solenv/sanitizers/ui/svx.suppr
@@ -1,6 +1,12 @@
-svx/uiconfig/ui/compressgraphicdialog.ui:GtkDialog[@id='CompressGraphicDialog']/GtkBox[@id='dialog-vbox1']/GtkGrid/GtkFrame[@id='frame2']/GtkAlignment[@id='alignment1']/GtkGrid[@id='grid2']/GtkAlignment/GtkGrid/GtkScale[@id='scale-quality']
 no-labelled-by
-svx/uiconfig/ui/compressgraphicdialog.ui:GtkDialog[@id='CompressGraphicDialog']/GtkBox[@id='dialog-vbox1']/GtkGrid/GtkFrame[@id='frame2']/GtkAlignment[@id='alignment1']/GtkGrid[@id='grid2']/GtkAlignment/GtkGrid/GtkScale[@id='scale-compression']
 no-labelled-by
-svx/uiconfig/ui/mediaplayback.ui:GtkGrid[@id='MediaPlaybackPanel']/GtkGrid[@id='grid1']/GtkScale[@id='timeslider']
 no-labelled-by
-svx/uiconfig/ui/mediaplayback.ui:GtkGrid[@id='MediaPlaybackPanel']/GtkGrid[@id='grid1']/GtkScale[@id='volumeslider']
 no-labelled-by
-svx/uiconfig/ui/sidebararea.ui:GtkGrid[@id='AreaPropertyPanel']/GtkBox[@id='box1']/GtkGrid[@id='grid1']/GtkScale[@id='transparencyslider']
 no-labelled-by
-svx/uiconfig/ui/sidebarshadow.ui:GtkGrid[@id='ShadowPropertyPanel']/GtkGrid[@id='grid3']/GtkBox[@id='box2']/GtkBox[@id='box1']/GtkGrid[@id='grid2']/GtkScale[@id='transparency_slider']
 no-labelled-by
+svx/uiconfig/ui/compressgraphicdialog.ui://GtkScale[@id='scale-quality'] 
no-labelled-by
+svx/uiconfig/ui/compressgraphicdialog.ui://GtkScale[@id='scale-compression'] 
no-labelled-by
+svx/uiconfig/ui/mediaplayback.ui://GtkLabel[@id='label1'] orphan-label
+svx/uiconfig/ui/mediaplayback.ui://GtkLabel[@id='label2'] orphan-label
+svx/uiconfig/ui/mediaplayback.ui://GtkLabel[@id='label3'] orphan-label
+svx/uiconfig/ui/mediaplayback.ui://GtkScale[@id='timeslider'] no-labelled-by
+svx/uiconfig/ui/mediaplayback.ui://GtkScale[@id='volumeslider'] no-labelled-by
+svx/uiconfig/ui/sidebarshadow.ui://GtkLabel[@id='angle'] orphan-label
+svx/uiconfig/ui/sidebarshadow.ui://GtkLabel[@id='distance'] orphan-label
+svx/uiconfig/ui/sidebarshadow.ui://GtkLabel[@id='transparency_label'] 
orphan-label
+svx/uiconfig/ui/sidebarshadow.ui://GtkScale[@id='transparency_slider'] 
no-labelled-by
+svx/uiconfig/ui/sidebarshadow.ui://GtkLabel[@id='color'] orphan-label
_______________________________________________
Libreoffice-commits mailing list
libreoffice-comm...@lists.freedesktop.org
https://lists.freedesktop.org/mailman/listinfo/libreoffice-commits

Reply via email to