001: /*
002: * Copyright 2000,2005 wingS development team.
003: *
004: * This file is part of wingS (http://wingsframework.org).
005: *
006: * wingS is free software; you can redistribute it and/or modify
007: * it under the terms of the GNU Lesser General Public License
008: * as published by the Free Software Foundation; either version 2.1
009: * of the License, or (at your option) any later version.
010: *
011: * Please see COPYING for the complete licence.
012: */
013: package org.wings.plaf.css;
014:
015: import org.wings.*;
016: import org.wings.io.Device;
017: import org.wings.plaf.CGManager;
018: import org.wings.plaf.Update;
019: import org.wings.resource.ResourceManager;
020: import org.wings.tree.SDefaultTreeSelectionModel;
021: import org.wings.tree.STreeCellRenderer;
022:
023: import javax.swing.tree.TreeModel;
024: import javax.swing.tree.TreePath;
025:
026: import java.awt.Rectangle;
027: import java.io.IOException;
028: import java.util.List;
029:
030: public final class TreeCG extends AbstractComponentCG implements
031: org.wings.plaf.TreeCG {
032: private static final long serialVersionUID = 1L;
033: private SIcon collapseControlIcon;
034: private SIcon emptyFillIcon;
035: private SIcon expandControlIcon;
036: private SIcon hashMark;
037: private SIcon leafControlIcon;
038: private SResourceIcon lineslash;
039: private SResourceIcon lineplus;
040: private SResourceIcon lineminus;
041: private boolean renderSelectableCells = true;
042:
043: /**
044: * Initialize properties from config
045: */
046: public TreeCG() {
047: setCollapseControlIcon((SIcon) ResourceManager.getObject(
048: "TreeCG.collapseControlIcon", SIcon.class));
049: setEmptyFillIcon((SIcon) ResourceManager.getObject(
050: "TreeCG.emptyFillIcon", SIcon.class));
051: setExpandControlIcon((SIcon) ResourceManager.getObject(
052: "TreeCG.expandControlIcon", SIcon.class));
053: setHashMark((SIcon) ResourceManager.getObject(
054: "TreeCG.hashMark", SIcon.class));
055: setLeafControlIcon((SIcon) ResourceManager.getObject(
056: "TreeCG.leafControlIcon", SIcon.class));
057: lineslash = new SResourceIcon("org/wings/icons/lineslash.gif");
058: lineslash.getId();
059: lineplus = new SResourceIcon("org/wings/icons/lineplus.gif");
060: lineplus.getId();
061: lineminus = new SResourceIcon("org/wings/icons/lineminus.gif");
062: lineminus.getId();
063: }
064:
065: public void installCG(final SComponent comp) {
066: super .installCG(comp);
067: final STree component = (STree) comp;
068: final CGManager manager = component.getSession().getCGManager();
069: Object value;
070: value = manager.getObject("STree.cellRenderer",
071: STreeCellRenderer.class);
072: if (value != null) {
073: component.setCellRenderer((STreeCellRenderer) value);
074: }
075: value = manager.getObject("STree.nodeIndentDepth",
076: Integer.class);
077: if (value != null) {
078: component.setNodeIndentDepth(((Integer) value).intValue());
079: }
080: }
081:
082: public boolean isRenderSelectableCells() {
083: return renderSelectableCells;
084: }
085:
086: public void setRenderSelectableCells(boolean renderSelectableCells) {
087: this .renderSelectableCells = renderSelectableCells;
088: }
089:
090: private void writeIcon(Device device, SIcon icon)
091: throws IOException {
092: if (icon == null) {
093: return;
094: }
095:
096: device.print("<img");
097: Utils.optAttribute(device, "src", icon.getURL());
098: Utils.optAttribute(device, "width", icon.getIconWidth());
099: Utils.optAttribute(device, "height", icon.getIconHeight());
100: Utils.attribute(device, "alt", icon.getIconTitle());
101: device.print("/>");
102: }
103:
104: private void writeTreeNode(STree component, Device device, int row,
105: int depth) throws IOException {
106: final TreePath path = component.getPathForRow(row);
107:
108: final Object node = path.getLastPathComponent();
109: final STreeCellRenderer cellRenderer = component
110: .getCellRenderer();
111:
112: TreeModel model = component.getModel();
113: final boolean isLeaf = model.isLeaf(node);
114: final boolean isExpanded = component.isExpanded(path);
115: final boolean isSelected = component.isPathSelected(path);
116:
117: final boolean isSelectable = renderSelectableCells
118: && (component.getSelectionModel() != SDefaultTreeSelectionModel.NO_SELECTION_MODEL);
119:
120: SComponent cellComp = cellRenderer
121: .getTreeCellRendererComponent(component, node,
122: isSelected, isExpanded, isLeaf, row, false);
123:
124: device.print("<tr>");
125:
126: String[] images = new String[] { " class=\"slash\"",
127: " class=\"plus\"", "", " class=\"minus\"", };
128:
129: Object[] pathElements = path.getPath();
130: Object parentElement = component.isRootVisible() ? null : model
131: .getRoot();
132: for (int i = component.isRootVisible() ? 0 : 1; i < pathElements.length; i++) {
133: Object element = pathElements[i];
134: boolean lastElement = i == pathElements.length - 1;
135: boolean lastChild = lastChild(model, parentElement, element);
136: int imageIndex = (lastElement ? 1 : 0)
137: + (lastChild ? 2 : 0);
138:
139: device.print("<td");
140: if (lastElement && !isLeaf) {
141: final String expansionParameter = component
142: .getExpansionParameter(row, false);
143: Utils.printClickability(device, component,
144: expansionParameter, true, component
145: .getShowAsFormComponent());
146: }
147:
148: device.print(images[imageIndex]);
149: Utils.optAttribute(device, "width", component
150: .getNodeIndentDepth());
151: device.print(">");
152:
153: if (lastElement && !(isLeaf && leafControlIcon == null))
154: renderControlIcon(device, isLeaf, isExpanded);
155:
156: device.print("</td>");
157: parentElement = element;
158: }
159:
160: /*
161: * now, write the component.
162: */
163: device.print("<td colspan=\"");
164: device.print(depth - path.getPathCount() + 1);
165: device.print("\"");
166: Utils.optAttribute(device, "row", "" + row);
167:
168: if (isSelected) {
169: Utils.optAttribute(device, "class", "selected");
170: } else {
171: Utils.optAttribute(device, "class", "norm");
172: }
173: if (isSelectable) {
174: final String selectionParameter = component
175: .getSelectionParameter(row, false);
176: Utils.printClickability(device, component,
177: selectionParameter, true, component
178: .getShowAsFormComponent());
179: Utils.optAttribute(device, "tabindex", component
180: .getFocusTraversalIndex());
181: }
182: device.print(">");
183:
184: SCellRendererPane rendererPane = component
185: .getCellRendererPane();
186: rendererPane.writeComponent(device, cellComp, component);
187:
188: device.print("</td></tr>");
189: Utils.printNewline(device, component);
190: }
191:
192: private void renderControlIcon(Device device, boolean leaf,
193: boolean expanded) throws IOException {
194: if (leaf) {
195: writeIcon(device, leafControlIcon);
196: } else if (expanded) {
197: if (collapseControlIcon == null) {
198: device.print("-");
199: } else {
200: writeIcon(device, collapseControlIcon);
201: }
202: } else {
203: if (expandControlIcon == null) {
204: device.print("+");
205: } else {
206: writeIcon(device, expandControlIcon);
207: }
208: }
209: }
210:
211: private boolean lastChild(TreeModel model, Object parentElement,
212: Object element) {
213: return parentElement == null
214: || model.getIndexOfChild(parentElement, element) == model
215: .getChildCount(parentElement) - 1;
216: }
217:
218: public void writeInternal(final Device device, final SComponent _c)
219: throws IOException {
220: final STree tree = (STree) _c;
221:
222: Rectangle currentViewport = tree.getViewportSize();
223: Rectangle maximalViewport = tree.getScrollableViewportSize();
224: int start = 0;
225: int end = tree.getRowCount();
226: int empty = maximalViewport != null ? maximalViewport.height
227: : end;
228:
229: if (currentViewport != null) {
230: start = currentViewport.y;
231: end = start + currentViewport.height;
232: }
233:
234: final int depth = tree.getMaximumExpandedDepth();
235:
236: device.print("<table");
237: Utils.writeAllAttributes(device, tree);
238: device.print(">");
239:
240: for (int i = start; i < end; ++i) {
241: if (i >= empty) {
242: device
243: .print("<tr class=\"empty\"><td> </td></tr>");
244: continue;
245: }
246: writeTreeNode(tree, device, i, depth);
247: }
248:
249: device.print("</table>");
250: }
251:
252: //--- setters and getters for the properties.
253:
254: public SIcon getCollapseControlIcon() {
255: return collapseControlIcon;
256: }
257:
258: public void setCollapseControlIcon(SIcon collapseControlIcon) {
259: this .collapseControlIcon = collapseControlIcon;
260: }
261:
262: public SIcon getEmptyFillIcon() {
263: return emptyFillIcon;
264: }
265:
266: public void setEmptyFillIcon(SIcon emptyFillIcon) {
267: this .emptyFillIcon = emptyFillIcon;
268: }
269:
270: public SIcon getExpandControlIcon() {
271: return expandControlIcon;
272: }
273:
274: public void setExpandControlIcon(SIcon expandControlIcon) {
275: this .expandControlIcon = expandControlIcon;
276: }
277:
278: public SIcon getHashMark() {
279: return hashMark;
280: }
281:
282: public void setHashMark(SIcon hashMark) {
283: this .hashMark = hashMark;
284: }
285:
286: public SIcon getLeafControlIcon() {
287: return leafControlIcon;
288: }
289:
290: public void setLeafControlIcon(SIcon leafControlIcon) {
291: this .leafControlIcon = leafControlIcon;
292: }
293:
294: public Update getSelectionUpdate(STree tree, List deselectedRows,
295: List selectedRows) {
296: return new SelectionUpdate(tree, deselectedRows, selectedRows);
297: }
298:
299: protected class SelectionUpdate extends AbstractUpdate {
300:
301: private List deselectedRows;
302: private List selectedRows;
303:
304: public SelectionUpdate(SComponent component,
305: List deselectedRows, List selectedRows) {
306: super (component);
307: this .deselectedRows = deselectedRows;
308: this .selectedRows = selectedRows;
309: }
310:
311: public Handler getHandler() {
312: UpdateHandler handler = new UpdateHandler("selectionTree");
313: handler.addParameter(component.getName());
314: handler.addParameter(Utils.listToJsArray(deselectedRows));
315: handler.addParameter(Utils.listToJsArray(selectedRows));
316: return handler;
317: }
318:
319: }
320:
321: }
|