|
#include <Wt/WTreeView>
|
|
#include <Wt/WApplication>
|
|
#include <Wt/WAbstractItemModel>
|
|
#include <Wt/WPushButton>
|
|
#include <Wt/WContainerWidget>
|
|
#include <Wt/WVBoxLayout>
|
|
|
|
|
|
/*
|
|
* Usage:
|
|
* 1) Build (link with -lwt -lwthttp) & start test program.
|
|
* 2) Note that there are 3 nodes visible, a parent node and a/b nodes under
|
|
* that.
|
|
* 3) Select the "a" (or "b") node by clicking it.
|
|
* 4) Press the "Remove A" button.
|
|
* 5) Observe that the server exits due to getting a stale index, either
|
|
* a or b depending on which one was selected.
|
|
* If neither "a" nor "b" was selected, there is no error.
|
|
*/
|
|
|
|
class TestModel : public Wt::WAbstractItemModel
|
|
{
|
|
public:
|
|
TestModel ()
|
|
: Wt::WAbstractItemModel (),
|
|
par (createIndex (0, 0, (void *)("parent"))),
|
|
a (createIndex (0, 0, (void *)("node a"))),
|
|
b (createIndex (1, 0, (void *)("node b"))),
|
|
b2 (createIndex (0, 0, (void *)("node b2"))),
|
|
invalid (),
|
|
a_deleted (false)
|
|
{
|
|
}
|
|
|
|
void remove_a ()
|
|
{
|
|
if (!a_deleted)
|
|
{
|
|
beginRemoveRows (par, a.row (), a.row ());
|
|
a_deleted = true;
|
|
endRemoveRows ();
|
|
// Request the index be updated, since its internal pointer
|
|
// has been changed.
|
|
dataChanged ().emit (b2, b2);
|
|
}
|
|
}
|
|
|
|
void assert_fresh (const Wt::WModelIndex &idx, const std::string &where) const
|
|
{
|
|
if (a_deleted && (idx == a || idx == b))
|
|
{
|
|
std::cout << "### Error: stale index '" <<
|
|
static_cast<const char *> (idx.internalPointer ()) <<
|
|
"' in " << where << "\n";
|
|
abort ();
|
|
}
|
|
}
|
|
|
|
int rowCount (const Wt::WModelIndex &idx) const
|
|
{
|
|
if (idx == invalid)
|
|
return 1;
|
|
if (idx == par)
|
|
return a_deleted ? 1 : 2;
|
|
return 0;
|
|
}
|
|
|
|
int columnCount (const Wt::WModelIndex &idx) const
|
|
{
|
|
if (idx == invalid || idx == par)
|
|
return 1;
|
|
return 0;
|
|
}
|
|
|
|
Wt::WModelIndex index (int row, int col, const Wt::WModelIndex &p) const
|
|
{
|
|
assert_fresh (p, "TestModel::index()");
|
|
|
|
if (p == invalid)
|
|
{
|
|
if (row == 0 && col == 0)
|
|
return par;
|
|
}
|
|
else if (p == par && col == 0)
|
|
{
|
|
if (a_deleted)
|
|
{
|
|
// The correct index at parent,0,0 is now b2, not a
|
|
if (row == 0) return b2;
|
|
}
|
|
else {
|
|
if (row == 0) return a;
|
|
if (row == 1) return b;
|
|
}
|
|
}
|
|
return invalid;
|
|
}
|
|
|
|
Wt::WModelIndex parent (const Wt::WModelIndex &idx) const
|
|
{
|
|
assert_fresh (idx, "TestModel::parent()");
|
|
if (idx == a || idx == b)
|
|
return par;
|
|
if (a_deleted && idx == b2)
|
|
return par;
|
|
return invalid;
|
|
}
|
|
|
|
boost::any data (const Wt::WModelIndex &idx, int role) const
|
|
{
|
|
assert_fresh (idx, "TestModel::data()");
|
|
|
|
if (role == Wt::DisplayRole)
|
|
return boost::any (
|
|
static_cast<const char *> (idx.internalPointer ()));
|
|
return boost::any ();
|
|
}
|
|
|
|
Wt::WFlags<Wt::ItemFlag> flags (const Wt::WModelIndex &idx) const
|
|
{
|
|
if (idx == par || idx == a || idx == b || idx == b2)
|
|
return Wt::ItemIsSelectable;
|
|
else
|
|
return 0;
|
|
}
|
|
|
|
private:
|
|
const Wt::WModelIndex par, a, b, b2, invalid;
|
|
bool a_deleted;
|
|
};
|
|
|
|
class TestApp : public Wt::WApplication
|
|
{
|
|
public:
|
|
explicit TestApp (const Wt::WEnvironment &env)
|
|
: Wt::WApplication (env),
|
|
model (new TestModel ())
|
|
{
|
|
Wt::WVBoxLayout *vbl = new Wt::WVBoxLayout ();
|
|
root ()->setLayout (vbl);
|
|
Wt::WTreeView *tv = new Wt::WTreeView ();
|
|
tv->setModel (model);
|
|
tv->expand (model->index (0, 0, Wt::WModelIndex ()));
|
|
tv->setSelectionMode (Wt::SingleSelection);
|
|
vbl->addWidget (tv, 100);
|
|
Wt::WPushButton *btn = new Wt::WPushButton ("Remove A");
|
|
btn->clicked ().connect (SLOT(model, TestModel::remove_a));
|
|
vbl->addWidget (btn);
|
|
}
|
|
|
|
private:
|
|
TestModel *model;
|
|
};
|
|
|
|
|
|
|
|
|
|
Wt::WApplication *
|
|
createApp (const Wt::WEnvironment &env)
|
|
{
|
|
return new TestApp (env);
|
|
}
|
|
|
|
int main (int argc, char *argv[])
|
|
{
|
|
return Wt::WRun (argc, argv, &createApp);
|
|
}
|