diff --git a/docs/changes.txt b/docs/changes.txt index 37d1984be3..f3c9b416d1 100644 --- a/docs/changes.txt +++ b/docs/changes.txt @@ -149,6 +149,7 @@ wxGTK: - Fix the build with glib < 2.32 (e.g. CentOS 6). - Fix field widths in wxStatusBar showing a size grip. - Fill column value in wxEVT_DATAVIEW_ITEM_ACTIVATED events. +- Implement wxDataViewCtrl::GetItemRect() (MrMeesek). wxMSW: diff --git a/interface/wx/dataview.h b/interface/wx/dataview.h index 84c7479df8..00a8069f06 100644 --- a/interface/wx/dataview.h +++ b/interface/wx/dataview.h @@ -1446,8 +1446,14 @@ public: int GetIndent() const; /** - Returns item rectangle. Coordinates of the rectangle are specified in - wxDataViewCtrl client area coordinates. + Returns item rectangle. + + If item is not currently visible, either because its parent is + collapsed or it is outside of the visible part of the control due to + the current vertical scrollbar position, return an empty rectangle. + + Coordinates of the rectangle are specified in wxDataViewCtrl client + area coordinates. @param item A valid item. @@ -1455,10 +1461,6 @@ public: If non-@NULL, the rectangle returned corresponds to the intersection of the item with the specified column. If @NULL, the rectangle spans all the columns. - - @note This method is currently not implemented at all in wxGTK and only - implemented for non-@NULL @a col argument in wxOSX. It is fully - implemented in the generic version of the control. */ virtual wxRect GetItemRect(const wxDataViewItem& item, const wxDataViewColumn* col = NULL) const; @@ -1556,6 +1558,9 @@ public: /** Return @true if the item is expanded. + + @note When using the native macOS version this method has a bug which + may result in returning @true even for items without children. */ virtual bool IsExpanded(const wxDataViewItem& item) const; diff --git a/src/generic/datavgen.cpp b/src/generic/datavgen.cpp index 2e1d1887e1..41c3b7fbed 100644 --- a/src/generic/datavgen.cpp +++ b/src/generic/datavgen.cpp @@ -3468,55 +3468,53 @@ int wxDataViewMainWindow::GetLineHeight( unsigned int row ) const class RowToTreeNodeJob: public DoJob { public: - RowToTreeNodeJob( unsigned int row_ , int current_, wxDataViewTreeNode * node ) + // Note that we initialize m_current to -1 because the first node passed to + // our operator() will be the root node, which doesn't appear in the window + // and so doesn't count as a real row. + explicit RowToTreeNodeJob(int row) + : m_row(row), m_current(-1), m_ret(NULL) { - this->row = row_; - this->current = current_; - ret = NULL; - parent = node; } virtual int operator() ( wxDataViewTreeNode * node ) wxOVERRIDE { - current ++; - if( current == static_cast(row)) + if( m_current == m_row) { - ret = node; + m_ret = node; return DoJob::DONE; } - if( node->GetSubTreeCount() + current < static_cast(row) ) + if( node->GetSubTreeCount() + m_current < m_row ) { - current += node->GetSubTreeCount(); + m_current += node->GetSubTreeCount() + 1; return DoJob::SKIP_SUBTREE; } else { - parent = node; - // If the current node has only leaf children, we can find the // desired node directly. This can speed up finding the node // in some cases, and will have a very good effect for list views. if ( node->HasChildren() && (int)node->GetChildNodes().size() == node->GetSubTreeCount() ) { - const int index = static_cast(row) - current - 1; - ret = node->GetChildNodes()[index]; + const int index = m_row - m_current - 1; + m_ret = node->GetChildNodes()[index]; return DoJob::DONE; } + m_current++; + return DoJob::CONTINUE; } } wxDataViewTreeNode * GetResult() const - { return ret; } + { return m_ret; } private: - unsigned int row; - int current; - wxDataViewTreeNode * ret; - wxDataViewTreeNode * parent; + const int m_row; + int m_current; + wxDataViewTreeNode* m_ret; }; wxDataViewTreeNode * wxDataViewMainWindow::GetTreeNodeByRow(unsigned int row) const @@ -3526,7 +3524,7 @@ wxDataViewTreeNode * wxDataViewMainWindow::GetTreeNodeByRow(unsigned int row) co if ( row == (unsigned)-1 ) return NULL; - RowToTreeNodeJob job( row , -2, m_root ); + RowToTreeNodeJob job(static_cast(row)); Walker( m_root , job ); return job.GetResult(); } @@ -3815,10 +3813,16 @@ wxRect wxDataViewMainWindow::GetItemRect( const wxDataViewItem & item, xpos = 0; } + const int row = GetRowByItem(item); + if ( row == -1 ) + { + // This means the row is currently not visible at all. + return wxRect(); + } + // we have to take an expander column into account and compute its indentation // to get the correct x position where the actual text is int indent = 0; - int row = GetRowByItem(item); if (!IsList() && (column == 0 || GetExpanderColumnOrFirstOne(GetOwner()) == column) ) { @@ -3835,6 +3839,14 @@ wxRect wxDataViewMainWindow::GetItemRect( const wxDataViewItem & item, GetOwner()->CalcScrolledPosition( itemRect.x, itemRect.y, &itemRect.x, &itemRect.y ); + // Check if the rectangle is completely outside of the currently visible + // area and, if so, return an empty rectangle to indicate that the item is + // not visible. + if ( itemRect.GetBottom() < 0 || itemRect.GetTop() > GetClientSize().y ) + { + return wxRect(); + } + return itemRect; } @@ -3856,43 +3868,49 @@ int wxDataViewMainWindow::RecalculateCount() const class ItemToRowJob : public DoJob { public: - ItemToRowJob(const wxDataViewItem& item_, wxVector::reverse_iterator iter) - : m_iter(iter), - item(item_) + // As with RowToTreeNodeJob above, we initialize m_current to -1 because + // the first node passed to our operator() is the root node which is not + // visible on screen and so we should return 0 for its first child node and + // not for the root itself. + ItemToRowJob(const wxDataViewItem& item, wxVector::reverse_iterator iter) + : m_item(item), m_iter(iter), m_current(-1) { - ret = -1; } // Maybe binary search will help to speed up this process virtual int operator() ( wxDataViewTreeNode * node) wxOVERRIDE { - ret ++; - if( node->GetItem() == item ) + if( node->GetItem() == m_item ) { return DoJob::DONE; } + // Is this node the next (grand)parent of the item we're looking for? if( node->GetItem() == *m_iter ) { + // Search for the next (grand)parent now and skip this item itself. ++m_iter; + ++m_current; return DoJob::CONTINUE; } else { - ret += node->GetSubTreeCount(); + // Skip this node and all its currently visible children. + m_current += node->GetSubTreeCount() + 1; return DoJob::SKIP_SUBTREE; } } - // the row number is begin from zero int GetResult() const - { return ret -1; } + { return m_current; } private: + const wxDataViewItem m_item; wxVector::reverse_iterator m_iter; - wxDataViewItem item; - int ret; + + // The row corresponding to the last node seen in our operator(). + int m_current; }; @@ -3926,7 +3944,9 @@ int wxDataViewMainWindow::GetRowByItem(const wxDataViewItem & item) const // the parent chain was created by adding the deepest parent first. // so if we want to start at the root node, we have to iterate backwards through the vector ItemToRowJob job( item, parentChain.rbegin() ); - Walker( m_root, job ); + if ( !Walker( m_root, job ) ) + return -1; + return job.GetResult(); } } @@ -5841,8 +5861,11 @@ wxRect wxDataViewCtrl::GetItemRect( const wxDataViewItem & item, // Convert position from the main window coordinates to the control coordinates. // (They can be different due to the presence of the header.). wxRect r = m_clientArea->GetItemRect(item, column); - const wxPoint ctrlPos = ScreenToClient(m_clientArea->ClientToScreen(r.GetPosition())); - r.SetPosition(ctrlPos); + if ( r.width || r.height ) + { + const wxPoint ctrlPos = ScreenToClient(m_clientArea->ClientToScreen(r.GetPosition())); + r.SetPosition(ctrlPos); + } return r; } diff --git a/src/gtk/dataview.cpp b/src/gtk/dataview.cpp index 8e1a6503a3..d2c1abf352 100644 --- a/src/gtk/dataview.cpp +++ b/src/gtk/dataview.cpp @@ -5289,10 +5289,71 @@ void wxDataViewCtrl::HitTest(const wxPoint& point, } wxRect -wxDataViewCtrl::GetItemRect(const wxDataViewItem& WXUNUSED(item), - const wxDataViewColumn *WXUNUSED(column)) const +wxDataViewCtrl::GetItemRect(const wxDataViewItem& item, + const wxDataViewColumn *column) const { - return wxRect(); + if ( !item ) + return wxRect(); + + GtkTreeViewColumn *gcolumn = NULL ; + if (column) + gcolumn = GTK_TREE_VIEW_COLUMN(column->GetGtkHandle()); + + GtkTreeIter iter; + iter.user_data = item.GetID(); + wxGtkTreePath path(m_internal->get_path( &iter )); + + GdkRectangle item_rect; + gtk_tree_view_get_cell_area(GTK_TREE_VIEW(m_treeview), path, gcolumn, &item_rect); + + // GTK returns rectangles with the position and height, but not width, for + // some reason, set to 0 if the item is not currently shown, so an explicit + // check is needed as this rectangle is not quite the empty rectangle we're + // supposed to return in this case. + if ( item_rect.height == 0 ) + return wxRect(); + + // If column is NULL we compute the combined width of all the columns + if ( !column ) + { + unsigned int cols = GetColumnCount(); + int width = 0; + for (unsigned int i = 0; i < cols; ++i) + { + wxDataViewColumn * col = GetColumn(i); + if ( !col->IsHidden() ) + width += col->GetWidth(); + } + item_rect.width = width; + } + + // We need to convert logical coordinates to physical ones, i.e. the + // rectangle of the topmost item should start at ~0, even if it's a 100th + // item shown on top only because the window is scrolled. +#if GTK_CHECK_VERSION(2, 12, 0) + if ( wx_is_at_least_gtk2(12) ) + { + gtk_tree_view_convert_bin_window_to_widget_coords + ( + GTK_TREE_VIEW(m_treeview), + item_rect.x, item_rect.y, + &item_rect.x, &item_rect.y + ); + + if ( item_rect.y > GetClientSize().y || + item_rect.y + item_rect.height < 0 ) + { + // If it turns out that the item is not visible at all, indicate it + // by returning an empty rectangle for it. + return wxRect(); + } + } + //else: There doesn't seem to be anything reasonable to do here, so we'll + // just return wrong values with the very old GTK+ versions if the + // window is scrolled. +#endif // GTK+ 2.12+ + + return wxRectFromGDKRect(&item_rect); } bool wxDataViewCtrl::SetRowHeight(int rowHeight) diff --git a/src/osx/cocoa/dataview.mm b/src/osx/cocoa/dataview.mm index 09a532dbef..6842102502 100644 --- a/src/osx/cocoa/dataview.mm +++ b/src/osx/cocoa/dataview.mm @@ -2295,8 +2295,33 @@ wxDataViewItem wxCocoaDataViewControl::GetTopItem() const wxRect wxCocoaDataViewControl::GetRectangle(const wxDataViewItem& item, const wxDataViewColumn *columnPtr) { - return wxFromNSRect([m_osxView superview],[m_OutlineView frameOfCellAtColumn:GetColumnPosition(columnPtr) + NSView* const parent = [m_osxView superview]; + + wxRect r = wxFromNSRect(parent, [m_OutlineView frameOfCellAtColumn:GetColumnPosition(columnPtr) row:[m_OutlineView rowForItem:[m_DataSource getDataViewItemFromBuffer:item]]]); + + // For hidden items, i.e. items not shown because their parent is + // collapsed, the native method returns rectangles with negative width, but + // we're supposed to just return an empty rectangle in this case. To be on + // the safe side, also check for the height as well, even if it seems to be + // always 0 in this case. + if ( r.width < 0 || r.height < 0 ) + return wxRect(); + + // Also adjust the vertical coordinates to use physical window coordinates + // instead of the logical ones returned by frameOfCellAtColumn:row: + NSScrollView* const scrollView = [m_OutlineView enclosingScrollView]; + const wxRect + visible = wxFromNSRect(parent, scrollView.contentView.visibleRect); + + // We are also supposed to return empty rectangle if the item is not + // visible because it is scrolled out of view. + if ( r.GetBottom() < visible.GetTop() || r.GetTop() > visible.GetBottom() ) + return wxRect(); + + r.y -= visible.y; + + return r; } bool wxCocoaDataViewControl::IsExpanded(const wxDataViewItem& item) const diff --git a/src/osx/dataview_osx.cpp b/src/osx/dataview_osx.cpp index f49a360dc6..57a1cf3970 100644 --- a/src/osx/dataview_osx.cpp +++ b/src/osx/dataview_osx.cpp @@ -547,10 +547,24 @@ wxDataViewColumn *wxDataViewCtrl::GetCurrentColumn() const wxRect wxDataViewCtrl::GetItemRect(wxDataViewItem const& item, wxDataViewColumn const* columnPtr) const { - if (item.IsOk() && (columnPtr != NULL)) - return GetDataViewPeer()->GetRectangle(item,columnPtr); - else - return wxRect(); + if ( !item.IsOk() ) + return wxRect(); + + wxRect rect = GetDataViewPeer()->GetRectangle(item, columnPtr ? columnPtr : GetColumn(0)); + + if ( !columnPtr ) + { + const unsigned columnCount = GetColumnCount(); + if ( columnCount != 1 ) + { + // Extend the rectangle to the rightmost part of the last column. + const wxRect rectLastCol = GetDataViewPeer()->GetRectangle(item, GetColumn(columnCount - 1)); + rect.SetRight(rectLastCol.GetRight()); + } + //else: We already have the rectangle we need. + } + + return rect; } int wxDataViewCtrl::GetSelectedItemsCount() const diff --git a/tests/asserthelper.cpp b/tests/asserthelper.cpp index 8f9f36d452..7b25cec2d6 100644 --- a/tests/asserthelper.cpp +++ b/tests/asserthelper.cpp @@ -67,3 +67,11 @@ std::ostream& operator<<(std::ostream& os, const wxPoint& p) return os; } + +std::ostream& operator<<(std::ostream& os, const wxRect& r) +{ + os << "{" + << r.x << ", " << r.y << " " << r.width << "*" << r.height + << "}"; + return os; +} diff --git a/tests/asserthelper.h b/tests/asserthelper.h index ce8c9c6a29..57772453bb 100644 --- a/tests/asserthelper.h +++ b/tests/asserthelper.h @@ -29,16 +29,12 @@ namespace wxTestPrivate std::ostream& operator<<(std::ostream& os, const ColourChannel& cc); } // wxTestPrivate namespace -// this operator is needed to use CPPUNIT_ASSERT_EQUAL with wxColour objects +// Operators used to show the values of the corresponding types when comparing +// them in the unit tests fails. std::ostream& operator<<(std::ostream& os, const wxColour& c); - -// this operator is needed to use CPPUNIT_ASSERT_EQUAL with wxSize objects std::ostream& operator<<(std::ostream& os, const wxSize& s); - -// this operator is needed to use CPPUNIT_ASSERT_EQUAL with wxFont objects std::ostream& operator<<(std::ostream& os, const wxFont& f); - -// this operator is needed to use CPPUNIT_ASSERT_EQUAL with wxPoint objects std::ostream& operator<<(std::ostream& os, const wxPoint& p); +std::ostream& operator<<(std::ostream& os, const wxRect& r); #endif diff --git a/tests/controls/dataviewctrltest.cpp b/tests/controls/dataviewctrltest.cpp index 45c10cf253..83e712a8f3 100644 --- a/tests/controls/dataviewctrltest.cpp +++ b/tests/controls/dataviewctrltest.cpp @@ -22,35 +22,19 @@ #include "wx/dataview.h" #include "testableframe.h" +#include "asserthelper.h" // ---------------------------------------------------------------------------- // test class // ---------------------------------------------------------------------------- -class DataViewCtrlTestCase : public CppUnit::TestCase +class DataViewCtrlTestCase { public: - DataViewCtrlTestCase() { } - - virtual void setUp() wxOVERRIDE; - virtual void tearDown() wxOVERRIDE; - -private: - CPPUNIT_TEST_SUITE( DataViewCtrlTestCase ); - CPPUNIT_TEST( DeleteSelected ); - CPPUNIT_TEST( DeleteNotSelected ); - CPPUNIT_TEST( GetSelectionForMulti ); - CPPUNIT_TEST( GetSelectionForSingle ); - CPPUNIT_TEST_SUITE_END(); - - // Create wxDataViewTreeCtrl with the given style. - void Create(long style); - - void DeleteSelected(); - void DeleteNotSelected(); - void GetSelectionForMulti(); - void GetSelectionForSingle(); + explicit DataViewCtrlTestCase(long style); + ~DataViewCtrlTestCase(); +protected: void TestSelectionFor0and1(); // the dataview control itself @@ -65,17 +49,29 @@ private: wxDECLARE_NO_COPY_CLASS(DataViewCtrlTestCase); }; -// register in the unnamed registry so that these tests are run by default -CPPUNIT_TEST_SUITE_REGISTRATION( DataViewCtrlTestCase ); +class SingleSelectDataViewCtrlTestCase : public DataViewCtrlTestCase +{ +public: + SingleSelectDataViewCtrlTestCase() + : DataViewCtrlTestCase(wxDV_SINGLE) + { + } +}; -// also include in its own registry so that these tests can be run alone -CPPUNIT_TEST_SUITE_NAMED_REGISTRATION( DataViewCtrlTestCase, "DataViewCtrlTestCase" ); +class MultiSelectDataViewCtrlTestCase : public DataViewCtrlTestCase +{ +public: + MultiSelectDataViewCtrlTestCase() + : DataViewCtrlTestCase(wxDV_MULTIPLE) + { + } +}; // ---------------------------------------------------------------------------- // test initialization // ---------------------------------------------------------------------------- -void DataViewCtrlTestCase::Create(long style) +DataViewCtrlTestCase::DataViewCtrlTestCase(long style) { m_dvc = new wxDataViewTreeCtrl(wxTheApp->GetTopWindow(), wxID_ANY, @@ -88,33 +84,24 @@ void DataViewCtrlTestCase::Create(long style) m_grandchild = m_dvc->AppendItem(m_child1, "grandchild"); m_child2 = m_dvc->AppendItem(m_root, "child2"); - m_dvc->SetSize(400, 200); - m_dvc->ExpandAncestors(m_root); + m_dvc->Layout(); + m_dvc->Expand(m_root); m_dvc->Refresh(); m_dvc->Update(); } -void DataViewCtrlTestCase::setUp() -{ - Create(wxDV_MULTIPLE); -} - -void DataViewCtrlTestCase::tearDown() +DataViewCtrlTestCase::~DataViewCtrlTestCase() { delete m_dvc; - m_dvc = NULL; - - m_root = - m_child1 = - m_child2 = - m_grandchild = wxDataViewItem(); } // ---------------------------------------------------------------------------- // the tests themselves // ---------------------------------------------------------------------------- -void DataViewCtrlTestCase::DeleteSelected() +TEST_CASE_METHOD(MultiSelectDataViewCtrlTestCase, + "wxDVC::DeleteSelected", + "[wxDataViewCtrl][delete]") { wxDataViewItemArray sel; sel.push_back(m_child1); @@ -128,14 +115,18 @@ void DataViewCtrlTestCase::DeleteSelected() m_dvc->GetSelections(sel); // m_child1 and its children should be removed from the selection now - CPPUNIT_ASSERT_EQUAL( 1, sel.size() ); - CPPUNIT_ASSERT( sel[0] == m_child2 ); + REQUIRE( sel.size() == 1 ); + CHECK( sel[0] == m_child2 ); } -void DataViewCtrlTestCase::DeleteNotSelected() +TEST_CASE_METHOD(MultiSelectDataViewCtrlTestCase, + "wxDVC::DeleteNotSelected", + "[wxDataViewCtrl][delete]") { // TODO not working on OS X as expected -#ifndef __WXOSX__ +#ifdef __WXOSX__ + WARN("Disabled under MacOS because this test currently fails"); +#else wxDataViewItemArray sel; sel.push_back(m_child1); sel.push_back(m_grandchild); @@ -147,9 +138,9 @@ void DataViewCtrlTestCase::DeleteNotSelected() m_dvc->GetSelections(sel); // m_child1 and its children should be unaffected - CPPUNIT_ASSERT_EQUAL( 2, sel.size() ); - CPPUNIT_ASSERT( sel[0] == m_child1 ); - CPPUNIT_ASSERT( sel[1] == m_grandchild ); + REQUIRE( sel.size() == 2 ); + CHECK( sel[0] == m_child1 ); + CHECK( sel[1] == m_grandchild ); #endif } @@ -158,44 +149,117 @@ void DataViewCtrlTestCase::TestSelectionFor0and1() wxDataViewItemArray selections; // Initially there is no selection. - CPPUNIT_ASSERT_EQUAL( 0, m_dvc->GetSelectedItemsCount() ); - CPPUNIT_ASSERT( !m_dvc->HasSelection() ); - CPPUNIT_ASSERT( !m_dvc->GetSelection().IsOk() ); + CHECK( m_dvc->GetSelectedItemsCount() == 0 ); + CHECK( !m_dvc->HasSelection() ); + CHECK( !m_dvc->GetSelection().IsOk() ); - CPPUNIT_ASSERT( !m_dvc->GetSelections(selections) ); - CPPUNIT_ASSERT( selections.empty() ); + CHECK( !m_dvc->GetSelections(selections) ); + CHECK( selections.empty() ); // Select one item. m_dvc->Select(m_child1); - CPPUNIT_ASSERT_EQUAL( 1, m_dvc->GetSelectedItemsCount() ); - CPPUNIT_ASSERT( m_dvc->HasSelection() ); - CPPUNIT_ASSERT( m_dvc->GetSelection().IsOk() ); - CPPUNIT_ASSERT_EQUAL( 1, m_dvc->GetSelections(selections) ); - CPPUNIT_ASSERT( selections[0] == 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 ); } -void DataViewCtrlTestCase::GetSelectionForMulti() +TEST_CASE_METHOD(MultiSelectDataViewCtrlTestCase, + "wxDVC::GetSelectionForMulti", + "[wxDataViewCtrl][select]") { wxDataViewItemArray selections; TestSelectionFor0and1(); - // Also test with more than one selected item. m_dvc->Select(m_child2); - CPPUNIT_ASSERT_EQUAL( 2, m_dvc->GetSelectedItemsCount() ); - CPPUNIT_ASSERT( m_dvc->HasSelection() ); - CPPUNIT_ASSERT( !m_dvc->GetSelection().IsOk() ); - CPPUNIT_ASSERT_EQUAL( 2, m_dvc->GetSelections(selections) ); - CPPUNIT_ASSERT( selections[1] == 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 ); } -void DataViewCtrlTestCase::GetSelectionForSingle() +TEST_CASE_METHOD(SingleSelectDataViewCtrlTestCase, + "wxDVC::SingleSelection", + "[wxDataViewCtrl][selection]") { - delete m_dvc; - Create(0); - 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 ); + } + + 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() ); +} + #endif //wxUSE_DATAVIEWCTRL diff --git a/tests/geometry/rect.cpp b/tests/geometry/rect.cpp index 07634a3ce6..94e67c9574 100644 --- a/tests/geometry/rect.cpp +++ b/tests/geometry/rect.cpp @@ -22,18 +22,7 @@ #include "wx/iosfwrap.h" -// ---------------------------------------------------------------------------- -// helper functions -// ---------------------------------------------------------------------------- - -// this operator is needed to use CPPUNIT_ASSERT_EQUAL with wxRects -std::ostream& operator<<(std::ostream& os, const wxRect& r) -{ - os << "{" - << r.x << ", " << r.y << ", " << r.width << ", " << r.height - << "}"; - return os; -} +#include "asserthelper.h" // ---------------------------------------------------------------------------- // test class