1 | |
|
2 | |
|
3 | |
|
4 | |
|
5 | |
|
6 | |
|
7 | |
|
8 | |
|
9 | |
|
10 | |
|
11 | |
|
12 | |
|
13 | |
|
14 | |
|
15 | |
|
16 | |
package org.kuali.student.common.ui.client.configurable.mvc.binding; |
17 | |
|
18 | |
import java.util.Iterator; |
19 | |
|
20 | |
import org.kuali.student.common.assembly.data.Data; |
21 | |
import org.kuali.student.common.assembly.data.QueryPath; |
22 | |
import org.kuali.student.common.assembly.data.Data.Key; |
23 | |
import org.kuali.student.common.assembly.data.Data.Property; |
24 | |
import org.kuali.student.common.assembly.data.Data.StringKey; |
25 | |
import org.kuali.student.common.ui.client.mvc.DataModel; |
26 | |
|
27 | |
|
28 | |
|
29 | |
|
30 | |
|
31 | |
|
32 | 0 | public abstract class ModelWidgetBindingSupport<WidgetType> implements ModelWidgetBinding<WidgetType> { |
33 | 0 | public static final StringKey RUNTIME_ROOT = new StringKey("_runtimeData"); |
34 | 0 | public static final StringKey DIRTY_PATH = new StringKey("dirty"); |
35 | |
|
36 | |
|
37 | |
|
38 | |
|
39 | |
|
40 | |
|
41 | |
|
42 | |
|
43 | |
|
44 | |
protected void setDirtyFlag(DataModel model, QueryPath qPath) { |
45 | 0 | QueryPath parent = qPath.subPath(0, qPath.size() - 1); |
46 | 0 | QueryPath qPathDirty = new QueryPath(); |
47 | 0 | qPathDirty.addAll(parent); |
48 | 0 | qPathDirty.add(RUNTIME_ROOT); |
49 | 0 | qPathDirty.add(DIRTY_PATH); |
50 | |
|
51 | 0 | ensureDirtyFlagPath(model.getRoot(), qPathDirty); |
52 | |
|
53 | 0 | Data flags = model.get(qPathDirty); |
54 | 0 | flags.set(qPath.get(qPath.size() - 1), Boolean.TRUE); |
55 | 0 | } |
56 | |
|
57 | |
|
58 | |
|
59 | |
|
60 | |
|
61 | |
|
62 | |
|
63 | |
|
64 | |
|
65 | |
protected void ensureDirtyFlagPath(Data root, QueryPath path) { |
66 | 0 | Data current = root; |
67 | 0 | for (int i = 0; i < path.size(); i++) { |
68 | 0 | Key key = path.get(i); |
69 | 0 | Data d = current.get(key); |
70 | 0 | if (d == null) { |
71 | 0 | d = new Data(); |
72 | 0 | current.set(key, d); |
73 | |
} |
74 | 0 | current = d; |
75 | |
} |
76 | 0 | } |
77 | |
|
78 | |
|
79 | |
|
80 | |
|
81 | |
|
82 | |
|
83 | |
protected static boolean nullsafeEquals(Object o1, Object o2) { |
84 | 0 | return (o1 == null && o2 == null) || (o1 != null && o1.equals(o2)); |
85 | |
} |
86 | |
|
87 | |
|
88 | |
|
89 | |
|
90 | |
|
91 | |
|
92 | |
protected static boolean nullsafeEquals(Data o1, Data o2) { |
93 | 0 | if (o1 == null && o2 == null) { |
94 | 0 | return true; |
95 | 0 | } else if (o1 != null && o2 != null && o1.size() != o2.size()) { |
96 | 0 | return false; |
97 | 0 | } else if (o1 != null && o2 != null && o1.size() == o2.size()) { |
98 | 0 | return deepEquals(o1, o2); |
99 | |
} else { |
100 | 0 | return false; |
101 | |
} |
102 | |
} |
103 | |
|
104 | |
|
105 | |
|
106 | |
|
107 | |
|
108 | |
|
109 | |
private static boolean deepEquals(Data o1, Data o2) { |
110 | 0 | Iterator<Property> iter = o1.iterator(); |
111 | 0 | while (iter.hasNext()) { |
112 | 0 | Property prop = iter.next(); |
113 | 0 | Key key = prop.getWrappedKey(); |
114 | 0 | Object value1 = prop.getValue(); |
115 | 0 | Object value2 = o2.get(key); |
116 | |
|
117 | 0 | if (value1 == null ^ value2 == null) { |
118 | 0 | return false; |
119 | 0 | } else if (value1 != null && value1 instanceof Data && value2 instanceof Data) { |
120 | 0 | boolean recursiveResult = deepEquals((Data) value1, (Data) value2); |
121 | 0 | if (!recursiveResult) { |
122 | 0 | return false; |
123 | |
} |
124 | 0 | } else if (value1 != value2 && !(value1.equals(value2))) { |
125 | 0 | return false; |
126 | |
} |
127 | 0 | } |
128 | 0 | return true; |
129 | |
} |
130 | |
} |