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 }