001: /* Treecell.java
002:
003: {{IS_NOTE
004: Purpose:
005:
006: Description:
007:
008: History:
009: Wed Jul 6 18:56:30 2005, Created by tomyeh
010: }}IS_NOTE
011:
012: Copyright (C) 2005 Potix Corporation. All Rights Reserved.
013:
014: {{IS_RIGHT
015: This program is distributed under GPL Version 2.0 in the hope that
016: it will be useful, but WITHOUT ANY WARRANTY.
017: }}IS_RIGHT
018: */
019: package org.zkoss.zul;
020:
021: import java.util.List;
022: import java.util.LinkedList;
023: import java.util.Iterator;
024:
025: import org.zkoss.xml.HTMLs;
026:
027: import org.zkoss.zk.ui.Component;
028: import org.zkoss.zk.ui.UiException;
029:
030: import org.zkoss.zul.impl.LabelImageElement;
031:
032: /**
033: * A treecell.
034: *
035: * <p>In XUL, treecell cannot have any child, but ZUL allows it.
036: * Thus, you could place any kind of children in it. They will be placed
037: * right after the image and label.
038: *
039: * @author tomyeh
040: */
041: public class Treecell extends LabelImageElement {
042: private static final String ROOT_OPEN = "root-open";
043: private static final String ROOT_CLOSE = "root-close";
044: private static final String LAST_OPEN = "last-open";
045: private static final String LAST_CLOSE = "last-close";
046: private static final String TEE_OPEN = "tee-open";
047: private static final String TEE_CLOSE = "tee-close";
048: private static final String TEE = "tee";
049: private static final String LAST = "last";
050: private static final String VBAR = "vbar";
051: private static final String SPACER = "spacer";
052:
053: private int _span = 1;
054:
055: public Treecell() {
056: }
057:
058: public Treecell(String label) {
059: setLabel(label);
060: }
061:
062: public Treecell(String label, String src) {
063: setLabel(label);
064: setImage(src);
065: }
066:
067: /** Return the tree that owns this cell.
068: */
069: public Tree getTree() {
070: for (Component n = this ; (n = n.getParent()) != null;)
071: if (n instanceof Tree)
072: return (Tree) n;
073: return null;
074: }
075:
076: /** Returns the tree col associated with this cell, or null if not available.
077: */
078: public Treecol getTreecol() {
079: final Tree tree = getTree();
080: if (tree != null) {
081: final Treecols lcs = tree.getTreecols();
082: if (lcs != null) {
083: final int j = getColumnIndex();
084: final List lcschs = lcs.getChildren();
085: if (j < lcschs.size())
086: return (Treecol) lcschs.get(j);
087: }
088: }
089: return null;
090: }
091:
092: /** Returns the column index of this cell, starting from 0.
093: */
094: public int getColumnIndex() {
095: int j = 0;
096: for (Iterator it = getParent().getChildren().iterator(); it
097: .hasNext(); ++j)
098: if (it.next() == this )
099: break;
100: return j;
101: }
102:
103: /** Returns the maximal length for this cell, which is decided by
104: * the corresponding {@link #getTreecol}'s {@link Treecol#getMaxlength}.
105: */
106: public int getMaxlength() {
107: final Tree tree = getTree();
108: if (tree == null)
109: return 0;
110: final Treecol lc = getTreecol();
111: return lc != null ? lc.getMaxlength() : 0;
112: }
113:
114: /** Returns the level this cell is. The root is level 0.
115: */
116: public int getLevel() {
117: final Component parent = getParent();
118: return parent != null ? ((Treerow) parent).getLevel() : 0;
119: }
120:
121: /** Returns number of columns to span this cell.
122: * Default: 1.
123: */
124: public int getSpan() {
125: return _span;
126: }
127:
128: /** Sets the number of columns to span this cell.
129: * <p>It is the same as the colspan attribute of HTML TD tag.
130: */
131: public void setSpan(int span) {
132: if (_span != span) {
133: _span = span;
134: smartUpdate("colspan", Integer.toString(_span));
135: }
136: }
137:
138: //-- Internal use only --//
139: /** Returns the prefix of the first column (in HTML tags), null if this
140: * is not first column. Called only by treecell.jsp.
141: *
142: * <p>Used only for component template, not for application developers.
143: */
144: public String getColumnHtmlPrefix() {
145: if (isFirstColumn()) {
146: final Treeitem item = getTreeitem();
147: final Tree tree = getTree();
148: final StringBuffer sb = new StringBuffer(80);
149: if (tree != null) {
150: if (tree.isCheckmark()) {
151: sb.append("<input type=\"").append(
152: tree.isMultiple() ? "checkbox" : "radio")
153: .append('"');
154: if (item.isDisabled())
155: sb.append(" disabled=\"disabled\"");
156: if (item.isSelected())
157: sb.append(" checked=\"checked\"");
158: //NOTE: use Treerow's uuid! NOT Treeitem's!
159: sb.append(" id=\"").append(getParent().getUuid())
160: .append("!cm\" z.type=\"Tcfc\"/>");
161: } else if (item.isFocusRequired()) {
162: //NOTE: use Treerow's uuid! NOT Treeitem's!
163: sb.append("<a href=\"javascript:;\" id=\"").append(
164: getParent().getUuid()).append(
165: "!sel\" z.type=\"Tcfc\"> </a>");
166: }
167: }
168: String iconScls = null;
169: if (tree != null)
170: iconScls = tree.getIconSclass();
171: if (iconScls == null)
172: iconScls = ""; //default
173:
174: final Treeitem[] pitems = getTreeitems(item);
175: for (int j = 0; j < pitems.length; ++j)
176: appendIcon(sb, iconScls, j == 0
177: || isLastChild(pitems[j]) ? SPACER : VBAR,
178: false);
179:
180: if (item.isContainer()) {
181: appendIcon(
182: sb,
183: iconScls,
184: item.isOpen() ? pitems.length == 0 ? ROOT_OPEN
185: : isLastChild(item) ? LAST_OPEN
186: : TEE_OPEN
187: : pitems.length == 0 ? ROOT_CLOSE
188: : isLastChild(item) ? LAST_CLOSE
189: : TEE_CLOSE, true);
190: } else {
191: appendIcon(sb, iconScls, pitems.length == 0 ? SPACER
192: : isLastChild(item) ? LAST : TEE, false);
193: }
194: return sb.toString();
195: } else {
196: //To make the tree's height more correct, we have to generate
197: //for empty cell. Otherwise, IE will make the height too small
198: final boolean empty = getImage() == null
199: && getLabel().length() == 0
200: && getChildren().isEmpty();
201: return empty ? " " : null;
202: }
203: }
204:
205: /** Returns the postfix of the first column (in HTML tags), null if this
206: * is not first column. Called only by treecell.jsp.
207: */
208: public String getColumnHtmlPostfix() {
209: return null;
210: }
211:
212: /** Returns whether this is the first column. */
213: private boolean isFirstColumn() {
214: final Component parent = getParent();
215: return parent != null && parent.getFirstChild() == this ;
216: }
217:
218: /** Returns whether an item is the last child.
219: */
220: public boolean isLastChild(Treeitem item) {
221: final Component parent = item.getParent();
222: if (parent == null)
223: return true;
224:
225: final List sibs = parent.getChildren();
226: return sibs.get(sibs.size() - 1) == item;
227: }
228:
229: /** Returns an array of Treeitem from the root.
230: */
231: private Treeitem[] getTreeitems(Component item) {
232: final List pitems = new LinkedList();
233: for (;;) {
234: final Component tch = item.getParent();
235: if (tch == null)
236: break;
237: item = tch.getParent();
238: if (item == null || item instanceof Tree)
239: break;
240: pitems.add(0, item);
241: }
242: return (Treeitem[]) pitems.toArray(new Treeitem[pitems.size()]);
243: }
244:
245: /** Returns the nestest parent {@link Treeitem}.
246: * @deprecated As of release 2.4.1, due to confusion
247: */
248: public Treeitem getTreeitem() {
249: final Component parent = getParent();
250: return parent != null ? (Treeitem) parent.getParent() : null;
251: }
252:
253: /** Generates HTML tags for <img>.
254: * @param button whether this is the button to toggle open/close
255: */
256: private void appendIcon(StringBuffer sb, String sclass,
257: String name, boolean button) {
258: sb.append("<span z.fc=\"t\" class=\"").append(sclass).append(
259: '-').append(name).append('"');
260: //z.fc used to let tree.js know what to clone
261:
262: if (button) {
263: final Treeitem item = getTreeitem();
264: if (item != null) {
265: final Treerow tr = item.getTreerow();
266: if (tr != null)
267: sb.append(" z.type=\"Tcop\" id=\"").append(
268: tr.getUuid()).append("!open\"");
269: }
270: }
271:
272: sb.append("></span>");
273: }
274:
275: //-- super --//
276: /** Returns the width which the same as {@link #getTreecol}'s width.
277: */
278: public String getWidth() {
279: final Treecol col = getTreecol();
280: return col != null ? col.getWidth() : null;
281: }
282:
283: public void setWidth(String width) {
284: throw new UnsupportedOperationException(
285: "Set treecol's width instead");
286: }
287:
288: /** Returns the attributes used by the embedded HTML LABEL tag.
289: * It returns text-relevant styles only.
290: * <p>Used only by component developer.
291: */
292: public String getLabelAttrs() {
293: final String style = HTMLs.getTextRelevantStyle(getRealStyle());
294: return style.length() > 0 ? " style=\"" + style + '"' : "";
295: }
296:
297: public String getOuterAttrs() {
298: final String attrs = super .getOuterAttrs();
299:
300: final Treecol col = getTreecol();
301: final String clkattrs = getAllOnClickAttrs(false);
302: if (col == null && clkattrs == null && _span == 1)
303: return attrs;
304:
305: final StringBuffer sb = new StringBuffer(64).append(attrs);
306: if (col != null)
307: sb.append(col.getColAttrs());
308: if (clkattrs != null)
309: sb.append(clkattrs);
310: if (_span != 1)
311: HTMLs.appendAttribute(sb, "colspan", _span);
312: return sb.toString();
313: }
314:
315: //-- Component --//
316: public void setParent(Component parent) {
317: if (parent != null && !(parent instanceof Treerow))
318: throw new UiException("Wrong parent: " + parent);
319: super.setParent(parent);
320: }
321: }
|