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