Add ellipsization support to wxDataViewCtrl.

Implemented ellipsization in the generic, GTK and both OS X Carbon and Cocoa
versions but it currently doesn't work well in GTK as it changes the item
alignment unconditionally, this will need to be fixed later.

The behaviour for the columns is currently inconsistent between ports too:
under MSW they (natively) use wxELLIPSIZE_END, under GTK -- wxELLIPSIZE_NONE
and under OS X the same ellipsization mode as the column contents, i.e.
wxELLIPSIZE_MIDDLE by default.

git-svn-id: https://svn.wxwidgets.org/svn/wx/wxWidgets/trunk@62433 c3d73ce0-8a6f-49c7-b76d-6d57e0e08775
This commit is contained in:
Vadim Zeitlin 2009-10-16 21:35:26 +00:00
parent 355ce7adea
commit c937bcac0f
15 changed files with 292 additions and 32 deletions

View File

@ -435,6 +435,7 @@ All (GUI):
- Added wxMouseEventsManager.
- Building OpenGL library is now enabled by default.
- Fixed wxDataViewCtrl::Set{Foreground,Background}Colour().
- Added wxDataViewRenderer::EnableEllipsize().
- Improve wxTreeCtrl::ScrollTo() in generic version (Raanan Barzel).
- Added wxFont::[Make]{Bold,Italic,Smaller,Larger} and Scale[d]() methods.
- Added wxDC::CopyAttributes() and use it in wxBufferedDC.

View File

@ -39,8 +39,11 @@ enum wxEllipsizeFlags
wxELLIPSIZE_FLAGS_EXPAND_TABS
};
// NB: Don't change the order of these values, they're the same as in
// PangoEllipsizeMode enum.
enum wxEllipsizeMode
{
wxELLIPSIZE_NONE,
wxELLIPSIZE_START,
wxELLIPSIZE_MIDDLE,
wxELLIPSIZE_END

View File

@ -411,7 +411,7 @@ public:
wxDataViewRendererBase( const wxString &varianttype,
wxDataViewCellMode mode = wxDATAVIEW_CELL_INERT,
int alignment = wxDVR_DEFAULT_ALIGNMENT );
~wxDataViewRendererBase();
virtual ~wxDataViewRendererBase();
virtual bool Validate( wxVariant& WXUNUSED(value) )
{ return true; }
@ -435,6 +435,14 @@ public:
virtual void SetAlignment( int align ) = 0;
virtual int GetAlignment() const = 0;
// enable or disable (if called with wxELLIPSIZE_NONE) replacing parts of
// the item text (hence this only makes sense for renderers showing
// text...) with ellipsis in order to make it fit the column width
virtual void EnableEllipsize(wxEllipsizeMode mode = wxELLIPSIZE_MIDDLE) = 0;
void DisableEllipsize() { EnableEllipsize(wxELLIPSIZE_NONE); }
virtual wxEllipsizeMode GetEllipsizeMode() const = 0;
// in-place editing
virtual bool HasEditorCtrl() const
{ return false; }

View File

@ -57,6 +57,11 @@ public:
virtual void SetAlignment( int align );
virtual int GetAlignment() const;
virtual void EnableEllipsize(wxEllipsizeMode mode = wxELLIPSIZE_MIDDLE)
{ m_ellipsizeMode = mode; }
virtual wxEllipsizeMode GetEllipsizeMode() const
{ return m_ellipsizeMode; }
virtual void SetMode( wxDataViewCellMode mode )
{ m_mode=mode; }
virtual wxDataViewCellMode GetMode() const
@ -110,6 +115,8 @@ private:
int m_align;
wxDataViewCellMode m_mode;
wxEllipsizeMode m_ellipsizeMode;
DECLARE_DYNAMIC_CLASS_NO_COPY(wxDataViewRenderer)
};

View File

@ -38,6 +38,8 @@ public:
virtual void SetAlignment( int align );
virtual int GetAlignment() const;
virtual void EnableEllipsize(wxEllipsizeMode mode = wxELLIPSIZE_MIDDLE);
virtual wxEllipsizeMode GetEllipsizeMode() const;
// GTK-specific implementation
// ---------------------------

View File

