1 package org.vaadin.extension.gridscroll.client;
2
3 import org.vaadin.extension.gridscroll.GridScrollExtension;
4 import org.vaadin.extension.gridscroll.shared.ColumnResizeCompensationMode;
5 import org.vaadin.extension.gridscroll.shared.GridScrollExtensionClientRPC;
6 import org.vaadin.extension.gridscroll.shared.GridScrollExtensionServerRPC;
7 import org.vaadin.extension.gridscroll.shared.GridScrollExtensionState;
8
9 import com.google.gwt.animation.client.AnimationScheduler;
10 import com.google.gwt.animation.client.AnimationScheduler.AnimationCallback;
11 import com.google.gwt.core.client.Scheduler;
12 import com.google.gwt.dom.client.Element;
13 import com.google.gwt.dom.client.NodeList;
14 import com.google.gwt.user.client.Timer;
15 import com.vaadin.client.BrowserInfo;
16 import com.vaadin.client.ComponentConnector;
17 import com.vaadin.client.ServerConnector;
18 import com.vaadin.client.extensions.AbstractExtensionConnector;
19 import com.vaadin.client.widgets.Grid;
20 import com.vaadin.client.widgets.Grid.Column;
21 import com.vaadin.shared.ui.Connect;
22
23 @SuppressWarnings("serial")
24 @Connect(GridScrollExtension.class)
25 public class GridScrollExtensionConnector extends AbstractExtensionConnector {
26
27 private Grid<?> grid;
28
29 private double xscroll = -1;
30 private double yscroll = -1;
31 private int width = -1;
32 private int heigth = -1;
33 Timer t = null;
34 int visibleColIndex = -1;
35
36 private double[] getColumnWidths() {
37 int columns = grid.getVisibleColumns().size();
38 double[] widths = new double[columns];
39 for (int i=0;i<columns;i++) widths[i] = grid.getVisibleColumns().get(i).getWidthActual();
40 return widths;
41 }
42
43 private double[] getColumnWidthsCapped() {
44 int columns = grid.getVisibleColumns().size();
45 double[] widths = new double[columns];
46 for (int i=0;i<columns;i++) {
47 widths[i] = grid.getVisibleColumns().get(i).getWidthActual();
48 double maxWidth = grid.getVisibleColumns().get(i).getMaximumWidth();
49 if (widths[i] > maxWidth && maxWidth > 0) {
50 widths[i] = maxWidth;
51 grid.getVisibleColumns().get(i).setWidth(maxWidth);
52 }
53 }
54 return widths;
55 }
56
57
58 private boolean hasWidths(double[] widths) {
59 boolean hasWidths = true;
60 for (int i=0;i<grid.getVisibleColumns().size();i++) {
61 if (!(widths[i] > 0)) hasWidths = false;
62 }
63 return hasWidths;
64 }
65
66
67 private void adjustGridWidth(double[] widths) {
68 Double width = 0d;
69 for (int i=0;i<widths.length;i++) width = width + widths[i];
70
71 Double totalWidth = width + 0.5;
72 Double scrollerWidth = getVerticalScrollBarWidth();
73 if (scrollerWidth > 0.0) totalWidth = totalWidth + scrollerWidth;
74 grid.setWidth(totalWidth.intValue()+"px");
75 }
76
77
78
79 private double adjustLastColumnWidth(double[] widths) {
80 Double width = 0d;
81 for (int i=0;i<widths.length;i++) width = width + widths[i];
82
83 Double totalWidth = width + 0.5;
84 Double scrollerWidth = getVerticalScrollBarWidth();
85 if (scrollerWidth > 0.0) totalWidth = totalWidth + scrollerWidth;
86 Double gridWidth = (double) grid.getOffsetWidth();
87 if (totalWidth < gridWidth) {
88 Double targetWidth = gridWidth - totalWidth;
89 grid.getVisibleColumns().get(grid.getVisibleColumns().size()-1).setWidth(targetWidth);
90 return targetWidth;
91 } else {
92 return -1.0;
93 }
94 }
95
96
97 private double getVerticalScrollBarWidth() {
98 for (Element e : getGridParts("div")) {
99 if (e.getClassName().contains("v-grid-scroller-vertical")) {
100 if (BrowserInfo.get().isIE11() || BrowserInfo.get().isEdge()) {
101 return e.getClientWidth();
102 } else {
103 return e.getOffsetWidth();
104 }
105 }
106 }
107 return -1.0;
108 }
109
110
111 private Element[] getGridParts(String elem) {
112 NodeList<Element> elems = grid.getElement().getElementsByTagName(elem);
113 Element[] ary = new Element[elems.getLength()];
114 for (int i = 0; i < ary.length; ++i) {
115 ary[i] = elems.getItem(i);
116 }
117 return ary;
118 }
119
120 @Override
121 protected void extend(ServerConnector target) {
122 grid = (Grid<?>)((ComponentConnector)target).getWidget();
123
124 grid.addAttachHandler(event -> {
125 if (event.isAttached()) {
126 getServerRPC().reportSize(grid.getOffsetWidth(), grid.getOffsetHeight());
127 Scheduler.get().scheduleFixedDelay(new Scheduler.RepeatingCommand() {
128 @Override
129 public boolean execute() {
130 double[] widths = getColumnWidths();
131 if (hasWidths(widths)) {
132 getServerRPC().reportColumns(widths,-1);
133 getServerRPC().gridInitialColumnWidthsCalculated();
134 if (getState().compensationMode == ColumnResizeCompensationMode.RESIZE_GRID) {
135 adjustGridWidth(widths);
136 }
137 return false;
138 }
139 else return true;
140 }
141 }, 100);
142 }
143 });
144
145 registerRpc(GridScrollExtensionClientRPC.class,
146 new GridScrollExtensionClientRPC() {
147
148 @Override
149 public void setScrollPosition(int x, int y) {
150 grid.setScrollLeft(x);
151 grid.setScrollTop(y);
152 xscroll = x;
153 yscroll = y;
154 }
155
156 @Override
157 public void recalculateGridWidth() {
158 AnimationCallback adjustCallback = new AnimationCallback() {
159 @Override
160 public void execute(double timestamp) {
161 double[] widths = getColumnWidths();
162 adjustGridWidth(widths);
163 getServerRPC().reportColumns(widths,-1);
164 }
165 };
166 AnimationScheduler.get().requestAnimationFrame(adjustCallback);
167 }
168
169 @Override
170 public void adjustLastColumn() {
171 AnimationCallback adjustCallback = new AnimationCallback() {
172 @Override
173 public void execute(double timestamp) {
174 double[] widths = getColumnWidths();
175 adjustLastColumnWidth(widths);
176 }
177 };
178 AnimationScheduler.get().requestAnimationFrame(adjustCallback);
179 }
180 });
181
182
183 grid.addSortHandler(event -> {
184 AnimationCallback adjustCallback = new AnimationCallback() {
185 @Override
186 public void execute(double timestamp) {
187 double[] widths = getColumnWidths();
188 if (getState().compensationMode == ColumnResizeCompensationMode.RESIZE_GRID) adjustGridWidth(widths);
189 else if (getState().compensationMode == ColumnResizeCompensationMode.RESIZE_COLUMN) adjustLastColumnWidth(widths);
190 }
191 };
192 if (getState().compensationMode != ColumnResizeCompensationMode.NONE) {
193 AnimationScheduler.get().requestAnimationFrame(adjustCallback);
194 }
195 });
196
197 grid.addColumnVisibilityChangeHandler(event -> {
198 Column<?, ?> column = event.getColumn();
199 updateGridDueColumnChange(column);
200 });
201
202 grid.addColumnResizeHandler(event -> {
203 Column<?, ?> column = event.getColumn();
204 updateGridDueColumnChange(column);
205 });
206
207 t = new Timer() {
208 @Override
209 public void run() {
210 if(xscroll == -1 || yscroll == -1) {
211 getServerRPC().reportPosition(-1, -1);
212 return;
213 }
214
215 boolean send = false;
216 double y = grid.getScrollTop();
217 if(y != yscroll) {
218 send = true;
219 yscroll = y;
220 }
221 double x = grid.getScrollLeft();
222 if(x != xscroll) {
223 send = true;
224 xscroll = x;
225 }
226 if(send) {
227 getServerRPC().reportPosition((int)(xscroll + .5),(int)(yscroll + .5));
228 }
229
230 send = false;
231 int w = grid.getOffsetWidth();
232 if (w != width) {
233 send = true;
234 width = w;
235 }
236 int h = grid.getOffsetHeight();
237 if (h != heigth) {
238 send = true;
239 heigth = h;
240 }
241 if(send) {
242 getServerRPC().reportSize(width, heigth);
243 if (getState().compensationMode == ColumnResizeCompensationMode.RESIZE_COLUMN) {
244 Scheduler.get().scheduleFinally(new Scheduler.ScheduledCommand() {
245 @Override
246 public void execute() {
247 double[] widths = getColumnWidthsCapped();
248 adjustLastColumnWidth(widths);
249 getServerRPC().reportColumns(widths,-1);
250 }
251 });
252 }
253 }
254 }
255 };
256 t.scheduleRepeating(250);
257 }
258
259 private void updateGridDueColumnChange(Column<?, ?> column) {
260 int i = 0;
261 visibleColIndex = -1;
262 for (Column<?, ?> col : grid.getVisibleColumns()) {
263 if (col == column) {
264 visibleColIndex = i;
265 break;
266 }
267 i++;
268 }
269 if (getState().compensationMode == ColumnResizeCompensationMode.RESIZE_GRID) {
270 Scheduler.get().scheduleFinally(new Scheduler.ScheduledCommand() {
271 @Override
272 public void execute() {
273 double[] widths = getColumnWidthsCapped();
274 getServerRPC().reportSize(grid.getOffsetWidth(), grid.getOffsetHeight());
275 adjustGridWidth(widths);
276 getServerRPC().reportColumns(widths,visibleColIndex);
277 }
278 });
279 } else if (getState().compensationMode == ColumnResizeCompensationMode.RESIZE_COLUMN) {
280 Scheduler.get().scheduleFinally(new Scheduler.ScheduledCommand() {
281 @Override
282 public void execute() {
283 double[] widths = getColumnWidthsCapped();
284 double adjustedWidth = adjustLastColumnWidth(widths);
285 if (visibleColIndex == grid.getVisibleColumns().size()-1) widths[visibleColIndex] = adjustedWidth;
286 getServerRPC().reportColumns(widths,visibleColIndex);
287 }
288 });
289 }
290 }
291
292 @Override
293 public void onUnregister() {
294 super.onUnregister();
295 t.cancel();
296 }
297
298 private GridScrollExtensionServerRPC getServerRPC() {
299 return getRpcProxy(GridScrollExtensionServerRPC.class);
300 }
301
302 @Override
303 public GridScrollExtensionState getState() {
304 return ((GridScrollExtensionState) super.getState());
305 }
306
307
308 }