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 /**
 10   An instance of this controller is created for every page where designers
 11   are involved.  The Designer's themselves will register with the
 12   controller so that you can hook to the controller to manage the views and
 13   their editors.
 14 
 15   Among other things, this controller implements global selection support for
 16   the designers.
 17 
 18   @extends SC.Object
 19   @since SproutCore 1.0
 20 */
 21 SC.PageDesignController = SC.Object.extend({
 22 
 23   isPageDesignController: YES,
 24 
 25   // ..........................................................
 26   // SELECTION
 27   //
 28 
 29   /** The current view builder selection. */
 30   selection: null,
 31 
 32   /**
 33     Updates the selection either by adding the item or by resetting the
 34     selection.  Calling this method with no parameters will reset the
 35     selection.
 36 
 37     The passed selection must be a Designer object.
 38   */
 39   select: function(sel, extend) {
 40     var base = this.get('selection');
 41     if (!base || !extend || !base.contains(sel)) {
 42       base = (!extend || !base) ? SC.CoreSet.create() : base.copy();
 43       base.add(sel);
 44       this.set('selection', base.freeze()) ;
 45       //make the designPane the firstResponder
 46       SC.designPage.getPath('designMainPane.container').becomeFirstResponder();
 47     }
 48     return this ;
 49   },
 50 
 51   /**
 52     Removes the passed items from the current selection.
 53 
 54     The passed selection must be a Designer object.
 55   */
 56   deselect: function(sel) {
 57 
 58     var base = this.get('selection');
 59     if (base && base.contains(sel)) {
 60       base = base.copy();
 61       base.remove(sel);
 62       this.set('selection', base.freeze());
 63     }
 64     return this;
 65   },
 66   /**
 67     Invoked whenever the selection changes.  Updates the selection states
 68     on the old and new views.
 69   */
 70   selectionDidChange: function() {
 71     var sel = this.get('selection'),
 72         oldSel = this._selection ;
 73 
 74     // save old selection for next time
 75     this._selection = sel ;
 76 
 77     // set the isSelected state on new selection.
 78     if (sel) sel.setEach('designIsSelected', YES);
 79 
 80     // remove the isSelected state for old selection not in new selection.
 81     if (oldSel) {
 82       oldSel.forEach(function(s){
 83         if (!sel || !sel.contains(s)) s.set('designIsSelected', NO);
 84       }, this);
 85     }
 86 
 87   }.observes('selection'),
 88 
 89 
 90   /**
 91     Called by a view to reposition the current selection during a mouse
 92     drag.
 93   */
 94   repositionSelection: function(evt, info) {
 95     var sel = this.get('selection');
 96     if (sel) sel.invoke('mouseReposition', evt, info);
 97   },
 98 
 99   /**
100     Called by a view to prepare all views in selection for repositioning
101   */
102   prepareReposition: function(info) {
103     var sel = this.get('selection');
104     if (sel) sel.invoke('prepareReposition', info);
105   },
106   /**
107     removes all views in the selection from their parent view
108   */
109   deleteSelection: function(){
110     var sel = this.get('selection'), first, parentView;
111 
112     if(sel && sel.get('length') > 0){
113       //TODO: delete multi selection
114       //this.beginPropertyChanges();
115       //while(sel.get('length') > 0){
116         first = sel.firstObject();
117         this.deselect(first);
118         first = first.get('view');
119         parentView = first.get('parentView');
120         first.removeFromParent();
121         if(parent.displayDidChange) parent.displayDidChange();
122         first = null;
123       //}
124       //this.endPropertyChanges();
125     }
126   },
127 
128 
129   // ..........................................................
130   // DESIGNERS
131   //
132 
133   /** All of the designers on the current page. */
134   designers: null,
135 
136   /**
137     Called by each designer when it is created to register itself with the
138     controller.  You can use this to know which designers are currently in
139     the document to delete them as needed.
140   */
141   registerDesigner: function(designer) {
142     this.get('designers').add(designer);
143   },
144 
145   // ..........................................................
146   // ROOT DESIGNER
147   //
148   rootDesigner: null,
149 
150   makeRootDesigner: function(designer){
151     var currRoot = this.get('rootDesigner');
152 
153     if(currRoot) currRoot.set('isRootDesigner', NO);
154 
155     this.deselect(designer);
156     designer.set('isRootDesigner', YES);
157     designer.set('prevRootDesigner', currRoot);
158     //TODO: allow greenhouse to highlight the root view!
159     this.set('rootDesigner', designer);
160   },
161 
162 
163   // ..........................................................
164   // INTERNAL SUPPORT
165   //
166   init: function() {
167     this.designers = SC.Set.create();
168     this.sel = [];
169     sc_super();
170   }
171 
172 }) ;
173