@ -219,12 +219,16 @@ public:
m_origTextColour = [textColour retain];
}
// The ellipsization mode which we need to set for each cell being rendered.
void SetEllipsizeMode(wxEllipsizeMode mode) { m_ellipsizeMode = mode; }
wxEllipsizeMode GetEllipsizeMode() const { return m_ellipsizeMode; }
// Set the line break mode for the given cell using our m_ellipsizeMode
void ApplyLineBreakMode(NSCell *cell);
private:
void Init()
{
m_origFont = NULL;
m_origTextColour = NULL;
}
// common part of all ctors
void Init();
id m_Item; // item NOT owned by renderer
id m_Object; // object that can be used by renderer for storing special data (owned by renderer)
@ -237,6 +241,8 @@ private:
// we own those if they're non-NULL
NSFont *m_origFont;
NSColor *m_origTextColour;
wxEllipsizeMode m_ellipsizeMode;
};
// ============================================================================

View File

@ -61,6 +61,9 @@ public:
return true;
}
virtual void EnableEllipsize(wxEllipsizeMode mode = wxELLIPSIZE_MIDDLE);
virtual wxEllipsizeMode GetEllipsizeMode() const;
//
// implementation
//

View File

@ -47,6 +47,9 @@ enum wxEllipsizeFlags
*/
enum wxEllipsizeMode
{
/// Don't ellipsize the text at all. @since 2.9.1
wxELLIPSIZE_NONE,
/// Put the ellipsis at the start of the string, if the string needs ellipsization.
wxELLIPSIZE_START,

View File

@ -1060,11 +1060,49 @@ public:
wxDataViewCellMode mode = wxDATAVIEW_CELL_INERT,
int align = wxDVR_DEFAULT_ALIGNMENT );
/**
Enable or disable replacing parts of the item text with ellipsis to
make it fit the column width.
This method only makes sense for the renderers working with text, such
as wxDataViewTextRenderer or wxDataViewIconTextRenderer.
By default wxELLIPSIZE_MIDDLE is used.
@param mode
Ellipsization mode, use wxELLIPSIZE_NONE to disable.
@since 2.9.1
*/
void EnableEllipsize(wxEllipsizeMode mode = wxELLIPSIZE_MIDDLE);
/**
Disable replacing parts of the item text with ellipsis.
If ellipsizing is disabled, the string will be truncated if it doesn't
fit.
This is the same as @code EnableEllipsize(wxELLIPSIZE_NONE) @endcode.
@since 2.9.1
*/
void DisableEllipsize();
/**
Returns the alignment. See SetAlignment()
*/
virtual int GetAlignment() const;
/**
Returns the ellipsize mode used by the renderer.
If the return value is wxELLIPSIZE_NONE, the text is simply truncated
if it doesn't fit.
@see EnableEllipsize()
*/
wxEllipsizeMode GetEllipsizeMode() const;
/**
Returns the cell mode.
*/

View File

@ -338,7 +338,8 @@ MyListModel::MyListModel() :
static const unsigned NUMBER_REAL_ITEMS = 100;
m_textColValues.reserve(NUMBER_REAL_ITEMS);
for (unsigned int i = 0; i < NUMBER_REAL_ITEMS; i++)
m_textColValues.push_back("first row with long label to test ellipsization");
for (unsigned int i = 1; i < NUMBER_REAL_ITEMS; i++)
{
m_textColValues.push_back(wxString::Format("real row %d", i));
}

View File

