1 /*
  2  * ***** BEGIN LICENSE BLOCK *****
  3  * Zimbra Collaboration Suite Web Client
  4  * Copyright (C) 2005, 2006, 2007, 2008, 2009, 2010, 2011, 2013, 2014, 2016 Synacor, Inc.
  5  *
  6  * The contents of this file are subject to the Common Public Attribution License Version 1.0 (the "License");
  7  * you may not use this file except in compliance with the License.
  8  * You may obtain a copy of the License at: https://www.zimbra.com/license
  9  * The License is based on the Mozilla Public License Version 1.1 but Sections 14 and 15
 10  * have been added to cover use of software over a computer network and provide for limited attribution
 11  * for the Original Developer. In addition, Exhibit A has been modified to be consistent with Exhibit B.
 12  *
 13  * Software distributed under the License is distributed on an "AS IS" basis,
 14  * WITHOUT WARRANTY OF ANY KIND, either express or implied.
 15  * See the License for the specific language governing rights and limitations under the License.
 16  * The Original Code is Zimbra Open Source Web Client.
 17  * The Initial Developer of the Original Code is Zimbra, Inc.  All rights to the Original Code were
 18  * transferred by Zimbra, Inc. to Synacor, Inc. on September 14, 2015.
 19  *
 20  * All portions of the code are Copyright (C) 2005, 2006, 2007, 2008, 2009, 2010, 2011, 2013, 2014, 2016 Synacor, Inc. All Rights Reserved.
 21  * ***** END LICENSE BLOCK *****
 22  */
 23 /**
 24  * @overview
 25  * This file defines a Zimlet tree controller.
 26  *
 27  */
 28 
 29 /**
 30  * Creates a Zimlet tree controller.
 31  * @class
 32  * This class represents a Zimlet tree controller.
 33  * 
 34  * @extends		ZmTreeController
 35  */
 36 ZmZimletTreeController = function() {
 37 
 38 	ZmTreeController.call(this, ZmOrganizer.ZIMLET);
 39 
 40     this._eventMgrs = {};
 41 
 42 	// don't select zimlet items via arrow shortcut since selection pops up dialog
 43 	this._treeSelectionShortcutDelay = 0;
 44 };
 45 
 46 ZmZimletTreeController.prototype = new ZmTreeController;
 47 ZmZimletTreeController.prototype.constructor = ZmZimletTreeController;
 48 
 49 ZmZimletTreeController.prototype.isZmZimletTreeController = true;
 50 ZmZimletTreeController.prototype.toString = function() { return "ZmZimletTreeController"; };
 51 
 52 // Public methods
 53 
 54 /**
 55  * Adds a selection listener.
 56  * 
 57  * @param	{constant}	overviewId	the overview id
 58  * @param	{AjxListener}	listener		the listener to add
 59  */
 60 ZmZimletTreeController.prototype.addSelectionListener =
 61 function(overviewId, listener) {
 62 	// Each overview gets its own event manager
 63 	if (!this._eventMgrs[overviewId]) {
 64 		this._eventMgrs[overviewId] = new AjxEventMgr;
 65 		// Each event manager has its own selection event to avoid
 66 		// multi-threaded collisions
 67 		this._eventMgrs[overviewId]._selEv = new DwtSelectionEvent(true);
 68 	}
 69 	this._eventMgrs[overviewId].addListener(DwtEvent.SELECTION, listener);
 70 };
 71 
 72 ZmZimletTreeController.prototype._createTreeView =
 73 function(params) {
 74 	params.actionSupported = false;
 75 	return new ZmTreeView(params);
 76 };
 77 
 78 /**
 79  * Removes the selection listener.
 80  * 
 81  * @param	{constant}	overviewId	the overview id
 82  * @param	{AjxListener}	listener		the listener to remove
 83  */
 84 ZmZimletTreeController.prototype.removeSelectionListener =
 85 function(overviewId, listener) {
 86 	if (this._eventMgrs[overviewId]) {
 87 		this._eventMgrs[overviewId].removeListener(DwtEvent.SELECTION, listener);
 88 	}
 89 };
 90 
 91 // Protected methods
 92 
 93 /**
 94  * @private
 95  */
 96 ZmZimletTreeController.prototype._postSetup =
 97 function(overviewId) {
 98 	var treeView = this.getTreeView(overviewId);
 99 	var root = treeView.getItems()[0];
100 	if (root) {
101 		var items = root.getItems();
102 		for (var i = 0; i < items.length; i++) {
103 			this.setToolTipText(items[i]);
104 		}
105 	}
106 };
107 
108 /**
109  * Sets the tool tip text.
110  * 
111  * @param	{object}	item		the item
112  */
113 ZmZimletTreeController.prototype.setToolTipText =
114 function (item) {
115 	var zimlet = item.getData(Dwt.KEY_OBJECT);
116 	if (zimlet) zimlet.setToolTipText(item);
117 };
118 
119 /**
120  * ZmTreeController removes existing DwtTreeItem object then add a new one on ZmEvent.E_MODIFY,
121  * wiping out any properties set on the object.
122  * 
123  * @private
124  */
125 ZmZimletTreeController.prototype._changeListener =
126 function(ev, treeView, overviewId) {
127 	ZmTreeController.prototype._changeListener.call(this, ev, treeView, overviewId);
128 	var organizers = ev.getDetail("organizers");
129 	if (!organizers && ev.source)
130 		organizers = [ev.source];
131 
132 	for (var i = 0; i < organizers.length; i++) {
133 		var organizer = organizers[i];
134 		var id = organizer.id;
135 		var item = treeView.getTreeItemById(id);
136 		this.setToolTipText(item);
137 	}
138 };
139 
140 /**
141  * @private
142  */
143 ZmZimletTreeController.prototype._getDataTree =
144 function() {
145 	return appCtxt.getZimletTree();
146 };
147 
148 /**
149  * Returns a list of desired header action menu operations.
150  * 
151  * @private
152  */
153 ZmZimletTreeController.prototype._getHeaderActionMenuOps = function() {
154 	return null;
155 };
156 
157 /**
158  * Returns a list of desired action menu operations.
159  * 
160  * @private
161  */
162 ZmZimletTreeController.prototype._getActionMenuOps = function() {
163 	return null;
164 };
165 
166 /**
167  * @private
168  */
169 ZmZimletTreeController.prototype._getActionMenu = function(ev) {
170 	var z = ev.item.getData(Dwt.KEY_OBJECT);
171 	// z is here a ZmZimlet
172 	z = z.getZimletContext();
173 	if(z) {
174 		return z.getPanelActionMenu();
175 	}
176 };
177 
178 /**
179  * Gets the tree style.
180  * 
181  * @return	{constant}	the style
182  * @see		DwtTree.SINGLE_STYLE
183  */
184 ZmZimletTreeController.prototype.getTreeStyle = function() {
185 	return DwtTree.SINGLE_STYLE;
186 };
187 
188 /**
189  * Method that is run when a tree item is left-clicked.
190  * 
191  * @private
192  */
193 ZmZimletTreeController.prototype._itemClicked = function(z) {
194 	if (z.id == ZmZimlet.ID_ZIMLET_ROOT) { return; }
195 
196 	// to allow both click and dbl-click, we should use a timeout here, as
197 	// this function gets called twice in the case of a dbl-click.  If the
198 	// timeout already exists, we do nothing since _itemDblClicked will be
199 	// called (the timeout is cleared there).
200 	if (!z.__dbl_click_timeout) {
201 		z.__dbl_click_timeout = setTimeout(function() {
202 			z.__dbl_click_timeout = null;
203 			z.getZimletContext().callHandler("_dispatch", [ "singleClicked" ]);
204 		}, 350);
205 	}
206 };
207 
208 /**
209  * @private
210  */
211 ZmZimletTreeController.prototype._itemDblClicked = function(z) {
212 	if (z.id == ZmZimlet.ID_ZIMLET_ROOT) { return; }
213 
214 	if (z.__dbl_click_timeout) {
215 		// click will never happen
216 		clearTimeout(z.__dbl_click_timeout);
217 		z.__dbl_click_timeout = null;
218 	}
219 	z.getZimletContext().callHandler("_dispatch", [ "doubleClicked" ]);
220 };
221 
222 /**
223  * Handles a drop event.
224  * 
225  * @private
226  */
227 ZmZimletTreeController.prototype._dropListener = function(ev) {
228 	var z = ev.targetControl.getData(Dwt.KEY_OBJECT);
229 	if (!z) {
230 		ev.doIt = false;
231 		return;
232 	}
233 	if (z.id == ZmZimlet.ID_ZIMLET_ROOT) {
234 		ev.doIt = false;
235 		return;
236 	}
237 	if (z.getZimletContext) {
238 		try {
239 			z = z.getZimletContext();
240 		} catch(ex) {
241 			ev.doIt = false;
242 			return;
243 		}
244 	} else {
245 		ev.doIt = false;
246 		return;
247 	}
248 	var srcData = ev.srcData.data;
249 	if (!z || !srcData) {
250 		ev.doIt = false;
251 		return;
252 	}
253 	var dragSrc = z.zimletPanelItem.dragSource;
254  	if (dragSrc && ev.action == DwtDropEvent.DRAG_DROP) {
255 		z.callHandler("_dispatch",
256 			[ "doDrop",
257 				ZmZimletContext._translateZMObject(srcData),
258 			dragSrc ]);
259 	}
260 };
261 
262 /**
263  * Handles a drag event.
264  * 
265  * @private
266  */
267 ZmZimletTreeController.prototype._dragListener = function(ev) {
268 	// for now there's nothing defined in the spec to allow this
269 	ev.operation = Dwt.DND_DROP_NONE;
270 };
271