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    }