]> git.argeo.org Git - gpl/argeo-slc.git/blob - org.argeo.slc.webapp/src/main/webapp/source/class/org/argeo/ria/util/TreeDataCellRenderer.js
Refactoring part I (src move)
[gpl/argeo-slc.git] / org.argeo.slc.webapp / src / main / webapp / source / class / org / argeo / ria / util / TreeDataCellRenderer.js
1 /* ************************************************************************
2
3 qooxdoo - the new era of web development
4
5 http://qooxdoo.org
6
7 Copyright:
8 2007 Derrell Lipman
9
10 License:
11 LGPL: http://www.gnu.org/licenses/lgpl.html
12 EPL: http://www.eclipse.org/org/documents/epl-v10.php
13 See the LICENSE file in the project's top-level directory for details.
14
15 Authors:
16 * Derrell Lipman (derrell)
17 * David Perez Carmona (david-perez)
18
19 ************************************************************************ */
20
21 /* ************************************************************************
22
23 #require(qx.theme.Modern)
24 #require(qx.theme.Classic)
25 #require(qx.log.Logger)
26
27 ************************************************************************ */
28
29 /**
30 * A data cell renderer for the tree column of a simple tree
31 */
32 qx.Class.define("org.argeo.ria.util.TreeDataCellRenderer",
33 {
34 extend : qx.ui.treevirtual.SimpleTreeDataCellRenderer,
35
36
37 construct : function()
38 {
39 this.base(arguments);
40
41 this.__am = qx.util.AliasManager.getInstance();
42 this.__rm = qx.util.ResourceManager;
43 this.__tm = qx.theme.manager.Appearance.getInstance();
44
45 // Base URL used for indentation
46 this.BLANK = this.__rm.toUri(this.__am.resolve("static/blank.gif"));
47 },
48
49
50 statics :
51 {
52 __icon : { }
53 },
54
55
56
57
58 /*
59 *****************************************************************************
60 MEMBERS
61 *****************************************************************************
62 */
63
64 members :
65 {
66 // overridden
67 _getCellStyle : function(cellInfo)
68 {
69 var node = cellInfo.value;
70
71 // Return the style for the div for the cell. If there's cell-specific
72 // style information provided, append it.
73 var html =
74 this.base(arguments, cellInfo) +
75 (node.cellStyle ? node.cellStyle + ";" : "");
76 return html;
77 },
78
79 // overridden
80 _getContentHtml : function(cellInfo)
81 {
82 var html = "";
83
84 // Horizontal position
85 var pos = 0;
86
87 // If needed, add extra content before indentation
88 var extra = this._addExtraContentBeforeIndentation(cellInfo, pos);
89 html += extra.html;
90 pos = extra.pos;
91
92 // Add the indentation (optionally with tree lines)
93 var indentation = this._addIndentation(cellInfo, pos);
94 html += indentation.html
95 pos = indentation.pos;
96
97 // If needed, add extra content before icon
98 extra = this._addExtraContentBeforeIcon(cellInfo, pos);
99 html += extra.html;
100 pos = extra.pos;
101
102 // Add the node icon
103 var icon = this._addIcon(cellInfo, pos);
104 html += icon.html;
105 pos = icon.pos;
106
107 // If needed, add extra content before label
108 extra = this._addExtraContentBeforeLabel(cellInfo, pos);
109 html += extra.html;
110 pos = extra.pos;
111
112 // Add the node's label
113 html += this._addLabel(cellInfo, pos);
114
115 return html;
116 },
117
118 /**
119 * Add an image to the tree. This might be a visible icon or it may be
120 * part of the indentation.
121 *
122 * @param imageInfo {Map}
123 * How to display the image. It optionally includes any of the
124 * following:
125 * <dl>
126 * <dt>position {Map}</dt>
127 * <dd>
128 * If provided, a div is created to hold the image. The div's top,
129 * right, bottom, left, width, and/or height may be specified with
130 * members of this map. Each is expected to be an integer value.
131 * </dd>
132 * <dt>imageWidth, imageHeight</dt>
133 * <dd>
134 * The image's width and height. These are used only if both are
135 * specified.
136 * </dd>
137 * </dl>
138 *
139 * @return {String}
140 * The html for this image, possibly with a surrounding div (see
141 * 'position', above).
142 */
143 _addImage : function(imageInfo)
144 {
145 var html = [];
146
147 // Resolve the URI
148 var source = this.__rm.toUri(this.__am.resolve(imageInfo.url));
149
150 // If we've been given positioning attributes, enclose image in a div
151 if (imageInfo.position)
152 {
153 var pos = imageInfo.position;
154
155 html.push('<div style="position:absolute;');
156
157 if (!qx.core.Variant.isSet("qx.client", "mshtml"))
158 {
159 html.push(qx.bom.element.BoxSizing.compile("content-box"));
160 }
161
162 if (pos.top !== undefined)
163 {
164 html.push('top:' + pos.top + 'px;');
165 }
166
167 if (pos.right !== undefined)
168 {
169 html.push('right:' + pos.right + 'px;');
170 }
171
172 if (pos.bottom !== undefined)
173 {
174 html.push('bottom:' + pos.bottom + 'px;');
175 }
176
177 if (pos.left !== undefined)
178 {
179 html.push('left:' + pos.left + 'px;');
180 }
181
182 if (pos.width !== undefined)
183 {
184 html.push('width:' + pos.width + 'px;');
185 }
186
187 if (pos.height !== undefined)
188 {
189 html.push('height:' + pos.height + 'px;');
190 }
191
192 html.push('">');
193 }
194
195 // Don't use an image tag. They render differently in Firefox and IE7
196 // even if both are enclosed in a div specified as content box. Instead,
197 // add the image as the background image of a div.
198 html.push('<div style="');
199 html.push('background-image:url(' + source + ');');
200 html.push('background-repeat:no-repeat;');
201
202 if (imageInfo.imageWidth && imageInfo.imageHeight)
203 {
204 html.push(
205 ';width:' +
206 imageInfo.imageWidth +
207 'px' +
208 ';height:' +
209 imageInfo.imageHeight +
210 'px');
211 }
212
213 var tooltip = imageInfo.tooltip;
214
215 if (tooltip != null)
216 {
217 html.push('" title="' + tooltip);
218 }
219
220 html.push('">&nbsp;</div>');
221
222 if (imageInfo.position)
223 {
224 html.push('</div>');
225 }
226
227 return html.join("");
228 },
229
230
231 /**
232 * Add the indentation for this node of the tree.
233 *
234 * The indentation optionally includes tree lines. Whether tree lines are
235 * used depends on (a) the properties 'useTreeLines' and
236 * 'excludeFirstLevelTreelines' within this class; and (b) the widget
237 * theme in use (some themes don't support tree lines).
238 *
239 * @param cellInfo {Map} The information about the cell.
240 * See {@link qx.ui.table.cellrenderer.Abstract#createDataCellHtml}.
241 *
242 * @param pos {Integer}
243 * The position from the left edge of the column at which to render this
244 * item.
245 *
246 * @return {Map}
247 * The returned map contains an 'html' member which contains the html for
248 * the indentation, and a 'pos' member which is the starting position
249 * plus the width of the indentation.
250 */
251 _addIndentation : function(cellInfo, pos)
252 {
253 var node = cellInfo.value;
254 var imageData;
255 var html = "";
256
257 // Generate the indentation. Obtain icon determination values once
258 // rather than each time through the loop.
259 var bUseTreeLines = this.getUseTreeLines();
260 var bExcludeFirstLevelTreeLines = this.getExcludeFirstLevelTreeLines();
261 var bAlwaysShowOpenCloseSymbol = this.getAlwaysShowOpenCloseSymbol();
262
263 for (var i=0; i<node.level; i++)
264 {
265 imageData = this._getIndentSymbol(i, node, bUseTreeLines,
266 bAlwaysShowOpenCloseSymbol,
267 bExcludeFirstLevelTreeLines);
268
269 html += this._addImage(
270 {
271 url : imageData.icon,
272 position :
273 {
274 top : 0 + (imageData.paddingTop || 5),
275 left : pos + (imageData.paddingLeft || 3),
276 width : 19,
277 height : 16
278 }
279 });
280 pos += 19;
281 }
282
283 return (
284 {
285 html : html,
286 pos : pos
287 });
288 },
289
290 /**
291 * Add the icon for this node of the tree.
292 *
293 * @param cellInfo {Map} The information about the cell.
294 * See {@link qx.ui.table.cellrenderer.Abstract#createDataCellHtml}.
295 *
296 * @param pos {Integer}
297 * The position from the left edge of the column at which to render this
298 * item.
299 *
300 * @return {Map}
301 * The returned map contains an 'html' member which contains the html for
302 * the icon, and a 'pos' member which is the starting position plus the
303 * width of the icon.
304 */
305 _addIcon : function(cellInfo, pos)
306 {
307 var node = cellInfo.value;
308
309 // Add the node's icon
310 var imageUrl = (node.bSelected ? node.iconSelected : node.icon);
311
312 if (!imageUrl)
313 {
314 if (node.type == qx.ui.treevirtual.SimpleTreeDataModel.Type.LEAF)
315 {
316 var o = this.__tm.styleFrom("treevirtual-file");
317 }
318 else
319 {
320 var states = { opened : node.bOpened };
321 var o = this.__tm.styleFrom("treevirtual-folder", states);
322 }
323
324 imageUrl = o.icon;
325 }
326
327 var html = this._addImage(
328 {
329 url : imageUrl,
330 position :
331 {
332 top : 0,
333 left : pos,
334 width : 19,
335 height : 16
336 }
337 });
338
339 return (
340 {
341 html : html,
342 pos : pos + 19
343 });
344 },
345
346 /**
347 * Add the label for this node of the tree.
348 *
349 * @param cellInfo {Map} The information about the cell.
350 * See {@link qx.ui.table.cellrenderer.Abstract#createDataCellHtml}.
351 * Additionally, if defined, the labelSpanStyle member is used to apply
352 * style to the span containing the label. (This member is for use by
353 * subclasses; it's not otherwise used by this class.)
354 *
355 * @param pos {Integer}
356 * The position from the left edge of the column at which to render this
357 * item.
358 *
359 * @return {String}
360 * The html for the label.
361 */
362 _addLabel : function(cellInfo, pos)
363 {
364 var node = cellInfo.value;
365
366 // Add the node's label. We calculate the "left" property with: each
367 // tree line (indentation) icon is 19 pixels wide; the folder icon is 16
368 // pixels wide, there are two pixels of padding at the left, and we want
369 // 2 pixels between the folder icon and the label
370 var html =
371 '<div style="position:absolute;' +
372 'left:' + pos + 'px;' +
373 'top:0;' +
374 (node.labelStyle ? node.labelStyle + ";" : "") +
375 '">' +
376 '<span' + (cellInfo.labelSpanStyle
377 ? 'style="' + cellInfo.labelSpanStyle + ';"'
378 : "") + '>' +
379 node.label +
380 '</span>' +
381 '</div>';
382
383 return html;
384 },
385
386 /**
387 * Adds extra content just before the indentation.
388 *
389 * @param cellInfo {Map} The information about the cell.
390 * See {@link qx.ui.table.cellrenderer.Abstract#createDataCellHtml}.
391 *
392 * @param pos {Integer}
393 * The position from the left edge of the column at which to render this
394 * item.
395 *
396 * @return {Map}
397 * The returned map contains an 'html' member which contains the html for
398 * the indentation, and a 'pos' member which is the starting position
399 * plus the width of the indentation.
400 */
401 _addExtraContentBeforeIndentation : function(cellInfo, pos)
402 {
403 return { html: '', pos: pos };
404 },
405
406 /**
407 * Adds extra content just before the icon.
408 *
409 * @param cellInfo {Map} The information about the cell.
410 * See {@link qx.ui.table.cellrenderer.Abstract#createDataCellHtml}.
411 *
412 * @param pos {Integer}
413 * The position from the left edge of the column at which to render this
414 * item.
415 *
416 * @return {Map}
417 * The returned map contains an 'html' member which contains the html for
418 * the indentation, and a 'pos' member which is the starting position
419 * plus the width of the indentation.
420 */
421 _addExtraContentBeforeIcon : function(cellInfo, pos)
422 {
423 return { html: '', pos: pos };
424 },
425
426 /**
427 * Adds extra content just before the label.
428 *
429 * @param cellInfo {Map} The information about the cell.
430 * See {@link qx.ui.table.cellrenderer.Abstract#createDataCellHtml}.
431 *
432 * @param pos {Integer}
433 * The position from the left edge of the column at which to render this
434 * item.
435 *
436 * @return {Map}
437 * The returned map contains an 'html' member which contains the html for
438 * the indentation, and a 'pos' member which is the starting position
439 * plus the width of the indentation.
440 */
441 _addExtraContentBeforeLabel : function(cellInfo, pos)
442 {
443 return { html: '', pos: pos };
444 },
445
446
447 /**
448 * Determine the symbol to use for indentation of a tree row, at a
449 * particular column. The indentation to use may be just white space or
450 * may be a tree line. Tree lines come in numerous varieties, so the
451 * appropriate one is selected.
452 *
453 * @type member
454 *
455 * @param column {Integer}
456 * The column of indentation being requested, zero-relative
457 *
458 * @param node {Node}
459 * The node being displayed in the row. The properties of a node are
460 * described in {@link qx.ui.treevirtual.SimpleTreeDataModel}
461 *
462 * @param bUseTreeLines {Boolean}
463 * Whether to find an appropriate tree line icon, or simply provide
464 * white space.
465 *
466 * @param bAlwaysShowOpenCloseSymbol {Boolean}
467 * Whether to display the open/close icon for a node even if it has no
468 * children.
469 *
470 * @param bExcludeFirstLevelTreeLines {Boolean}
471 * If bUseTreeLines is enabled, then further filtering of the left-most
472 * tree line may be specified here. If <i>true</i> then the left-most
473 * tree line, between top-level siblings, will not be displayed.
474 * If <i>false</i>, then the left-most tree line wiill be displayed
475 * just like all of the other tree lines.
476 *
477 * @return {var} TODOC
478 */
479 _getIndentSymbol : function(column,
480 node,
481 bUseTreeLines,
482 bAlwaysShowOpenCloseSymbol,
483 bExcludeFirstLevelTreeLines)
484 {
485 var STDCR = org.argeo.ria.util.TreeDataCellRenderer;
486
487 // If we're in column 0 and excludeFirstLevelTreeLines is enabled, then
488 // we treat this as if no tree lines were requested.
489 if (column == 0 && bExcludeFirstLevelTreeLines)
490 {
491 bUseTreeLines = false;
492 }
493
494 // If we're not on the final column...
495 if (column < node.level - 1)
496 {
497 // then return either a line or a blank icon, depending on
498 // bUseTreeLines
499 return (bUseTreeLines && ! node.lastChild[column]
500 ? STDCR.__icon.line
501 : { icon : this.BLANK });
502 }
503
504 var bLastChild = node.lastChild[node.lastChild.length - 1];
505
506 // Is this a branch node that does not have the open/close button hidden?
507 if (node.type == qx.ui.treevirtual.SimpleTreeDataModel.Type.BRANCH &&
508 ! node.bHideOpenClose)
509 {
510 // Does this node have any children, or do we always want the
511 // open/close symbol to be shown?
512 if (node.children.length > 0 || bAlwaysShowOpenCloseSymbol)
513 {
514 // If we're not showing tree lines...
515 if (!bUseTreeLines)
516 {
517 // ... then just use a expand or contract
518 return (node.bOpened
519 ? STDCR.__icon.contract
520 : STDCR.__icon.expand);
521 }
522
523 // Are we looking at a top-level, first child of its parent?
524 if (column == 0 && node.bFirstChild)
525 {
526 // Yup. If it's also a last child...
527 if (bLastChild)
528 {
529 // ... then use no tree lines.
530 return (node.bOpened
531 ? STDCR.__icon.onlyContract
532 : STDCR.__icon.onlyExpand);
533 }
534 else
535 {
536 // otherwise, use descender lines but no ascender.
537 return (node.bOpened
538 ? STDCR.__icon.startContract
539 : STDCR.__icon.startExpand);
540 }
541 }
542
543 // It's not a top-level, first child. Is this the last child of its
544 // parent?
545 if (bLastChild)
546 {
547 // Yup. Return an ending expand or contract.
548 return (node.bOpened
549 ? STDCR.__icon.endContract
550 : STDCR.__icon.endExpand);
551 }
552
553 // Otherwise, return a crossing expand or contract.
554 return (node.bOpened
555 ? STDCR.__icon.crossContract
556 : STDCR.__icon.crossExpand);
557 }
558 }
559
560 // This node does not have any children. Return an end or cross, if
561 // we're using tree lines.
562 if (bUseTreeLines)
563 {
564 // If this is a child of the root node...
565 if (node.parentNodeId == 0)
566 {
567 // If this is the only child...
568 if (bLastChild && node.bFirstChild)
569 {
570 // ... then return a blank.
571 return { icon : this.BLANK };
572 }
573
574 // Otherwise, if this is the last child...
575 if (bLastChild)
576 {
577 // ... then return an end line.
578 return STDCR.__icon.end;
579 }
580
581 // Otherwise if this is the first child...
582 if (node.bFirstChild)
583 {
584 // ... then return a start line.
585 return STDCR.__icon.start;
586 }
587 }
588
589 // If this is a last child, return and ending line; otherwise cross.
590 return (bLastChild
591 ? STDCR.__icon.end
592 : STDCR.__icon.cross);
593 }
594
595 return { icon : this.BLANK };
596 }
597 },
598
599 defer : function()
600 {
601 // Ensure that the theme is initialized
602 qx.theme.manager.Meta.getInstance().initialize();
603
604 var STDCR = org.argeo.ria.util.TreeDataCellRenderer;
605
606 var ImageLoader = qx.io2.ImageLoader;
607
608 var am = qx.util.AliasManager.getInstance();
609 var rm = qx.util.ResourceManager;
610 var tm = qx.theme.manager.Appearance.getInstance();
611
612 var loadImage = function(f)
613 {
614 ImageLoader.load(rm.toUri(am.resolve(f)));
615 };
616
617 STDCR.__icon.line = tm.styleFrom("treevirtual-line");
618 loadImage(STDCR.__icon.line.icon);
619
620 STDCR.__icon.contract = tm.styleFrom("treevirtual-contract");
621 loadImage(STDCR.__icon.contract.icon);
622
623 STDCR.__icon.expand = tm.styleFrom("treevirtual-expand");
624 loadImage(STDCR.__icon.expand.icon);
625
626 STDCR.__icon.onlyContract = tm.styleFrom("treevirtual-only-contract");
627 loadImage(STDCR.__icon.onlyContract.icon);
628
629 STDCR.__icon.onlyExpand = tm.styleFrom("treevirtual-only-expand");
630 loadImage(STDCR.__icon.onlyExpand.icon);
631
632 STDCR.__icon.startContract = tm.styleFrom("treevirtual-start-contract");
633 loadImage(STDCR.__icon.startContract.icon);
634
635 STDCR.__icon.startExpand = tm.styleFrom("treevirtual-start-expand");
636 loadImage(STDCR.__icon.startExpand.icon);
637
638 STDCR.__icon.endContract = tm.styleFrom("treevirtual-end-contract");
639 loadImage(STDCR.__icon.endContract.icon);
640
641 STDCR.__icon.endExpand = tm.styleFrom("treevirtual-end-expand");
642 loadImage(STDCR.__icon.endExpand.icon);
643
644 STDCR.__icon.crossContract = tm.styleFrom("treevirtual-cross-contract");
645 loadImage(STDCR.__icon.crossContract.icon);
646
647 STDCR.__icon.crossExpand = tm.styleFrom("treevirtual-cross-expand");
648 loadImage(STDCR.__icon.crossExpand.icon);
649
650 STDCR.__icon.end = tm.styleFrom("treevirtual-end");
651 loadImage(STDCR.__icon.end.icon);
652
653 STDCR.__icon.cross = tm.styleFrom("treevirtual-cross");
654 loadImage(STDCR.__icon.cross.icon);
655 },
656
657 destruct : function()
658 {
659 this._disposeFields(
660 "__am",
661 "__rm",
662 "__tm",
663 "BLANK");
664 }
665 });