001: /*
002: * MyGWT Widget Library
003: * Copyright(c) 2007, MyGWT.
004: * licensing@mygwt.net
005: *
006: * http://mygwt.net/license
007: */
008: package net.mygwt.ui.client.widget.tree;
009:
010: import java.util.ArrayList;
011: import java.util.List;
012:
013: import net.mygwt.ui.client.Events;
014: import net.mygwt.ui.client.MyGWT;
015: import net.mygwt.ui.client.event.BaseEvent;
016: import net.mygwt.ui.client.event.Listener;
017: import net.mygwt.ui.client.util.Observable;
018:
019: import com.google.gwt.user.client.Command;
020: import com.google.gwt.user.client.DeferredCommand;
021: import com.google.gwt.user.client.ui.KeyboardListener;
022:
023: /**
024: * A single-select tree selection model.
025: *
026: * <dl>
027: * <dt><b>Events:</b></dt>
028: *
029: * <dd><b>SelectionChange</b> : (source, widget, item, items)<br>
030: * <div>Fires after the selection has changed.</div>
031: * <ul>
032: * <li>source : this</li>
033: * <li>widget : the table</li>
034: * <li>item : single selection or null</li>
035: * <li>items : multi selection or null</li>
036: * </ul>
037: * </dd>
038: * </dl>
039: *
040: * @see MultiSelectionModel
041: */
042: public class TreeSelectionModel extends Observable {
043:
044: protected Tree tree;
045: protected TreeItem selItem;
046: protected TreeItem lastSelItem;
047: protected Listener treeListener;
048:
049: public TreeSelectionModel() {
050: treeListener = new Listener() {
051: public void handleEvent(BaseEvent be) {
052: int type = be.type;
053: TreeItem item = (TreeItem) be.widget;
054: switch (type) {
055: case Events.MouseDown:
056: if (!be.isRightClick()) {
057: onItemClick(item, be);
058: }
059: break;
060: case Events.KeyDown:
061: onKeyDown(be);
062: break;
063: }
064: be.cancelBubble();
065: }
066: };
067: }
068:
069: /**
070: * Deselects all selections.
071: */
072: public void deselectAll() {
073: if (selItem != null) {
074: selItem.getUI().onSelectedChange(false);
075: selItem = null;
076: BaseEvent be = new BaseEvent();
077: be.widget = tree;
078: fireEvent(Events.SelectionChange, be);
079: tree.fireEvent(Events.SelectionChange, be);
080: }
081: }
082:
083: /**
084: * Returns the selected item.
085: *
086: * @return the selected item or <code>null</code> if no selection
087: */
088: public TreeItem getSelected() {
089: return selItem;
090: }
091:
092: /**
093: * Returns a array of selected items.
094: *
095: * @return the selected items
096: */
097: public TreeItem[] getSelection() {
098: List list = new ArrayList();
099: if (selItem != null) {
100: list.add(selItem);
101: }
102: return (TreeItem[]) list.toArray(new TreeItem[list.size()]);
103: }
104:
105: /**
106: * Returns the model's tree.
107: *
108: * @return the tree
109: */
110: public Tree getTree() {
111: return tree;
112: }
113:
114: /**
115: * Binds the model to the specified tree.
116: *
117: * @param tree the tree
118: */
119: public void init(Tree tree) {
120: this .tree = tree;
121: tree.addListener(Events.MouseDown, treeListener);
122: tree.addListener(Events.KeyDown, treeListener);
123: }
124:
125: /**
126: * Returns <code>true</code> if the item is selected.
127: *
128: * @param item the item
129: * @return the selected state
130: */
131: public boolean isSelected(TreeItem item) {
132: return selItem == item;
133: }
134:
135: /**
136: * Selects a item.
137: *
138: * @param item the item to be selected
139: */
140: public void select(final TreeItem item) {
141: if (isSelected(item)) {
142: return;
143: }
144: if (!tree.isRendered()) {
145: tree.addListener(Events.Render, new Listener() {
146: public void handleEvent(BaseEvent be) {
147: removeListener(Events.Render, this );
148: select(item);
149: }
150: });
151: return;
152: }
153: TreeItem last = selItem != null ? selItem : lastSelItem;
154: if (last != null) {
155: last.getUI().onSelectedChange(false);
156: }
157: selItem = item;
158: lastSelItem = item;
159: selItem.getUI().onSelectedChange(true);
160: BaseEvent be = new BaseEvent(tree);
161: be.item = item;
162: be.items = getSelection();
163: be.widget = tree;
164: fireEvent(Events.SelectionChange, be);
165: tree.fireEvent(Events.SelectionChange, be);
166: if (MyGWT.isSafari) {
167: DeferredCommand.addCommand(new Command() {
168: public void execute() {
169: tree.focus();
170: }
171: });
172: }
173: }
174:
175: /**
176: * Selects the item below the selected item in the tree, intelligently walking
177: * the nodes.
178: */
179: public void selectNext() {
180: TreeItem sel = selItem != null ? selItem : lastSelItem;
181: if (sel == null) {
182: return;
183: }
184: if (sel.firstChild() != null && sel.isExpanded()) {
185: select(sel.firstChild());
186: } else if (sel.nextSibling() != null) {
187: select(sel.nextSibling());
188: } else if (sel.getParentItem() != null) {
189: TreeItem p = sel.getParentItem();
190: while (p != null) {
191: if (p.nextSibling() != null) {
192: select(p.nextSibling());
193: return;
194: }
195: p = p.getParentItem();
196: }
197: }
198: }
199:
200: /**
201: * Selects the item above the selected item in the tree, intelligently walking
202: * the nodes.
203: */
204: public void selectPrevious() {
205: TreeItem sel = selItem != null ? selItem : lastSelItem;
206: if (sel == null) {
207: return;
208: }
209: TreeItem prev = sel.previousSibling();
210: if (prev != null) {
211: if (!prev.isExpanded() || prev.getItemCount() < 1) {
212: select(prev);
213: } else {
214: TreeItem lastChild = prev.lastChild();
215: while (lastChild != null
216: && lastChild.getItemCount() > 0) {
217: lastChild = lastChild.lastChild();
218: }
219: select(lastChild);
220: }
221: } else if (sel.getParentItem() != null
222: && !sel.getParentItem().isRoot()) {
223: select(sel.getParentItem());
224: }
225: }
226:
227: /**
228: * Deselect a item.
229: *
230: * @param item the item to be deselected
231: */
232: public void deselect(TreeItem item) {
233: if (selItem == item) {
234: deselectAll();
235: }
236: }
237:
238: protected void onItemClick(TreeItem item, BaseEvent be) {
239: if (!be.within(item.getUI().getJointEl())
240: && !be.within(item.getUI().getCheckEl())) {
241: if (isSelected(item) && be.isControlKey()) {
242: deselect(item);
243: } else {
244: select(item);
245: }
246: }
247: }
248:
249: protected void onKeyDown(BaseEvent be) {
250: TreeItem sel = selItem != null ? selItem : lastSelItem;
251: if (sel == null) {
252: return;
253: }
254: int key = be.getKeyCode();
255: switch (key) {
256: case KeyboardListener.KEY_DOWN:
257: be.stopEvent();
258: selectNext();
259: break;
260: case KeyboardListener.KEY_UP:
261: be.stopEvent();
262: selectPrevious();
263: break;
264: case KeyboardListener.KEY_LEFT:
265: be.preventDefault();
266: if (!sel.isLeaf() && sel.isExpanded()) {
267: sel.setExpanded(false);
268: } else if (sel.getParentItem() != null
269: && !sel.getParentItem().isRoot()) {
270: select(sel.getParentItem());
271: }
272: break;
273: case KeyboardListener.KEY_RIGHT:
274: be.preventDefault();
275: if (!sel.isLeaf()) {
276: if (!sel.isExpanded()) {
277: sel.setExpanded(true);
278: return;
279: }
280:
281: }
282: selectNext();
283: break;
284: }
285: }
286:
287: }
|