WTreeView not loading all child rows

Added by adam s 2 months ago

Hi,

I'm playing with WTreeView using WAbstractItemModel. For some reason TreeView sometimes is not loading everything (it's displaying "spacer").
From what i can see under gdb it looks like viewportTop_ is not being updated (no updates from scrollbar) and as a result validRowCount_ is not changed in OnExpand.

I think this used to work some time ago. Can someone check if this is Wt4.1 issue or there is something wrong with my setup?

Code :

        std::shared_ptr<TestModel>    model2 = std::make_shared<TestModel>();
        auto treeTable = std::make_unique<Wt::WTreeView>();
        treeTable->setModel(model2);
        treeTable->setColumnResizeEnabled(true);
        treeTable->setSortingEnabled(false);
        treeTable->setAlternatingRowColors(true);
        treeTable->setRowHeight(34);
        treeTable->setHeaderHeight(34);
        treeTable->setSelectionMode(Wt::SelectionMode::Single);
        treeTable->setEditTriggers(Wt::EditTrigger::SingleClicked);
        root()->addWidget(std::move(treeTable));

And model:

#include <map>
#include <vector>
#include <Wt/WAbstractItemModel.h>

struct TestModel : public Wt::WAbstractItemModel
{
    std::map<uint64_t, std::vector<uint64_t>> childrenMap;

    enum Columns
    {
        colId,
        colModelIndex,
        colRow,
        colChild,
        colParent,
        colCount
    };
    int columnCount(const Wt::WModelIndex& parent = Wt::WModelIndex()) const override 
    {
        return colCount;
    }
    int rowCount(const Wt::WModelIndex& parent = Wt::WModelIndex()) const override
    {
        auto it = childrenMap.find(parent.internalId());
        if(it == childrenMap.end())
            return 0;
        return it->second.size();
    }
    virtual Wt::WModelIndex parent(const Wt::WModelIndex& index) const override
    {
        auto parentIt = std::find_if(childrenMap.begin(), childrenMap.end(), [&](const std::pair<const uint64_t, std::vector<uint64_t>>& p)
        { return std::find(p.second.begin(), p.second.end(), index.internalId()) != p.second.end(); });
        if(parentIt->first == 0)
            return Wt::WModelIndex();
        auto parentIt2 = std::find_if(childrenMap.begin(), childrenMap.end(), [&](const std::pair<const uint64_t, std::vector<uint64_t>>& p)
        { return std::find(p.second.begin(), p.second.end(), parentIt->first) != p.second.end(); });

        auto row = std::find(parentIt2->second.begin(), parentIt2->second.end(), parentIt->first) - parentIt2->second.begin();
        return createIndex(row, 0, parentIt->first);
    }

    Wt::WModelIndex index(int row, int column, const Wt::WModelIndex& parent ) const override
    {
        return createIndex(row, column, childrenMap.at(parent.internalId()).at(row));
    }
    Wt::cpp17::any headerData(int section, Wt::Orientation  orientation, Wt::ItemDataRole role) const override
    {
        if(role == Wt::ItemDataRole::Display)
        {
            switch(section)
            {        
            case colId: return "colId";
            case colModelIndex: return "ModelIndex";
            case colRow: return "rowCount";
            case colChild: return "index";
            case colParent: return "colParent";
            };
        }
        return Wt::cpp17::any();
    }
    Wt::cpp17::any data(const Wt::WModelIndex& index, Wt::ItemDataRole role = Wt::ItemDataRole::Display) const override
    {
        if(role == Wt::ItemDataRole::Display)
        {
            switch(index.column())
            {
                case colId: return std::to_string(index.internalId());
                case colRow: return std::to_string(rowCount(index));
                case colChild: 
                {
                    auto p = parent(index);
                    auto i = this->index(index.row(), index.column(), p);
                    return std::to_string(i.row()) + " , " + std::to_string(i.internalId());
                }
                case colModelIndex: return std::to_string(index.row()) + " , " + std::to_string(index.internalId());
                case colParent: 
                {
                    auto p = parent(index);
                    return std::to_string(p.row()) + " , " + std::to_string(p.internalId());
                }
            }
        }
        return Wt::cpp17::any();
    }

