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