Files
wxWidgets/tests/controls/dataviewctrltest.cpp
Vadim Zeitlin d47fa718cd Add wxDataViewCtrl::ExpandChildren()
This convenient method allows to expand all children of the item
recursively.

This is directly supported by both native implementations, so it makes
sense to have this in wxDataViewCtrl itself, even if it could be also
(less efficiently) implemented in the user code.
2020-12-05 16:37:13 +01:00

398 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) );
m_dvc->Collapse(m_root);
CHECK( !m_dvc->IsExpanded(m_root) );
m_dvc->ExpandChildren(m_root);
CHECK( m_dvc->IsExpanded(m_root) );
CHECK( m_dvc->IsExpanded(m_child1) );
// Expanding an already expanded node must still expand all its children.
m_dvc->Collapse(m_child1);
CHECK( !m_dvc->IsExpanded(m_child1) );
m_dvc->ExpandChildren(m_root);
CHECK( m_dvc->IsExpanded(m_child1) );
}
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