@ -245,6 +245,8 @@ wxString wxControlBase::DoEllipsizeSingleLine(const wxString& curLine, const wxD
wxASSERT_MSG(!curLine.Contains('\n'),
"Use Ellipsize() instead!");
wxASSERT_MSG( mode != wxELLIPSIZE_NONE, "shouldn't be called at all then" );
// NOTE: this function assumes that any mnemonic/tab character has already
// been handled if it was necessary to handle them (see Ellipsize())
@ -348,6 +350,7 @@ wxString wxControlBase::DoEllipsizeSingleLine(const wxString& curLine, const wxD
}
break;
case wxELLIPSIZE_NONE:
default:
wxFAIL_MSG("invalid ellipsize mode");
return curLine;

View File

@ -612,6 +612,7 @@ wxDataViewRenderer::wxDataViewRenderer( const wxString &varianttype,
m_dc = NULL;
m_align = align;
m_mode = mode;
m_ellipsizeMode = wxELLIPSIZE_MIDDLE;
}
wxDataViewRenderer::~wxDataViewRenderer()
@ -752,7 +753,22 @@ wxDataViewCustomRenderer::RenderText(wxDC& dc,
rectText.x += xoffset;
rectText.width -= xoffset;
dc.DrawLabel(text, rectText, align);
// check if we want to ellipsize the text if it doesn't fit
wxString ellipsizedText;
if ( GetEllipsizeMode() != wxELLIPSIZE_NONE )
{
ellipsizedText = wxControl::Ellipsize
(
text,
dc,
GetEllipsizeMode(),
rect.width,
wxELLIPSIZE_FLAGS_NONE
);
}
dc.DrawLabel(ellipsizedText.empty() ? text : ellipsizedText,
rectText, align);
}
// ---------------------------------------------------------

View File

@ -1691,6 +1691,35 @@ int wxDataViewRenderer::GetAlignment() const
return m_alignment;
}
void wxDataViewRenderer::EnableEllipsize(wxEllipsizeMode mode)
{
if ( gtk_check_version(2, 6, 0) != NULL )
return;
// we use the same values in wxEllipsizeMode as PangoEllipsizeMode so we
// can just cast between them
GValue gvalue = { 0, };
g_value_init( &gvalue, PANGO_TYPE_ELLIPSIZE_MODE );
g_value_set_enum( &gvalue, static_cast<PangoEllipsizeMode>(mode) );
g_object_set_property( G_OBJECT(m_renderer), "ellipsize", &gvalue );
g_value_unset( &gvalue );
}
wxEllipsizeMode wxDataViewRenderer::GetEllipsizeMode() const
{
if ( gtk_check_version(2, 6, 0) != NULL )
return wxELLIPSIZE_NONE;
GValue gvalue = { 0, };
g_value_init( &gvalue, PANGO_TYPE_ELLIPSIZE_MODE );
g_object_get_property( G_OBJECT(m_renderer), "ellipsize", &gvalue );
wxEllipsizeMode
mode = static_cast<wxEllipsizeMode>(g_value_get_enum( &gvalue ));
g_value_unset( &gvalue );
return mode;
}
void
wxDataViewRenderer::GtkOnTextEdited(const gchar *itempath, const wxString& str)
{

View File

@ -2186,35 +2186,114 @@ void wxDataViewRenderer::SetAlignment(int align)
m_alignment = align;
}
namespace
{
// get the browser control or NULL if anything went wrong (it's not supposed to
// so we assert if it did)
wxMacDataViewDataBrowserListViewControl *
GetBrowserFromCol(wxDataViewColumn *col)
{
wxCHECK_MSG( col, NULL, "should have a valid column" );
wxDataViewCtrl * const dvc = col->GetOwner();
wxCHECK_MSG( dvc, NULL, "column must be associated with the control" );
return static_cast<wxMacDataViewDataBrowserListViewControl *>(dvc->GetPeer());
}
} // anonymous namespace
void wxDataViewRenderer::SetMode(wxDataViewCellMode mode)
{
wxDataViewColumn* dataViewColumnPtr;
wxDataViewColumn * const col = GetOwner();
wxMacDataViewDataBrowserListViewControl * const
browser = GetBrowserFromCol(col);
wxCHECK_RET( browser, "must be fully initialized" );
const DataBrowserPropertyID colID = col->GetNativeData()->GetPropertyID();
m_mode = mode;
dataViewColumnPtr = GetOwner();
if (dataViewColumnPtr != NULL)
{
wxDataViewCtrl* dataViewCtrlPtr(dataViewColumnPtr->GetOwner());
DataBrowserPropertyFlags flags;
verify_noerr( browser->GetPropertyFlags(colID, &flags) );
if (dataViewCtrlPtr != NULL)
if ( (mode == wxDATAVIEW_CELL_EDITABLE) ||
(mode == wxDATAVIEW_CELL_ACTIVATABLE) )
flags |= kDataBrowserPropertyIsEditable;
else
flags &= ~kDataBrowserPropertyIsEditable;
verify_noerr( browser->SetPropertyFlags(colID, flags) );
}
void wxDataViewRenderer::EnableEllipsize(wxEllipsizeMode mode)
{
wxDataViewColumn * const col = GetOwner();
wxMacDataViewDataBrowserListViewControl * const
browser = GetBrowserFromCol(col);
wxCHECK_RET( browser, "must be fully initialized" );
const DataBrowserPropertyID colID = col->GetNativeData()->GetPropertyID();
DataBrowserPropertyFlags flags;
browser->GetPropertyFlags(colID, &flags);
flags &= ~(kDataBrowserDoNotTruncateText |
kDataBrowserTruncateTextAtStart |
kDataBrowserTruncateTextMiddle |
kDataBrowserTruncateTextAtEnd);
int flagToSet = 0;
switch ( mode )
{
wxMacDataViewDataBrowserListViewControlPointer macDataViewListCtrlPtr(dynamic_cast<wxMacDataViewDataBrowserListViewControlPointer>(dataViewCtrlPtr->GetPeer()));
case wxELLIPSIZE_NONE:
flagToSet = kDataBrowserDoNotTruncateText;
break;
if (macDataViewListCtrlPtr != NULL)
{
DataBrowserPropertyFlags flags;
case wxELLIPSIZE_START:
flagToSet = kDataBrowserTruncateTextAtStart;
break;
verify_noerr(macDataViewListCtrlPtr->GetPropertyFlags(dataViewColumnPtr->GetNativeData()->GetPropertyID(),&flags));
if ((mode == wxDATAVIEW_CELL_EDITABLE) ||
(mode == wxDATAVIEW_CELL_ACTIVATABLE))
flags |= kDataBrowserPropertyIsEditable;
else
flags &= ~kDataBrowserPropertyIsEditable;
verify_noerr(macDataViewListCtrlPtr->SetPropertyFlags(dataViewColumnPtr->GetNativeData()->GetPropertyID(),flags));
}
case wxELLIPSIZE_MIDDLE:
flagToSet = kDataBrowserTruncateTextMiddle;
break;
case wxELLIPSIZE_END:
flagToSet = kDataBrowserTruncateTextAtEnd;
break;
}
}
wxCHECK_RET( flagToSet, "unknown wxEllipsizeMode value" );
flags |= flagToSet;
verify_noerr( browser->SetPropertyFlags(colID, flags) );
}
wxEllipsizeMode wxDataViewRenderer::GetEllipsizeMode() const
{
wxDataViewColumn * const col = GetOwner();
wxMacDataViewDataBrowserListViewControl * const
browser = GetBrowserFromCol(col);
wxCHECK_MSG( browser, wxELLIPSIZE_NONE, "must be fully initialized" );
const DataBrowserPropertyID colID = col->GetNativeData()->GetPropertyID();
DataBrowserPropertyFlags flags;
browser->GetPropertyFlags(colID, &flags);
if ( flags & kDataBrowserDoNotTruncateText )
return wxELLIPSIZE_NONE;
if ( flags & kDataBrowserTruncateTextAtStart )
return wxELLIPSIZE_START;
if ( flags & kDataBrowserTruncateTextMiddle )
return wxELLIPSIZE_MIDDLE;
if ( flags & kDataBrowserTruncateTextAtEnd )
return wxELLIPSIZE_END;
wxFAIL_MSG( "unknown flags" );
return wxELLIPSIZE_NONE;
}
void wxDataViewRenderer::SetNativeData(wxDataViewRendererNativeData* newNativeDataPtr)

