001 /*
002 * Licensed to the Apache Software Foundation (ASF) under one
003 * or more contributor license agreements. See the NOTICE file
004 * distributed with this work for additional information
005 * regarding copyright ownership. The ASF licenses this file
006 * to you under the Apache License, Version 2.0 (the
007 * "License"); you may not use this file except in compliance
008 * with the License. You may obtain a copy of the License at
009 *
010 * http://www.apache.org/licenses/LICENSE-2.0
011 *
012 * Unless required by applicable law or agreed to in writing,
013 * software distributed under the License is distributed on an
014 * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
015 * KIND, either express or implied. See the License for the
016 * specific language governing permissions and limitations
017 * under the License.
018 */
019
020 package org.apache.myfaces.tobago.component;
021
022 import org.apache.commons.logging.Log;
023 import org.apache.commons.logging.LogFactory;
024 import org.apache.myfaces.tobago.TobagoConstants;
025 import static org.apache.myfaces.tobago.TobagoConstants.ATTR_TAB_INDEX;
026 import org.apache.myfaces.tobago.context.ResourceManagerUtil;
027 import org.apache.myfaces.tobago.model.TreeState;
028 import org.apache.myfaces.tobago.taglib.component.ToolBarTag;
029 import org.apache.myfaces.tobago.util.MessageFactory;
030 import org.apache.myfaces.tobago.util.StringUtils;
031
032 import javax.faces.application.FacesMessage;
033 import javax.faces.component.ActionSource;
034 import javax.faces.component.NamingContainer;
035 import javax.faces.component.UICommand;
036 import javax.faces.component.UIComponent;
037 import javax.faces.component.UIPanel;
038 import javax.faces.context.FacesContext;
039 import javax.faces.el.MethodBinding;
040 import javax.faces.el.ValueBinding;
041 import javax.faces.event.AbortProcessingException;
042 import javax.faces.event.ActionListener;
043 import javax.faces.event.FacesEvent;
044 import javax.faces.validator.Validator;
045 import javax.faces.validator.ValidatorException;
046 import javax.swing.tree.DefaultMutableTreeNode;
047 import javax.swing.tree.TreeNode;
048 import java.io.IOException;
049 import java.io.Serializable;
050 import java.util.Iterator;
051 import java.util.Set;
052
053 @Deprecated
054 public class UITreeOld extends javax.faces.component.UIInput implements NamingContainer, ActionSource {
055
056 private static final Log LOG = LogFactory.getLog(UITreeOld.class);
057
058 public static final String COMPONENT_TYPE = "org.apache.myfaces.tobago.TreeOld";
059 public static final String MESSAGE_NOT_LEAF = "tobago.tree.MESSAGE_NOT_LEAF";
060
061 public static final String SEP = "-";
062 // TODO should moved to renderer
063 public static final String TREE_DIV = SEP + "div";
064 public static final String TREE_STATE = SEP + "treeState";
065 public static final String SELECT_STATE = SEP + "selectState";
066 public static final String MARKER = SEP + "marker";
067 public static final String SCROLL_POSITION = SEP + "scrollPosition";
068
069 public static final String FACET_TREE_NODE_COMMAND = "treeNodeCommand";
070 public static final String PARAMETER_TREE_NODE_ID = "treeNodeId";
071
072 public static final String COMMAND_PREFIX = "command";
073
074 public static final String COMMAND_NEW = "new";
075 public static final String COMMAND_DELETE = "delete";
076 public static final String COMMAND_EDIT = "edit";
077 public static final String COMMAND_CUT = "cut";
078 public static final String COMMAND_COPY = "copy";
079 public static final String COMMAND_PASTE = "paste";
080 public static final String COMMAND_MOVE_UP = "moveUp";
081 public static final String COMMAND_MOVE_DOWN = "moveDown";
082
083 private UITreeOld.Command[] treeCommands;
084
085 private MethodBinding actionListenerBinding;
086 private TreeState treeState;
087
088 private boolean showJunctions = true;
089 private boolean showJunctionsSet = false;
090 private boolean showIcons = true;
091 private boolean showIconsSet = false;
092 private boolean showRoot = true;
093 private boolean showRootSet = false;
094 private boolean showRootJunction = true;
095 private boolean showRootJunctionSet = false;
096
097 private String mode;
098
099 private Integer tabIndex;
100
101 public UITreeOld() {
102 treeCommands = new UITreeOld.Command[]{
103 new UITreeOld.Command(COMMAND_NEW),
104 new UITreeOld.Command(COMMAND_DELETE),
105 new UITreeOld.Command(COMMAND_EDIT),
106 new UITreeOld.Command(COMMAND_CUT),
107 new UITreeOld.Command(COMMAND_COPY),
108 new UITreeOld.Command(COMMAND_PASTE),
109 new UITreeOld.Command(COMMAND_MOVE_UP),
110 new UITreeOld.Command(COMMAND_MOVE_DOWN),
111 };
112 }
113
114 // ---------------------------- interface ActionSource
115
116 public void broadcast(FacesEvent event) throws AbortProcessingException {
117 super.broadcast(event);
118
119 MethodBinding binding = getActionListener();
120
121 if (binding != null) {
122 FacesContext context = getFacesContext();
123 binding.invoke(context, new Object[]{event});
124 }
125 }
126
127 public MethodBinding getAction() {
128 return null;
129 }
130
131 public void setAction(MethodBinding methodBinding) {
132
133 }
134
135 public String getMode() {
136 if (mode != null) {
137 return mode;
138 }
139 ValueBinding vb = getValueBinding(TobagoConstants.ATTR_MODE);
140 if (vb != null) {
141 return (String) vb.getValue(getFacesContext());
142 } else {
143 return "tree";
144 }
145 }
146
147 public void setMode(String mode) {
148 this.mode = mode;
149 }
150
151 public MethodBinding getActionListener() {
152 return actionListenerBinding;
153 }
154
155 public void setActionListener(MethodBinding actionListener) {
156 this.actionListenerBinding = actionListener;
157 }
158
159 public void addActionListener(ActionListener actionListener) {
160 addFacesListener(actionListener);
161 }
162
163 public ActionListener[] getActionListeners() {
164 return (ActionListener[]) getFacesListeners(ActionListener.class);
165 }
166
167 public void removeActionListener(ActionListener actionListener) {
168 removeFacesListener(actionListener);
169 }
170
171 public void encodeBegin(FacesContext facesContext)
172 throws IOException {
173 recreateTreeNodes();
174 if (ComponentUtil.getBooleanAttribute(this, TobagoConstants.ATTR_MUTABLE)
175 && getFacet("mutableToolbar") == null
176 && getFacet("defaultToolbar") == null) {
177 createDefaultToolbar(facesContext);
178 }
179 super.encodeBegin(facesContext);
180 }
181
182 // TODO move this to renderkit
183 public void createDefaultToolbar(FacesContext facesContext) {
184
185 UIComponent toolbar = ComponentUtil.createComponent(
186 facesContext, UIPanel.COMPONENT_TYPE,
187 TobagoConstants.RENDERER_TYPE_TOOL_BAR);
188 toolbar.getAttributes().put(TobagoConstants.ATTR_ICON_SIZE, ToolBarTag.ICON_SMALL);
189 toolbar.getAttributes().put(TobagoConstants.ATTR_LABEL_POSITION, ToolBarTag.LABEL_OFF);
190 ActionListener[] handlers = getActionListeners();
191
192 if ((handlers == null || handlers.length == 0) && getActionListener() == null) {
193 LOG.error("No actionListener found in tree, so tree editing will not work!");
194 }
195
196 UITreeOld.Command[] commands = getCommands();
197 for (int i = 0; i < commands.length; i++) {
198 UICommand command = (UICommand) ComponentUtil.createComponent(
199 facesContext, UICommand.COMPONENT_TYPE,
200 TobagoConstants.RENDERER_TYPE_LINK, commands[i].getCommand());
201 toolbar.getChildren().add(command);
202
203 for (ActionListener listener : getActionListeners()) {
204 command.addActionListener(listener);
205 }
206 command.setActionListener(getActionListener());
207 command.getAttributes().put(
208 TobagoConstants.ATTR_IMAGE, "image/tobago.tree." + commands[i].getCommand() + ".gif");
209 String title = ResourceManagerUtil.getPropertyNotNull(facesContext, "tobago",
210 "tree" + StringUtils.firstToUpperCase(commands[i].getCommand()));
211 command.getAttributes().put(TobagoConstants.ATTR_TIP, title);
212
213 }
214
215 getFacets().put("defaultToolbar", toolbar);
216
217 }
218
219 private void recreateTreeNodes() {
220 UITreeOldNode root = getRoot();
221 // Delete all UIComponent childs, because moving of childen will not work
222 // in Mutable Tree.
223 // They may have invalid modelReferences.
224 try {
225 if (root != null) {
226 if (LOG.isDebugEnabled()) {
227 LOG.debug("removing root 1");
228 }
229 getChildren().remove(root);
230 if (LOG.isDebugEnabled()) {
231 LOG.debug("removing root 2");
232 }
233 }
234 } catch (Exception e) {
235 LOG.error("", e);
236 }
237
238 try {
239 root = new UITreeOldNode(this, 0);
240 root.createTreeNodes();
241 } catch (Exception e) {
242 LOG.error(e, e);
243 }
244 }
245
246 public UITreeOldNode getRoot() {
247 // find the UITreeOldNode in the childen.
248 for (Iterator i = getChildren().iterator(); i.hasNext();) {
249 UIComponent child = (UIComponent) i.next();
250 if (child instanceof UITreeOldNode) {
251 return (UITreeOldNode) child;
252 }
253 }
254 // in a new UITree isn't a root
255 return null;
256 }
257
258 public void encodeChildren(FacesContext context)
259 throws IOException {
260 // will be called from end.jsp
261 }
262
263 public UITreeOldNode findUITreeNode(UITreeOldNode node, TreeNode treeNode) {
264 UITreeOldNode found = null;
265 if (node.getTreeNode().equals(treeNode)) {
266 return node;
267 } else {
268 for (Iterator iter = node.getChildren().iterator(); iter.hasNext();) {
269 UITreeOldNode uiTreeNode = (UITreeOldNode) iter.next();
270 found = findUITreeNode(uiTreeNode, treeNode);
271 if (found != null) {
272 break;
273 }
274 }
275 }
276 return found;
277 }
278
279 public boolean getRendersChildren() {
280 return true;
281 }
282
283 public boolean isSelectableTree() {
284 final Object selectable
285 = ComponentUtil.getAttribute(this, TobagoConstants.ATTR_SELECTABLE);
286 return selectable != null
287 && (selectable.equals("multi") || selectable.equals("multiLeafOnly")
288 || selectable.equals("single") || selectable.equals("singleLeafOnly")
289 || selectable.equals("sibling") || selectable.equals("siblingLeafOnly"));
290 }
291
292 public void processDecodes(FacesContext facesContext) {
293
294 if (!isRendered()) {
295 return;
296 }
297
298 if (ComponentUtil.isOutputOnly(this)) {
299 setValid(true);
300 } else {
301 // in tree first decode node and than decode children
302
303 decode(facesContext);
304
305 for (Iterator i = getFacetsAndChildren(); i.hasNext();) {
306 UIComponent uiComponent = ((UIComponent) i.next());
307 uiComponent.processDecodes(facesContext);
308 }
309 }
310 }
311
312 public void validate(FacesContext context) {
313 if (isRequired() && getState().getSelection().size() == 0) {
314 setValid(false);
315 FacesMessage facesMessage = MessageFactory.createFacesMessage(context,
316 UISelectOne.MESSAGE_VALUE_REQUIRED, FacesMessage.SEVERITY_ERROR);
317 context.addMessage(getClientId(context), facesMessage);
318 }
319
320 String selectable = ComponentUtil.getStringAttribute(this,
321 TobagoConstants.ATTR_SELECTABLE);
322 if (selectable != null && selectable.endsWith("LeafOnly")) {
323
324 Set<DefaultMutableTreeNode> selection = getState().getSelection();
325
326 for (DefaultMutableTreeNode node : selection) {
327 if (!node.isLeaf()) {
328 setValid(false);
329 FacesMessage facesMessage = MessageFactory.createFacesMessage(
330 context, MESSAGE_NOT_LEAF, FacesMessage.SEVERITY_ERROR);
331 context.addMessage(getClientId(context), facesMessage);
332 break; // don't continue iteration, no dublicate messages needed
333 }
334 }
335 }
336
337 // call all validators
338 if (getValidators() != null) {
339 for (Validator validator : getValidators()) {
340 try {
341 validator.validate(context, this, null);
342 } catch (ValidatorException ve) {
343 // If the validator throws an exception, we're
344 // invalid, and we need to add a message
345 setValid(false);
346 FacesMessage message = ve.getFacesMessage();
347 if (message != null) {
348 message.setSeverity(FacesMessage.SEVERITY_ERROR);
349 context.addMessage(getClientId(context), message);
350 }
351 }
352 }
353 }
354 }
355
356 public void updateModel(FacesContext facesContext) {
357 // nothig to update for tree's
358 // TODO: updateing the model here and *NOT* in the decode phase
359 }
360
361 public Object saveState(FacesContext context) {
362 Object[] state = new Object[8];
363 state[0] = super.saveState(context);
364 state[1] = saveAttachedState(context, actionListenerBinding);
365 state[2] = showJunctionsSet ? showJunctions : null;
366 state[3] = showIconsSet ? showIcons : null;
367 state[4] = showRootSet ? showRoot : null;
368 state[5] = showRootJunctionSet ? showRootJunction : null;
369 state[6] = mode;
370 state[7] = tabIndex;
371 return state;
372 }
373
374 public void restoreState(FacesContext context, Object state) {
375 Object[] values = (Object[]) state;
376 super.restoreState(context, values[0]);
377 actionListenerBinding = (MethodBinding) restoreAttachedState(context, values[1]);
378 if (values[2] != null) {
379 showJunctions = (Boolean) values[2];
380 showJunctionsSet = true;
381 }
382 if (values[3] != null) {
383 showIcons = (Boolean) values[3];
384 showIconsSet = true;
385 }
386 if (values[4] != null) {
387 showRoot = (Boolean) values[4];
388 showRootSet = true;
389 }
390 if (values[5] != null) {
391 showRootJunction = (Boolean) values[5];
392 showRootJunctionSet = true;
393 }
394 mode = (String) values[6];
395 tabIndex = (Integer) values[7];
396 }
397
398 public UITreeOld.Command[] getCommands() {
399 return treeCommands;
400 }
401
402 public TreeState getState() {
403 if (treeState != null) {
404 return treeState;
405 }
406 ValueBinding valueBinding = getValueBinding(TobagoConstants.ATTR_STATE);
407 if (valueBinding != null) {
408 FacesContext facesContext = getFacesContext();
409 TreeState state = (TreeState) valueBinding.getValue(facesContext);
410 if (state == null) {
411 state = new TreeState();
412 valueBinding.setValue(facesContext, state);
413 }
414 return state;
415 } else {
416 treeState = new TreeState();
417 return treeState;
418 }
419 }
420
421 public void setState(TreeState state) {
422 this.treeState = state;
423 }
424
425 public boolean isShowJunctions() {
426 if (showJunctionsSet) {
427 return (showJunctions);
428 }
429 ValueBinding vb = getValueBinding(TobagoConstants.ATTR_SHOW_JUNCTIONS);
430 if (vb != null) {
431 return (!Boolean.FALSE.equals(vb.getValue(getFacesContext())));
432 } else {
433 return (this.showJunctions);
434 }
435 }
436
437 public void setShowJunctions(boolean showJunctions) {
438 this.showJunctions = showJunctions;
439 this.showJunctionsSet = true;
440 }
441
442 public boolean isShowIcons() {
443 if (showIconsSet) {
444 return (showIcons);
445 }
446 ValueBinding vb = getValueBinding(TobagoConstants.ATTR_SHOW_ICONS);
447 if (vb != null) {
448 return (!Boolean.FALSE.equals(vb.getValue(getFacesContext())));
449 } else {
450 return (this.showIcons);
451 }
452 }
453
454 public void setShowIcons(boolean showIcons) {
455 this.showIcons = showIcons;
456 this.showIconsSet = true;
457 }
458
459 public boolean isShowRoot() {
460 if (showRootSet) {
461 return (showRoot);
462 }
463 ValueBinding vb = getValueBinding(TobagoConstants.ATTR_SHOW_ROOT);
464 if (vb != null) {
465 return (!Boolean.FALSE.equals(vb.getValue(getFacesContext())));
466 } else {
467 return (this.showRoot);
468 }
469 }
470
471 public void setShowRoot(boolean showRoot) {
472 this.showRoot = showRoot;
473 this.showRootSet = true;
474 }
475
476 public boolean isShowRootJunction() {
477 if (showRootJunctionSet) {
478 return (showRootJunction);
479 }
480 ValueBinding vb = getValueBinding(TobagoConstants.ATTR_SHOW_ROOT_JUNCTION);
481 if (vb != null) {
482 return (!Boolean.FALSE.equals(vb.getValue(getFacesContext())));
483 } else {
484 return (this.showRootJunction);
485 }
486 }
487
488 public void setShowRootJunction(boolean showRootJunction) {
489 this.showRootJunction = showRootJunction;
490 this.showRootJunctionSet = true;
491 }
492
493 public static class Command implements Serializable {
494 private String command;
495
496 public Command(String command) {
497 this.command = command;
498 }
499
500 public String getCommand() {
501 return command;
502 }
503 }
504
505 public Integer getTabIndex() {
506 if (tabIndex != null) {
507 return tabIndex;
508 }
509 ValueBinding vb = getValueBinding(ATTR_TAB_INDEX);
510 if (vb != null) {
511 Number number = (Number) vb.getValue(getFacesContext());
512 if (number != null) {
513 return Integer.valueOf(number.intValue());
514 }
515 }
516 return null;
517 }
518
519 public void setTabIndex(Integer tabIndex) {
520 this.tabIndex = tabIndex;
521 }
522 }