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 }