    TestModel()
    {
           childrenMap[0]={1, 149, 150, 151, 152, 292, 293, 294, 295, 302, 310, 314, 318, 321, 322, 338, 351, 352, 356, 371, 375, 432, 433, 
                          434, 435, 449, 450, 451, 457, 474, 482, 499, 804, 892, 893, 894, 998, 1001, 1002, 1006, 1015, 1040, 1044, 1051, 
                          1070, 1071, 1076, 1077, 1114, 1115, 1116, 1119, 1120, 1121, 1122, 1127, 1138, 1139, 1140, 1141, 1145, 1158, 1165, 
                          1180, 1181, 1186, 1189, 1190, 1194, 1195, 1196, 1197, 1204, 1207, 1208, 1243, 1274, 1278, 1307, 
                          1308, 1309, 1310, 1315, 1321, 1322, 1323, 1327};
        childrenMap[1323]={1324, 1325, 1326};
        childrenMap[1327]={1328, 1329, 1330};
    }

};


Replies (11)

RE: WTreeView not loading all child rows - Added by Roel Standaert 2 months ago

I can indeed see this with a normal WStandardItemModel too. Must be some sort of off-by-one error or something, since it seems to always be the last child that has issues?

RE: WTreeView not loading all child rows - Added by Roel Standaert 2 months ago

It appears to have been a side effect of the fixes for issue #6884 and #7063 (commit bb8dce870d9496bce1ca792b250c697c7612d1f3).

RE: WTreeView not loading all child rows - Added by adam s 2 months ago

Thanks Roel,

This is not only last child, it's when node row + node items count > root node count (WTreeView::validRowCount_ is set to node count and not being updated).

BTW. If you are going to change WTreeView.C could you please change WTreeView::setRootNodeStyle() to:

if (!rootNode_)
    return;

  WApplication::instance()->theme()->apply(this, rootNode_, TableViewRowContainer);

This should keep current logic and will allow to modify backgroundImage.

Regards,
Adam

RE: WTreeView not loading all child rows - Added by Roel Standaert about 1 month ago

I think this happens because no ResizeSensor is applied to a certain div, so it doesn't react to those size changes.

What I see is that StdWidgetItemImpl (JavaScript-based layout items) items are ending up inside of a Flex-based layout.

RE: WTreeView not loading all child rows - Added by Roel Standaert about 1 month ago

I pushed some changes that should fix this issue. Only on the master, not 4.1-release.

RE: WTreeView not loading all child rows - Added by Roel Standaert about 1 month ago

As for the alternating row colors, there's more to it than that. The rows won't be alternating when using the bootstrap theme if done that way.

RE: WTreeView not loading all child rows - Added by adam s about 1 month ago

Thanks Roel!

Just cherry-picked your change to 4.1.0 and it works like a charm.

Regarding alternate colors you are right - looks like themes/bootstrap/(2 or 3)/wt.css only supports table views - it's missing style for tree view:

.Wt-treeview .Wt-striped li.Wt-trunk:nth-child(odd) {
background-color: #f9f9f9;
}
.Wt-treeview .Wt-striped div.active {
background-color: #428bca;
}

Thanks for your help.

RE: WTreeView not loading all child rows - Added by Roel Standaert about 1 month ago

The reason why it's not currently done like that with CSS is that that starts to break once you start to expand items. Also, the colors of the rows will shift when you scroll up and down (sometimes it's the even items that are in grey, sometimes it's the odd items).

RE: WTreeView not loading all child rows - Added by Roel Standaert about 1 month ago

Shoot, that actually causes a regression (I was worried about that, that's why I only pushed it to master and not 4.1-release). If you have a tree view that needs to grow it's fine, but if you have a tree view that you set a certain height on, it gets too big. I'll have to see if this is really a regression, or just uncovering another issue.

RE: WTreeView not loading all child rows - Added by adam s about 1 month ago

Thanks for update Roel. I've just started using treeview so for me it's more important for treeview to work and looks good rather than webpage.
Regards,
Adam

RE: WTreeView not loading all child rows - Added by Roel Standaert about 1 month ago

Ok, I just pushed a commit that should fix this issue, and not cause a regression. The related issue #7230 remains, though.

I felt that this was safe enough to push to 4.1-release as well as master.

(1-11/11)