Iterating over items in Qt views

Last edited on

import os

def main():
    startApplication("%s/examples/qt/itemviews/itemviews" % os.getenv("SQUISH_PREFIX"))

    tw = waitForObject({"type": "QTreeWidget"}, 3000)


    test.startSection("iterate_items_via_object_children_breadth_first()")
    file_handle, handle_item_func = log_item_function("iterate_items_via_object_children_breadth_first.txt")
    try:
        iterate_items_via_object_children_breadth_first(tw, handle_item_func)
    finally:
        test.endSection()
        file_handle.close()


    test.startSection("iterate_tree_items_via_model_breadth_first()")
    file_handle, handle_item_func = log_item_function("iterate_tree_items_via_model_breadth_first.txt")
    try:
        iterate_tree_items_via_model_breadth_first(tw, handle_item_func)
    finally:
        test.endSection()
        file_handle.close()


    test.startSection("iterate_items_via_object_children_depth_first()")
    file_handle, handle_item_func = log_item_function("iterate_items_via_object_children_depth_first.txt")
    try:
        iterate_items_via_object_children_depth_first(tw, handle_item_func)
    finally:
        test.endSection()
        pass


    test.startSection("iterate_tree_items_via_model_depth_first()")
    file_handle, handle_item_func = log_item_function("iterate_tree_items_via_model_depth_first.txt")
    try:
        iterate_tree_items_via_model_depth_first(tw, handle_item_func)
    finally:
        test.endSection()
        file_handle.close()

    return


def log_item_function(file_name):
    f = codecs.open(file_name, "w", "utf8")
    def func(item, absolute_row=None, absolute_column=None):
        log_item(item, absolute_row, absolute_column, f)
    return f, func


def log_item(item, absolute_row=None, absolute_column=None, file_handle=None):
    msg = "Absolute: %s/%s: relative: %s/%s: %s" % (absolute_row, absolute_column, item.row, item.column, item.text)
    test.log("'%s'" % msg)
    if file_handle is not None:
        file_handle.write("'%s'\n" % msg)


def iterate_tree_items_via_model_depth_first(tree_obj, handle_item_function):
    model = tree_obj.model()
    absolute_row = [-1]
    for row in range(model.rowCount()):
        for column in range(tree_obj.columnCount):
            item = model.index(row, column)
            if column == 0:
                absolute_row[0] += 1
            handle_item_function(item, absolute_row[0], column)
        _iterate_items_via_model_depth_first(model.index(row, 0), model, handle_item_function, absolute_row)


def _iterate_items_via_model_depth_first(parent_item, model, handle_item_function, absolute_row):
    for row in range(model.rowCount(parent_item)):
        for column in range(model.columnCount(parent_item)):
            item = model.index(row, column, parent_item)
            if column == 0:
                absolute_row[0] += 1
            handle_item_function(item, absolute_row[0], column)

        item_0 = model.index(row, column, parent_item)
        if model.hasChildren(item_0):
            _iterate_items_via_model_depth_first(item_0, model, handle_item_function, absolute_row)


def iterate_tree_items_via_model_breadth_first(tree_obj, handle_item_function):
    model = tree_obj.model()
    for row in range(model.rowCount()):
        for column in range(tree_obj.columnCount):
            item = model.index(row, column)
            handle_item_function(item)

    for row in range(model.rowCount()):
        _iterate_tree_items_via_model_breadth_first(model.index(row, 0), model, handle_item_function)


def _iterate_tree_items_via_model_breadth_first(parent_item, model, handle_item_function):
    for row in range(model.rowCount(parent_item)):
        for column in range(model.columnCount(parent_item)):
            item = model.index(row, column, parent_item)
            handle_item_function(item)

    for row in range(model.rowCount(parent_item)):
        item_0 = model.index(row, column, parent_item)
        if model.hasChildren(item_0):
            _iterate_tree_items_via_model_breadth_first(item_0, model, handle_item_function)


