GetItemByRow() returned a valid row even for an item which was collapsed which is clearly inappropriate for its use in GetItemRect(), which is supposed return an invalid rectangle if the item is not visible. It also might be inappropriate in other cases, but this is not totally clear and it seems like it is supposed to return a valid row even for collapsed items at least sometimes, so just make its behaviour conditional by adding a new flags parameter to GetItemRect() and to Walker() helper used by it itself, so that it could skip over collapsed items. Update the test to show that it succeeds now even when the item is present in the tree, as it only passed before because the item had never been expanded at all, and so wasn't really present in the tree structure and the updated test would have failed without the changes to the code in this commit.
385 lines
11 KiB
C++
385 lines
11 KiB
C++
///////////////////////////////////////////////////////////////////////////////
|
|
// Name: tests/controls/dataviewctrltest.cpp
|
|
// Purpose: wxDataViewCtrl unit test
|
|
// Author: Vaclav Slavik
|
|
// Created: 2011-08-08
|
|
// Copyright: (c) 2011 Vaclav Slavik <vslavik@gmail.com>
|
|
///////////////////////////////////////////////////////////////////////////////
|
|
|
|
// ----------------------------------------------------------------------------
|
|
// headers
|
|
// ----------------------------------------------------------------------------
|
|
|
|
#include "testprec.h"
|
|
|
|
#if wxUSE_DATAVIEWCTRL
|
|
|
|
|
|
#include "wx/app.h"
|
|
#include "wx/dataview.h"
|
|
#ifdef __WXGTK__
|
|
#include "wx/stopwatch.h"
|
|
#endif // __WXGTK__
|
|
|
|
#include "testableframe.h"
|
|
#include "asserthelper.h"
|
|
|
|
// ----------------------------------------------------------------------------
|
|
// test class
|
|
// ----------------------------------------------------------------------------
|
|
|
|
class DataViewCtrlTestCase
|
|
{
|
|
public:
|
|
explicit DataViewCtrlTestCase(long style);
|
|
~DataViewCtrlTestCase();
|
|
|
|
protected:
|
|
void TestSelectionFor0and1();
|
|
|
|
// the dataview control itself
|
|
wxDataViewTreeCtrl *m_dvc;
|
|
|
|
// and some of its items
|
|
wxDataViewItem m_root,
|
|
m_child1,
|
|
m_child2,
|
|
m_grandchild;
|
|
|
|
wxDECLARE_NO_COPY_CLASS(DataViewCtrlTestCase);
|
|
};
|
|
|
|
class SingleSelectDataViewCtrlTestCase : public DataViewCtrlTestCase
|
|
{
|
|
public:
|
|
SingleSelectDataViewCtrlTestCase()
|
|
: DataViewCtrlTestCase(wxDV_SINGLE)
|
|
{
|
|
}
|
|
};
|
|
|
|
class MultiSelectDataViewCtrlTestCase : public DataViewCtrlTestCase
|
|
{
|
|
public:
|
|
MultiSelectDataViewCtrlTestCase()
|
|
: DataViewCtrlTestCase(wxDV_MULTIPLE)
|
|
{
|
|
}
|
|
};
|
|
|
|
class MultiColumnsDataViewCtrlTestCase
|
|
{
|
|
public:
|
|
MultiColumnsDataViewCtrlTestCase();
|
|
~MultiColumnsDataViewCtrlTestCase();
|
|
|
|
protected:
|
|
// the dataview control itself
|
|
wxDataViewListCtrl *m_dvc;
|
|
|
|
// constants
|
|
const wxSize m_size;
|
|
const int m_firstColumnWidth;
|
|
|
|
// and the columns
|
|
wxDataViewColumn* m_firstColumn;
|
|
wxDataViewColumn* m_lastColumn;
|
|
|
|
wxDECLARE_NO_COPY_CLASS(MultiColumnsDataViewCtrlTestCase);
|
|
};
|
|
|
|
// ----------------------------------------------------------------------------
|
|
// test initialization
|
|
// ----------------------------------------------------------------------------
|
|
|
|
DataViewCtrlTestCase::DataViewCtrlTestCase(long style)
|
|
{
|
|
m_dvc = new wxDataViewTreeCtrl(wxTheApp->GetTopWindow(),
|
|
wxID_ANY,
|
|
wxDefaultPosition,
|
|
wxSize(400, 200),
|
|
style);
|
|
|
|
m_root = m_dvc->AppendContainer(wxDataViewItem(), "The root");
|
|
m_child1 = m_dvc->AppendContainer(m_root, "child1");
|
|
m_grandchild = m_dvc->AppendItem(m_child1, "grandchild");
|
|
m_child2 = m_dvc->AppendItem(m_root, "child2");
|
|
|
|
m_dvc->Layout();
|
|
m_dvc->Expand(m_root);
|
|
m_dvc->Refresh();
|
|
m_dvc->Update();
|
|
}
|
|
|
|
DataViewCtrlTestCase::~DataViewCtrlTestCase()
|
|
{
|
|
delete m_dvc;
|
|
}
|
|
|
|
MultiColumnsDataViewCtrlTestCase::MultiColumnsDataViewCtrlTestCase()
|
|
: m_size(200, 100),
|
|
m_firstColumnWidth(50)
|
|
{
|
|
m_dvc = new wxDataViewListCtrl(wxTheApp->GetTopWindow(), wxID_ANY);
|
|
|
|
m_firstColumn =
|
|
m_dvc->AppendTextColumn(wxString(), wxDATAVIEW_CELL_INERT, m_firstColumnWidth);
|
|
m_lastColumn =
|
|
m_dvc->AppendTextColumn(wxString(), wxDATAVIEW_CELL_INERT);
|
|
|
|
// Set size after columns appending to extend size of the last column.
|
|
m_dvc->SetSize(m_size);
|
|
m_dvc->Layout();
|
|
m_dvc->Refresh();
|
|
m_dvc->Update();
|
|
}
|
|
|
|
MultiColumnsDataViewCtrlTestCase::~MultiColumnsDataViewCtrlTestCase()
|
|
{
|
|
delete m_dvc;
|
|
}
|
|
|
|
// ----------------------------------------------------------------------------
|
|
// the tests themselves
|
|
// ----------------------------------------------------------------------------
|
|
|
|
TEST_CASE_METHOD(MultiSelectDataViewCtrlTestCase,
|
|
"wxDVC::Selection",
|
|
"[wxDataViewCtrl][select]")
|
|
{
|
|
// Check selection round-trip.
|
|
wxDataViewItemArray sel;
|
|
sel.push_back(m_child1);
|
|
sel.push_back(m_grandchild);
|
|
REQUIRE_NOTHROW( m_dvc->SetSelections(sel) );
|
|
|
|
wxDataViewItemArray sel2;
|
|
CHECK( m_dvc->GetSelections(sel2) == static_cast<int>(sel.size()) );
|
|
|
|
CHECK( sel2 == sel );
|
|
|
|
// Invalid items in GetSelections() input are supposed to be just skipped.
|
|
sel.clear();
|
|
sel.push_back(wxDataViewItem());
|
|
REQUIRE_NOTHROW( m_dvc->SetSelections(sel) );
|
|
|
|
CHECK( m_dvc->GetSelections(sel2) == 0 );
|
|
CHECK( sel2.empty() );
|
|
}
|
|
|
|
TEST_CASE_METHOD(MultiSelectDataViewCtrlTestCase,
|
|
"wxDVC::DeleteSelected",
|
|
"[wxDataViewCtrl][delete]")
|
|
{
|
|
wxDataViewItemArray sel;
|
|
sel.push_back(m_child1);
|
|
sel.push_back(m_grandchild);
|
|
sel.push_back(m_child2);
|
|
m_dvc->SetSelections(sel);
|
|
|
|
// delete a selected item
|
|
m_dvc->DeleteItem(m_child1);
|
|
|
|
m_dvc->GetSelections(sel);
|
|
|
|
// m_child1 and its children should be removed from the selection now
|
|
REQUIRE( sel.size() == 1 );
|
|
CHECK( sel[0] == m_child2 );
|
|
}
|
|
|
|
TEST_CASE_METHOD(MultiSelectDataViewCtrlTestCase,
|
|
"wxDVC::DeleteNotSelected",
|
|
"[wxDataViewCtrl][delete]")
|
|
{
|
|
// TODO not working on OS X as expected
|
|
#ifdef __WXOSX__
|
|
WARN("Disabled under MacOS because this test currently fails");
|
|
#else
|
|
wxDataViewItemArray sel;
|
|
sel.push_back(m_child1);
|
|
sel.push_back(m_grandchild);
|
|
m_dvc->SetSelections(sel);
|
|
|
|
// delete unselected item
|
|
m_dvc->DeleteItem(m_child2);
|
|
|
|
m_dvc->GetSelections(sel);
|
|
|
|
// m_child1 and its children should be unaffected
|
|
REQUIRE( sel.size() == 2 );
|
|
CHECK( sel[0] == m_child1 );
|
|
CHECK( sel[1] == m_grandchild );
|
|
#endif
|
|
}
|
|
|
|
void DataViewCtrlTestCase::TestSelectionFor0and1()
|
|
{
|
|
wxDataViewItemArray selections;
|
|
|
|
// Initially there is no selection.
|
|
CHECK( m_dvc->GetSelectedItemsCount() == 0 );
|
|
CHECK( !m_dvc->HasSelection() );
|
|
CHECK( !m_dvc->GetSelection().IsOk() );
|
|
|
|
CHECK( !m_dvc->GetSelections(selections) );
|
|
CHECK( selections.empty() );
|
|
|
|
// Select one item.
|
|
m_dvc->Select(m_child1);
|
|
CHECK( m_dvc->GetSelectedItemsCount() == 1 );
|
|
CHECK( m_dvc->HasSelection() );
|
|
CHECK( m_dvc->GetSelection().IsOk() );
|
|
REQUIRE( m_dvc->GetSelections(selections) == 1 );
|
|
CHECK( selections[0] == m_child1 );
|
|
}
|
|
|
|
TEST_CASE_METHOD(MultiSelectDataViewCtrlTestCase,
|
|
"wxDVC::GetSelectionForMulti",
|
|
"[wxDataViewCtrl][select]")
|
|
{
|
|
wxDataViewItemArray selections;
|
|
|
|
TestSelectionFor0and1();
|
|
|
|
m_dvc->Select(m_child2);
|
|
|
|
CHECK( m_dvc->GetSelectedItemsCount() == 2 );
|
|
CHECK( m_dvc->HasSelection() );
|
|
CHECK( !m_dvc->GetSelection().IsOk() );
|
|
REQUIRE( m_dvc->GetSelections(selections) == 2 );
|
|
CHECK( selections[1] == m_child2 );
|
|
}
|
|
|
|
TEST_CASE_METHOD(SingleSelectDataViewCtrlTestCase,
|
|
"wxDVC::SingleSelection",
|
|
"[wxDataViewCtrl][selection]")
|
|
{
|
|
TestSelectionFor0and1();
|
|
}
|
|
|
|
TEST_CASE_METHOD(SingleSelectDataViewCtrlTestCase,
|
|
"wxDVC::IsExpanded",
|
|
"[wxDataViewCtrl][expand]")
|
|
{
|
|
CHECK( m_dvc->IsExpanded(m_root) );
|
|
CHECK( !m_dvc->IsExpanded(m_child1) );
|
|
// No idea why, but the native NSOutlineView isItemExpanded: method returns
|
|
// true for this item for some reason.
|
|
#ifdef __WXOSX__
|
|
WARN("Disabled under MacOS: IsExpanded() returns true for grand child");
|
|
#else
|
|
CHECK( !m_dvc->IsExpanded(m_grandchild) );
|
|
#endif
|
|
CHECK( !m_dvc->IsExpanded(m_child2) );
|
|
}
|
|
|
|
TEST_CASE_METHOD(SingleSelectDataViewCtrlTestCase,
|
|
"wxDVC::GetItemRect",
|
|
"[wxDataViewCtrl][item]")
|
|
{
|
|
#ifdef __WXGTK__
|
|
// We need to let the native control have some events to lay itself out.
|
|
wxYield();
|
|
#endif // __WXGTK__
|
|
|
|
const wxRect rect1 = m_dvc->GetItemRect(m_child1);
|
|
const wxRect rect2 = m_dvc->GetItemRect(m_child2);
|
|
|
|
CHECK( rect1 != wxRect() );
|
|
CHECK( rect2 != wxRect() );
|
|
|
|
CHECK( rect1.x == rect2.x );
|
|
CHECK( rect1.width == rect2.width );
|
|
CHECK( rect1.height == rect2.height );
|
|
|
|
{
|
|
INFO("First child: " << rect1 << ", second one: " << rect2);
|
|
CHECK( rect1.y < rect2.y );
|
|
}
|
|
|
|
// This forces generic implementation to add m_grandchild to the tree, as
|
|
// it does it only on demand. We want the item to really be there to check
|
|
// that GetItemRect() returns an empty rectangle for collapsed items.
|
|
m_dvc->Expand(m_child1);
|
|
m_dvc->Collapse(m_child1);
|
|
|
|
const wxRect rectNotShown = m_dvc->GetItemRect(m_grandchild);
|
|
CHECK( rectNotShown == wxRect() );
|
|
|
|
// Append enough items to make the window scrollable.
|
|
for ( int i = 3; i < 100; ++i )
|
|
m_dvc->AppendItem(m_root, wxString::Format("child%d", i));
|
|
|
|
const wxDataViewItem last = m_dvc->AppendItem(m_root, "last");
|
|
|
|
// This should scroll the window to bring this item into view.
|
|
m_dvc->EnsureVisible(last);
|
|
|
|
#ifdef __WXGTK__
|
|
// And again to let it scroll the correct items into view.
|
|
wxYield();
|
|
#endif
|
|
|
|
// Check that this was indeed the case.
|
|
const wxDataViewItem top = m_dvc->GetTopItem();
|
|
CHECK( top != m_root );
|
|
|
|
// Verify that the coordinates are returned in physical coordinates of the
|
|
// window and not the logical coordinates affected by scrolling.
|
|
const wxRect rectScrolled = m_dvc->GetItemRect(top);
|
|
CHECK( rectScrolled.GetBottom() > 0 );
|
|
CHECK( rectScrolled.GetTop() <= m_dvc->GetClientSize().y );
|
|
|
|
// Also check that the root item is not currently visible (because it's
|
|
// scrolled off).
|
|
const wxRect rectRoot = m_dvc->GetItemRect(m_root);
|
|
CHECK( rectRoot == wxRect() );
|
|
}
|
|
|
|
TEST_CASE_METHOD(SingleSelectDataViewCtrlTestCase,
|
|
"wxDVC::DeleteAllItems",
|
|
"[wxDataViewCtrl][delete]")
|
|
{
|
|
// The invalid item corresponds to the root of tree store model, so it
|
|
// should have a single item (our m_root) initially.
|
|
CHECK( m_dvc->GetChildCount(wxDataViewItem()) == 1 );
|
|
|
|
m_dvc->DeleteAllItems();
|
|
|
|
// And none at all after deleting all the items.
|
|
CHECK( m_dvc->GetChildCount(wxDataViewItem()) == 0 );
|
|
}
|
|
|
|
TEST_CASE_METHOD(MultiColumnsDataViewCtrlTestCase,
|
|
"wxDVC::AppendTextColumn",
|
|
"[wxDataViewCtrl][column]")
|
|
{
|
|
#ifdef __WXGTK__
|
|
// Wait for the list control to be realized.
|
|
wxStopWatch sw;
|
|
while ( m_firstColumn->GetWidth() == 0 )
|
|
{
|
|
if ( sw.Time() > 500 )
|
|
{
|
|
WARN("Timed out waiting for wxDataViewListCtrl to be realized");
|
|
break;
|
|
}
|
|
wxYield();
|
|
}
|
|
#endif
|
|
|
|
// Check the width of the first column.
|
|
CHECK( m_firstColumn->GetWidth() == m_firstColumnWidth );
|
|
|
|
// Check that the last column was extended to fit client area.
|
|
const int lastColumnMaxWidth =
|
|
m_dvc->GetClientSize().GetWidth() - m_firstColumnWidth;
|
|
// In GTK and under Mac the width of the last column is less then
|
|
// a remaining client area.
|
|
const int lastColumnMinWidth = lastColumnMaxWidth - 10;
|
|
CHECK( m_lastColumn->GetWidth() <= lastColumnMaxWidth );
|
|
CHECK( m_lastColumn->GetWidth() >= lastColumnMinWidth );
|
|
}
|
|
|
|
#endif //wxUSE_DATAVIEWCTRL
|