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.StringUtils; 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, commands[i].getCommand()); 199 toolbar.getChildren().add(command); 200 201 for (ActionListener listener : getActionListeners()) { 202 command.addActionListener(listener); 203 } 204 command.setActionListener(getActionListener()); 205 command.getAttributes().put( 206 TobagoConstants.ATTR_IMAGE, "image/tobago.tree." + commands[i].getCommand() + ".gif"); 207 String title = ResourceManagerUtil.getPropertyNotNull(facesContext, "tobago", 208 "tree" + StringUtils.firstToUpperCase(commands[i].getCommand())); 209 command.getAttributes().put(TobagoConstants.ATTR_TIP, title); 210 211 } 212 213 getFacets().put("defaultToolbar", toolbar); 214 215 } 216 217 private void recreateTreeNodes() { 218 UITreeOldNode root = getRoot(); 219 // Delete all UIComponent childs, because moving of childen will not work 220 // in Mutable Tree. 221 // They may have invalid modelReferences. 222 try { 223 if (root != null) { 224 if (LOG.isDebugEnabled()) { 225 LOG.debug("removing root 1"); 226 } 227 getChildren().remove(root); 228 if (LOG.isDebugEnabled()) { 229 LOG.debug("removing root 2"); 230 } 231 } 232 } catch (Exception e) { 233 LOG.error("", e); 234 } 235 236 try { 237 root = new UITreeOldNode(this, 0); 238 root.createTreeNodes(); 239 } catch (Exception e) { 240 LOG.error(e, e); 241 } 242 } 243 244 public UITreeOldNode getRoot() { 245 // find the UITreeOldNode in the childen. 246 for (Iterator i = getChildren().iterator(); i.hasNext();) { 247 UIComponent child = (UIComponent) i.next(); 248 if (child instanceof UITreeOldNode) { 249 return (UITreeOldNode) child; 250 } 251 } 252 // in a new UITree isn't a root 253 return null; 254 } 255 256 public void encodeChildren(FacesContext context) 257 throws IOException { 258 // will be called from end.jsp 259 } 260 261 public UITreeOldNode findUITreeNode(UITreeOldNode node, TreeNode treeNode) { 262 UITreeOldNode found = null; 263 if (node.getTreeNode().equals(treeNode)) { 264 return node; 265 } else { 266 for (Iterator iter = node.getChildren().iterator(); iter.hasNext();) { 267 UITreeOldNode uiTreeNode = (UITreeOldNode) iter.next(); 268 found = findUITreeNode(uiTreeNode, treeNode); 269 if (found != null) { 270 break; 271 } 272 } 273 } 274 return found; 275 } 276 277 public boolean getRendersChildren() { 278 return true; 279 } 280 281 public boolean isSelectableTree() { 282 final Object selectable 283 = ComponentUtil.getAttribute(this, TobagoConstants.ATTR_SELECTABLE); 284 return selectable != null 285 && (selectable.equals("multi") || selectable.equals("multiLeafOnly") 286 || selectable.equals("single") || selectable.equals("singleLeafOnly") 287 || selectable.equals("sibling") || selectable.equals("siblingLeafOnly")); 288 } 289 290 public void processDecodes(FacesContext facesContext) { 291 292 if (!isRendered()) { 293 return; 294 } 295 296 if (ComponentUtil.isOutputOnly(this)) { 297 setValid(true); 298 } else { 299 // in tree first decode node and than decode children 300 301 decode(facesContext); 302 303 for (Iterator i = getFacetsAndChildren(); i.hasNext();) { 304 UIComponent uiComponent = ((UIComponent) i.next()); 305 uiComponent.processDecodes(facesContext); 306 } 307 } 308 } 309 310 public void validate(FacesContext context) { 311 if (isRequired() && getState().getSelection().size() == 0) { 312 setValid(false); 313 FacesMessage facesMessage = MessageFactory.createFacesMessage(context, 314 UISelectOne.MESSAGE_VALUE_REQUIRED, FacesMessage.SEVERITY_ERROR); 315 context.addMessage(getClientId(context), facesMessage); 316 } 317 318 String selectable = ComponentUtil.getStringAttribute(this, 319 TobagoConstants.ATTR_SELECTABLE); 320 if (selectable != null && selectable.endsWith("LeafOnly")) { 321 322 Set<DefaultMutableTreeNode> selection = getState().getSelection(); 323 324 for (DefaultMutableTreeNode node : selection) { 325 if (!node.isLeaf()) { 326 setValid(false); 327 FacesMessage facesMessage = MessageFactory.createFacesMessage( 328 context, MESSAGE_NOT_LEAF, FacesMessage.SEVERITY_ERROR); 329 context.addMessage(getClientId(context), facesMessage); 330 break; // don't continue iteration, no dublicate messages needed 331 } 332 } 333 } 334 335 // call all validators 336 if (getValidators() != null) { 337 for (Validator validator : getValidators()) { 338 try { 339 validator.validate(context, this, null); 340 } catch (ValidatorException ve) { 341 // If the validator throws an exception, we're 342 // invalid, and we need to add a message 343 setValid(false); 344 FacesMessage message = ve.getFacesMessage(); 345 if (message != null) { 346 message.setSeverity(FacesMessage.SEVERITY_ERROR); 347 context.addMessage(getClientId(context), message); 348 } 349 } 350 } 351 } 352 } 353 354 public void updateModel(FacesContext facesContext) { 355 // nothig to update for tree's 356 // TODO: updateing the model here and *NOT* in the decode phase 357 } 358 359 public Object saveState(FacesContext context) { 360 Object[] state = new Object[8]; 361 state[0] = super.saveState(context); 362 state[1] = saveAttachedState(context, actionListenerBinding); 363 state[2] = showJunctionsSet ? showJunctions : null; 364 state[3] = showIconsSet ? showIcons : null; 365 state[4] = showRootSet ? showRoot : null; 366 state[5] = showRootJunctionSet ? showRootJunction : null; 367 state[6] = mode; 368 state[7] = tabIndex; 369 return state; 370 } 371 372 public void restoreState(FacesContext context, Object state) { 373 Object[] values = (Object[]) state; 374 super.restoreState(context, values[0]); 375 actionListenerBinding = (MethodBinding) restoreAttachedState(context, values[1]); 376 if (values[2] != null) { 377 showJunctions = (Boolean) values[2]; 378 showJunctionsSet = true; 379 } 380 if (values[3] != null) { 381 showIcons = (Boolean) values[3]; 382 showIconsSet = true; 383 } 384 if (values[4] != null) { 385 showRoot = (Boolean) values[4]; 386 showRootSet = true; 387 } 388 if (values[5] != null) { 389 showRootJunction = (Boolean) values[5]; 390 showRootJunctionSet = true; 391 } 392 mode = (String) values[6]; 393 tabIndex = (Integer) values[7]; 394 } 395 396 public UITreeOld.Command[] getCommands() { 397 return treeCommands; 398 } 399 400 public TreeState getState() { 401 if (treeState != null) { 402 return treeState; 403 } 404 ValueBinding valueBinding = getValueBinding(TobagoConstants.ATTR_STATE); 405 if (valueBinding != null) { 406 FacesContext facesContext = getFacesContext(); 407 TreeState state = (TreeState) valueBinding.getValue(facesContext); 408 if (state == null) { 409 state = new TreeState(); 410 valueBinding.setValue(facesContext, state); 411 } 412 return state; 413 } else { 414 treeState = new TreeState(); 415 return treeState; 416 } 417 } 418 419 public void setState(TreeState state) { 420 this.treeState = state; 421 } 422 423 public boolean isShowJunctions() { 424 if (showJunctionsSet) { 425 return (showJunctions); 426 } 427 ValueBinding vb = getValueBinding(TobagoConstants.ATTR_SHOW_JUNCTIONS); 428 if (vb != null) { 429 return (!Boolean.FALSE.equals(vb.getValue(getFacesContext()))); 430 } else { 431 return (this.showJunctions); 432 } 433 } 434 435 public void setShowJunctions(boolean showJunctions) { 436 this.showJunctions = showJunctions; 437 this.showJunctionsSet = true; 438 } 439 440 public boolean isShowIcons() { 441 if (showIconsSet) { 442 return (showIcons); 443 } 444 ValueBinding vb = getValueBinding(TobagoConstants.ATTR_SHOW_ICONS); 445 if (vb != null) { 446 return (!Boolean.FALSE.equals(vb.getValue(getFacesContext()))); 447 } else { 448 return (this.showIcons); 449 } 450 } 451 452 public void setShowIcons(boolean showIcons) { 453 this.showIcons = showIcons; 454 this.showIconsSet = true; 455 } 456 457 public boolean isShowRoot() { 458 if (showRootSet) { 459 return (showRoot); 460 } 461 ValueBinding vb = getValueBinding(TobagoConstants.ATTR_SHOW_ROOT); 462 if (vb != null) { 463 return (!Boolean.FALSE.equals(vb.getValue(getFacesContext()))); 464 } else { 465 return (this.showRoot); 466 } 467 } 468 469 public void setShowRoot(boolean showRoot) { 470 this.showRoot = showRoot; 471 this.showRootSet = true; 472 } 473 474 public boolean isShowRootJunction() { 475 if (showRootJunctionSet) { 476 return (showRootJunction); 477 } 478 ValueBinding vb = getValueBinding(TobagoConstants.ATTR_SHOW_ROOT_JUNCTION); 479 if (vb != null) { 480 return (!Boolean.FALSE.equals(vb.getValue(getFacesContext()))); 481 } else { 482 return (this.showRootJunction); 483 } 484 } 485 486 public void setShowRootJunction(boolean showRootJunction) { 487 this.showRootJunction = showRootJunction; 488 this.showRootJunctionSet = true; 489 } 490 491 public static class Command implements Serializable { 492 private String command; 493 494 public Command(String command) { 495 this.command = command; 496 } 497 498 public String getCommand() { 499 return command; 500 } 501 } 502 503 public Integer getTabIndex() { 504 if (tabIndex != null) { 505 return tabIndex; 506 } 507 ValueBinding vb = getValueBinding(ATTR_TAB_INDEX); 508 if (vb != null) { 509 Number number = (Number) vb.getValue(getFacesContext()); 510 if (number != null) { 511 return Integer.valueOf(number.intValue()); 512 } 513 } 514 return null; 515 } 516 517 public void setTabIndex(Integer tabIndex) { 518 this.tabIndex = tabIndex; 519 } 520 }