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 java.util.List; |
19 | |
20 | import com.google.gwt.user.client.ui.TreeItem; |
21 | import com.google.gwt.user.client.ui.UIObject; |
22 | import com.google.gwt.user.client.ui.Widget; |
23 | |
24 | /** |
25 | * TreeItem Model. This model will store a list of open events to ignore to |
26 | * prevent infinite feedback loops between the user actions and the server |
27 | * feedback. |
28 | * |
29 | * @author Steve McDuff |
30 | * |
31 | */ |
32 | public class TreeItemModel extends UserInterfaceModel implements ModelContainer |
33 | { |
34 | |
35 | /** |
36 | * serialVersionUID |
37 | */ |
38 | private static final long serialVersionUID = -4210089978465016482L; |
39 | |
40 | /** |
41 | * tree node text. If the component field is null, this text will be |
42 | * displayed in the tree item. |
43 | */ |
44 | private String text; |
45 | |
46 | /** |
47 | * is the tree node open |
48 | */ |
49 | private boolean isOpen; |
50 | |
51 | /** |
52 | * widget to display in the tree node |
53 | */ |
54 | private WidgetModel component; |
55 | |
56 | /** |
57 | * the ordered child tree item list |
58 | */ |
59 | private OrderedListModel<OrderedTreeItemModel> treeItemList; |
60 | |
61 | /** |
62 | * TreeItemModel constructor |
63 | */ |
64 | public TreeItemModel() |
65 | { |
66 | |
67 | } |
68 | |
69 | /** |
70 | * (non-JSDoc) |
71 | * |
72 | * @see org.deduced.viewer.web.shared.Model#registerChildModels() |
73 | */ |
74 | @Override |
75 | protected void registerChildModels() |
76 | { |
77 | registerChildModel(getTreeItemList(), this); |
78 | registerChildModel(getComponent(), this); |
79 | super.registerChildModels(); |
80 | } |
81 | |
82 | /** |
83 | * (non-JSDoc) |
84 | * |
85 | * @see org.deduced.viewer.web.shared.UserInterfaceModel#createUIObject() |
86 | */ |
87 | @Override |
88 | public UIObject createUIObject() |
89 | { |
90 | TreeItem treeItem = new TreeItem(); |
91 | treeItem.setUserObject(this); |
92 | return treeItem; |
93 | } |
94 | |
95 | /** |
96 | * get TreeItem |
97 | * |
98 | * @return the tree item |
99 | */ |
100 | public TreeItem getTreeItem() |
101 | { |
102 | return (TreeItem) getUIObject(); |
103 | } |
104 | |
105 | /** |
106 | * (non-JSDoc) |
107 | * |
108 | * @see org.deduced.viewer.web.shared.Model#deleteChildModels() |
109 | */ |
110 | @Override |
111 | protected void deleteChildModels() |
112 | { |
113 | deleteTreeItemList(); |
114 | deleteComponent(); |
115 | super.deleteChildModels(); |
116 | } |
117 | |
118 | /** |
119 | * delete Tree Item List |
120 | */ |
121 | private void deleteTreeItemList() |
122 | { |
123 | if (getTreeItemList() != null) |
124 | { |
125 | getTreeItemList().delete(); |
126 | setTreeItemList(null); |
127 | } |
128 | } |
129 | |
130 | /** |
131 | * (non-JSDoc) |
132 | * |
133 | * @see org.deduced.viewer.web.shared.UserInterfaceModel#internalSynchronizeWithUI() |
134 | */ |
135 | @Override |
136 | public void internalSynchronizeWithUI() |
137 | { |
138 | TreeItem treeItem = getTreeItem(); |
139 | |
140 | Widget setWidget = null; |
141 | if (getComponent() != null) |
142 | { |
143 | setWidget = getComponent().getWidget(); |
144 | treeItem.setWidget(setWidget); |
145 | } |
146 | else |
147 | { |
148 | treeItem.setText(getText()); |
149 | } |
150 | |
151 | synchronizeChildTreeItemList(); |
152 | |
153 | if (treeItem.getState() != isOpen()) |
154 | { |
155 | treeItem.setState(isOpen(), false); |
156 | } |
157 | super.internalSynchronizeWithUI(); |
158 | } |
159 | |
160 | /** |
161 | * synchronize Child Tree Item List based on the model if necessary |
162 | */ |
163 | private void synchronizeChildTreeItemList() |
164 | { |
165 | if (!isUISynchronized()) |
166 | { |
167 | rebuildChildTreeItemList(); |
168 | } |
169 | } |
170 | |
171 | /** |
172 | * test if the UI is synchronized with the model |
173 | * |
174 | * @return true if the model is synchronized |
175 | */ |
176 | private boolean isUISynchronized() |
177 | { |
178 | TreeItem treeItem = getTreeItem(); |
179 | int widgetCount = treeItem.getChildCount(); |
180 | boolean isUISynchronized = true; |
181 | OrderedListModel<OrderedTreeItemModel> currentTreeItemList = |
182 | getTreeItemList(); |
183 | |
184 | if (currentTreeItemList == null) |
185 | { |
186 | isUISynchronized = widgetCount == 0; |
187 | } |
188 | else |
189 | { |
190 | List<OrderedTreeItemModel> widgetContainerList = |
191 | currentTreeItemList.getList(); |
192 | |
193 | int expectedWidgetCount = widgetContainerList.size(); |
194 | |
195 | if (widgetCount == expectedWidgetCount) |
196 | { |
197 | for (int i = 0; i < widgetCount; i++) |
198 | { |
199 | TreeItem currentWidget = treeItem.getChild(i); |
200 | TreeItem expectedWidget = |
201 | widgetContainerList.get(i).getTreeItem().getTreeItem(); |
202 | |
203 | if (currentWidget != expectedWidget) |
204 | { |
205 | isUISynchronized = false; |
206 | break; |
207 | } |
208 | } |
209 | } |
210 | else |
211 | { |
212 | isUISynchronized = false; |
213 | } |
214 | } |
215 | return isUISynchronized; |
216 | } |
217 | |
218 | /** |
219 | * rebuild Child Tree Item List |
220 | */ |
221 | private void rebuildChildTreeItemList() |
222 | { |
223 | TreeItem treeItem = getTreeItem(); |
224 | |
225 | TreeItem firstItem = null; |
226 | |
227 | if (getTreeItemList() != null) |
228 | { |
229 | List<OrderedTreeItemModel> widgetContainerList = |
230 | getTreeItemList().getList(); |
231 | |
232 | for (OrderedTreeItemModel orderedWidgetModel : widgetContainerList) |
233 | { |
234 | TreeItemModel childTreeItem = orderedWidgetModel.getTreeItem(); |
235 | if (childTreeItem != null) |
236 | { |
237 | childTreeItem.setParent(this); |
238 | TreeItem addChild = childTreeItem.getTreeItem(); |
239 | treeItem.addItem(addChild); |
240 | if (firstItem == null) |
241 | { |
242 | firstItem = addChild; |
243 | } |
244 | } |
245 | } |
246 | } |
247 | |
248 | if (firstItem == null) |
249 | { |
250 | treeItem.removeItems(); |
251 | } |
252 | else |
253 | { |
254 | // after adding all the items in the tree again, all the items to |
255 | // delete should be at the beginning. |
256 | int childCount = treeItem.getChildCount(); |
257 | for (int i = 0; i < childCount; ++i) |
258 | { |
259 | TreeItem childZero = treeItem.getChild(0); |
260 | if (childZero == firstItem) |
261 | { |
262 | break; |
263 | } |
264 | treeItem.removeItem(childZero); |
265 | } |
266 | } |
267 | } |
268 | |
269 | /** |
270 | * set the Component |
271 | * |
272 | * @param widget the component in the tree item |
273 | */ |
274 | public void setComponent( |
275 | WidgetModel widget) |
276 | { |
277 | component = widget; |
278 | } |
279 | |
280 | /** |
281 | * delete the Component in the tree item |
282 | */ |
283 | private void deleteComponent() |
284 | { |
285 | if (component != null) |
286 | { |
287 | component.delete(); |
288 | setComponent(null); |
289 | } |
290 | } |
291 | |
292 | /** |
293 | * (non-JSDoc) |
294 | * |
295 | * @see org.deduced.viewer.web.shared.UserInterfaceModel#propertyChanged(org.deduced.viewer.web.shared.ChangeEvent) |
296 | */ |
297 | @SuppressWarnings("unchecked") |
298 | @Override |
299 | public void propertyChanged( |
300 | ChangeEvent event) |
301 | { |
302 | String eventName = event.getName(); |
303 | if (Utilities.equals(eventName, "component")) |
304 | { |
305 | WidgetModel newComponent = |
306 | (WidgetModel) event.getSerializableValue(); |
307 | updateComponent(newComponent); |
308 | } |
309 | else if (Utilities.equals(eventName, "text")) |
310 | { |
311 | String newText = (String) event.getSerializableValue(); |
312 | textChanged(newText); |
313 | } |
314 | else if (Utilities.equals(eventName, "tree item list")) |
315 | { |
316 | OrderedListModel<OrderedTreeItemModel> newOrderedTreeItemList = |
317 | (OrderedListModel<OrderedTreeItemModel>) event |
318 | .getSerializableValue(); |
319 | treeItemListChanged(newOrderedTreeItemList); |
320 | } |
321 | else if (Utilities.equals(eventName, "is open")) |
322 | { |
323 | Boolean newOpen = (Boolean) event.getSerializableValue(); |
324 | |
325 | isOpenChanged(newOpen); |
326 | } |
327 | else |
328 | { |
329 | super.propertyChanged(event); |
330 | } |
331 | } |
332 | |
333 | /** |
334 | * update the component and register it |
335 | * |
336 | * @param newComponent the new component |
337 | */ |
338 | public void updateComponent( |
339 | WidgetModel newComponent) |
340 | { |
341 | setComponent(updateModel(newComponent, getComponent(), this)); |
342 | |
343 | synchronizeWithUI(); |
344 | } |
345 | |
346 | /** |
347 | * is Open Changed. This method will verify if the event should be ignored |
348 | * before applying it to the local object. |
349 | * |
350 | * @param newOpen the new isOpen flag. |
351 | */ |
352 | private void isOpenChanged( |
353 | Boolean newOpen) |
354 | { |
355 | setIsOpen(newOpen.booleanValue()); |
356 | synchronizeWithUI(); |
357 | } |
358 | |
359 | /** |
360 | * tree Item List Changed |
361 | * |
362 | * @param newOrderedTreeItemList the new tree item list |
363 | */ |
364 | public void treeItemListChanged( |
365 | OrderedListModel<OrderedTreeItemModel> newOrderedTreeItemList) |
366 | { |
367 | setTreeItemList(updateModel(newOrderedTreeItemList, getTreeItemList(), |
368 | this)); |
369 | synchronizeWithUI(); |
370 | } |
371 | |
372 | /** |
373 | * text Changed |
374 | * |
375 | * @param newText the new text |
376 | */ |
377 | public void textChanged( |
378 | String newText) |
379 | { |
380 | setText(newText); |
381 | synchronizeWithUI(); |
382 | } |
383 | |
384 | /** |
385 | * @return the component |
386 | */ |
387 | public WidgetModel getComponent() |
388 | { |
389 | return component; |
390 | } |
391 | |
392 | /** |
393 | * @param setIsOpen the isOpen to set |
394 | */ |
395 | public void setIsOpen( |
396 | boolean setIsOpen) |
397 | { |
398 | isOpen = setIsOpen; |
399 | } |
400 | |
401 | /** |
402 | * @return the isOpen |
403 | */ |
404 | public boolean isOpen() |
405 | { |
406 | return isOpen; |
407 | } |
408 | |
409 | /** |
410 | * @param setText the text to set |
411 | */ |
412 | public void setText( |
413 | String setText) |
414 | { |
415 | text = setText; |
416 | } |
417 | |
418 | /** |
419 | * @return the text |
420 | */ |
421 | public String getText() |
422 | { |
423 | return text; |
424 | } |
425 | |
426 | /** |
427 | * @param setTreeItemList the treeItemList to set |
428 | */ |
429 | public void setTreeItemList( |
430 | OrderedListModel<OrderedTreeItemModel> setTreeItemList) |
431 | { |
432 | treeItemList = setTreeItemList; |
433 | } |
434 | |
435 | /** |
436 | * @return the treeItemList |
437 | */ |
438 | public OrderedListModel<OrderedTreeItemModel> getTreeItemList() |
439 | { |
440 | return treeItemList; |
441 | } |
442 | |
443 | /** |
444 | * (non-JSDoc) |
445 | * |
446 | * @see org.deduced.viewer.web.shared.ModelContainer#modelChanged(org.deduced.viewer.web.shared.Model) |
447 | */ |
448 | @Override |
449 | public void modelChanged( |
450 | Model model) |
451 | { |
452 | synchronizeWithUI(); |
453 | } |
454 | |
455 | } |