1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19 package org.apache.myfaces.trinidad.change;
20
21 import javax.faces.component.NamingContainer;
22 import javax.faces.component.UIComponent;
23 import javax.faces.context.FacesContext;
24
25 import org.apache.myfaces.trinidad.component.UIXComponent;
26 import org.apache.myfaces.trinidad.logging.TrinidadLogger;
27 import org.apache.myfaces.trinidad.util.ComponentUtils;
28
29 import org.w3c.dom.Node;
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47 public final class MoveChildComponentChange
48 extends ComponentChange
49 implements DocumentChange
50 {
51
52
53
54
55
56
57
58
59
60 public MoveChildComponentChange(
61 UIComponent movableChild,
62 UIComponent destinationContainer)
63 {
64 this(movableChild, destinationContainer, null);
65 }
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84 public MoveChildComponentChange(
85 UIComponent movableChild,
86 UIComponent destinationContainer,
87 UIComponent insertBeforeComponent)
88 {
89 if (movableChild == null)
90 throw new IllegalArgumentException(
91 _LOG.getMessage("MOVABLE_CHILD_REQUIRED"));
92
93 if (destinationContainer == null)
94 throw new IllegalArgumentException(
95 _LOG.getMessage("DESTINATION_CONTAINER_REQUIRED"));
96
97 UIComponent viewRoot = FacesContext.getCurrentInstance().getViewRoot();
98
99 String sourceAbsoluteLogicalScopedId = ComponentUtils.getLogicalScopedIdForComponent(movableChild, viewRoot);
100
101 String destinationContainerLogicalPrefix = _getScopedIdPrefix(destinationContainer,
102 ComponentUtils.getLogicalScopedIdForComponent(destinationContainer, viewRoot));
103
104 String movableChildId = movableChild.getId();
105
106 String destinationAbsoluteLogicalScopedId = (destinationContainerLogicalPrefix != null)
107 ? new StringBuilder(destinationContainerLogicalPrefix).
108 append(NamingContainer.SEPARATOR_CHAR).
109 append(movableChildId).toString()
110 : movableChildId;
111
112
113 _commonParent =
114 _getClosestCommonParentUIXComponent(movableChild, destinationContainer);
115
116 if (_commonParent == null)
117 throw new IllegalArgumentException(
118 _LOG.getMessage("COMMON_PARENT_NOT_FOUND"));
119
120
121 _movableChildScopedId =
122 ComponentUtils.getScopedIdForComponent(movableChild, _commonParent);
123 _sourceParentScopedId =
124 ComponentUtils.getScopedIdForComponent(movableChild.getParent(),
125 _commonParent);
126 _destinationContainerScopedId =
127 ComponentUtils.getScopedIdForComponent(destinationContainer, _commonParent);
128
129 _commonParentScopedId =
130 ComponentUtils.getScopedIdForComponent(_commonParent, viewRoot);
131 if (_movableChildScopedId == null ||
132 _sourceParentScopedId == null ||
133 _destinationContainerScopedId == null ||
134 _commonParentScopedId == null)
135 throw new IllegalArgumentException(
136 _LOG.getMessage("MOVE_PARTICIPANTS_WITHOUT_ID"));
137
138
139
140 String commonParentPrefix = _getScopedIdPrefix(_commonParent, _commonParentScopedId);
141
142 _sourceAbsoluteScopedId = (commonParentPrefix != null)
143 ? new StringBuilder(commonParentPrefix).
144 append(NamingContainer.SEPARATOR_CHAR).
145 append(_movableChildScopedId).toString()
146 : _movableChildScopedId;
147
148 _sourceAbsoluteLogicalScopedId = _sourceAbsoluteScopedId.equals(sourceAbsoluteLogicalScopedId) ? null :
149 sourceAbsoluteLogicalScopedId;
150
151
152 String destinationContainerPrefix = _getScopedIdPrefix(destinationContainer,
153 _destinationContainerScopedId);
154
155 StringBuilder destinationScopedIdBuilder = new StringBuilder();
156
157 if (commonParentPrefix != null)
158 {
159 destinationScopedIdBuilder.append(commonParentPrefix).append(NamingContainer.SEPARATOR_CHAR);
160 }
161
162 if (destinationContainerPrefix != null)
163 {
164 destinationScopedIdBuilder.append(destinationContainerPrefix).append(NamingContainer.SEPARATOR_CHAR);
165 }
166
167 _destinationAbsoluteScopedId = destinationScopedIdBuilder.append(movableChildId).toString();
168
169 _destinationAbsoluteLogicalScopedId = _destinationAbsoluteScopedId.equals(destinationAbsoluteLogicalScopedId) ? null :
170 destinationAbsoluteLogicalScopedId;
171
172
173 _insertBeforeId = (insertBeforeComponent == null) ?
174 null:insertBeforeComponent.getId();
175 }
176
177 private String _getScopedIdPrefix(UIComponent component, String scopedId)
178 {
179 if (component instanceof NamingContainer)
180 return scopedId;
181 else
182 {
183
184 int separatorIndex = scopedId.lastIndexOf(NamingContainer.SEPARATOR_CHAR);
185
186 if (separatorIndex >= 0)
187 return scopedId.substring(0, separatorIndex);
188 else
189 {
190
191 return null;
192 }
193 }
194 }
195
196
197
198
199
200
201
202
203
204
205
206
207 public UIComponent add(
208 FacesContext facesContext,
209 ChangeManager changeManager)
210 {
211 UIComponent commonParent = _commonParent;
212
213 if (commonParent == null)
214 commonParent =
215 facesContext.getViewRoot().findComponent(_commonParentScopedId);
216 if (commonParent == null)
217 {
218 _LOG.warning("COMMON_PARENT_NOT_FOUND", _commonParentScopedId);
219 return null;
220 }
221
222
223 changeManager.addComponentChange(facesContext, commonParent, this);
224
225
226 _commonParent = null;
227
228 return commonParent;
229 }
230
231
232
233
234
235
236
237
238 @Override
239 public void changeComponent(UIComponent changeTargetComponent)
240 {
241 if (changeTargetComponent == null)
242 throw new IllegalArgumentException(
243 _LOG.getMessage("COMPONENT_REQUIRED"));
244
245
246 UIComponent destinationContainer =
247 changeTargetComponent.findComponent(_destinationContainerScopedId);
248 if(destinationContainer == null)
249 {
250 _LOG.warning("DESTINATION_CONTAINER_NOT_FOUND",
251 _destinationContainerScopedId);
252 return;
253 }
254
255
256
257
258
259
260
261
262
263
264
265
266
267
268
269
270
271
272
273 UIComponent sourceParent =
274 changeTargetComponent.findComponent(_sourceParentScopedId);
275
276 UIComponent foundChild =
277 changeTargetComponent.findComponent(_movableChildScopedId);
278
279
280 boolean isChildIdAtDestination = false;
281
282 UIComponent movableChild = null;
283 int movableChildIndex = 0;
284 UIComponent movedChild = null;
285 int movedChildIndex = 0;
286 UIComponent duplicateChild = null;
287 int duplicateChildIndex = 0;
288 UIComponent duplicateChildParent = null;
289
290 while (foundChild != null)
291 {
292
293
294 if (foundChild.getParent().equals(sourceParent))
295 {
296 movableChild = foundChild;
297 movableChildIndex = sourceParent.getChildren().indexOf(movableChild);
298 }
299
300
301
302
303
304 else if (foundChild.getParent().equals(destinationContainer))
305 {
306 isChildIdAtDestination = true;
307 movedChild = foundChild;
308 movedChildIndex = destinationContainer.getChildren().indexOf(movedChild);
309 }
310
311
312
313
314 else
315 {
316 duplicateChild = foundChild;
317 duplicateChildIndex = foundChild.getParent().getChildren().indexOf(foundChild);
318 duplicateChildParent = foundChild.getParent();
319 }
320
321
322
323
324
325 foundChild.getParent().getChildren().remove(foundChild);
326
327
328 foundChild = changeTargetComponent.findComponent(_movableChildScopedId);
329 }
330
331
332
333 if (duplicateChild != null)
334 {
335 duplicateChildParent.getChildren().add(duplicateChildIndex, duplicateChild);
336 }
337
338
339 if(movableChild == null)
340 {
341 _LOG.warning("MOVABLE_CHILD_NOT_FOUND", _movableChildScopedId);
342
343 if (movedChild != null)
344 {
345 destinationContainer.getChildren().add(movedChildIndex, movedChild);
346 }
347 return;
348 }
349
350
351
352 if (!isChildIdAtDestination)
353 {
354 String movableChildId = movableChild.getId();
355 for (UIComponent childComponent:destinationContainer.getChildren())
356 {
357 if (movableChildId.equals(childComponent.getId()))
358 {
359 isChildIdAtDestination = true;
360 movedChild = childComponent;
361
362 movedChild.getParent().getChildren().remove(movedChild);
363 break;
364 }
365 }
366 }
367
368
369 if (isChildIdAtDestination)
370 {
371 _LOG.warning("MOVABLE_CHILD_SAME_ID_FOUND", _movableChildScopedId);
372
373
374
375 if ( (movableChild.getFamily().equals(movedChild.getFamily())) &&
376 (movableChild.getRendererType().equals(movedChild.getRendererType())) )
377 {
378
379 destinationContainer.getChildren().add(movedChildIndex, movedChild);
380 }
381 else
382 {
383
384
385 sourceParent.getChildren().add(movableChildIndex, movableChild);
386 }
387 return;
388 }
389
390
391
392 sourceParent.getChildren().add(movableChildIndex, movableChild);
393
394
395 int insertIndex = -1;
396 if (_insertBeforeId != null)
397 {
398 for (UIComponent childComponent:destinationContainer.getChildren())
399 {
400 if (_insertBeforeId.equals(childComponent.getId()))
401 {
402 insertIndex =
403 destinationContainer.getChildren().indexOf(childComponent);
404 break;
405 }
406 }
407
408
409 if (insertIndex == -1)
410 {
411 _LOG.warning("INSERT_BEFORE_NOT_FOUND", _insertBeforeId);
412 return;
413 }
414 }
415
416
417 if (insertIndex == -1)
418 destinationContainer.getChildren().add(movableChild);
419 else
420 destinationContainer.getChildren().add(insertIndex, movableChild);
421 }
422
423
424
425
426
427
428
429
430
431
432
433
434 public void changeDocument(Node changeTargetNode)
435 {
436 if (changeTargetNode == null)
437 throw new IllegalArgumentException(_LOG.getMessage("NO_NODE_SPECIFIED"));
438
439
440
441 Node movableChildNode =
442 ChangeUtils.__findNodeByScopedId(changeTargetNode,
443 _movableChildScopedId,
444 Integer.MAX_VALUE);
445
446 if(movableChildNode == null)
447 {
448 _LOG.warning("MOVABLE_CHILD_NOT_FOUND", _movableChildScopedId);
449 return;
450 }
451
452
453 Node destinationContainerNode =
454 ChangeUtils.__findNodeByScopedId(changeTargetNode,
455 _destinationContainerScopedId,
456 Integer.MAX_VALUE);
457
458
459 if(destinationContainerNode == null)
460 {
461 _LOG.warning("DESTINATION_CONTAINER_NOT_FOUND",
462 _destinationContainerScopedId);
463 return;
464 }
465
466
467 Node insertBeforeNode = (_insertBeforeId == null) ?
468 null:ChangeUtils.__findNodeByScopedId(destinationContainerNode,
469 _insertBeforeId,
470 1);
471
472
473 if(_insertBeforeId != null && insertBeforeNode == null)
474 {
475 _LOG.warning("INSERT_BEFORE_NOT_FOUND", _insertBeforeId);
476 return;
477 }
478
479
480 destinationContainerNode.insertBefore(movableChildNode, insertBeforeNode);
481 }
482
483
484
485
486
487
488 public boolean getForcesDocumentReload()
489 {
490 return true;
491 }
492
493
494
495
496
497
498
499
500
501 private static UIComponent _getClosestCommonParentUIXComponent(
502 UIComponent firstComponent,
503 UIComponent secondComponent)
504 {
505 if (firstComponent == null || secondComponent == null)
506 return null;
507
508
509 int firstDepth = _computeDepth(firstComponent);
510 int secondDepth = _computeDepth(secondComponent);
511
512
513
514 if (secondDepth > firstDepth)
515 {
516 secondComponent = _getAncestor(secondComponent, secondDepth - firstDepth);
517 }
518 else if(secondDepth < firstDepth)
519 {
520 firstComponent = _getAncestor(firstComponent, firstDepth - secondDepth);
521 }
522
523
524 while (firstComponent != null && (firstComponent != secondComponent))
525 {
526 firstComponent = firstComponent.getParent();
527 secondComponent = secondComponent.getParent();
528 }
529
530
531
532 UIComponent sharedRoot = firstComponent;
533
534 while ((sharedRoot != null) && !(sharedRoot instanceof UIXComponent))
535 sharedRoot = sharedRoot.getParent();
536
537 return sharedRoot;
538 }
539
540
541
542
543 public String getSourceScopedId()
544 {
545 return _sourceAbsoluteScopedId;
546 }
547
548
549
550
551
552 public String getDestinationScopedId()
553 {
554 return _destinationAbsoluteScopedId;
555 }
556
557
558
559
560
561 public String getSourceLogicalScopedId()
562 {
563 return (_sourceAbsoluteLogicalScopedId == null) ? _sourceAbsoluteScopedId : _sourceAbsoluteLogicalScopedId;
564 }
565
566
567
568
569 public String getDestinationLogicalScopedId()
570 {
571 return (_destinationAbsoluteLogicalScopedId == null) ? _destinationAbsoluteScopedId : _destinationAbsoluteLogicalScopedId;
572 }
573
574 @Override
575 public boolean equals(Object o)
576 {
577 if (o == this)
578 return true;
579
580 if (!(o instanceof MoveChildComponentChange))
581 return false;
582
583 MoveChildComponentChange other = (MoveChildComponentChange)o;
584
585 return getSourceLogicalScopedId().equals(other.getSourceLogicalScopedId()) &&
586 getDestinationLogicalScopedId().equals(other.getDestinationLogicalScopedId()) &&
587 _equalsOrNull(_insertBeforeId, other._insertBeforeId);
588 }
589
590 @Override
591 public int hashCode()
592 {
593 int hashCode = getSourceLogicalScopedId().hashCode() + 37 * getDestinationLogicalScopedId().hashCode();
594 if (_insertBeforeId != null)
595 {
596 hashCode = hashCode + 1369 * _insertBeforeId.hashCode();
597 }
598 return hashCode;
599 }
600
601 @Override
602 public String toString()
603 {
604 return super.toString() + "[logical_source=" + getSourceLogicalScopedId() + " logical_destination=" + getDestinationLogicalScopedId() +
605 " absolute source=" + getSourceScopedId() + " absolute destination" + getDestinationScopedId() +" insert_before=" + _insertBeforeId + "]";
606 }
607
608
609
610
611
612
613 private static int _computeDepth(UIComponent comp)
614 {
615 int i = 0;
616 while((comp = comp.getParent()) != null)
617 {
618 i++;
619 }
620 return i;
621 }
622
623
624
625
626
627
628
629 private static UIComponent _getAncestor(UIComponent component, int level)
630 {
631 assert(level >= 0);
632
633 while(level > 0)
634 {
635 component = component.getParent();
636 level--;
637 }
638 return component;
639 }
640
641 private boolean _equalsOrNull(Object obj1, Object obj2)
642 {
643 return (obj1 == null) ? (obj2 == null) : obj1.equals(obj2);
644 }
645
646 private transient UIComponent _commonParent;
647
648 private final String _movableChildScopedId;
649 private final String _sourceParentScopedId;
650 private final String _destinationContainerScopedId;
651 private final String _commonParentScopedId;
652 private final String _insertBeforeId;
653 private final String _sourceAbsoluteScopedId;
654 private final String _destinationAbsoluteScopedId;
655 private final String _sourceAbsoluteLogicalScopedId;
656 private final String _destinationAbsoluteLogicalScopedId;
657 private static final long serialVersionUID = 1L;
658
659 private static final TrinidadLogger _LOG = TrinidadLogger.createTrinidadLogger(
660 MoveChildComponentChange.class);
661 }