1 | /** |
2 | * Copyright 2005-2011 Steve McDuff d-duff@users.sourceforge.net |
3 | * |
4 | * Licensed under the Apache License, Version 2.0 (the "License"); |
5 | * you may not use this file except in compliance with the License. |
6 | * You may obtain a copy of the License at |
7 | * |
8 | * http://www.apache.org/licenses/LICENSE-2.0 |
9 | * |
10 | * Unless required by applicable law or agreed to in writing, software |
11 | * distributed under the License is distributed on an "AS IS" BASIS, |
12 | * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. |
13 | * See the License for the specific language governing permissions and |
14 | * limitations under the License. |
15 | */ |
16 | package org.deduced.viewer.web.shared; |
17 | |
18 | import com.google.gwt.user.client.ui.HorizontalSplitPanel; |
19 | import com.google.gwt.user.client.ui.Label; |
20 | import com.google.gwt.user.client.ui.Panel; |
21 | import com.google.gwt.user.client.ui.VerticalSplitPanel; |
22 | import com.google.gwt.user.client.ui.Widget; |
23 | |
24 | /** |
25 | * SplitPanel Model. This model will always contain a horizontal panel as a host |
26 | * to the split panel. This is done so that when the split panel implementation |
27 | * changes between horizontal and vertical, the correct widget can be rebuilt |
28 | * without notifying the parent tree to add the newly rebuilt widget. |
29 | * |
30 | * @author Steve McDuff |
31 | * |
32 | */ |
33 | @SuppressWarnings("deprecation") |
34 | public class SplitPanelModel extends PanelModel |
35 | { |
36 | |
37 | /** |
38 | * serialVersionUID |
39 | */ |
40 | private static final long serialVersionUID = 1482166358069630065L; |
41 | |
42 | /** |
43 | * is the split panel vertical or horizontal |
44 | */ |
45 | private boolean vertical; |
46 | |
47 | /** |
48 | * divider location in pixel starting from the top-left position. |
49 | */ |
50 | private int dividerLocation; |
51 | |
52 | /** |
53 | * Resize weight in percentage. Indicates how space should be allocated |
54 | * between the two sides of the split panel when the panel size changes. |
55 | * Note that this feature isn't implemented in the GWT widget. |
56 | */ |
57 | private double resizeWeight; |
58 | |
59 | /** |
60 | * If vertical is false, this field is the left component. Otherwise it is |
61 | * the top component. |
62 | */ |
63 | private WidgetModel topLeftComponent; |
64 | |
65 | /** |
66 | * If vertical is true, this field is the right component. Otherwise it is |
67 | * the bottom component. |
68 | */ |
69 | private WidgetModel bottomRightComponent; |
70 | |
71 | /** |
72 | * SplitPanelModel constructor |
73 | */ |
74 | public SplitPanelModel() |
75 | { |
76 | |
77 | } |
78 | |
79 | /** |
80 | * (non-JSDoc) |
81 | * |
82 | * @see org.deduced.viewer.web.shared.Model#registerChildModels() |
83 | */ |
84 | @Override |
85 | protected void registerChildModels() |
86 | { |
87 | registerChildModel(getTopLeftComponent(), this); |
88 | registerChildModel(getBottomRightComponent(), this); |
89 | super.registerChildModels(); |
90 | } |
91 | |
92 | /** |
93 | * (non-JSDoc) |
94 | * |
95 | * @see org.deduced.viewer.web.shared.WidgetModel#createUIObject() |
96 | */ |
97 | @Override |
98 | public Panel createUIObject() |
99 | { |
100 | return rebuildSplit(); |
101 | } |
102 | |
103 | /** |
104 | * force a rebuild of the Split panel |
105 | * |
106 | * @return the new split panel in use |
107 | */ |
108 | private Panel rebuildSplit() |
109 | { |
110 | Panel splitPanel = null; |
111 | if (isVertical()) |
112 | { |
113 | splitPanel = new VerticalSplitPanel(); |
114 | } |
115 | else |
116 | { |
117 | splitPanel = new HorizontalSplitPanel(); |
118 | } |
119 | setUIObject(splitPanel); |
120 | notifyParentThatModelChanged(); |
121 | return splitPanel; |
122 | } |
123 | |
124 | /** |
125 | * (non-JSDoc) |
126 | * |
127 | * @see org.deduced.viewer.web.shared.Model#deleteChildModels() |
128 | */ |
129 | @Override |
130 | protected void deleteChildModels() |
131 | { |
132 | deleteBottomRightComponent(); |
133 | deleteTopLeftComponent(); |
134 | super.deleteChildModels(); |
135 | } |
136 | |
137 | /** |
138 | * (non-JSDoc) |
139 | * |
140 | * @see org.deduced.viewer.web.shared.UserInterfaceModel#internalSynchronizeWithUI() |
141 | */ |
142 | @Override |
143 | public void internalSynchronizeWithUI() |
144 | { |
145 | Widget currentWidget = rebuildSplitWidgetIfNecessary(); |
146 | |
147 | if (isVertical()) |
148 | { |
149 | VerticalSplitPanel verticalSplit = |
150 | (VerticalSplitPanel) currentWidget; |
151 | |
152 | verticalSplit.setTopWidget(getTopLeftWidget()); |
153 | verticalSplit.setBottomWidget(getBottomRightWidget()); |
154 | |
155 | verticalSplit.setSplitPosition(getSplitPositionString()); |
156 | verticalSplit.setVisible(true); |
157 | } |
158 | else |
159 | { |
160 | HorizontalSplitPanel horizontalSplit = |
161 | (HorizontalSplitPanel) currentWidget; |
162 | |
163 | horizontalSplit.setLeftWidget(getTopLeftWidget()); |
164 | horizontalSplit.setRightWidget(getBottomRightWidget()); |
165 | |
166 | horizontalSplit.setSplitPosition(getSplitPositionString()); |
167 | horizontalSplit.setVisible(true); |
168 | } |
169 | |
170 | super.internalSynchronizeWithUI(); |
171 | } |
172 | |
173 | /** |
174 | * rebuild the Split Widget If Necessary. This method will verify if the |
175 | * type of split widget in use matches the required type in the model. If a |
176 | * match is detected, nothing will change, otherwise the split widget will |
177 | * be re-created. |
178 | * |
179 | * @return the split widget in use. |
180 | */ |
181 | private Widget rebuildSplitWidgetIfNecessary() |
182 | { |
183 | Widget currentWidget = getPanel(); |
184 | |
185 | boolean isCurrentlyVertical = |
186 | currentWidget instanceof VerticalSplitPanel; |
187 | |
188 | if (isCurrentlyVertical != isVertical()) |
189 | { |
190 | currentWidget = rebuildSplit(); |
191 | } |
192 | return currentWidget; |
193 | } |
194 | |
195 | /** |
196 | * get Bottom Right Widget. This method never returns a null. It will create |
197 | * a dummy widget if necessary. |
198 | * |
199 | * @return the Bottom Right widget |
200 | */ |
201 | private Widget getBottomRightWidget() |
202 | { |
203 | return getNonNullWidget(getBottomRightComponent()); |
204 | } |
205 | |
206 | /** |
207 | * get a Non Null Widget by returning the widget associated with the model. |
208 | * If that widget is null, a dummy widget will be created. |
209 | * |
210 | * @param model the model from which to fetch the widget |
211 | * @return the widget from the model, or a dummy widget if the model is |
212 | * empty. |
213 | */ |
214 | private static Widget getNonNullWidget( |
215 | WidgetModel model) |
216 | { |
217 | Widget returnValue = null; |
218 | |
219 | if (model != null) |
220 | { |
221 | returnValue = model.getWidget(); |
222 | } |
223 | |
224 | if (returnValue == null) |
225 | { |
226 | returnValue = new Label(); |
227 | } |
228 | |
229 | return returnValue; |
230 | } |
231 | |
232 | /** |
233 | * get Top Left Widget. This method never returns a null. It will create a |
234 | * dummy widget if necessary. |
235 | * |
236 | * @return the top left widget |
237 | */ |
238 | private Widget getTopLeftWidget() |
239 | { |
240 | return getNonNullWidget(getTopLeftComponent()); |
241 | } |
242 | |
243 | /** |
244 | * get the Split Position String |
245 | * |
246 | * @return the Split Position String |
247 | */ |
248 | private String getSplitPositionString() |
249 | { |
250 | return (getDividerLocation()) + "px"; |
251 | } |
252 | |
253 | /** |
254 | * set BottomRightComponent |
255 | * |
256 | * @param widget the new bottom right component |
257 | */ |
258 | public void setBottomRightComponent( |
259 | WidgetModel widget) |
260 | { |
261 | bottomRightComponent = widget; |
262 | } |
263 | |
264 | /** |
265 | * set TopLeftComponent |
266 | * |
267 | * @param widget the new top left component |
268 | */ |
269 | public void setTopLeftComponent( |
270 | WidgetModel widget) |
271 | { |
272 | topLeftComponent = widget; |
273 | } |
274 | |
275 | /** |
276 | * delete top left Component |
277 | */ |
278 | private void deleteTopLeftComponent() |
279 | { |
280 | if (topLeftComponent != null) |
281 | { |
282 | topLeftComponent.delete(); |
283 | setTopLeftComponent(null); |
284 | } |
285 | } |
286 | |
287 | /** |
288 | * delete Bottom Right Component |
289 | */ |
290 | private void deleteBottomRightComponent() |
291 | { |
292 | if (getBottomRightComponent() != null) |
293 | { |
294 | getBottomRightComponent().delete(); |
295 | setBottomRightComponent(null); |
296 | } |
297 | } |
298 | |
299 | /** |
300 | * (non-JSDoc) |
301 | * |
302 | * @see org.deduced.viewer.web.shared.UserInterfaceModel#propertyChanged(org.deduced.viewer.web.shared.ChangeEvent) |
303 | */ |
304 | @Override |
305 | public void propertyChanged( |
306 | ChangeEvent event) |
307 | { |
308 | String eventName = event.getName(); |
309 | if (Utilities.equals(eventName, "bottom right component")) |
310 | { |
311 | WidgetModel newBottomRightComponent = |
312 | (WidgetModel) event.getSerializableValue(); |
313 | updateBottomRightComponent(newBottomRightComponent); |
314 | } |
315 | else if (Utilities.equals(eventName, "top left component")) |
316 | { |
317 | WidgetModel newTopLeftComponent = |
318 | (WidgetModel) event.getSerializableValue(); |
319 | updateTopLeftComponent(newTopLeftComponent); |
320 | } |
321 | else if (Utilities.equals(eventName, "divider location")) |
322 | { |
323 | setDividerLocation(((Integer) event.getSerializableValue()) |
324 | .intValue()); |
325 | synchronizeWithUI(); |
326 | } |
327 | else if (Utilities.equals(eventName, "resize weight")) |
328 | { |
329 | setResizeWeight(((Double) event.getSerializableValue()) |
330 | .doubleValue()); |
331 | synchronizeWithUI(); |
332 | } |
333 | else if (Utilities.equals(eventName, "vertical")) |
334 | { |
335 | setVertical(((Boolean) event.getSerializableValue()).booleanValue()); |
336 | synchronizeWithUI(); |
337 | } |
338 | else |
339 | { |
340 | super.propertyChanged(event); |
341 | } |
342 | } |
343 | |
344 | /** |
345 | * updateTopLeftComponent |
346 | * |
347 | * @param newTopLeftComponent new top left component |
348 | */ |
349 | public void updateTopLeftComponent( |
350 | WidgetModel newTopLeftComponent) |
351 | { |
352 | setTopLeftComponent(updateModel(newTopLeftComponent, |
353 | getTopLeftComponent(), this)); |
354 | |
355 | synchronizeWithUI(); |
356 | } |
357 | |
358 | /** |
359 | * updateBottomRightComponent |
360 | * |
361 | * @param newBottomRightComponent new bottom right component |
362 | */ |
363 | public void updateBottomRightComponent( |
364 | WidgetModel newBottomRightComponent) |
365 | { |
366 | setBottomRightComponent(updateModel(newBottomRightComponent, |
367 | getBottomRightComponent(), this)); |
368 | synchronizeWithUI(); |
369 | } |
370 | |
371 | /** |
372 | * @return the bottomRightComponent |
373 | */ |
374 | public WidgetModel getBottomRightComponent() |
375 | { |
376 | return bottomRightComponent; |
377 | } |
378 | |
379 | /** |
380 | * @return the topLeftComponent |
381 | */ |
382 | public WidgetModel getTopLeftComponent() |
383 | { |
384 | return topLeftComponent; |
385 | } |
386 | |
387 | /** |
388 | * @param setResizeWeight the resizeWeight to set |
389 | */ |
390 | public void setResizeWeight( |
391 | double setResizeWeight) |
392 | { |
393 | resizeWeight = setResizeWeight; |
394 | } |
395 | |
396 | /** |
397 | * @return the resizeWeight |
398 | */ |
399 | public double getResizeWeight() |
400 | { |
401 | return resizeWeight; |
402 | } |
403 | |
404 | /** |
405 | * @param setDividerLocation the dividerLocation to set |
406 | */ |
407 | public void setDividerLocation( |
408 | int setDividerLocation) |
409 | { |
410 | dividerLocation = setDividerLocation; |
411 | } |
412 | |
413 | /** |
414 | * @return the dividerLocation |
415 | */ |
416 | public int getDividerLocation() |
417 | { |
418 | return dividerLocation; |
419 | } |
420 | |
421 | /** |
422 | * @param setVertical the vertical to set |
423 | */ |
424 | public void setVertical( |
425 | boolean setVertical) |
426 | { |
427 | vertical = setVertical; |
428 | } |
429 | |
430 | /** |
431 | * @return the vertical |
432 | */ |
433 | public boolean isVertical() |
434 | { |
435 | return vertical; |
436 | } |
437 | |
438 | } |