/
LayoutBuilder.java
172 lines (132 loc) · 5.75 KB
/
LayoutBuilder.java
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
package name.shamansir.mvp4glayout.client.ui;
import java.util.HashMap;
import java.util.Map;
import com.allen_sauer.gwt.log.client.Log;
import name.shamansir.mvp4glayout.client.mvp.ChildEventBus;
import name.shamansir.mvp4glayout.client.mvp.IsMainEventBus;
import name.shamansir.mvp4glayout.client.ui.state.LayoutWithState;
import name.shamansir.mvp4glayout.client.ui.state.State;
import name.shamansir.mvp4glayout.client.ui.structure.LayoutId;
import name.shamansir.mvp4glayout.client.ui.structure.PortalId;
import name.shamansir.mvp4glayout.client.ui.widget.Layout;
public abstract class LayoutBuilder<E extends ChildEventBus> {
private static final Map<Portal, CanBuildLayout> cache = new HashMap<Portal, CanBuildLayout>();
public static interface CanBuildLayout {
public static final State DEFAULT_LAYOUT_STATE = State.LOADING_DATA;
public Layout build(State state);
public boolean built();
public void reset();
public boolean layoutHasStates();
public LayoutId layoutId();
public Layout getLayout();
public Portal getPortal();
public State curState();
}
public final CanBuildLayout make(final Portal view, final E eventBus) {
if (cache.containsKey(view)) {
final CanBuildLayout builder = cache.get(view);
//builder.reset(); // it will be manually reseted in handler, if required
return builder;
} else {
final CanBuildLayout newBuilder = new CanLayoutModuleView(view, eventBus);
cache.put(view, newBuilder);
return newBuilder;
}
}
protected abstract boolean layout(Portal view, Layout layout, State state, E eventBus);
protected static abstract class CanBuildStatedLayout implements CanBuildLayout {
protected final Portal view;
protected final Layout layout;
protected final boolean hasStates;
protected boolean built;
protected State curState;
protected CanBuildStatedLayout(Portal view) {
this.view = view;
this.layout = Layouts.get(view.layout);
this.hasStates = (this.layout instanceof LayoutWithState);
}
protected void prepare(State state) {
Log.debug("Preparing to build layout " + layout.id() + " with state " + state + " (Layout has states: " + hasStates + ")");
if (!hasStates) throw new IllegalStateException("Layout " + layout.id() + " requires to support states to use prepare() method");
if (state == null) throw new IllegalArgumentException("Passed state is null");
if ((curState != null) && curState.equals(state)) throw new IllegalStateException("Current state is already prepared");
curState = state;
((LayoutWithState)layout).changeState(state);
}
@Override
public final Layout build(State state) {
Log.debug("Building layout " + layout.id() + " with state " + state + " (Layout has states: " + hasStates + ") for view " + view);
if (built && (hasStates && curState.equals(state))) throw new IllegalStateException("Layout " + layout.id() + " was already built for state " + state + " with this builder, reset it or use another builder");
if (built && (!hasStates && (state == null))) throw new IllegalStateException("Layout " + layout.id() + " was already built with this builder, reset it or use another builder");
if (hasStates && (state == null)) throw new IllegalStateException("Layout " + layout.id() + " requires state to be set, use layoutHasStates() method of builder to determine is current layout requires states");
if (state != null) prepare(state);
if (!doLayout(view, layout, state)) {
throw new IllegalStateException("Layout " + layout.id() + " was not built ");
}
built = true;
layout.whenBuilt();
return layout;
}
protected abstract boolean doLayout(Portal view, Layout layout, State state);
@Override
public boolean built() { return built; }
@Override
public boolean layoutHasStates() { return hasStates; }
@Override
public LayoutId layoutId() { return view.layout; }
@Override
public Layout getLayout() { return layout; }
@Override
public Portal getPortal() { return view; }
@Override
public State curState() { return curState; }
@Override
public void reset() {
curState = null;
built = false;
layout.clear();
}
}
protected class CanLayoutModuleView extends CanBuildStatedLayout {
protected final E eventBus;
protected CanLayoutModuleView(Portal view, E eventBus) {
super(view);
this.eventBus = eventBus;
}
@Override
protected boolean doLayout(Portal view, Layout layout, State state) {
boolean result = layout(view, layout, state, eventBus);
//TODO: if (result) eventBus.layoutBuilt(view);
return result;
}
}
/**
* Use like:
*
* <pre>
* new CanLayoutMainView(Portal.VIEW_404, eventBus) {
*
* protected boolean doLayout(Portal view, Layout layout, State state,
* Map<Place, HasWidgets> outlets) {
* outlets.get(Place.MAIN).clear();
* outlets.get(Place.MAIN).add(dialog);
* return true;
* }
*
* }.run();
* </pre>
*
*/
public static abstract class CanLayoutMainView extends CanBuildStatedLayout implements Runnable {
protected final IsMainEventBus eventBus;
public CanLayoutMainView(PortalId view, IsMainEventBus eventBus) {
super(Portal.fromId(view));
this.eventBus = eventBus;
}
@Override
public final void run() {
eventBus.newPortal(view, this);
//TODO: eventBus.layoutBuilt(view);
}
}
}