Flip some state flags in an attempt to get mouse events working.
[armadillo.git] / web_frontend / actor.js
1 //
2 // Armadillo File Manager
3 // Copyright (c) 2010, Robert Sesek <http://www.bluestatic.org>
4 //
5 // This program is free software: you can redistribute it and/or modify it under
6 // the terms of the GNU General Public License as published by the Free Software
7 // Foundation, either version 3 of the License, or any later version.
8 //
9
10 goog.provide('armadillo.Actor');
11 goog.provide('armadillo.Actor.TileControlRenderer_');
12
13 goog.require('armadillo.PathControl');
14 goog.require('armadillo.TVRenamer');
15 goog.require('goog.array');
16 goog.require('goog.dom');
17 goog.require('goog.events');
18 goog.require('goog.events.EventHandler');
19 goog.require('goog.style');
20 goog.require('goog.ui.Button');
21 goog.require('goog.ui.Container');
22 goog.require('goog.ui.Dialog');
23
24 /**
25 * The Actor is a popup that displays the various actions that can be performed
26 * on a given File.
27 * @param {armadillo.File} file The file to act on.
28 * @param {goog.dom.DomHelper} opt_domHelper
29 * @constructor
30 */
31 armadillo.Actor = function(file, opt_domHelper) {
32 goog.ui.Container.call(this, null, null, opt_domHelper);
33
34 this.setFocusable(false);
35 this.setFocusableChildrenAllowed(true);
36
37 /**
38 * The file object on which this acts.
39 * @type {armadillo.File}
40 */
41 this.file_ = file;
42
43 /**
44 * Registrar for all the Actor's events.
45 * @type {goog.events.EventHandler}
46 */
47 this.eh_ = new goog.events.EventHandler();
48
49 /**
50 * The UI element used for a specific action.
51 * @type {goog.Disposable}
52 */
53 this.actionObject_ = null;
54
55 /**
56 * Controls for the current action.
57 * @type {goog.ui.Control}
58 */
59 this.controlContainer_ = null;
60 }
61 goog.inherits(armadillo.Actor, goog.ui.Container);
62
63 /**
64 * The different options that the Actor can perform.
65 */
66 armadillo.Actor.options_ = {
67 OPEN : 'open',
68 MOVE : 'move',
69 RENAME : 'rename',
70 DELETE : 'delete',
71 TV_RENAME : 'tv-rename'
72 };
73
74 /**
75 * String values for the options.
76 */
77 armadillo.Actor.optionStrings_ = {
78 'open' : 'Open',
79 'move' : 'Move',
80 'rename' : 'Rename',
81 'delete' : 'Delete',
82 'tv-rename' : 'Rename TV Episode'
83 };
84
85 /**
86 * Disposer
87 * @protected
88 */
89 armadillo.Actor.prototype.disposeInternal = function() {
90 armadillo.Actor.superClass_.disposeInternal.call(this);
91
92 this.eh_.dispose();
93
94 if (this.controlContainer_)
95 this.controlContainer_.dispose();
96 this.controlContainer_ = null;
97
98 // Remove the actor display element.
99 goog.dom.removeNode(this.element_);
100 this.element_ = null;
101
102 if (this.actionObject_) {
103 this.actionObject_.dispose();
104 this.actionObject_ = null;
105 }
106
107 this.file_ = null;
108 };
109
110 armadillo.Actor.prototype.createDom = function() {
111 this.setElementInternal(this.dom_.createDom('div'));
112 this.decorate(this.getElement());
113 };
114
115 /**
116 * Decorates the given element into a path control.
117 * @param {Element} element
118 */
119 armadillo.Actor.prototype.decorateInternal = function(element) {
120 this.element_ = element;
121 goog.dom.classes.add(this.element_, 'actor');
122 this.dom_.removeChildren(this.element_);
123 for (var option in armadillo.Actor.options_) {
124 var tile = this.createTile_(option);
125 if (tile) {
126 this.addChild(tile, true);
127 }
128 }
129 this.controlContainer_ = new goog.ui.Control();
130 this.controlContainer_.setSupportedState(goog.ui.Component.State.FOCUSED, false);
131 this.addChild(this.controlContainer_, true);
132 };
133
134 /**
135 * Creates the DOM Element that is inserted into the popup.
136 * @param {armadillo.Actor.options_} Key of the option to create
137 * @returns {goog.ui.Control}
138 */
139 armadillo.Actor.prototype.createTile_ = function(option) {
140 var value = armadillo.Actor.options_[option];
141
142 // Create the title element.
143 var title = this.dom_.createDom('span', 'title',
144 armadillo.Actor.optionStrings_[value]);
145
146 var tile = new goog.ui.Control(title, new armadillo.Actor.TileControlRenderer_());
147 tile.actorOption = value;
148
149 // Cannot open non-directory files.
150 if (value == armadillo.Actor.options_.OPEN && !this.file_.isDirectory()) {
151 return null;
152 }
153
154 this.eh_.listen(tile, goog.ui.Component.EventType.ACTION,
155 this.tileClickHandler_, false, this);
156 return tile;
157 };
158
159 /**
160 * Click handler for individual tiles.
161 * @param {Event} e
162 */
163 armadillo.Actor.prototype.tileClickHandler_ = function(e) {
164 var option = e.target.actorOption;
165 this.controlContainer_.removeChildren(true);
166 this.controlContainer_.setVisible(true);
167 if (option == armadillo.Actor.options_.OPEN) {
168 // TODO: assert that this.file_.isDirectory().
169 app.navigate(this.file_.getName());
170 } else if (option == armadillo.Actor.options_.MOVE ||
171 option == armadillo.Actor.options_.RENAME) {
172 this.performMove_();
173 } else if (option == armadillo.Actor.options_.DELETE) {
174 this.performDelete_();
175 } else if (option == armadillo.Actor.options_.TV_RENAME) {
176 this.performTVRename_();
177 }
178 };
179
180 /**
181 * Subroutine to handle bringing up the move confirmation UI.
182 * @private
183 */
184 armadillo.Actor.prototype.performMove_ = function() {
185 var editor = new armadillo.PathControl(this.file_.getFullPath(), true);
186 this.controlContainer_.addChild(editor, true);
187
188 var okCallback = function(e) {
189 var newPath = editor.getPath();
190 this.file_.move(newPath);
191 };
192 this.createOkCancel_(goog.bind(okCallback, this), null);
193 };
194
195 /**
196 * Subroutine to handle bringing up the delete confirmation UI.
197 * @private
198 */
199 armadillo.Actor.prototype.performDelete_ = function() {
200 this.actionObject_ = this.createActionDialog_();
201 this.actionObject_.setTitle('Confirm Delete');
202
203 var container = this.actionObject_.getContentElement();
204 var content = goog.dom.createDom('span', null,
205 'Are you sure you want to delete:',
206 goog.dom.createElement('br'),
207 goog.dom.createDom('strong', null, this.file_.getName()));
208 goog.dom.appendChild(container, content);
209
210 var closeCallback = function(e) {
211 if (e.key != goog.ui.Dialog.DefaultButtonKeys.CANCEL) {
212 this.file_.remove();
213 }
214 };
215 // Will be removed when the event source closes.
216 this.eh_.listen(this.actionObject_, goog.ui.Dialog.SELECT_EVENT,
217 closeCallback, false, this);
218
219 this.actionObject_.setVisible(true);
220 };
221
222 /**
223 * Subroutine that renames a file to it's title based on season and episode.
224 * @private
225 */
226 armadillo.Actor.prototype.performTVRename_ = function() {
227 var renamer = new armadillo.TVRenamer(this.file_);
228 renamer.run();
229 };
230
231 /**
232 * Creates a new instance of a Dialog that has some basic properties set that
233 * are common to performing actions.
234 * @private
235 */
236 armadillo.Actor.prototype.createActionDialog_ = function() {
237 var confirm = new goog.ui.Dialog();
238 confirm.setDisposeOnHide(true);
239 confirm.setEscapeToCancel(true);
240 confirm.setModal(true);
241 confirm.setDraggable(false);
242 confirm.setHasTitleCloseButton(false);
243 return confirm;
244 };
245
246 /**
247 * Creates two buttons: one for OK one for Cancel and attahes them to the
248 * |controlContainer_|.
249 * @param {function(Event)?} okCallback
250 * @param {function(Event)?} cancelCallback
251 */
252 armadillo.Actor.prototype.createOkCancel_ = function(okCallback, cancelCallback) {
253 var ok = new goog.ui.Button('OK');
254 if (okCallback)
255 this.eh_.listen(ok, goog.ui.Component.EventType.ACTION, okCallback);
256 var cancel = new goog.ui.Button('Cancel');
257 if (!cancelCallback)
258 cancelCallback = goog.bind(this.defaultCancelCallback_, this);
259 this.eh_.listen(cancel, goog.ui.Component.EventType.ACTION, cancelCallback);
260 this.controlContainer_.addChild(ok, true);
261 this.controlContainer_.addChild(cancel, true);
262 };
263
264 /**
265 * The default cancel callback for the above createOkCancel_().
266 * @param {event} e
267 * @private
268 */
269 armadillo.Actor.prototype.defaultCancelCallback_ = function(e) {
270 this.controlContainer_.removeChildren(true);
271 };
272
273 /**
274 * Tile Control Renderer
275 * @constructor
276 */
277 armadillo.Actor.TileControlRenderer_ = function() {
278 goog.ui.ControlRenderer.call(this);
279 };
280 goog.inherits(armadillo.Actor.TileControlRenderer_, goog.ui.ControlRenderer);
281
282 /**
283 * Returns the control's contents wrapped in a DIV, with the renderer's own
284 * CSS class and additional state-specific classes applied to it.
285 * @param {goog.ui.Control} control Control to render.
286 * @return {Element} Root element for the control.
287 */
288 armadillo.Actor.TileControlRenderer_.prototype.createDom = function(control) {
289 // Create and return DIV wrapping contents.
290 return control.getDomHelper().createDom('div', 'tile', control.getContent());
291 };