1 /////////////////////////////////////////////////////////////////////////////
2 // Name:        wx/osx/cocoa/dataview.h
3 // Purpose:     wxDataViewCtrl native implementation header for carbon
4 // Author:
5 // Copyright:   (c) 2009
6 // Licence:     wxWindows licence
7 /////////////////////////////////////////////////////////////////////////////
8 
9 #ifndef _WX_DATAVIEWCTRL_COCOOA_H_
10 #define _WX_DATAVIEWCTRL_COCOOA_H_
11 
12 #include "wx/defs.h"
13 
14 #import <Cocoa/Cocoa.h>
15 
16 #include "wx/osx/core/dataview.h"
17 #include "wx/osx/private.h"
18 
19 // Forward declaration
20 class wxCocoaDataViewControl;
21 
22 /*
23     Dramatis personae:
24 
25     [vertical arrows indicate inheritance, horizontal -- aggregation]
26 
27 
28         wxWindow ---> wxWidgetCocoaImpl  wxDataViewWidgetImpl   NSOutlineView
29             |                 \                  /                   |
30             |                  \                /                    |
31             |                   \              /                     |
32             v                   \/            \/                     v
33      wxDataViewCtrl -------> wxCocoaDataViewControl <-------> wxCocoaOutlineView
34 
35 
36      The right most classes are Objective-C only and can't be used from (pure)
37      C++ code.
38  */
39 
40 // ============================================================================
41 // wxPointerObject: simply stores a pointer, without taking its ownership
42 // ============================================================================
43 
44 // Two pointer objects are equal if the containing pointers are equal. This
45 // means also that the hash value of a pointer object depends only on the
46 // stored pointer.
47 
48 @interface wxPointerObject : NSObject
49 {
50     void* pointer;
51 }
52 
53     -(id) initWithPointer:(void*)initPointer;
54 
55     -(void*) pointer;
56     -(void)  setPointer:(void*)newPointer;
57 @end
58 
59 // ============================================================================
60 // wxSortDescriptorObject: helper class to use native sorting facilities
61 // ============================================================================
62 
63 @interface wxSortDescriptorObject : NSSortDescriptor<NSCopying>
64 {
65     wxDataViewColumn* columnPtr; // pointer to the sorting column
66 
67     wxDataViewModel* modelPtr; // pointer to model
68 }
69 
70     -(id)
71     initWithModelPtr:(wxDataViewModel*)initModelPtr
72         sortingColumnPtr:(wxDataViewColumn*)initColumnPtr
73         ascending:(BOOL)sortAscending;
74 
75     -(wxDataViewColumn*) columnPtr;
76     -(wxDataViewModel*) modelPtr;
77 
78     -(void) setColumnPtr:(wxDataViewColumn*)newColumnPtr;
79     -(void) setModelPtr:(wxDataViewModel*)newModelPtr;
80 @end
81 
82 // ============================================================================
83 // wxDataViewColumnNativeData: extra data for wxDataViewColumn
84 // ============================================================================
85 
86 class wxDataViewColumnNativeData
87 {
88 public:
wxDataViewColumnNativeData()89     wxDataViewColumnNativeData() : m_NativeColumnPtr(NULL)
90     {
91     }
92 
wxDataViewColumnNativeData(NSTableColumn * initNativeColumnPtr)93     wxDataViewColumnNativeData(NSTableColumn* initNativeColumnPtr)
94         : m_NativeColumnPtr(initNativeColumnPtr)
95     {
96     }
97 
GetNativeColumnPtr()98     NSTableColumn* GetNativeColumnPtr() const
99     {
100         return m_NativeColumnPtr;
101     }
102 
SetNativeColumnPtr(NSTableColumn * newNativeColumnPtr)103     void SetNativeColumnPtr(NSTableColumn* newNativeColumnPtr)
104     {
105         m_NativeColumnPtr = newNativeColumnPtr;
106     }
107 
108 private:
109     // not owned by us
110     NSTableColumn* m_NativeColumnPtr;
111 };
112 
113 // ============================================================================
114 // wxDataViewRendererNativeData: extra data for wxDataViewRenderer
115 // ============================================================================
116 
117 class wxDataViewRendererNativeData
118 {
119 public:
wxDataViewRendererNativeData()120     wxDataViewRendererNativeData()
121         : m_Object(NULL), m_ColumnCell(NULL)
122     {
123         Init();
124     }
125 
wxDataViewRendererNativeData(NSCell * initColumnCell)126     wxDataViewRendererNativeData(NSCell* initColumnCell)
127         : m_Object(NULL), m_ColumnCell([initColumnCell retain])
128     {
129         Init();
130     }
131 
wxDataViewRendererNativeData(NSCell * initColumnCell,id initObject)132     wxDataViewRendererNativeData(NSCell* initColumnCell, id initObject)
133         : m_Object([initObject retain]), m_ColumnCell([initColumnCell retain])
134     {
135         Init();
136     }
137 
~wxDataViewRendererNativeData()138     ~wxDataViewRendererNativeData()
139     {
140         [m_ColumnCell release];
141         [m_Object release];
142 
143         [m_origFont release];
144         [m_origTextColour release];
145     }
146 
GetColumnCell()147     NSCell* GetColumnCell() const { return m_ColumnCell; }
GetColumnPtr()148     NSTableColumn* GetColumnPtr() const { return m_TableColumnPtr; }
GetItem()149     id GetItem() const { return m_Item; }
GetItemCell()150     NSCell* GetItemCell() const { return m_ItemCell; }
GetObject()151     id GetObject() const { return m_Object; }
152 
SetColumnCell(NSCell * newCell)153     void SetColumnCell(NSCell* newCell)
154     {
155         [newCell retain];
156         [m_ColumnCell release];
157         m_ColumnCell = newCell;
158     }
SetColumnPtr(NSTableColumn * newColumnPtr)159     void SetColumnPtr(NSTableColumn* newColumnPtr)
160     {
161         m_TableColumnPtr = newColumnPtr;
162     }
SetItem(id newItem)163     void SetItem(id newItem)
164     {
165         m_Item = newItem;
166     }
SetItemCell(NSCell * newCell)167     void SetItemCell(NSCell* newCell)
168     {
169         m_ItemCell = newCell;
170     }
SetObject(id newObject)171     void SetObject(id newObject)
172     {
173         [newObject retain];
174         [m_Object release];
175         m_Object = newObject;
176     }
177 
178     // The original cell font and text colour stored here are NULL by default
179     // and are only initialized to the values retrieved from the cell when we
180     // change them from wxCocoaOutlineView:willDisplayCell:forTableColumn:item:
181     // which calls our SaveOriginalXXX() methods before changing the cell
182     // attributes.
183     //
184     // This allows us to avoid doing anything for the columns without any
185     // attributes but still be able to restore the correct attributes for the
186     // ones that do.
GetOriginalFont()187     NSFont *GetOriginalFont() const { return m_origFont; }
GetOriginalTextColour()188     NSColor *GetOriginalTextColour() const { return m_origTextColour; }
189 
SaveOriginalFont(NSFont * font)190     void SaveOriginalFont(NSFont *font)
191     {
192         m_origFont = [font retain];
193     }
194 
SaveOriginalTextColour(NSColor * textColour)195     void SaveOriginalTextColour(NSColor *textColour)
196     {
197         m_origTextColour = [textColour retain];
198     }
199 
200     // The ellipsization mode which we need to set for each cell being rendered.
SetEllipsizeMode(wxEllipsizeMode mode)201     void SetEllipsizeMode(wxEllipsizeMode mode) { m_ellipsizeMode = mode; }
GetEllipsizeMode()202     wxEllipsizeMode GetEllipsizeMode() const { return m_ellipsizeMode; }
203 
204     // Set the line break mode for the given cell using our m_ellipsizeMode
205     void ApplyLineBreakMode(NSCell *cell);
206 
207 private:
208     // common part of all ctors
209     void Init();
210 
211     id m_Item;   // item NOT owned by renderer
212 
213     // object that can be used by renderer for storing special data (owned by
214     // renderer)
215     id m_Object;
216 
217     NSCell* m_ColumnCell; // column's cell is owned by renderer
218     NSCell* m_ItemCell;   // item's cell is NOT owned by renderer
219 
220     NSTableColumn* m_TableColumnPtr; // column NOT owned by renderer
221 
222     // we own those if they're non-NULL
223     NSFont *m_origFont;
224     NSColor *m_origTextColour;
225 
226     wxEllipsizeMode m_ellipsizeMode;
227 };
228 
229 // ============================================================================
230 // wxCocoaOutlineDataSource
231 // ============================================================================
232 
233 // This class implements the data source delegate for the outline view.
234 // As only an informal protocol exists this class inherits from NSObject only.
235 //
236 // As mentioned in the documentation for NSOutlineView the native control does
237 // not own any data. Therefore, it has to be done by the data source.
238 // Unfortunately, wxWidget's data source is a C++ data source but
239 // NSOutlineDataSource requires objects as data. Therefore, the data (or better
240 // the native item objects) have to be stored additionally in the native data
241 // source.
242 // NSOutlineView requires quick access to the item objects and quick linear
243 // access to an item's children. This requires normally a hash type of storage
244 // for the item object itself and an array structure for each item's children.
245 // This means that basically two times the whole structure of wxWidget's model
246 // class has to be stored.
247 // This implementation is using a compromise: all items that are in use by the
248 // control are stored in a set (from there they can be easily retrieved) and
249 // owned by the set. Furthermore, children of the last parent are stored
250 // in a linear list.
251 //
252 @interface wxCocoaOutlineDataSource : NSObject wxOSX_10_6_AND_LATER(<NSOutlineViewDataSource>)
253 {
254     // descriptors specifying the sorting (currently the array only holds one
255     // object only)
256     NSArray* sortDescriptors;
257 
258     NSMutableArray* children; // buffered children
259 
260     NSMutableSet* items; // stores all items that are in use by the control
261 
262     wxCocoaDataViewControl* implementation;
263 
264     wxDataViewModel* model;
265 
266     // parent of the buffered children; the object is owned
267     wxPointerObject* currentParentItem;
268 }
269 
270     // methods of informal protocol:
271     -(BOOL)
272     outlineView:(NSOutlineView*)outlineView
273         acceptDrop:(id<NSDraggingInfo>)info
274         item:(id)item
275         childIndex:(NSInteger)index;
276 
277     -(id)
278     outlineView:(NSOutlineView*)outlineView
279         child:(NSInteger)index
280         ofItem:(id)item;
281 
282     -(id)
283     outlineView:(NSOutlineView*)outlineView
284         objectValueForTableColumn:(NSTableColumn*)tableColumn
285         byItem:(id)item;
286 
287     -(BOOL)
288     outlineView:(NSOutlineView*)outlineView
289         isItemExpandable:(id)item;
290 
291     -(NSInteger)
292     outlineView:(NSOutlineView*)outlineView
293         numberOfChildrenOfItem:(id)item;
294 
295     -(NSDragOperation)
296     outlineView:(NSOutlineView*)outlineView
297         validateDrop:(id<NSDraggingInfo>)info
298         proposedItem:(id)item
299         proposedChildIndex:(NSInteger)index;
300 
301     -(BOOL)
302     outlineView:(NSOutlineView*)outlineView
303         writeItems:(NSArray*)items
304         toPasteboard:(NSPasteboard*)pasteboard;
305 
306     // buffer for items handling
307     -(void)             addToBuffer:(wxPointerObject*)item;
308     -(void)             clearBuffer;
309     // returns the item in the buffer that has got the same pointer as "item",
310     // if such an item does not exist nil is returned
311     -(wxPointerObject*) getDataViewItemFromBuffer:(const wxDataViewItem&)item;
312     -(wxPointerObject*) getItemFromBuffer:(wxPointerObject*)item;
313     -(BOOL)             isInBuffer:(wxPointerObject*)item;
314     -(void)             removeFromBuffer:(wxPointerObject*)item;
315 
316     // buffered children handling
317     -(void)             appendChild:(wxPointerObject*)item;
318     -(void)             clearChildren;
319     -(wxPointerObject*) getChild:(NSUInteger)index;
320     -(NSUInteger)       getChildCount;
321     -(void)             removeChild:(NSUInteger)index;
322 
323     // buffer handling
324     -(void) clearBuffers;
325 
326     // sorting
327     -(NSArray*) sortDescriptors;
328     -(void)     setSortDescriptors:(NSArray*)newSortDescriptors;
329 
330     // access to wxWidgets variables
331     -(wxPointerObject*) currentParentItem;
332     -(wxCocoaDataViewControl*) implementation;
333     -(wxDataViewModel*) model;
334     -(void) setCurrentParentItem:(wxPointerObject*)newCurrentParentItem;
335     -(void) setImplementation:(wxCocoaDataViewControl*)newImplementation;
336     -(void) setModel:(wxDataViewModel*)newModel;
337 
338     // other methods
339     -(void)
340     bufferItem:(wxPointerObject*)parentItem
341         withChildren:(wxDataViewItemArray*)dataViewChildrenPtr;
342 @end
343 
344 // ============================================================================
345 // wxCustomCell: used for custom renderers
346 // ============================================================================
347 
348 @interface wxCustomCell : NSTextFieldCell
349 {
350 }
351 
352     -(NSSize) cellSize;
353 @end
354 
355 // ============================================================================
356 // wxImageTextCell
357 // ============================================================================
358 //
359 // As the native cocoa environment does not have a cell displaying an icon/
360 // image and text at the same time, it has to be implemented by the user.
361 // This implementation follows the implementation of Chuck Pisula in Apple's
362 // DragNDropOutline sample application.
363 // Although in wxDataViewCtrl icons are used on OSX icons do not exist for
364 // display. Therefore, the cell is also called wxImageTextCell.
365 // Instead of displaying images of any size (which is possible) this cell uses
366 // a fixed size for displaying the image. Larger images are scaled to fit
367 // into their reserved space. Smaller or not existing images use the fixed
368 // reserved size and are scaled if necessary.
369 //
370 @interface wxImageTextCell : NSTextFieldCell
371 {
372 @private
373     CGFloat xImageShift;    // shift for the image in x-direction from border
374     CGFloat spaceImageText; // space between image and text
375 
376     NSImage* image; // the image itself
377 
378     NSSize imageSize; // largest size of the image; default size is (16, 16)
379 
380     // the text alignment is used to align the whole cell (image and text)
381     NSTextAlignment cellAlignment;
382 }
383 
384     -(NSTextAlignment) alignment;
385     -(void) setAlignment:(NSTextAlignment)newAlignment;
386 
387     -(NSImage*) image;
388     -(void) setImage:(NSImage*)newImage;
389 
390     -(NSSize) imageSize;
391     -(void) setImageSize:(NSSize) newImageSize;
392 
393     -(NSSize) cellSize;
394 @end
395 
396 // ============================================================================
397 // wxCocoaOutlineView
398 // ============================================================================
399 
400 @interface wxCocoaOutlineView : NSOutlineView wxOSX_10_6_AND_LATER(<NSOutlineViewDelegate>)
401 {
402 @private
403     // column and row of the cell being edited or -1 if none
404     int currentlyEditedColumn,
405         currentlyEditedRow;
406 
407     wxCocoaDataViewControl* implementation;
408 }
409 
410     -(wxCocoaDataViewControl*) implementation;
411     -(void) setImplementation:(wxCocoaDataViewControl*) newImplementation;
412 @end
413 
414 // ============================================================================
415 // wxCocoaDataViewControl
416 // ============================================================================
417 
418 // This is the internal interface class between wxDataViewCtrl (wxWidget) and
419 // the native source view (Mac OS X cocoa).
420 class wxCocoaDataViewControl : public wxWidgetCocoaImpl,
421                                public wxDataViewWidgetImpl
422 {
423 public:
424     // constructors / destructor
425     wxCocoaDataViewControl(wxWindow* peer,
426                            const wxPoint& pos,
427                            const wxSize& size,
428                            long style);
429     virtual ~wxCocoaDataViewControl();
430 
GetDataViewCtrl()431     wxDataViewCtrl* GetDataViewCtrl() const
432     {
433         return static_cast<wxDataViewCtrl*>(GetWXPeer());
434     }
435 
436     // column related methods (inherited from wxDataViewWidgetImpl)
437     virtual bool ClearColumns();
438     virtual bool DeleteColumn(wxDataViewColumn* columnPtr);
439     virtual void DoSetExpanderColumn(wxDataViewColumn const* columnPtr);
440     virtual wxDataViewColumn* GetColumn(unsigned int pos) const;
441     virtual int GetColumnPosition(wxDataViewColumn const* columnPtr) const;
442     virtual bool InsertColumn(unsigned int pos, wxDataViewColumn* columnPtr);
443     virtual void FitColumnWidthToContent(unsigned int pos);
444 
445     // item related methods (inherited from wxDataViewWidgetImpl)
446     virtual bool Add(const wxDataViewItem& parent, const wxDataViewItem& item);
447     virtual bool Add(const wxDataViewItem& parent,
448                      const wxDataViewItemArray& items);
449     virtual void Collapse(const wxDataViewItem& item);
450     virtual void EnsureVisible(const wxDataViewItem& item,
451                                wxDataViewColumn const* columnPtr);
452     virtual void Expand(const wxDataViewItem& item);
453     virtual unsigned int GetCount() const;
454     virtual wxRect GetRectangle(const wxDataViewItem& item,
455                                 wxDataViewColumn const* columnPtr);
456     virtual bool IsExpanded(const wxDataViewItem& item) const;
457     virtual bool Reload();
458     virtual bool Remove(const wxDataViewItem& parent,
459                         const wxDataViewItem& item);
460     virtual bool Remove(const wxDataViewItem& parent,
461                         const wxDataViewItemArray& item);
462     virtual bool Update(const wxDataViewColumn* columnPtr);
463     virtual bool Update(const wxDataViewItem& parent,
464                         const wxDataViewItem& item);
465     virtual bool Update(const wxDataViewItem& parent,
466                         const wxDataViewItemArray& items);
467 
468     // model related methods
469     virtual bool AssociateModel(wxDataViewModel* model);
470 
471     //
472     // selection related methods (inherited from wxDataViewWidgetImpl)
473     //
474     virtual wxDataViewItem GetCurrentItem() const;
475     virtual void SetCurrentItem(const wxDataViewItem& item);
476     virtual wxDataViewColumn *GetCurrentColumn() const;
477     virtual int  GetSelectedItemsCount() const;
478     virtual int  GetSelections(wxDataViewItemArray& sel)   const;
479     virtual bool IsSelected(const wxDataViewItem& item) const;
480     virtual void Select(const wxDataViewItem& item);
481     virtual void SelectAll();
482     virtual void Unselect(const wxDataViewItem& item);
483     virtual void UnselectAll();
484 
485     //
486     // sorting related methods
487     //
488     virtual wxDataViewColumn* GetSortingColumn () const;
489     virtual void Resort();
490 
491     //
492     // other methods (inherited from wxDataViewWidgetImpl)
493     //
494     virtual void DoSetIndent(int indent);
495     virtual void HitTest(const wxPoint& point,
496                          wxDataViewItem& item,
497                          wxDataViewColumn*& columnPtr) const;
498     virtual void SetRowHeight(const wxDataViewItem& item, unsigned int height);
499     virtual void OnSize();
500 
501     virtual void StartEditor( const wxDataViewItem & item, unsigned int column );
502 
503     // drag & drop helper methods
504     wxDataFormat GetDnDDataFormat(wxDataObjectComposite* dataObjects);
505     wxDataObjectComposite* GetDnDDataObjects(NSData* dataObject) const;
506 
507     // Cocoa-specific helpers
508     id GetItemAtRow(int row) const;
509 
510 private:
511     void InitOutlineView(long style);
512 
513     wxCocoaOutlineDataSource* m_DataSource;
514 
515     wxCocoaOutlineView* m_OutlineView;
516 };
517 
518 #endif // _WX_DATAVIEWCTRL_COCOOA_H_
519