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