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