1 // ==========================================================================
  2 // Project:   SproutCore - JavaScript Application Framework
  3 // Copyright: ©2006-2011 Strobe Inc. and contributors.
  4 //            Portions ©2008-2011 Apple Inc. All rights reserved.
  5 // License:   Licensed under MIT license (see license.js)
  6 // ==========================================================================
  7 
  8 /**
  9   @namespace
 10 
 11   A Collection View Delegate is consulted by a `SC.CollectionView` to make
 12   policy decisions about certain behaviors such as selection control and
 13   drag and drop.  If you need to control other aspects of your data, you may
 14   also want to add the `SC.CollectionContent` mixin.
 15   
 16   To act as a Collection Delegate, just apply this mixin to your class.  You
 17   must then set the "delegate" property on the CollectionView to your object.
 18   
 19   Alternatively, if no delegate is set on a CollectionView, but the content 
 20   implements this mixin, the content object will be used as the delegate 
 21   instead.
 22   
 23   If you set an ArrayController or its arrangedObjects property as the content
 24   of a CollectionView, the ArrayController will automatically act as the 
 25   delegate for the view.
 26   
 27   @since SproutCore 1.0
 28 */
 29 SC.CollectionViewDelegate = {
 30 
 31   /**
 32     Walk like a duck. Used to detect the mixin by SC.CollectionView.
 33     
 34     @type Boolean
 35     @default YES
 36     @constant
 37   */
 38   isCollectionViewDelegate: YES,
 39 
 40 
 41   // ..........................................................
 42   // SELECTION
 43   // 
 44 
 45   /**
 46     This method will be called anytime the collection view is about to
 47     change the selection in response to user mouse clicks or keyboard events.
 48     
 49     You can use this method to adjust the proposed selection, eliminating any
 50     selected objects that cannot be selected.  The default implementation of
 51     this method simply returns the proposed selection.
 52     
 53     @param {SC.CollectionView} view the collection view
 54     @param {SC.IndexSet} sel Proposed array of selected objects.
 55     @returns {SC.IndexSet} Actual allow selection index set
 56   */
 57   collectionViewSelectionForProposedSelection: function(view, sel) {
 58     return sel;
 59   },
 60 
 61   /**
 62     Called by the collection when attempting to select an item.  Return the
 63     actual indexes you want to allow to be selected.  Return null to disallow
 64     the change.  The default allows all selection.
 65     
 66     @param {SC.CollectionView} view the view collection view
 67     @param {SC.IndexSet} indexes the indexes to be selected
 68     @param {Boolean} extend YES if the indexes will extend existing sel
 69     @returns {SC.IndexSet} allowed index set
 70   */
 71   collectionViewShouldSelectIndexes: function (view, indexes, extend) {
 72     return indexes;
 73   },
 74 
 75   /**
 76     Called by the collection when attempting to deselect an item.  Return the
 77     actual indexes you want to allow to be deselected.  Return `null` to
 78     disallow the change.  The default allows all selection.
 79     
 80     Note that you should not modify the passed in IndexSet.  clone it instead.
 81     
 82     @param {SC.CollectionView} view the view collection view
 83     @param {SC.IndexSet} indexes the indexes to be selected
 84     @returns {SC.IndexSet} allowed index set
 85   */
 86   collectionViewShouldDeselectIndexes: function (view, indexes) {
 87     return indexes;
 88   },
 89 
 90 
 91   // ..........................................................
 92   // EDIT OPERATIONS
 93   // 
 94 
 95   /**
 96     Called by the collection view whenever the `deleteSelection()` method is
 97     called.  You can implement this method to get fine-grained control over
 98     which items can be deleted.  To prevent deletion, return null.
 99     
100     This method is only called if canDeleteContent is `YES` on the collection
101     view.
102     
103     @param {SC.CollectionView} view the collection view
104     @param {SC.IndexSet} indexes proposed index set of items to delete.
105     @returns {SC.IndexSet} index set allowed to delete or null.
106   */
107   collectionViewShouldDeleteIndexes: function(view, indexes) {
108     return indexes;
109   },
110 
111   /**
112     Called by the collection view to actually delete the selected items.
113     
114     The default behavior will use standard array operators to delete the
115     indexes from the array. You can implement this method to provide your own
116     deletion method.
117     
118     If you simply want to control the items to be deleted, you should instead
119     implement `collectionViewShouldDeleteItems()`. This method will only be
120     called if canDeleteContent is `YES` and `collectionViewShouldDeleteIndexes()`
121     returns a non-empty index set
122     
123     @param {SC.CollectionView} view collection view
124     @param {SC.IndexSet} indexes the items to delete
125     @returns {Boolean} YES if the deletion was a success.
126   */
127   collectionViewDeleteContent: function(view, content, indexes) {
128     if (!content) return NO ;
129 
130     if (SC.typeOf(content.destroyAt) === SC.T_FUNCTION) {
131       content.destroyAt(indexes);
132       view.selectPreviousItem(NO, 1);
133       return YES ;
134     } else if (SC.typeOf(content.removeAt) === SC.T_FUNCTION) {
135       content.removeAt(indexes);
136       view.selectPreviousItem(NO, 1);
137       return YES;
138     } else {
139       return NO;
140     }
141   },
142 
143 
144   // ..........................................................
145   // DRAGGING
146   // 
147   
148   /**
149     Called by the collection view just before it starts a drag to give you
150     an opportunity to decide if the drag should be allowed.
151     
152     You can use this method to implement fine-grained control over when a
153     drag will be allowed and when it will not be allowed. For example, you
154     may enable content reordering but then implement this method to prevent
155     reordering of certain items in the view.
156     
157     The default implementation always returns `YES`.
158     
159     @param {SC.CollectionView} view the collection view
160     @returns {Boolean} YES to allow, NO to prevent it
161   */
162   collectionViewShouldBeginDrag: function(view) {
163     return YES;
164   },
165 
166   /**
167     Called by the collection view just before it starts a drag so that
168     you can provide the data types you would like to support in the data.
169     
170     You can implement this method to return an array of the data types you
171     will provide for the drag data.
172     
173     If you return `null` or an empty array, can you have set `canReorderContent`
174     to `YES` on the CollectionView, then the drag will go ahead but only
175     reordering will be allowed.  If `canReorderContent` is `NO`, then the drag
176     will not be allowed to start.
177     
178     If you simply want to control whether a drag is allowed or not, you
179     should instead implement `collectionViewShouldBeginDrag()`.
180     
181     The default returns an empty array.
182     
183     @param {SC.CollectionView} view the collection view to begin dragging.
184     @returns {Array} array of supported data types.
185   */
186   collectionViewDragDataTypes: function(view) {
187     return [];
188   },
189 
190   /**
191     Called by a collection view when a drag concludes to give you the option
192     to provide the drag data for the drop.
193     
194     This method should be implemented essentially as you would implement the
195     `dragDataForType()` if you were a drag data source.  You will never be asked
196     to provide drag data for a reorder event, only for other types of data.
197     
198     The default implementation returns null.
199     
200     @param view {SC.CollectionView} the collection view that initiated the drag
201     @param dataType {String} the data type to provide
202     @param drag {SC.Drag} the drag object
203     @returns {Object} the data object or null if the data could not be provided.
204   */
205   collectionViewDragDataForType: function(view, drag, dataType) {
206     return null;
207   },
208 
209   /**
210     Called once during a drag the first time view is entered. Return all
211     possible drag operations OR'd together.
212     
213     @param {SC.CollectionView} view the collection view that initiated the drag
214     @param {SC.Drag} drag the drag object
215     @param {Number} proposedDragOperations proposed logical OR of allowed drag operations.
216     @returns {Number} the allowed drag operations. Defaults to op
217   */
218   collectionViewComputeDragOperations: function(view, drag, proposedDragOperations) {
219     return proposedDragOperations;
220   },
221 
222   /**
223     Called by the collection view during a drag to let you determine the
224     kind and location of a drop you might want to accept.
225     
226     You can override this method to implement fine-grained control over how
227     and when a dragged item is allowed to be dropped into a collection view.
228     
229     This method will be called by the collection view both to determine in
230     general which operations you might support and specifically the operations
231     you would support if the user dropped an item over a specific location.
232     
233     If the `proposedDropOperation` parameter is `SC.DROP_ON` or `SC.DROP_BEFORE`,
234     then the `proposedInsertionPoint` will be a non-negative value and you
235     should determine the specific operations you will support if the user
236     dropped the drag item at that point.
237     
238     If you do not like the proposed drop operation or insertion point, you
239     can override these properties as well by setting the `proposedDropOperation`
240     and `proposedInsertionIndex` properties on the collection view during this
241     method. These properties are ignored all other times.
242     
243     @param {SC.CollectionView} view the collection view
244     @param {SC.Drag} drag the current drag object
245     @param {Number} op proposed logical OR of allowed drag operations.
246     @param {Number} proposedInsertionIndex an index into the content array representing the proposed insertion point.
247     @param {String} proposedDropOperation the proposed drop operation. Will be one of SC.DROP_ON, SC.DROP_BEFORE, or SC.DROP_ANY.
248     @returns the allowed drag operation. Defaults to op
249   */
250   collectionViewValidateDragOperation: function(view, drag, op, proposedInsertionIndex, proposedDropOperation) {
251     // don't allow dropping on by default
252     return (proposedDropOperation & SC.DROP_ON) ? SC.DRAG_NONE : op ;
253   },
254   
255   /**
256     Called by the collection view to actually accept a drop.  This method will
257     only be invoked AFTER your `validateDrop method has been called to
258     determine if you want to even allow the drag operation to go through.
259     
260     You should actually make changes to the data model if needed here and
261     then return the actual drag operation that was performed. If you return
262     `SC.DRAG_NONE` and the dragOperation was `SC.DRAG_REORDER`, then the default
263     reorder behavior will be provided by the collection view.
264     
265     @param {SC.CollectionView} view
266     @param {SC.Drag} drag the current drag object
267     @param {Number} op proposed logical OR of allowed drag operations.
268     @param {Number} proposedInsertionIndex an index into the content array representing the proposed insertion point.
269     @param {String} proposedDropOperation the proposed drop operation.  Will be one of SC.DROP_ON, SC.DROP_BEFORE, or SC.DROP_ANY.
270     @returns the allowed drag operation. Defaults to proposedDragOperation
271   */
272   collectionViewPerformDragOperation: function(view, drag, op, proposedInsertionIndex, proposedDropOperation) {
273     return SC.DRAG_NONE;
274   },
275   
276   /**
277     Renders a drag view for the passed content indexes. If you return null
278     from this, then a default drag view will be generated for you.
279     
280     The default implementation returns null.
281     
282     @param {SC.CollectionView} view
283     @param {SC.IndexSet} dragContent
284     @returns {SC.View} view or null
285   */
286   collectionViewDragViewFor: function(view, dragContent) {
287     return null;
288   },
289 
290   /**
291     Allows the ghost view created in `collectionViewDragViewFor` to be displayed
292     like a cursor instead of the default implementation. This sets the view 
293     origin to be the location of the mouse cursor.
294     
295     @type Boolean
296     @default NO
297   */
298   ghostActsLikeCursor: NO
299   
300 };
301