diff --git a/docs/changes.txt b/docs/changes.txt index d79c1041c9..1c86ad19ec 100644 --- a/docs/changes.txt +++ b/docs/changes.txt @@ -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. diff --git a/include/wx/control.h b/include/wx/control.h index f947f0f203..8f1a1767c1 100644 --- a/include/wx/control.h +++ b/include/wx/control.h @@ -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 diff --git a/include/wx/dataview.h b/include/wx/dataview.h index 9c6205d95e..ef5cc45dbd 100644 --- a/include/wx/dataview.h +++ b/include/wx/dataview.h @@ -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; } diff --git a/include/wx/generic/dataview.h b/include/wx/generic/dataview.h index ec81d7e6de..a9c57e1c4e 100644 --- a/include/wx/generic/dataview.h +++ b/include/wx/generic/dataview.h @@ -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) }; diff --git a/include/wx/gtk/dataview.h b/include/wx/gtk/dataview.h index d217d2f88e..8ed57ec0d8 100644 --- a/include/wx/gtk/dataview.h +++ b/include/wx/gtk/dataview.h @@ -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 // --------------------------- diff --git a/include/wx/osx/cocoa/dataview.h b/include/wx/osx/cocoa/dataview.h index a5aa4509b3..1fffc75bd7 100644 --- a/include/wx/osx/cocoa/dataview.h +++ b/include/wx/osx/cocoa/dataview.h @@ -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; }; // ============================================================================ diff --git a/include/wx/osx/dataview.h b/include/wx/osx/dataview.h index e564a42b70..a484880222 100644 --- a/include/wx/osx/dataview.h +++ b/include/wx/osx/dataview.h @@ -61,6 +61,9 @@ public: return true; } + virtual void EnableEllipsize(wxEllipsizeMode mode = wxELLIPSIZE_MIDDLE); + virtual wxEllipsizeMode GetEllipsizeMode() const; + // // implementation // diff --git a/interface/wx/control.h b/interface/wx/control.h index 9dcbf8f136..d96a9bc28c 100644 --- a/interface/wx/control.h +++ b/interface/wx/control.h @@ -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, diff --git a/interface/wx/dataview.h b/interface/wx/dataview.h index 4e6639b172..a76c28ae67 100644 --- a/interface/wx/dataview.h +++ b/interface/wx/dataview.h @@ -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. */ diff --git a/samples/dataview/mymodels.cpp b/samples/dataview/mymodels.cpp index 4be852d6ff..0424b24936 100644 --- a/samples/dataview/mymodels.cpp +++ b/samples/dataview/mymodels.cpp @@ -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)); } diff --git a/src/common/ctrlcmn.cpp b/src/common/ctrlcmn.cpp index b4a0eb6e65..f7145a78a5 100644 --- a/src/common/ctrlcmn.cpp +++ b/src/common/ctrlcmn.cpp @@ -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; diff --git a/src/generic/datavgen.cpp b/src/generic/datavgen.cpp index bdeadffd36..1eeff556ad 100644 --- a/src/generic/datavgen.cpp +++ b/src/generic/datavgen.cpp @@ -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); } // --------------------------------------------------------- diff --git a/src/gtk/dataview.cpp b/src/gtk/dataview.cpp index d951f74ea9..3f8eb008c1 100644 --- a/src/gtk/dataview.cpp +++ b/src/gtk/dataview.cpp @@ -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(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(g_value_get_enum( &gvalue )); + g_value_unset( &gvalue ); + + return mode; +} + void wxDataViewRenderer::GtkOnTextEdited(const gchar *itempath, const wxString& str) { diff --git a/src/osx/carbon/dataview.cpp b/src/osx/carbon/dataview.cpp index c3724b0048..38f94678c9 100644 --- a/src/osx/carbon/dataview.cpp +++ b/src/osx/carbon/dataview.cpp @@ -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(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(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) diff --git a/src/osx/cocoa/dataview.mm b/src/osx/cocoa/dataview.mm index 50ca83236f..127e4bb2a2 100644 --- a/src/osx/cocoa/dataview.mm +++ b/src/osx/cocoa/dataview.mm @@ -159,13 +159,19 @@ static NSTableColumn* CreateNativeColumn(wxDataViewColumn const* columnPtr) // setting the visibility: [nativeColumn setHidden:static_cast(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];