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    }