Search code examples
qtdiffcommitqt-designer

Qt ui file - xml order - QGridLayout row order leads to large commit differences


Sometimes when using QT Designer, in the resulting ui file xml format, the order of the rows is not respected (row="11" is presented before row="0").

I understand that functionally it has zero impact on the compiled code. I have two concerns about this behaviour:

a) the differences generated for "small modifications" are big, this reduces my capacity to review a PR and increases the probability of an oversight.

b) I sometimes edit ui files in text mode from the terminal. Having the rows order sorted is desirable.

Concern a) is by far more important to me.

Example is this PR, which concerns the removal of three rows.

Because the external link may be removed, here I include a relevant excerpt showing the issue:

        <layout class="QGridLayout" name="gridLayout_2">
-        <item row="0" column="0">
-         <widget class="QLabel" name="label_17">
+        <item row="11" column="0">
+         <widget class="QLabel" name="label_43">
           <property name="minimumSize">
            <size>
             <width>182</width>
@@ -31,27 +31,7 @@
            </size>
           </property>
           <property name="text">
-           <string>Default edge color</string>
-          </property>
-         </widget>
-        </item>
-        <item row="0" column="1">
-         <widget class="Gui::PrefColorButton" name="SketchEdgeColor">
-          <property name="toolTip">
-           <string>Color of edges</string>
-          </property>
-          <property name="color">
-           <color>
-            <red>255</red>
-            <green>255</green>
-            <blue>255</blue>
-           </color>
-          </property>
-          <property name="prefEntry" stdset="0">
-           <cstring>SketchEdgeColor</cstring>
-          </property>
-          <property name="prefPath" stdset="0">
-           <cstring>View</cstring>
+           <string>Fully constrained edit internal alignment edge color</string>
           </property>
          </widget>
         </item>
@@ -68,61 +48,28 @@
           </property>
          </widget>
         </item>
-        <item row="1" column="1">
-         <widget class="Gui::PrefColorButton" name="SketchVertexColor">
-          <property name="toolTip">
-           <string>Color of vertices</string>
-          </property>
-          <property name="color">
-           <color>
-            <red>255</red>
-            <green>255</green>
-            <blue>255</blue>
-           </color>
-          </property>
-          <property name="prefEntry" stdset="0">
-           <cstring>SketchVertexColor</cstring>
-          </property>
-          <property name="prefPath" stdset="0">
-           <cstring>View</cstring>
-          </property>
-         </widget>
-        </item>
-        <item row="2" column="0">
-         <widget class="QLabel" name="label_6">
-          <property name="minimumSize">
-           <size>
-            <width>182</width>
-            <height>0</height>
-           </size>
-          </property>
-          <property name="text">
-           <string>Making line color</string>
-          </property>
-         </widget>
-        </item>
-        <item row="2" column="1">
-         <widget class="Gui::PrefColorButton" name="CreateLineColor">
+        <item row="6" column="1">
+         <widget class="Gui::PrefColorButton" name="InternalAlignedGeoColor">
           <property name="toolTip">
-           <string>Color used while new sketch elements are created</string>
+           <string>Color of edges of internal alignment geometry</string>
           </property>
           <property name="color">
            <color>
-            <red>204</red>
-            <green>204</green>
-            <blue>204</blue>
+            <red>178</red>
+            <green>178</green>
+            <blue>127</blue>
            </color>
           </property>
           <property name="prefEntry" stdset="0">
-           <cstring>CreateLineColor</cstring>
+           <cstring>InternalAlignedGeoColor</cstring>
           </property>
           <property name="prefPath" stdset="0">
            <cstring>View</cstring>
           </property>
          </widget>
         </item>
-        <item row="3" column="0">
-         <widget class="QLabel" name="label">

In some cases even the second column of the same row () appears in the source after the first column ().

I do understand that order is not important from a functional point of view and that there is no functional requirement that rows and cols are sorted.

My question is: Is there any reasonable way (for example an option or plugin for Qt Designer, or an alternative, or a tool for reformatting an ui file) so that the columns are sorted in the ui file, leading to reasonable to review differences?

Thanks in advance for your time, abdullah


Solution

  • This python script will sort the children item of any QGridLayout widget in a Qt UI file by row-column order.

    #!/usr/bin/env python
    # encoding: utf-8
    
    from __future__ import print_function
    
    import logging
    from lxml import etree
    
    
    # Inspired from here: https://stackoverflow.com/a/46128043
    
    
    def sort_children(node, klass, key):
        """ Sort children along tag and given attribute.
        if attr is None, sort along all attributes"""
        if not isinstance(node.tag, str):  # PYTHON 2: use basestring instead
            # not a TAG, it is comment or DATA
            # no need to sort
            return
    
    
        if node.get('class') == klass:
            # sort child along attr
            node[:] = sorted(node, key=key)
        else:
            # and recurse
            for child in node:
                sort_children(child, klass, key)
    
    
    def sort(unsorted_file, sorted_file, klass, key):
        """Sort unsorted xml file and save to sorted_file"""
        tree = etree.parse(unsorted_file)
        root = tree.getroot()
        sort_children(root, klass, key)
    
        sorted_unicode = etree.tostring(root,
                                        pretty_print=True,
                                        encoding='unicode')
        with open(sorted_file, 'w') as output_fp:
            output_fp.write('<?xml version="1.0" encoding="UTF-8"?>\n')
            output_fp.write('%s' % sorted_unicode)
            logging.info('written sorted file %s', sorted_unicode)
    
    
    filename = "Path_to_unsorted_QML_file.ui"
    filename_out = "Path_to_sorted_QML_file.ui"
    
    def row_col_key(node):
        """Return the sorting key of an xml node"""
        row = node.get('row') if node.get('row') else -1
        col = node.get('column') if node.get('column') else -1
    
        return '{:04d}{:04d}'.format(int(row), int(col))
    
    
    sort(filename, filename_out, "QGridLayout", row_col_key)