Merge branch 'dvc-getitemrect'
Make wxDataViewCtrl::GetIremRect() work under all platforms and improve tests, documentation and fix a couple of other problems in the same code area. See https://github.com/wxWidgets/wxWidgets/pull/1015
This commit is contained in:
@@ -149,6 +149,7 @@ wxGTK:
|
|||||||
- Fix the build with glib < 2.32 (e.g. CentOS 6).
|
- Fix the build with glib < 2.32 (e.g. CentOS 6).
|
||||||
- Fix field widths in wxStatusBar showing a size grip.
|
- Fix field widths in wxStatusBar showing a size grip.
|
||||||
- Fill column value in wxEVT_DATAVIEW_ITEM_ACTIVATED events.
|
- Fill column value in wxEVT_DATAVIEW_ITEM_ACTIVATED events.
|
||||||
|
- Implement wxDataViewCtrl::GetItemRect() (MrMeesek).
|
||||||
|
|
||||||
wxMSW:
|
wxMSW:
|
||||||
|
|
||||||
|
@@ -1446,8 +1446,14 @@ public:
|
|||||||
int GetIndent() const;
|
int GetIndent() const;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
Returns item rectangle. Coordinates of the rectangle are specified in
|
Returns item rectangle.
|
||||||
wxDataViewCtrl client area coordinates.
|
|
||||||
|
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
|
@param item
|
||||||
A valid item.
|
A valid item.
|
||||||
@@ -1455,10 +1461,6 @@ public:
|
|||||||
If non-@NULL, the rectangle returned corresponds to the
|
If non-@NULL, the rectangle returned corresponds to the
|
||||||
intersection of the item with the specified column. If @NULL, the
|
intersection of the item with the specified column. If @NULL, the
|
||||||
rectangle spans all the columns.
|
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,
|
virtual wxRect GetItemRect(const wxDataViewItem& item,
|
||||||
const wxDataViewColumn* col = NULL) const;
|
const wxDataViewColumn* col = NULL) const;
|
||||||
@@ -1556,6 +1558,9 @@ public:
|
|||||||
|
|
||||||
/**
|
/**
|
||||||
Return @true if the item is expanded.
|
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;
|
virtual bool IsExpanded(const wxDataViewItem& item) const;
|
||||||
|
|
||||||
|
@@ -3468,55 +3468,53 @@ int wxDataViewMainWindow::GetLineHeight( unsigned int row ) const
|
|||||||
class RowToTreeNodeJob: public DoJob
|
class RowToTreeNodeJob: public DoJob
|
||||||
{
|
{
|
||||||
public:
|
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
|
virtual int operator() ( wxDataViewTreeNode * node ) wxOVERRIDE
|
||||||
{
|
{
|
||||||
current ++;
|
if( m_current == m_row)
|
||||||
if( current == static_cast<int>(row))
|
|
||||||
{
|
{
|
||||||
ret = node;
|
m_ret = node;
|
||||||
return DoJob::DONE;
|
return DoJob::DONE;
|
||||||
}
|
}
|
||||||
|
|
||||||
if( node->GetSubTreeCount() + current < static_cast<int>(row) )
|
if( node->GetSubTreeCount() + m_current < m_row )
|
||||||
{
|
{
|
||||||
current += node->GetSubTreeCount();
|
m_current += node->GetSubTreeCount() + 1;
|
||||||
return DoJob::SKIP_SUBTREE;
|
return DoJob::SKIP_SUBTREE;
|
||||||
}
|
}
|
||||||
else
|
else
|
||||||
{
|
{
|
||||||
parent = node;
|
|
||||||
|
|
||||||
// If the current node has only leaf children, we can find the
|
// If the current node has only leaf children, we can find the
|
||||||
// desired node directly. This can speed up finding the node
|
// desired node directly. This can speed up finding the node
|
||||||
// in some cases, and will have a very good effect for list views.
|
// in some cases, and will have a very good effect for list views.
|
||||||
if ( node->HasChildren() &&
|
if ( node->HasChildren() &&
|
||||||
(int)node->GetChildNodes().size() == node->GetSubTreeCount() )
|
(int)node->GetChildNodes().size() == node->GetSubTreeCount() )
|
||||||
{
|
{
|
||||||
const int index = static_cast<int>(row) - current - 1;
|
const int index = m_row - m_current - 1;
|
||||||
ret = node->GetChildNodes()[index];
|
m_ret = node->GetChildNodes()[index];
|
||||||
return DoJob::DONE;
|
return DoJob::DONE;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
m_current++;
|
||||||
|
|
||||||
return DoJob::CONTINUE;
|
return DoJob::CONTINUE;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
wxDataViewTreeNode * GetResult() const
|
wxDataViewTreeNode * GetResult() const
|
||||||
{ return ret; }
|
{ return m_ret; }
|
||||||
|
|
||||||
private:
|
private:
|
||||||
unsigned int row;
|
const int m_row;
|
||||||
int current;
|
int m_current;
|
||||||
wxDataViewTreeNode * ret;
|
wxDataViewTreeNode* m_ret;
|
||||||
wxDataViewTreeNode * parent;
|
|
||||||
};
|
};
|
||||||
|
|
||||||
wxDataViewTreeNode * wxDataViewMainWindow::GetTreeNodeByRow(unsigned int row) const
|
wxDataViewTreeNode * wxDataViewMainWindow::GetTreeNodeByRow(unsigned int row) const
|
||||||
@@ -3526,7 +3524,7 @@ wxDataViewTreeNode * wxDataViewMainWindow::GetTreeNodeByRow(unsigned int row) co
|
|||||||
if ( row == (unsigned)-1 )
|
if ( row == (unsigned)-1 )
|
||||||
return NULL;
|
return NULL;
|
||||||
|
|
||||||
RowToTreeNodeJob job( row , -2, m_root );
|
RowToTreeNodeJob job(static_cast<int>(row));
|
||||||
Walker( m_root , job );
|
Walker( m_root , job );
|
||||||
return job.GetResult();
|
return job.GetResult();
|
||||||
}
|
}
|
||||||
@@ -3815,10 +3813,16 @@ wxRect wxDataViewMainWindow::GetItemRect( const wxDataViewItem & item,
|
|||||||
xpos = 0;
|
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
|
// we have to take an expander column into account and compute its indentation
|
||||||
// to get the correct x position where the actual text is
|
// to get the correct x position where the actual text is
|
||||||
int indent = 0;
|
int indent = 0;
|
||||||
int row = GetRowByItem(item);
|
|
||||||
if (!IsList() &&
|
if (!IsList() &&
|
||||||
(column == 0 || GetExpanderColumnOrFirstOne(GetOwner()) == column) )
|
(column == 0 || GetExpanderColumnOrFirstOne(GetOwner()) == column) )
|
||||||
{
|
{
|
||||||
@@ -3835,6 +3839,14 @@ wxRect wxDataViewMainWindow::GetItemRect( const wxDataViewItem & item,
|
|||||||
GetOwner()->CalcScrolledPosition( itemRect.x, itemRect.y,
|
GetOwner()->CalcScrolledPosition( itemRect.x, itemRect.y,
|
||||||
&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;
|
return itemRect;
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -3856,43 +3868,49 @@ int wxDataViewMainWindow::RecalculateCount() const
|
|||||||
class ItemToRowJob : public DoJob
|
class ItemToRowJob : public DoJob
|
||||||
{
|
{
|
||||||
public:
|
public:
|
||||||
ItemToRowJob(const wxDataViewItem& item_, wxVector<wxDataViewItem>::reverse_iterator iter)
|
// As with RowToTreeNodeJob above, we initialize m_current to -1 because
|
||||||
: m_iter(iter),
|
// the first node passed to our operator() is the root node which is not
|
||||||
item(item_)
|
// 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<wxDataViewItem>::reverse_iterator iter)
|
||||||
|
: m_item(item), m_iter(iter), m_current(-1)
|
||||||
{
|
{
|
||||||
ret = -1;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
// Maybe binary search will help to speed up this process
|
// Maybe binary search will help to speed up this process
|
||||||
virtual int operator() ( wxDataViewTreeNode * node) wxOVERRIDE
|
virtual int operator() ( wxDataViewTreeNode * node) wxOVERRIDE
|
||||||
{
|
{
|
||||||
ret ++;
|
if( node->GetItem() == m_item )
|
||||||
if( node->GetItem() == item )
|
|
||||||
{
|
{
|
||||||
return DoJob::DONE;
|
return DoJob::DONE;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// Is this node the next (grand)parent of the item we're looking for?
|
||||||
if( node->GetItem() == *m_iter )
|
if( node->GetItem() == *m_iter )
|
||||||
{
|
{
|
||||||
|
// Search for the next (grand)parent now and skip this item itself.
|
||||||
++m_iter;
|
++m_iter;
|
||||||
|
++m_current;
|
||||||
return DoJob::CONTINUE;
|
return DoJob::CONTINUE;
|
||||||
}
|
}
|
||||||
else
|
else
|
||||||
{
|
{
|
||||||
ret += node->GetSubTreeCount();
|
// Skip this node and all its currently visible children.
|
||||||
|
m_current += node->GetSubTreeCount() + 1;
|
||||||
return DoJob::SKIP_SUBTREE;
|
return DoJob::SKIP_SUBTREE;
|
||||||
}
|
}
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
// the row number is begin from zero
|
|
||||||
int GetResult() const
|
int GetResult() const
|
||||||
{ return ret -1; }
|
{ return m_current; }
|
||||||
|
|
||||||
private:
|
private:
|
||||||
|
const wxDataViewItem m_item;
|
||||||
wxVector<wxDataViewItem>::reverse_iterator m_iter;
|
wxVector<wxDataViewItem>::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.
|
// 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
|
// so if we want to start at the root node, we have to iterate backwards through the vector
|
||||||
ItemToRowJob job( item, parentChain.rbegin() );
|
ItemToRowJob job( item, parentChain.rbegin() );
|
||||||
Walker( m_root, job );
|
if ( !Walker( m_root, job ) )
|
||||||
|
return -1;
|
||||||
|
|
||||||
return job.GetResult();
|
return job.GetResult();
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@@ -5841,8 +5861,11 @@ wxRect wxDataViewCtrl::GetItemRect( const wxDataViewItem & item,
|
|||||||
// Convert position from the main window coordinates to the control coordinates.
|
// Convert position from the main window coordinates to the control coordinates.
|
||||||
// (They can be different due to the presence of the header.).
|
// (They can be different due to the presence of the header.).
|
||||||
wxRect r = m_clientArea->GetItemRect(item, column);
|
wxRect r = m_clientArea->GetItemRect(item, column);
|
||||||
|
if ( r.width || r.height )
|
||||||
|
{
|
||||||
const wxPoint ctrlPos = ScreenToClient(m_clientArea->ClientToScreen(r.GetPosition()));
|
const wxPoint ctrlPos = ScreenToClient(m_clientArea->ClientToScreen(r.GetPosition()));
|
||||||
r.SetPosition(ctrlPos);
|
r.SetPosition(ctrlPos);
|
||||||
|
}
|
||||||
return r;
|
return r;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@@ -5289,10 +5289,71 @@ void wxDataViewCtrl::HitTest(const wxPoint& point,
|
|||||||
}
|
}
|
||||||
|
|
||||||
wxRect
|
wxRect
|
||||||
wxDataViewCtrl::GetItemRect(const wxDataViewItem& WXUNUSED(item),
|
wxDataViewCtrl::GetItemRect(const wxDataViewItem& item,
|
||||||
const wxDataViewColumn *WXUNUSED(column)) const
|
const wxDataViewColumn *column) const
|
||||||
{
|
{
|
||||||
|
if ( !item )
|
||||||
return wxRect();
|
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)
|
bool wxDataViewCtrl::SetRowHeight(int rowHeight)
|
||||||
|
@@ -2295,8 +2295,33 @@ wxDataViewItem wxCocoaDataViewControl::GetTopItem() const
|
|||||||
|
|
||||||
wxRect wxCocoaDataViewControl::GetRectangle(const wxDataViewItem& item, const wxDataViewColumn *columnPtr)
|
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]]]);
|
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
|
bool wxCocoaDataViewControl::IsExpanded(const wxDataViewItem& item) const
|
||||||
|
@@ -547,10 +547,24 @@ wxDataViewColumn *wxDataViewCtrl::GetCurrentColumn() const
|
|||||||
|
|
||||||
wxRect wxDataViewCtrl::GetItemRect(wxDataViewItem const& item, wxDataViewColumn const* columnPtr) const
|
wxRect wxDataViewCtrl::GetItemRect(wxDataViewItem const& item, wxDataViewColumn const* columnPtr) const
|
||||||
{
|
{
|
||||||
if (item.IsOk() && (columnPtr != NULL))
|
if ( !item.IsOk() )
|
||||||
return GetDataViewPeer()->GetRectangle(item,columnPtr);
|
|
||||||
else
|
|
||||||
return wxRect();
|
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
|
int wxDataViewCtrl::GetSelectedItemsCount() const
|
||||||
|
@@ -67,3 +67,11 @@ std::ostream& operator<<(std::ostream& os, const wxPoint& p)
|
|||||||
|
|
||||||
return os;
|
return os;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
std::ostream& operator<<(std::ostream& os, const wxRect& r)
|
||||||
|
{
|
||||||
|
os << "{"
|
||||||
|
<< r.x << ", " << r.y << " " << r.width << "*" << r.height
|
||||||
|
<< "}";
|
||||||
|
return os;
|
||||||
|
}
|
||||||
|
@@ -29,16 +29,12 @@ namespace wxTestPrivate
|
|||||||
std::ostream& operator<<(std::ostream& os, const ColourChannel& cc);
|
std::ostream& operator<<(std::ostream& os, const ColourChannel& cc);
|
||||||
} // wxTestPrivate namespace
|
} // 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);
|
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);
|
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);
|
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 wxPoint& p);
|
||||||
|
std::ostream& operator<<(std::ostream& os, const wxRect& r);
|
||||||
|
|
||||||
#endif
|
#endif
|
||||||
|
@@ -22,35 +22,19 @@
|
|||||||
#include "wx/dataview.h"
|
#include "wx/dataview.h"
|
||||||
|
|
||||||
#include "testableframe.h"
|
#include "testableframe.h"
|
||||||
|
#include "asserthelper.h"
|
||||||
|
|
||||||
// ----------------------------------------------------------------------------
|
// ----------------------------------------------------------------------------
|
||||||
// test class
|
// test class
|
||||||
// ----------------------------------------------------------------------------
|
// ----------------------------------------------------------------------------
|
||||||
|
|
||||||
class DataViewCtrlTestCase : public CppUnit::TestCase
|
class DataViewCtrlTestCase
|
||||||
{
|
{
|
||||||
public:
|
public:
|
||||||
DataViewCtrlTestCase() { }
|
explicit DataViewCtrlTestCase(long style);
|
||||||
|
~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();
|
|
||||||
|
|
||||||
|
protected:
|
||||||
void TestSelectionFor0and1();
|
void TestSelectionFor0and1();
|
||||||
|
|
||||||
// the dataview control itself
|
// the dataview control itself
|
||||||
@@ -65,17 +49,29 @@ private:
|
|||||||
wxDECLARE_NO_COPY_CLASS(DataViewCtrlTestCase);
|
wxDECLARE_NO_COPY_CLASS(DataViewCtrlTestCase);
|
||||||
};
|
};
|
||||||
|
|
||||||
// register in the unnamed registry so that these tests are run by default
|
class SingleSelectDataViewCtrlTestCase : public DataViewCtrlTestCase
|
||||||
CPPUNIT_TEST_SUITE_REGISTRATION( DataViewCtrlTestCase );
|
{
|
||||||
|
public:
|
||||||
|
SingleSelectDataViewCtrlTestCase()
|
||||||
|
: DataViewCtrlTestCase(wxDV_SINGLE)
|
||||||
|
{
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
// also include in its own registry so that these tests can be run alone
|
class MultiSelectDataViewCtrlTestCase : public DataViewCtrlTestCase
|
||||||
CPPUNIT_TEST_SUITE_NAMED_REGISTRATION( DataViewCtrlTestCase, "DataViewCtrlTestCase" );
|
{
|
||||||
|
public:
|
||||||
|
MultiSelectDataViewCtrlTestCase()
|
||||||
|
: DataViewCtrlTestCase(wxDV_MULTIPLE)
|
||||||
|
{
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
// ----------------------------------------------------------------------------
|
// ----------------------------------------------------------------------------
|
||||||
// test initialization
|
// test initialization
|
||||||
// ----------------------------------------------------------------------------
|
// ----------------------------------------------------------------------------
|
||||||
|
|
||||||
void DataViewCtrlTestCase::Create(long style)
|
DataViewCtrlTestCase::DataViewCtrlTestCase(long style)
|
||||||
{
|
{
|
||||||
m_dvc = new wxDataViewTreeCtrl(wxTheApp->GetTopWindow(),
|
m_dvc = new wxDataViewTreeCtrl(wxTheApp->GetTopWindow(),
|
||||||
wxID_ANY,
|
wxID_ANY,
|
||||||
@@ -88,33 +84,24 @@ void DataViewCtrlTestCase::Create(long style)
|
|||||||
m_grandchild = m_dvc->AppendItem(m_child1, "grandchild");
|
m_grandchild = m_dvc->AppendItem(m_child1, "grandchild");
|
||||||
m_child2 = m_dvc->AppendItem(m_root, "child2");
|
m_child2 = m_dvc->AppendItem(m_root, "child2");
|
||||||
|
|
||||||
m_dvc->SetSize(400, 200);
|
m_dvc->Layout();
|
||||||
m_dvc->ExpandAncestors(m_root);
|
m_dvc->Expand(m_root);
|
||||||
m_dvc->Refresh();
|
m_dvc->Refresh();
|
||||||
m_dvc->Update();
|
m_dvc->Update();
|
||||||
}
|
}
|
||||||
|
|
||||||
void DataViewCtrlTestCase::setUp()
|
DataViewCtrlTestCase::~DataViewCtrlTestCase()
|
||||||
{
|
|
||||||
Create(wxDV_MULTIPLE);
|
|
||||||
}
|
|
||||||
|
|
||||||
void DataViewCtrlTestCase::tearDown()
|
|
||||||
{
|
{
|
||||||
delete m_dvc;
|
delete m_dvc;
|
||||||
m_dvc = NULL;
|
|
||||||
|
|
||||||
m_root =
|
|
||||||
m_child1 =
|
|
||||||
m_child2 =
|
|
||||||
m_grandchild = wxDataViewItem();
|
|
||||||
}
|
}
|
||||||
|
|
||||||
// ----------------------------------------------------------------------------
|
// ----------------------------------------------------------------------------
|
||||||
// the tests themselves
|
// the tests themselves
|
||||||
// ----------------------------------------------------------------------------
|
// ----------------------------------------------------------------------------
|
||||||
|
|
||||||
void DataViewCtrlTestCase::DeleteSelected()
|
TEST_CASE_METHOD(MultiSelectDataViewCtrlTestCase,
|
||||||
|
"wxDVC::DeleteSelected",
|
||||||
|
"[wxDataViewCtrl][delete]")
|
||||||
{
|
{
|
||||||
wxDataViewItemArray sel;
|
wxDataViewItemArray sel;
|
||||||
sel.push_back(m_child1);
|
sel.push_back(m_child1);
|
||||||
@@ -128,14 +115,18 @@ void DataViewCtrlTestCase::DeleteSelected()
|
|||||||
m_dvc->GetSelections(sel);
|
m_dvc->GetSelections(sel);
|
||||||
|
|
||||||
// m_child1 and its children should be removed from the selection now
|
// m_child1 and its children should be removed from the selection now
|
||||||
CPPUNIT_ASSERT_EQUAL( 1, sel.size() );
|
REQUIRE( sel.size() == 1 );
|
||||||
CPPUNIT_ASSERT( sel[0] == m_child2 );
|
CHECK( sel[0] == m_child2 );
|
||||||
}
|
}
|
||||||
|
|
||||||
void DataViewCtrlTestCase::DeleteNotSelected()
|
TEST_CASE_METHOD(MultiSelectDataViewCtrlTestCase,
|
||||||
|
"wxDVC::DeleteNotSelected",
|
||||||
|
"[wxDataViewCtrl][delete]")
|
||||||
{
|
{
|
||||||
// TODO not working on OS X as expected
|
// TODO not working on OS X as expected
|
||||||
#ifndef __WXOSX__
|
#ifdef __WXOSX__
|
||||||
|
WARN("Disabled under MacOS because this test currently fails");
|
||||||
|
#else
|
||||||
wxDataViewItemArray sel;
|
wxDataViewItemArray sel;
|
||||||
sel.push_back(m_child1);
|
sel.push_back(m_child1);
|
||||||
sel.push_back(m_grandchild);
|
sel.push_back(m_grandchild);
|
||||||
@@ -147,9 +138,9 @@ void DataViewCtrlTestCase::DeleteNotSelected()
|
|||||||
m_dvc->GetSelections(sel);
|
m_dvc->GetSelections(sel);
|
||||||
|
|
||||||
// m_child1 and its children should be unaffected
|
// m_child1 and its children should be unaffected
|
||||||
CPPUNIT_ASSERT_EQUAL( 2, sel.size() );
|
REQUIRE( sel.size() == 2 );
|
||||||
CPPUNIT_ASSERT( sel[0] == m_child1 );
|
CHECK( sel[0] == m_child1 );
|
||||||
CPPUNIT_ASSERT( sel[1] == m_grandchild );
|
CHECK( sel[1] == m_grandchild );
|
||||||
#endif
|
#endif
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -158,44 +149,117 @@ void DataViewCtrlTestCase::TestSelectionFor0and1()
|
|||||||
wxDataViewItemArray selections;
|
wxDataViewItemArray selections;
|
||||||
|
|
||||||
// Initially there is no selection.
|
// Initially there is no selection.
|
||||||
CPPUNIT_ASSERT_EQUAL( 0, m_dvc->GetSelectedItemsCount() );
|
CHECK( m_dvc->GetSelectedItemsCount() == 0 );
|
||||||
CPPUNIT_ASSERT( !m_dvc->HasSelection() );
|
CHECK( !m_dvc->HasSelection() );
|
||||||
CPPUNIT_ASSERT( !m_dvc->GetSelection().IsOk() );
|
CHECK( !m_dvc->GetSelection().IsOk() );
|
||||||
|
|
||||||
CPPUNIT_ASSERT( !m_dvc->GetSelections(selections) );
|
CHECK( !m_dvc->GetSelections(selections) );
|
||||||
CPPUNIT_ASSERT( selections.empty() );
|
CHECK( selections.empty() );
|
||||||
|
|
||||||
// Select one item.
|
// Select one item.
|
||||||
m_dvc->Select(m_child1);
|
m_dvc->Select(m_child1);
|
||||||
CPPUNIT_ASSERT_EQUAL( 1, m_dvc->GetSelectedItemsCount() );
|
CHECK( m_dvc->GetSelectedItemsCount() == 1 );
|
||||||
CPPUNIT_ASSERT( m_dvc->HasSelection() );
|
CHECK( m_dvc->HasSelection() );
|
||||||
CPPUNIT_ASSERT( m_dvc->GetSelection().IsOk() );
|
CHECK( m_dvc->GetSelection().IsOk() );
|
||||||
CPPUNIT_ASSERT_EQUAL( 1, m_dvc->GetSelections(selections) );
|
REQUIRE( m_dvc->GetSelections(selections) == 1 );
|
||||||
CPPUNIT_ASSERT( selections[0] == m_child1 );
|
CHECK( selections[0] == m_child1 );
|
||||||
}
|
}
|
||||||
|
|
||||||
void DataViewCtrlTestCase::GetSelectionForMulti()
|
TEST_CASE_METHOD(MultiSelectDataViewCtrlTestCase,
|
||||||
|
"wxDVC::GetSelectionForMulti",
|
||||||
|
"[wxDataViewCtrl][select]")
|
||||||
{
|
{
|
||||||
wxDataViewItemArray selections;
|
wxDataViewItemArray selections;
|
||||||
|
|
||||||
TestSelectionFor0and1();
|
TestSelectionFor0and1();
|
||||||
|
|
||||||
// Also test with more than one selected item.
|
|
||||||
m_dvc->Select(m_child2);
|
m_dvc->Select(m_child2);
|
||||||
|
|
||||||
CPPUNIT_ASSERT_EQUAL( 2, m_dvc->GetSelectedItemsCount() );
|
CHECK( m_dvc->GetSelectedItemsCount() == 2 );
|
||||||
CPPUNIT_ASSERT( m_dvc->HasSelection() );
|
CHECK( m_dvc->HasSelection() );
|
||||||
CPPUNIT_ASSERT( !m_dvc->GetSelection().IsOk() );
|
CHECK( !m_dvc->GetSelection().IsOk() );
|
||||||
CPPUNIT_ASSERT_EQUAL( 2, m_dvc->GetSelections(selections) );
|
REQUIRE( m_dvc->GetSelections(selections) == 2 );
|
||||||
CPPUNIT_ASSERT( selections[1] == m_child2 );
|
CHECK( selections[1] == m_child2 );
|
||||||
}
|
}
|
||||||
|
|
||||||
void DataViewCtrlTestCase::GetSelectionForSingle()
|
TEST_CASE_METHOD(SingleSelectDataViewCtrlTestCase,
|
||||||
|
"wxDVC::SingleSelection",
|
||||||
|
"[wxDataViewCtrl][selection]")
|
||||||
{
|
{
|
||||||
delete m_dvc;
|
|
||||||
Create(0);
|
|
||||||
|
|
||||||
TestSelectionFor0and1();
|
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
|
#endif //wxUSE_DATAVIEWCTRL
|
||||||
|
@@ -22,18 +22,7 @@
|
|||||||
|
|
||||||
#include "wx/iosfwrap.h"
|
#include "wx/iosfwrap.h"
|
||||||
|
|
||||||
// ----------------------------------------------------------------------------
|
#include "asserthelper.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;
|
|
||||||
}
|
|
||||||
|
|
||||||
// ----------------------------------------------------------------------------
|
// ----------------------------------------------------------------------------
|
||||||
// test class
|
// test class
|
||||||
|
Reference in New Issue
Block a user