View File

@ -159,13 +159,19 @@ static NSTableColumn* CreateNativeColumn(wxDataViewColumn const* columnPtr)
// setting the visibility:
[nativeColumn setHidden:static_cast<BOOL>(columnPtr->IsHidden())];
#endif
wxDataViewRendererNativeData * const
renderData = columnPtr->GetRenderer()->GetNativeData();
// setting the header:
[[nativeColumn headerCell] setAlignment:ConvertToNativeHorizontalTextAlignment(columnPtr->GetAlignment())];
[[nativeColumn headerCell] setStringValue:[[wxCFStringRef(columnPtr->GetTitle()).AsNSString() retain] autorelease]];
renderData->ApplyLineBreakMode([nativeColumn headerCell]);
// setting data cell's properties:
[[nativeColumn dataCell] setWraps:NO];
// setting the default data cell:
[nativeColumn setDataCell:columnPtr->GetRenderer()->GetNativeData()->GetColumnCell()];
[nativeColumn setDataCell:renderData->GetColumnCell()];
// setting the editablility:
bool const dataCellIsEditable = (columnPtr->GetRenderer()->GetMode() == wxDATAVIEW_CELL_EDITABLE);
@ -1026,7 +1032,6 @@ wxWidgetImplType* CreateDataView(wxWindowMac* wxpeer, wxWindowMac* WXUNUSED(pare
if (self != nil)
{
// initializing the text part:
[self setLineBreakMode:NSLineBreakByTruncatingMiddle];
[self setSelectable:YES];
// initializing the image part:
image = nil;
@ -1566,6 +1571,7 @@ wxWidgetImplType* CreateDataView(wxWindowMac* wxpeer, wxWindowMac* WXUNUSED(pare
if ( colText )
[cell setTextColor:colText];
data->SetColumnPtr(tableColumn);
data->SetItem(item);
data->SetItemCell(cell);
@ -2120,6 +2126,47 @@ wxDataObjectComposite* wxCocoaDataViewControl::GetDnDDataObjects(NSData* dataObj
}
}
// ----------------------------------------------------------------------------
// wxDataViewRendererNativeData
// ----------------------------------------------------------------------------
void wxDataViewRendererNativeData::Init()
{
m_origFont = NULL;
m_origTextColour = NULL;
m_ellipsizeMode = wxELLIPSIZE_MIDDLE;
if ( m_ColumnCell )
ApplyLineBreakMode(m_ColumnCell);
}
void wxDataViewRendererNativeData::ApplyLineBreakMode(NSCell *cell)
{
NSLineBreakMode nsMode = NSLineBreakByWordWrapping;
switch ( m_ellipsizeMode )
{
case wxELLIPSIZE_NONE:
nsMode = NSLineBreakByClipping;
break;
case wxELLIPSIZE_START:
nsMode = NSLineBreakByTruncatingHead;
break;
case wxELLIPSIZE_MIDDLE:
nsMode = NSLineBreakByTruncatingMiddle;
break;
case wxELLIPSIZE_END:
nsMode = NSLineBreakByTruncatingTail;
break;
}
wxASSERT_MSG( nsMode != NSLineBreakByWordWrapping, "unknown wxEllipsizeMode" );
[cell setLineBreakMode: nsMode];
}
// ---------------------------------------------------------
// wxDataViewRenderer
// ---------------------------------------------------------
@ -2152,6 +2199,22 @@ void wxDataViewRenderer::SetNativeData(wxDataViewRendererNativeData* newNativeDa
m_NativeDataPtr = newNativeDataPtr;
}
void wxDataViewRenderer::EnableEllipsize(wxEllipsizeMode mode)
{
// we need to store this value to apply it to the columns headerCell in
// CreateNativeColumn()
GetNativeData()->SetEllipsizeMode(mode);
// but we may already apply it to the column cell which will be used for
// this column
GetNativeData()->ApplyLineBreakMode(GetNativeData()->GetColumnCell());
}
wxEllipsizeMode wxDataViewRenderer::GetEllipsizeMode() const
{
return GetNativeData()->GetEllipsizeMode();
}
IMPLEMENT_ABSTRACT_CLASS(wxDataViewRenderer,wxDataViewRendererBase)
// ---------------------------------------------------------
@ -2182,7 +2245,6 @@ wxDataViewTextRenderer::wxDataViewTextRenderer(wxString const& varianttype, wxDa
cell = [[NSTextFieldCell alloc] init];
[cell setAlignment:ConvertToNativeHorizontalTextAlignment(align)];
[cell setLineBreakMode:NSLineBreakByTruncatingMiddle];
SetNativeData(new wxDataViewRendererNativeData(cell));
[cell release];
}
@ -2285,7 +2347,6 @@ wxDataViewDateRenderer::wxDataViewDateRenderer(wxString const& varianttype, wxDa
[dateFormatter setDateStyle:NSDateFormatterShortStyle];
cell = [[NSTextFieldCell alloc] init];
[cell setFormatter:dateFormatter];
[cell setLineBreakMode:NSLineBreakByTruncatingMiddle];
SetNativeData(new wxDataViewRendererNativeData(cell,[NSDate dateWithString:@"2000-12-30 20:00:00 +0000"]));
[cell release];
[dateFormatter release];