def iterate_items_via_object_children_depth_first(parent, handle_item_function):
    column_0_item = None
    for child in object.children(parent):
        if className(child) == "QModelIndex":
            handle_item_function(child)
            if child.column == 0:
                column_0_item = child
            elif column_0_item is not None:
                iterate_items_via_object_children_depth_first(column_0_item, handle_item_function)
                column_0_item = None


def iterate_items_via_object_children_breadth_first(parent, handle_item_function):
    for child in object.children(parent):
        if className(child) == "QModelIndex":
            handle_item_function(child)

    for child in object.children(parent):
        if className(child) == "QModelIndex":
            iterate_items_via_object_children_breadth_first(child, handle_item_function)


def squish_qmodelindex(view_object_name, qmodelindex):
    """
    Get a QModelIndex wrapped by Squish for a QModelIndex obtained from QAbstractItemView.model().

    This is required to use the Squish convenience functions mouseClick(), etc. with the QModelIndex.

    Example:

        import os


        def main():
            startApplication("%s/examples/qt/itemviews/itemviews" % os.getenv("SQUISH_PREFIX"))

            # Let's assume the following obtains a QModelIndex
            # from the model of the QTreeView:
            qmi = waitForObject({"column": 0, "container": {"column": 0, "container": {"column": 0, "container": {"occurrence": 2, "type": "QTreeView"}, "text": "Green algae", "type": "QModelIndex"}, "text": "Desmids & Charophytes", "type": "QModelIndex"}, "text": "Desmidiaceae", "type": "QModelIndex"})

            # Get a QModelIndex wrapped by Squish for this QModelIndex:
            sqmi = squish_qmodelindex({"occurrence": 2, "type": "QTreeView"}, qmi)

            # Now we can use the Squish convenience API with
            # the wrapped QModelIndex:
            mouseClick(sqmi)
            snooze(2)


            # Set a different root index, change selection
            # (to be able to see the effect of another
            # mouseClick()):
            qmi2 = findObject({"column": 0, "container": names.item_Views_QTreeView, "text": "Green algae", "type": "QModelIndex"})
            mouseClick(qmi2)
            findObject({"occurrence": 2, "type": "QTreeView"}).setRootIndex(qmi2)

            # Try again:
            sqmi = squish_qmodelindex({"occurrence": 2, "type": "QTreeView"}, qmi)
            mouseClick(sqmi)
            snooze(2)

            test.breakpoint()
    """

    def same_qmodelindex(qmodelindex1, qmodelindex2):
        return qmodelindex1.isValid() == qmodelindex2.isValid() \
                and qmodelindex1.row == qmodelindex2.row \
                and qmodelindex1.column == qmodelindex2.column \
                and qmodelindex1.internalId() == qmodelindex2.internalId()

    def name(qmi):
        n = {}
        n["row"] = qmi.row
        n["column"] = qmi.column
        n["text"] = qmi.text
        n["type"] = "QModelIndex"
        return n

    # Based on the model, get all object names up
    # to the top most parent QModelIndex, or the
    # view's root index, whichever comes first:
    view = findObject(view_object_name)
    root_index = view.rootIndex()
    model = view.model()
    qmi = qmodelindex
    obj_names = [name(qmi)]
    while True:
        parent = model.parent(qmi)
        if not parent.isValid() \
                or same_qmodelindex(parent, root_index):
            break
        obj_names.append(name(parent))
        qmi = parent

    # Connect the object names by setting the
    # "container" of each:
    previous = None
    n = None
    for n in obj_names:
        if previous is None:
            previous = n
            continue
        previous["container"] = n
        previous = n

    # Set the "container" of the top QModelIndex
    # to the specified view:
    n["container"] = view_object_name

    # Fetch the full object name:
    obj_name = obj_names[0]

    # Look up the QModelIndex via the created
    # object name:
    return waitForObject(obj_name)