1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17 package com.vaadin.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.ImageElement;
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.Element;
38 import com.google.gwt.user.client.Event;
39 import com.google.gwt.user.client.ui.Widget;
40 import com.vaadin.client.ComputedStyle;
41 import com.vaadin.client.UIDL;
42 import com.vaadin.client.Util;
43 import com.vaadin.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, boolean shift) {
54 this.keycode = keycode;
55 this.ctrl = ctrl;
56 this.shift = shift;
57 }
58
59 @Override
60 public String toString() {
61 String string = "Keyboard event: " + keycode;
62 if (ctrl) {
63 string += " + ctrl";
64 }
65 if (shift) {
66 string += " + shift";
67 }
68 return string;
69 }
70 }
71
72
73 public boolean collapseRequest;
74
75 private boolean selectionPending;
76
77
78 public int colIndexOfHierarchy;
79
80
81 public String collapsedRowKey;
82
83
84 public VTreeTableScrollBody scrollBody;
85
86
87 public boolean animationsEnabled;
88
89
90 public LinkedList<PendingNavigationEvent> pendingNavigationEvents = new LinkedList<VTreeTablePatched.PendingNavigationEvent>();
91
92
93 public boolean focusParentResponsePending;
94
95 @Override
96 protected VScrollTableBody createScrollBody() {
97 scrollBody = new VTreeTableScrollBody();
98 return scrollBody;
99 }
100
101
102
103
104 @Override
105 public void addAndRemoveRows(UIDL partialRowAdditions) {
106 if (partialRowAdditions == null) {
107 return;
108 }
109
110 if (animationsEnabled) {
111 if (partialRowAdditions.hasAttribute("hide")) {
112 scrollBody.unlinkRowsAnimatedAndUpdateCacheWhenFinished(
113 partialRowAdditions.getIntAttribute("firstprowix"),
114 partialRowAdditions.getIntAttribute("numprows"));
115 } else {
116 scrollBody.insertRowsAnimated(partialRowAdditions,
117 partialRowAdditions.getIntAttribute("firstprowix"),
118 partialRowAdditions.getIntAttribute("numprows"));
119 discardRowsOutsideCacheWindow();
120 }
121 } else {
122 super.addAndRemoveRows(partialRowAdditions);
123 }
124 }
125
126 @Override
127 protected int getHierarchyColumnIndex() {
128 return colIndexOfHierarchy + (showRowHeaders ? 1 : 0);
129 }
130
131 public class VTreeTableScrollBody extends VMagnoliaTable.MagnoliaTableBody {
132 private int indentWidth = -1;
133 private int maxIndent = 0;
134
135 protected VTreeTableScrollBody() {
136 super();
137 }
138
139 @Override
140 protected VScrollTableRow createRow(UIDL uidl, char[] aligns2) {
141 if (uidl.hasAttribute("gen_html")) {
142
143 return new VTreeTableGeneratedRow(uidl, aligns2);
144 }
145 return new VTreeTableRow(uidl, aligns2);
146 }
147
148 public class VTreeTableRow extends
149 VMagnoliaTable.MagnoliaTableBody.MagnoliaTableRow {
150
151 protected boolean isTreeCellAdded = false;
152 protected com.google.gwt.dom.client.Element treeSpacer;
153 protected boolean open;
154 protected int depth;
155 protected boolean canHaveChildren;
156 protected Widget widgetInHierarchyColumn;
157
158 public VTreeTableRow(UIDL uidl, char[] aligns2) {
159 super(uidl, aligns2);
160 }
161
162 @Override
163 public void addCell(UIDL rowUidl, String text, char align,
164 String style, boolean textIsHTML, boolean isSorted,
165 String description) {
166 super.addCell(rowUidl, text, align, style, textIsHTML,
167 isSorted, description);
168
169 addTreeSpacer(rowUidl);
170 }
171
172 protected boolean addTreeSpacer(UIDL rowUidl) {
173 if (cellShowsTreeHierarchy(getElement().getChildCount() - 1)) {
174 Element container = (Element) getElement().getLastChild()
175 .getFirstChild();
176
177 if (rowUidl.hasAttribute("icon")) {
178
179 ImageElement icon = Document.get().createImageElement();
180 icon.setClassName("v-icon");
181 icon.setAlt("icon");
182 icon.setSrc(client.translateVaadinUri(rowUidl
183 .getStringAttribute("icon")));
184 container.insertFirst(icon);
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") ? rowUidl
200 .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,
363 colCount);
364 } else {
365 addSpannedCell(uidl, (Widget) cell, aligns[0], "",
366 false, colCount);
367 }
368 }
369 } else {
370 super.addCellsFromUIDL(uidl, aligns, col,
371 visibleColumnIndex);
372 }
373 }
374
375 private void addSpannedCell(UIDL rowUidl, Widget w, char align,
376 String style, boolean sorted, int colCount) {
377 TableCellElement td = DOM.createTD().cast();
378 td.setColSpan(colCount);
379 initCellWithWidget(w, align, style, sorted, td);
380 td.getStyle().setHeight(getRowHeight(), Unit.PX);
381 if (addTreeSpacer(rowUidl)) {
382 widgetInHierarchyColumn = w;
383 }
384 }
385
386 private void addSpannedCell(UIDL rowUidl, String text, char align,
387 String style, boolean textIsHTML, boolean sorted,
388 String description, int colCount) {
389
390 final TableCellElement td = DOM.createTD().cast();
391 td.setColSpan(colCount);
392 initCellWithText(text, align, style, textIsHTML, sorted,
393 description, td);
394 td.getStyle().setHeight(getRowHeight(), Unit.PX);
395 addTreeSpacer(rowUidl);
396 }
397
398 @Override
399 protected void setCellWidth(int cellIx, int width) {
400 if (isSpanColumns()) {
401 if (showRowHeaders) {
402 if (cellIx == 0) {
403 super.setCellWidth(0, width);
404 } else {
405
406
407 calcAndSetSpanWidthOnCell(1);
408 }
409 } else {
410
411 calcAndSetSpanWidthOnCell(0);
412 }
413 } else {
414 super.setCellWidth(cellIx, width);
415 }
416 }
417
418 private void calcAndSetSpanWidthOnCell(final int cellIx) {
419 int spanWidth = 0;
420 for (int ix = (showRowHeaders ? 1 : 0); ix < tHead
421 .getVisibleCellCount(); ix++) {
422 spanWidth += tHead.getHeaderCell(ix).getOffsetWidth();
423 }
424 Util.setWidthExcludingPaddingAndBorder((Element) getElement()
425 .getChild(cellIx), spanWidth, 13, 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(rows.get(0).getIndex() - 1);
632 preparator.prepareTableForAnimation();
633 for (VScrollTableRow row : rows) {
634 cloneAndAppendRow(row);
635 row.addStyleName("v-table-row-animating");
636 setCellWrapperDivsToDisplayNone(row);
637 row.setHeight(getInitialHeight());
638 }
639 }
640
641 protected String getInitialHeight() {
642 return "0px";
643 }
644
645 private void cloneAndAppendRow(VScrollTableRow row) {
646 Element clonedTR = null;
647 clonedTR = row.getElement().cloneNode(true).cast();
648 clonedTR.getStyle().setVisibility(Visibility.VISIBLE);
649 cloneTable.appendChild(clonedTR);
650 }
651
652 protected double getBaseOffset() {
653 return rows.get(0).getAbsoluteTop()
654 - rows.get(0).getParent().getAbsoluteTop()
655 - rows.size() * getRowHeight();
656 }
657
658 private void buildAndInsertAnimatingDiv() {
659 cloneDiv = DOM.createDiv();
660 cloneDiv.addClassName("v-treetable-animation-clone-wrapper");
661 cloneTable = DOM.createTable();
662 cloneTable.addClassName("v-treetable-animation-clone");
663 cloneDiv.appendChild(cloneTable);
664 insertAnimatingDiv();
665 }
666
667 private void insertAnimatingDiv() {
668 Element tableBody = getElement().cast();
669 Element tableBodyParent = tableBody.getParentElement().cast();
670 tableBodyParent.insertAfter(cloneDiv, tableBody);
671 }
672
673 @Override
674 protected void onUpdate(double progress) {
675 animateDiv(progress);
676 animateRowHeights(progress);
677 }
678
679 private void animateDiv(double progress) {
680 double offset = calculateDivOffset(progress, getRowHeight());
681
682 cloneDiv.getStyle().setTop(getBaseOffset() + offset, Unit.PX);
683 }
684
685 private void animateRowHeights(double progress) {
686 double rh = getRowHeight();
687 double vlh = calculateHeightOfAllVisibleLines(progress, rh);
688 int ix = 0;
689
690 while (ix < rows.size()) {
691 double height = vlh < rh ? vlh : rh;
692 rows.get(ix).setHeight(height + "px");
693 vlh -= height;
694 ix++;
695 }
696 }
697
698 protected double calculateHeightOfAllVisibleLines(double progress,
699 double rh) {
700 return rows.size() * rh * progress;
701 }
702
703 protected double calculateDivOffset(double progress, double rh) {
704 return progress * rows.size() * rh;
705 }
706
707 @Override
708 protected void onComplete() {
709 preparator.restoreTableAfterAnimation();
710 for (VScrollTableRow row : rows) {
711 resetCellWrapperDivsDisplayProperty(row);
712 row.removeStyleName("v-table-row-animating");
713 }
714 Element tableBodyParent = (Element) getElement()
715 .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(VScrollTableRow row) {
732 Element tr = row.getElement();
733 for (int ix = 0; ix < tr.getChildCount(); ix++) {
734 getWrapperDiv(tr, ix).getStyle().clearProperty("display");
735 }
736 }
737
738 }
739
740
741
742
743
744 private class RowCollapseAnimation extends RowExpandAnimation {
745
746 private final List<VScrollTableRow> rows;
747
748
749
750
751
752 public RowCollapseAnimation(List<VScrollTableRow> rows) {
753 super(rows);
754 this.rows = rows;
755 }
756
757 @Override
758 protected String getInitialHeight() {
759 return getRowHeight() + "px";
760 }
761
762 @Override
763 protected double getBaseOffset() {
764 return getRowHeight();
765 }
766
767 @Override
768 protected double calculateHeightOfAllVisibleLines(double progress,
769 double rh) {
770 return rows.size() * rh * (1 - progress);
771 }
772
773 @Override
774 protected double calculateDivOffset(double progress, double rh) {
775 return -super.calculateDivOffset(progress, rh);
776 }
777 }
778 }
779
780
781
782
783
784 @Override
785 protected String buildCaptionHtmlSnippet(UIDL uidl) {
786 if (uidl.getTag().equals("column")) {
787 return super.buildCaptionHtmlSnippet(uidl);
788 } else {
789 String s = uidl.getStringAttribute("caption");
790 return s;
791 }
792 }
793
794
795 @Override
796 public boolean handleNavigation(int keycode, boolean ctrl, boolean shift) {
797 if (collapseRequest || focusParentResponsePending) {
798
799
800 if (pendingNavigationEvents.size() < 10) {
801
802 PendingNavigationEvent pendingNavigationEvent = new PendingNavigationEvent(
803 keycode, ctrl, shift);
804 pendingNavigationEvents.add(pendingNavigationEvent);
805 }
806 return true;
807 }
808
809 VTreeTableRow focusedRow = (VTreeTableRow) getFocusedRow();
810 if (focusedRow != null) {
811 if (focusedRow.canHaveChildren
812 && ((keycode == KeyCodes.KEY_RIGHT && !focusedRow.open) || (keycode == KeyCodes.KEY_LEFT && focusedRow.open))) {
813 if (!ctrl) {
814 client.updateVariable(paintableId, "selectCollapsed", true,
815 false);
816 }
817 sendSelectedRows(false);
818 sendToggleCollapsedUpdate(focusedRow.getKey());
819 return true;
820 } else if (keycode == KeyCodes.KEY_RIGHT && focusedRow.open) {
821
822
823 VTreeTableScrollBody body = (VTreeTableScrollBody) focusedRow
824 .getParent();
825 Iterator<Widget> iterator = body.iterator();
826 VTreeTableRow next = null;
827 while (iterator.hasNext()) {
828 next = (VTreeTableRow) iterator.next();
829 if (next == focusedRow) {
830 next = (VTreeTableRow) iterator.next();
831 break;
832 }
833 }
834 if (next != null) {
835 if (next.depth > focusedRow.depth) {
836 selectionPending = true;
837 return super.handleNavigation(getNavigationDownKey(),
838 ctrl, shift);
839 }
840 } else {
841
842
843
844 selectionPending = true;
845 return super.handleNavigation(getNavigationDownKey(), ctrl,
846 shift);
847 }
848 } else if (keycode == KeyCodes.KEY_LEFT) {
849
850
851
852
853
854 client.updateVariable(paintableId, "focusParent",
855 focusedRow.getKey(), true);
856
857
858
859 focusParentResponsePending = true;
860
861 return true;
862 }
863 }
864 return super.handleNavigation(keycode, ctrl, shift);
865 }
866
867 public void sendToggleCollapsedUpdate(String rowKey) {
868 collapsedRowKey = rowKey;
869 collapseRequest = true;
870 client.updateVariable(paintableId, "toggleCollapsed", rowKey, true);
871 }
872
873 @Override
874 public void onBrowserEvent(Event event) {
875 super.onBrowserEvent(event);
876 if (event.getTypeInt() == Event.ONKEYUP && selectionPending) {
877 sendSelectedRows();
878 }
879 }
880
881 @Override
882 protected void sendSelectedRows(boolean immediately) {
883 super.sendSelectedRows(immediately);
884 selectionPending = false;
885 }
886
887 @Override
888 protected void reOrderColumn(String columnKey, int newIndex) {
889 super.reOrderColumn(columnKey, newIndex);
890
891
892 client.sendPendingVariableChanges();
893 }
894
895 @Override
896 public void setStyleName(String style) {
897 super.setStyleName(style + " v-treetable");
898 }
899
900 @Override
901 public void updateTotalRows(UIDL uidl) {
902
903
904 int newTotalRows = uidl.getIntAttribute("totalrows");
905 setTotalRows(newTotalRows);
906 }
907
908 }