1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17 package com.vaadin.v7.client.ui;
18
19 import info.magnolia.ui.vaadin.gwt.client.grid.VMagnoliaTable;
20
21 import java.util.ArrayList;
22 import java.util.Iterator;
23 import java.util.LinkedList;
24 import java.util.List;
25
26 import com.google.gwt.animation.client.Animation;
27 import com.google.gwt.core.client.Scheduler;
28 import com.google.gwt.core.client.Scheduler.ScheduledCommand;
29 import com.google.gwt.dom.client.Document;
30 import com.google.gwt.dom.client.Element;
31 import com.google.gwt.dom.client.Style.Display;
32 import com.google.gwt.dom.client.Style.Unit;
33 import com.google.gwt.dom.client.Style.Visibility;
34 import com.google.gwt.dom.client.TableCellElement;
35 import com.google.gwt.event.dom.client.KeyCodes;
36 import com.google.gwt.user.client.DOM;
37 import com.google.gwt.user.client.Event;
38 import com.google.gwt.user.client.ui.Widget;
39 import com.vaadin.client.ComputedStyle;
40 import com.vaadin.client.UIDL;
41 import com.vaadin.client.WidgetUtil;
42 import com.vaadin.client.ui.Icon;
43 import com.vaadin.v7.client.ui.VTreeTablePatched.VTreeTableScrollBody.VTreeTableRow;
44
45 public class VTreeTablePatched extends VMagnoliaTable {
46
47
48 public static class PendingNavigationEvent {
49 public final int keycode;
50 public final boolean ctrl;
51 public final boolean shift;
52
53 public PendingNavigationEvent(int keycode, boolean ctrl,
54 boolean shift) {
55 this.keycode = keycode;
56 this.ctrl = ctrl;
57 this.shift = shift;
58 }
59
60 @Override
61 public String toString() {
62 String string = "Keyboard event: " + keycode;
63 if (ctrl) {
64 string += " + ctrl";
65 }
66 if (shift) {
67 string += " + shift";
68 }
69 return string;
70 }
71 }
72
73
74 public boolean collapseRequest;
75
76 private boolean selectionPending;
77
78
79 public int colIndexOfHierarchy;
80
81
82 public String collapsedRowKey;
83
84
85 public VTreeTableScrollBody scrollBody;
86
87
88 public boolean animationsEnabled;
89
90
91 public LinkedList<PendingNavigationEvent> pendingNavigationEvents = new LinkedList<VTreeTablePatched.PendingNavigationEvent>();
92
93
94 public boolean focusParentResponsePending;
95
96 @Override
97 protected VScrollTableBody createScrollBody() {
98 scrollBody = new VTreeTableScrollBody();
99 return scrollBody;
100 }
101
102
103
104
105 @Override
106 public void addAndRemoveRows(UIDL partialRowAdditions) {
107 if (partialRowAdditions == null) {
108 return;
109 }
110
111 if (animationsEnabled) {
112 if (partialRowAdditions.hasAttribute("hide")) {
113 scrollBody.unlinkRowsAnimatedAndUpdateCacheWhenFinished(
114 partialRowAdditions.getIntAttribute("firstprowix"),
115 partialRowAdditions.getIntAttribute("numprows"));
116 } else {
117 scrollBody.insertRowsAnimated(partialRowAdditions,
118 partialRowAdditions.getIntAttribute("firstprowix"),
119 partialRowAdditions.getIntAttribute("numprows"));
120 discardRowsOutsideCacheWindow();
121 }
122 } else {
123 super.addAndRemoveRows(partialRowAdditions);
124 }
125 }
126
127 @Override
128 protected int getHierarchyColumnIndex() {
129 return colIndexOfHierarchy + (showRowHeaders ? 1 : 0);
130 }
131
132 public class VTreeTableScrollBody extends VMagnoliaTable.MagnoliaTableBody {
133 private int indentWidth = -1;
134 private int maxIndent = 0;
135
136 protected VTreeTableScrollBody() {
137 super();
138 }
139
140 @Override
141 protected VScrollTableRow createRow(UIDL uidl, char[] aligns2) {
142 if (uidl.hasAttribute("gen_html")) {
143
144 return new VTreeTableGeneratedRow(uidl, aligns2);
145 }
146 return new VTreeTableRow(uidl, aligns2);
147 }
148
149 public class VTreeTableRow
150 extends VMagnoliaTable.MagnoliaTableBody.MagnoliaTableRow {
151
152 protected boolean isTreeCellAdded = false;
153 protected com.google.gwt.dom.client.Element treeSpacer;
154 protected boolean open;
155 protected int depth;
156 protected boolean canHaveChildren;
157 protected Widget widgetInHierarchyColumn;
158
159 public VTreeTableRow(UIDL uidl, char[] aligns2) {
160 super(uidl, aligns2);
161
162 applyZeroWidthFix = false;
163 }
164
165 @Override
166 public void addCell(UIDL rowUidl, String text, char align,
167 String style, boolean textIsHTML, boolean isSorted,
168 String description) {
169 super.addCell(rowUidl, text, align, style, textIsHTML, isSorted,
170 description);
171
172 addTreeSpacer(rowUidl);
173 }
174
175 protected boolean addTreeSpacer(UIDL rowUidl) {
176 if (cellShowsTreeHierarchy(getElement().getChildCount() - 1)) {
177 Element container = (Element) getElement().getLastChild()
178 .getFirstChild();
179
180 if (rowUidl.hasAttribute("icon")) {
181 Icon icon = client
182 .getIcon(rowUidl.getStringAttribute("icon"));
183 icon.setAlternateText("icon");
184 container.insertFirst(icon.getElement());
185 }
186
187 String classname = "v-treetable-treespacer";
188 if (rowUidl.getBooleanAttribute("ca")) {
189 canHaveChildren = true;
190 open = rowUidl.getBooleanAttribute("open");
191 classname += open ? " v-treetable-node-open"
192 : " v-treetable-node-closed";
193 }
194
195 treeSpacer = Document.get().createSpanElement();
196
197 treeSpacer.setClassName(classname);
198 container.insertFirst(treeSpacer);
199 depth = rowUidl.hasAttribute("depth")
200 ? rowUidl.getIntAttribute("depth") : 0;
201 setIndent();
202 isTreeCellAdded = true;
203 return true;
204 }
205 return false;
206 }
207
208 protected boolean cellShowsTreeHierarchy(int curColIndex) {
209 if (isTreeCellAdded) {
210 return false;
211 }
212 return curColIndex == getHierarchyColumnIndex();
213 }
214
215 @Override
216 public void onBrowserEvent(Event event) {
217 if (event.getEventTarget().cast() == treeSpacer
218 && treeSpacer.getClassName().contains("node")) {
219 if (event.getTypeInt() == Event.ONMOUSEUP) {
220 sendToggleCollapsedUpdate(getKey());
221 }
222 return;
223 }
224 super.onBrowserEvent(event);
225 }
226
227 @Override
228 public void addCell(UIDL rowUidl, Widget w, char align,
229 String style, boolean isSorted, String description) {
230 super.addCell(rowUidl, w, align, style, isSorted, description);
231 if (addTreeSpacer(rowUidl)) {
232 widgetInHierarchyColumn = w;
233 }
234
235 }
236
237 protected void setIndent() {
238 if (getIndentWidth() > 0) {
239 treeSpacer.getParentElement().getStyle()
240 .setPaddingLeft(getIndent(), Unit.PX);
241 treeSpacer.getStyle().setWidth(getIndent(), Unit.PX);
242 int colWidth = getColWidth(getHierarchyColumnIndex());
243 if (colWidth > 0 && getIndent() > colWidth) {
244 VTreeTablePatched.this.setColWidth(getHierarchyColumnIndex(),
245 getIndent(), false);
246 }
247 }
248 }
249
250 @Override
251 protected void onAttach() {
252 super.onAttach();
253 if (getIndentWidth() < 0) {
254 detectIndent(this);
255
256
257
258 int w = getCellWidthFromDom(getHierarchyColumnIndex());
259 if (w >= 0) {
260 setColWidth(getHierarchyColumnIndex(), w);
261 }
262 }
263 }
264
265 private int getCellWidthFromDom(int cellIndex) {
266 final Element cell = DOM.getChild(getElement(), cellIndex);
267 String w = cell.getStyle().getProperty("width");
268 if (w == null || "".equals(w) || !w.endsWith("px")) {
269 return -1;
270 } else {
271 return Integer.parseInt(w.substring(0, w.length() - 2));
272 }
273 }
274
275 private int getHierarchyAndIconWidth() {
276 int consumedSpace = treeSpacer.getOffsetWidth();
277 if (treeSpacer.getParentElement().getChildCount() > 2) {
278
279 consumedSpace += ((com.google.gwt.dom.client.Element) treeSpacer
280 .getNextSibling()).getOffsetWidth();
281 }
282 return consumedSpace;
283 }
284
285 @Override
286 protected void setCellWidth(int cellIx, int width) {
287 if (cellIx == getHierarchyColumnIndex()) {
288
289
290 int indent = getIndent();
291 if (indent != -1) {
292 width = Math.max(width - indent, 0);
293 }
294 }
295 super.setCellWidth(cellIx, width);
296 }
297
298 protected int getIndent() {
299 return (depth + 1) * getIndentWidth();
300 }
301 }
302
303 protected class VTreeTableGeneratedRow extends VTreeTableRow {
304 private boolean spanColumns;
305 private boolean htmlContentAllowed;
306
307 public VTreeTableGeneratedRow(UIDL uidl, char[] aligns) {
308 super(uidl, aligns);
309 addStyleName("v-table-generated-row");
310 }
311
312 public boolean isSpanColumns() {
313 return spanColumns;
314 }
315
316 @Override
317 protected void initCellWidths() {
318 if (spanColumns) {
319 setSpannedColumnWidthAfterDOMFullyInited();
320 } else {
321 super.initCellWidths();
322 }
323 }
324
325 private void setSpannedColumnWidthAfterDOMFullyInited() {
326
327
328
329 Scheduler.get().scheduleDeferred(new ScheduledCommand() {
330
331 @Override
332 public void execute() {
333 if (showRowHeaders) {
334 setCellWidth(0, tHead.getHeaderCell(0)
335 .getWidthWithIndent());
336 calcAndSetSpanWidthOnCell(1);
337 } else {
338 calcAndSetSpanWidthOnCell(0);
339 }
340 }
341 });
342 }
343
344 @Override
345 protected boolean isRenderHtmlInCells() {
346 return htmlContentAllowed;
347 }
348
349 @Override
350 protected void addCellsFromUIDL(UIDL uidl, char[] aligns, int col,
351 int visibleColumnIndex) {
352 htmlContentAllowed = uidl.getBooleanAttribute("gen_html");
353 spanColumns = uidl.getBooleanAttribute("gen_span");
354
355 final Iterator<?> cells = uidl.getChildIterator();
356 if (spanColumns) {
357 int colCount = uidl.getChildCount();
358 if (cells.hasNext()) {
359 final Object cell = cells.next();
360 if (cell instanceof String) {
361 addSpannedCell(uidl, cell.toString(), aligns[0], "",
362 htmlContentAllowed, false, null, colCount);
363 } else {
364 addSpannedCell(uidl, (Widget) cell, aligns[0], "",
365 false, colCount);
366 }
367 }
368 } else {
369 super.addCellsFromUIDL(uidl, aligns, col,
370 visibleColumnIndex);
371 }
372 }
373
374 private void addSpannedCell(UIDL rowUidl, Widget w, char align,
375 String style, boolean sorted, int colCount) {
376 TableCellElement td = DOM.createTD().cast();
377 td.setColSpan(colCount);
378 initCellWithWidget(w, align, style, sorted, td);
379 td.getStyle().setHeight(getRowHeight(), Unit.PX);
380 if (addTreeSpacer(rowUidl)) {
381 widgetInHierarchyColumn = w;
382 }
383 }
384
385 private void addSpannedCell(UIDL rowUidl, String text, char align,
386 String style, boolean textIsHTML, boolean sorted,
387 String description, int colCount) {
388
389 final TableCellElement td = DOM.createTD().cast();
390 td.setColSpan(colCount);
391 initCellWithText(text, align, style, textIsHTML, sorted,
392 description, td);
393 td.getStyle().setHeight(getRowHeight(), Unit.PX);
394 addTreeSpacer(rowUidl);
395 }
396
397 @Override
398 protected void setCellWidth(int cellIx, int width) {
399 if (isSpanColumns()) {
400 if (showRowHeaders) {
401 if (cellIx == 0) {
402 super.setCellWidth(0, width);
403 } else {
404
405
406 calcAndSetSpanWidthOnCell(1);
407 }
408 } else {
409
410 calcAndSetSpanWidthOnCell(0);
411 }
412 } else {
413 super.setCellWidth(cellIx, width);
414 }
415 }
416
417 private void calcAndSetSpanWidthOnCell(final int cellIx) {
418 int spanWidth = 0;
419 for (int ix = (showRowHeaders ? 1 : 0); ix < tHead
420 .getVisibleCellCount(); ix++) {
421 spanWidth += tHead.getHeaderCell(ix).getOffsetWidth();
422 }
423 WidgetUtil.setWidthExcludingPaddingAndBorder(
424 (Element) getElement().getChild(cellIx), spanWidth, 13,
425 false);
426 }
427 }
428
429 public int getIndentWidth() {
430 return indentWidth;
431 }
432
433 @Override
434 protected int getMaxIndent() {
435 return maxIndent;
436 }
437
438 @Override
439 protected void calculateMaxIndent() {
440 int maxIndent = 0;
441 Iterator<Widget> iterator = iterator();
442 while (iterator.hasNext()) {
443 VTreeTableRow next = (VTreeTableRow) iterator.next();
444 maxIndent = Math.max(maxIndent, next.getIndent());
445 }
446
447
448 }
449
450 private void detectIndent(VTreeTableRow vTreeTableRow) {
451 indentWidth = vTreeTableRow.treeSpacer.getOffsetWidth();
452 if (indentWidth == 0) {
453 indentWidth = -1;
454 return;
455 }
456 Iterator<Widget> iterator = iterator();
457 while (iterator.hasNext()) {
458 VTreeTableRow next = (VTreeTableRow) iterator.next();
459 next.setIndent();
460 }
461 calculateMaxIndent();
462 }
463
464 protected void unlinkRowsAnimatedAndUpdateCacheWhenFinished(
465 final int firstIndex, final int rows) {
466 List<VScrollTableRow> rowsToDelete = new ArrayList<VScrollTableRow>();
467 for (int ix = firstIndex; ix < firstIndex + rows; ix++) {
468 VScrollTableRow row = getRowByRowIndex(ix);
469 if (row != null) {
470 rowsToDelete.add(row);
471 }
472 }
473 if (!rowsToDelete.isEmpty()) {
474
475 RowCollapseAnimation anim = new RowCollapseAnimation(
476 rowsToDelete) {
477 @Override
478 protected void onComplete() {
479 super.onComplete();
480
481
482
483 unlinkAndReindexRows(firstIndex, rows);
484 discardRowsOutsideCacheWindow();
485 ensureCacheFilled();
486 }
487 };
488 anim.run(150);
489 }
490 }
491
492 protected List<VScrollTableRow> insertRowsAnimated(UIDL rowData,
493 int firstIndex, int rows) {
494 List<VScrollTableRow> insertedRows = insertAndReindexRows(rowData,
495 firstIndex, rows);
496 if (!insertedRows.isEmpty()) {
497
498 RowExpandAnimation anim = new RowExpandAnimation(insertedRows);
499 anim.run(150);
500 }
501 scrollBody.calculateMaxIndent();
502 return insertedRows;
503 }
504
505
506
507
508
509
510
511 private class AnimationPreparator {
512 private final int lastItemIx;
513
514 public AnimationPreparator(int lastItemIx) {
515 this.lastItemIx = lastItemIx;
516 }
517
518 public void prepareTableForAnimation() {
519 int ix = lastItemIx;
520 VScrollTableRow row = null;
521 while ((row = getRowByRowIndex(ix)) != null) {
522 copyTRBackgroundsToTDs(row);
523 --ix;
524 }
525 }
526
527 private void copyTRBackgroundsToTDs(VScrollTableRow row) {
528 Element tr = row.getElement();
529 ComputedStyle cs = new ComputedStyle(tr);
530 String backgroundAttachment = cs
531 .getProperty("backgroundAttachment");
532 String backgroundClip = cs.getProperty("backgroundClip");
533 String backgroundColor = cs.getProperty("backgroundColor");
534 String backgroundImage = cs.getProperty("backgroundImage");
535 String backgroundOrigin = cs.getProperty("backgroundOrigin");
536 for (int ix = 0; ix < tr.getChildCount(); ix++) {
537 Element td = tr.getChild(ix).cast();
538 if (!elementHasBackground(td)) {
539 td.getStyle().setProperty("backgroundAttachment",
540 backgroundAttachment);
541 td.getStyle().setProperty("backgroundClip",
542 backgroundClip);
543 td.getStyle().setProperty("backgroundColor",
544 backgroundColor);
545 td.getStyle().setProperty("backgroundImage",
546 backgroundImage);
547 td.getStyle().setProperty("backgroundOrigin",
548 backgroundOrigin);
549 }
550 }
551 }
552
553 private boolean elementHasBackground(Element element) {
554 ComputedStyle cs = new ComputedStyle(element);
555 String clr = cs.getProperty("backgroundColor");
556 String img = cs.getProperty("backgroundImage");
557 return !("rgba(0, 0, 0, 0)".equals(clr.trim())
558 || "transparent".equals(clr.trim()) || img == null);
559 }
560
561 public void restoreTableAfterAnimation() {
562 int ix = lastItemIx;
563 VScrollTableRow row = null;
564 while ((row = getRowByRowIndex(ix)) != null) {
565 restoreStyleForTDsInRow(row);
566
567 --ix;
568 }
569 }
570
571 private void restoreStyleForTDsInRow(VScrollTableRow row) {
572 Element tr = row.getElement();
573 for (int ix = 0; ix < tr.getChildCount(); ix++) {
574 Element td = tr.getChild(ix).cast();
575 td.getStyle().clearProperty("backgroundAttachment");
576 td.getStyle().clearProperty("backgroundClip");
577 td.getStyle().clearProperty("backgroundColor");
578 td.getStyle().clearProperty("backgroundImage");
579 td.getStyle().clearProperty("backgroundOrigin");
580 }
581 }
582 }
583
584
585
586
587
588
589
590
591
592
593
594
595
596
597
598
599
600
601
602
603
604
605
606
607
608
609
610
611
612
613
614
615
616
617 private class RowExpandAnimation extends Animation {
618
619 private final List<VScrollTableRow> rows;
620 private Element cloneDiv;
621 private Element cloneTable;
622 private AnimationPreparator preparator;
623
624
625
626
627
628 public RowExpandAnimation(List<VScrollTableRow> rows) {
629 this.rows = rows;
630 buildAndInsertAnimatingDiv();
631 preparator = new AnimationPreparator(
632 rows.get(0).getIndex() - 1);
633 preparator.prepareTableForAnimation();
634 for (VScrollTableRow row : rows) {
635 cloneAndAppendRow(row);
636 row.addStyleName("v-table-row-animating");
637 setCellWrapperDivsToDisplayNone(row);
638 row.setHeight(getInitialHeight());
639 }
640 }
641
642 protected String getInitialHeight() {
643 return "0px";
644 }
645
646 private void cloneAndAppendRow(VScrollTableRow row) {
647 Element clonedTR = null;
648 clonedTR = row.getElement().cloneNode(true).cast();
649 clonedTR.getStyle().setVisibility(Visibility.VISIBLE);
650 cloneTable.appendChild(clonedTR);
651 }
652
653 protected double getBaseOffset() {
654 return rows.get(0).getAbsoluteTop()
655 - rows.get(0).getParent().getAbsoluteTop()
656 - rows.size() * getRowHeight();
657 }
658
659 private void buildAndInsertAnimatingDiv() {
660 cloneDiv = DOM.createDiv();
661 cloneDiv.addClassName("v-treetable-animation-clone-wrapper");
662 cloneTable = DOM.createTable();
663 cloneTable.addClassName("v-treetable-animation-clone");
664 cloneDiv.appendChild(cloneTable);
665 insertAnimatingDiv();
666 }
667
668 private void insertAnimatingDiv() {
669 Element tableBody = getElement();
670 Element tableBodyParent = tableBody.getParentElement();
671 tableBodyParent.insertAfter(cloneDiv, tableBody);
672 }
673
674 @Override
675 protected void onUpdate(double progress) {
676 animateDiv(progress);
677 animateRowHeights(progress);
678 }
679
680 private void animateDiv(double progress) {
681 double offset = calculateDivOffset(progress, getRowHeight());
682
683 cloneDiv.getStyle().setTop(getBaseOffset() + offset, Unit.PX);
684 }
685
686 private void animateRowHeights(double progress) {
687 double rh = getRowHeight();
688 double vlh = calculateHeightOfAllVisibleLines(progress, rh);
689 int ix = 0;
690
691 while (ix < rows.size()) {
692 double height = vlh < rh ? vlh : rh;
693 rows.get(ix).setHeight(height + "px");
694 vlh -= height;
695 ix++;
696 }
697 }
698
699 protected double calculateHeightOfAllVisibleLines(double progress,
700 double rh) {
701 return rows.size() * rh * progress;
702 }
703
704 protected double calculateDivOffset(double progress, double rh) {
705 return progress * rows.size() * rh;
706 }
707
708 @Override
709 protected void onComplete() {
710 preparator.restoreTableAfterAnimation();
711 for (VScrollTableRow row : rows) {
712 resetCellWrapperDivsDisplayProperty(row);
713 row.removeStyleName("v-table-row-animating");
714 }
715 Element tableBodyParent = getElement().getParentElement();
716 tableBodyParent.removeChild(cloneDiv);
717 }
718
719 private void setCellWrapperDivsToDisplayNone(VScrollTableRow row) {
720 Element tr = row.getElement();
721 for (int ix = 0; ix < tr.getChildCount(); ix++) {
722 getWrapperDiv(tr, ix).getStyle().setDisplay(Display.NONE);
723 }
724 }
725
726 private Element getWrapperDiv(Element tr, int tdIx) {
727 Element td = tr.getChild(tdIx).cast();
728 return td.getChild(0).cast();
729 }
730
731 private void resetCellWrapperDivsDisplayProperty(
732 VScrollTableRow row) {
733 Element tr = row.getElement();
734 for (int ix = 0; ix < tr.getChildCount(); ix++) {
735 getWrapperDiv(tr, ix).getStyle().clearProperty("display");
736 }
737 }
738
739 }
740
741
742
743
744
745 private class RowCollapseAnimation extends RowExpandAnimation {
746
747 private final List<VScrollTableRow> rows;
748
749
750
751
752
753 public RowCollapseAnimation(List<VScrollTableRow> rows) {
754 super(rows);
755 this.rows = rows;
756 }
757
758 @Override
759 protected String getInitialHeight() {
760 return getRowHeight() + "px";
761 }
762
763 @Override
764 protected double getBaseOffset() {
765 return getRowHeight();
766 }
767
768 @Override
769 protected double calculateHeightOfAllVisibleLines(double progress,
770 double rh) {
771 return rows.size() * rh * (1 - progress);
772 }
773
774 @Override
775 protected double calculateDivOffset(double progress, double rh) {
776 return -super.calculateDivOffset(progress, rh);
777 }
778 }
779 }
780
781
782
783
784
785 @Override
786 protected String buildCaptionHtmlSnippet(UIDL uidl) {
787 if (uidl.getTag().equals("column")) {
788 return super.buildCaptionHtmlSnippet(uidl);
789 } else {
790 String s = uidl.getStringAttribute("caption");
791 return s;
792 }
793 }
794
795
796 @Override
797 public boolean handleNavigation(int keycode, boolean ctrl, boolean shift) {
798 if (collapseRequest || focusParentResponsePending) {
799
800
801 if (pendingNavigationEvents.size() < 10) {
802
803 PendingNavigationEvent pendingNavigationEvent = new PendingNavigationEvent(
804 keycode, ctrl, shift);
805 pendingNavigationEvents.add(pendingNavigationEvent);
806 }
807 return true;
808 }
809
810 VTreeTableRow focusedRow = (VTreeTableRow) getFocusedRow();
811 if (focusedRow != null) {
812 if (focusedRow.canHaveChildren && ((keycode == KeyCodes.KEY_RIGHT
813 && !focusedRow.open)
814 || (keycode == KeyCodes.KEY_LEFT && focusedRow.open))) {
815 if (!ctrl) {
816 client.updateVariable(paintableId, "selectCollapsed", true,
817 false);
818 }
819 sendSelectedRows(false);
820 sendToggleCollapsedUpdate(focusedRow.getKey());
821 return true;
822 } else if (keycode == KeyCodes.KEY_RIGHT && focusedRow.open) {
823
824
825 VTreeTableScrollBody body = (VTreeTableScrollBody) focusedRow
826 .getParent();
827 Iterator<Widget> iterator = body.iterator();
828 VTreeTableRow next = null;
829 while (iterator.hasNext()) {
830 next = (VTreeTableRow) iterator.next();
831 if (next == focusedRow) {
832 next = (VTreeTableRow) iterator.next();
833 break;
834 }
835 }
836 if (next != null) {
837 if (next.depth > focusedRow.depth) {
838 selectionPending = true;
839 return super.handleNavigation(getNavigationDownKey(),
840 ctrl, shift);
841 }
842 } else {
843
844
845
846 selectionPending = true;
847 return super.handleNavigation(getNavigationDownKey(), ctrl,
848 shift);
849 }
850 } else if (keycode == KeyCodes.KEY_LEFT) {
851
852
853
854
855
856 client.updateVariable(paintableId, "focusParent",
857 focusedRow.getKey(), true);
858
859
860
861 focusParentResponsePending = true;
862
863 return true;
864 }
865 }
866 return super.handleNavigation(keycode, ctrl, shift);
867 }
868
869 public void sendToggleCollapsedUpdate(String rowKey) {
870 collapsedRowKey = rowKey;
871 collapseRequest = true;
872 client.updateVariable(paintableId, "toggleCollapsed", rowKey, true);
873 }
874
875 @Override
876 public void onBrowserEvent(Event event) {
877 super.onBrowserEvent(event);
878 if (event.getTypeInt() == Event.ONKEYUP && selectionPending) {
879 sendSelectedRows();
880 }
881 }
882
883 @Override
884 protected void sendSelectedRows(boolean immediately) {
885 super.sendSelectedRows(immediately);
886 selectionPending = false;
887 }
888
889 @Override
890 protected void reOrderColumn(String columnKey, int newIndex) {
891 super.reOrderColumn(columnKey, newIndex);
892
893
894 client.sendPendingVariableChanges();
895 }
896
897 @Override
898 public void setStyleName(String style) {
899 super.setStyleName(style + " v-treetable");
900 }
901
902 @Override
903 public void updateTotalRows(UIDL uidl) {
904
905
906 int newTotalRows = uidl.getIntAttribute("totalrows");
907 setTotalRows(newTotalRows);
908 }
909
910 @Override
911 public void updateFirstVisibleAndScrollIfNeeded(UIDL uidl) {
912
913 }
914 }