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 }