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