|
@@ -1,506 +1,505 @@ |
1 |
|
- |
// This Source Code is in the Public Domain per: http://unlicense.org |
2 |
|
- |
package org.litesoft.GWT.client.widgets.nonpublic; |
3 |
|
- |
|
4 |
|
- |
import org.litesoft.commonfoundation.base.*; |
5 |
|
- |
import org.litesoft.commonfoundation.typeutils.Objects; |
6 |
|
- |
import org.litesoft.commonfoundation.typeutils.*; |
7 |
|
- |
import org.litesoft.core.simpletypes.*; |
8 |
|
- |
|
9 |
|
- |
import java.util.*; |
10 |
|
- |
|
11 |
|
- |
import static org.litesoft.core.simpletypes.nonpublic.EqualSupport.*; |
12 |
|
- |
|
13 |
|
- |
public class InjectionPointSelectorController<T extends Synopsisable> { |
14 |
|
- |
public interface View<U extends Synopsisable> { |
15 |
|
- |
public void injectBetween( U pLowerBound, U pUpperBound ); |
16 |
|
- |
|
17 |
|
- |
public void show( DrillDownSet pDrillDownSet ); |
18 |
|
- |
|
19 |
|
- |
public void notEnoughVisibleEntries(); |
20 |
|
- |
} |
21 |
|
- |
|
22 |
|
- |
public static abstract class ViewEntry<U extends Synopsisable> { |
23 |
|
- |
private String mText; |
24 |
|
- |
|
25 |
|
- |
protected ViewEntry( String pText ) { |
26 |
|
- |
mText = Strings.assertNotNullNotEmpty( "Text", pText ); |
27 |
|
- |
} |
28 |
|
- |
|
29 |
|
- |
public U getUpperReference() { |
30 |
|
- |
return null; |
31 |
|
- |
} |
32 |
|
- |
|
33 |
|
- |
public U getLowerReference() { |
34 |
|
- |
return null; |
35 |
|
- |
} |
36 |
|
- |
|
37 |
|
- |
/** |
38 |
|
- |
* If Selectable, then is NOT a reference, but one of: Between, There, Top, or Bottom |
39 |
|
- |
*/ |
40 |
|
- |
public boolean isSelectable() { |
41 |
|
- |
return false; |
42 |
|
- |
} |
43 |
|
- |
|
44 |
|
- |
public boolean isBetween() { |
45 |
|
- |
return false; |
46 |
|
- |
} |
47 |
|
- |
|
48 |
|
- |
public boolean isSelected() { |
49 |
|
- |
return false; |
50 |
|
- |
} |
51 |
|
- |
|
52 |
|
- |
public final String getText() { |
53 |
|
- |
return mText; |
54 |
|
- |
} |
55 |
|
- |
|
56 |
|
- |
@Override |
57 |
|
- |
public boolean equals( Object o ) { |
58 |
|
- |
if ( this == o ) { |
59 |
|
- |
return true; |
60 |
|
- |
} |
61 |
|
- |
if ( (o == null) || !this.getClass().getName().equals( o.getClass().getName() ) ) { |
62 |
|
- |
return false; |
63 |
|
- |
} |
64 |
|
- |
ViewEntry them = (ViewEntry) o; |
65 |
|
- |
return Objects.areEqual( this.getText(), them.getText() ) && // |
66 |
|
- |
Objects.areEqual( this.getUpperReference(), them.getUpperReference() ) && // |
67 |
|
- |
Objects.areEqual( this.getLowerReference(), them.getLowerReference() ); |
68 |
|
- |
} |
69 |
|
- |
|
70 |
|
- |
@Override |
71 |
|
- |
public int hashCode() { |
72 |
|
- |
return hashCodeEm( calcHashCode( getText() ), // |
73 |
|
- |
calcHashCode( getUpperReference() ), // |
74 |
|
- |
calcHashCode( getLowerReference() ) ); |
75 |
|
- |
} |
76 |
|
- |
} |
77 |
|
- |
|
78 |
|
- |
public static class ViewSet { |
79 |
|
- |
private List<ViewEntry> mEntries; |
80 |
|
- |
|
81 |
|
- |
public ViewSet( List<ViewEntry> pEntries ) { |
82 |
|
- |
mEntries = pEntries; |
83 |
|
- |
} |
84 |
|
- |
|
85 |
|
- |
public ViewSet( ViewEntry... pEntries ) { |
86 |
|
- |
mEntries = Arrays.asList( pEntries ); |
87 |
|
- |
} |
88 |
|
- |
|
89 |
|
- |
public ViewEntry[] getEntries() { |
90 |
|
- |
return mEntries.toArray( new ViewEntry[mEntries.size()] ); |
91 |
|
- |
} |
92 |
|
- |
|
93 |
|
- |
@Override |
94 |
|
- |
public String toString() { |
95 |
|
- |
return mEntries.toString(); |
96 |
|
- |
} |
97 |
|
- |
|
98 |
|
- |
@Override |
99 |
|
- |
public boolean equals( Object o ) { |
100 |
|
- |
if ( this == o ) { |
101 |
|
- |
return true; |
102 |
|
- |
} |
103 |
|
- |
if ( (o == null) || !this.getClass().getName().equals( o.getClass().getName() ) ) { |
104 |
|
- |
return false; |
105 |
|
- |
} |
106 |
|
- |
ViewSet them = (ViewSet) o; |
107 |
|
- |
return Objects.areEqual( this.mEntries, them.mEntries ); |
108 |
|
- |
} |
109 |
|
- |
|
110 |
|
- |
@Override |
111 |
|
- |
public int hashCode() { |
112 |
|
- |
return calcHashCode( mEntries ); |
113 |
|
- |
} |
114 |
|
- |
} |
115 |
|
- |
|
116 |
|
- |
public static class DrillDownSet { |
117 |
|
- |
private ViewSet mHomeSet; |
118 |
|
- |
private boolean mSomethingBetweenHomeAndPreviousSets; |
119 |
|
- |
private ViewSet mPreviousSet; |
120 |
|
- |
private ViewSet mCurrentSet; |
121 |
|
- |
|
122 |
|
- |
public DrillDownSet( ViewSet pHomeSet, boolean pSomethingBetweenHomeAndPreviousSets, ViewSet pPreviousSet, ViewSet pCurrentSet ) { |
123 |
|
- |
mHomeSet = pHomeSet; |
124 |
|
- |
mSomethingBetweenHomeAndPreviousSets = pSomethingBetweenHomeAndPreviousSets; |
125 |
|
- |
mPreviousSet = pPreviousSet; |
126 |
|
- |
mCurrentSet = pCurrentSet; |
127 |
|
- |
} |
128 |
|
- |
|
129 |
|
- |
public ViewSet getHomeSet() { |
130 |
|
- |
return mHomeSet; |
131 |
|
- |
} |
132 |
|
- |
|
133 |
|
- |
public boolean isSomethingBetweenHomeAndPreviousSets() { |
134 |
|
- |
return mSomethingBetweenHomeAndPreviousSets; |
135 |
|
- |
} |
136 |
|
- |
|
137 |
|
- |
public ViewSet getPreviousSet() { |
138 |
|
- |
return mPreviousSet; |
139 |
|
- |
} |
140 |
|
- |
|
141 |
|
- |
public ViewSet getCurrentSet() { |
142 |
|
- |
return mCurrentSet; |
143 |
|
- |
} |
144 |
|
- |
|
145 |
|
- |
@Override |
146 |
|
- |
public String toString() { |
147 |
|
- |
StringBuilder sb = new StringBuilder( "DrillDownSet:" ); |
148 |
|
- |
add( sb, "Home", mHomeSet ); |
149 |
|
- |
if ( mSomethingBetweenHomeAndPreviousSets ) { |
150 |
|
- |
sb.append( "\n ..." ); |
151 |
|
- |
} |
152 |
|
- |
add( sb, "Prev", mPreviousSet ); |
153 |
|
- |
add( sb, "Curr", mCurrentSet ); |
154 |
|
- |
return sb.toString(); |
155 |
|
- |
} |
156 |
|
- |
|
157 |
|
- |
private void add( StringBuilder pSb, String pWhat, ViewSet pSet ) { |
158 |
|
- |
if ( pSet != null ) { |
159 |
|
- |
pSb.append( '\n' ).append( pWhat ).append( ": " ).append( pSet ); |
160 |
|
- |
} |
161 |
|
- |
} |
162 |
|
- |
|
163 |
|
- |
@Override |
164 |
|
- |
public boolean equals( Object o ) { |
165 |
|
- |
if ( this == o ) { |
166 |
|
- |
return true; |
167 |
|
- |
} |
168 |
|
- |
if ( (o == null) || !this.getClass().getName().equals( o.getClass().getName() ) ) { |
169 |
|
- |
return false; |
170 |
|
- |
} |
171 |
|
- |
DrillDownSet them = (DrillDownSet) o; |
172 |
|
- |
return (this.mSomethingBetweenHomeAndPreviousSets == them.mSomethingBetweenHomeAndPreviousSets) && // |
173 |
|
- |
Objects.areEqual( this.mHomeSet, them.mHomeSet ) && // |
174 |
|
- |
Objects.areEqual( this.mPreviousSet, them.mPreviousSet ) && // |
175 |
|
- |
Objects.areEqual( this.mCurrentSet, them.mCurrentSet ); |
176 |
|
- |
} |
177 |
|
- |
|
178 |
|
- |
@Override |
179 |
|
- |
public int hashCode() { |
180 |
|
- |
return hashCodeEm( calcHashCode( mHomeSet ), // |
181 |
|
- |
calcHashCode( mPreviousSet ), // |
182 |
|
- |
calcHashCode( mCurrentSet ) ); |
183 |
|
- |
} |
184 |
|
- |
} |
185 |
|
- |
|
186 |
|
- |
static abstract class SelectionPointEntry<U extends Synopsisable> extends ViewEntry<U> { |
187 |
|
- |
private boolean mSelected; |
188 |
|
- |
private U mUpperReference; |
189 |
|
- |
private U mLowerReference; |
190 |
|
- |
|
191 |
|
- |
protected SelectionPointEntry( boolean pSelected, String pText, U pUpperReference, U pLowerReference ) { |
192 |
|
- |
super( pText ); |
193 |
|
- |
mSelected = pSelected; |
194 |
|
- |
mUpperReference = pUpperReference; |
195 |
|
- |
mLowerReference = pLowerReference; |
196 |
|
- |
} |
197 |
|
- |
|
198 |
|
- |
@Override |
199 |
|
- |
public U getUpperReference() { |
200 |
|
- |
return mUpperReference; |
201 |
|
- |
} |
202 |
|
- |
|
203 |
|
- |
@Override |
204 |
|
- |
public U getLowerReference() { |
205 |
|
- |
return mLowerReference; |
206 |
|
- |
} |
207 |
|
- |
|
208 |
|
- |
@Override |
209 |
|
- |
public boolean isSelectable() { |
210 |
|
- |
return true; |
211 |
|
- |
} |
212 |
|
- |
|
213 |
|
- |
@Override |
214 |
|
- |
public boolean isSelected() { |
215 |
|
- |
return mSelected; |
216 |
|
- |
} |
217 |
|
- |
|
218 |
|
- |
@Override |
219 |
|
- |
public String toString() { |
220 |
|
- |
return Strings.replace( getText(), '\n', "\\n" ) + ":" + addXtra(); |
221 |
|
- |
} |
222 |
|
- |
|
223 |
|
- |
protected String addXtra() { |
224 |
|
- |
return ""; |
225 |
|
- |
} |
226 |
|
- |
} |
227 |
|
- |
|
228 |
|
- |
@SuppressWarnings("EqualsAndHashcode") |
229 |
|
- |
static class Between<U extends Synopsisable> extends SelectionPointEntry<U> { |
230 |
|
- |
private Between( boolean pSelected, U pUpperReference, U pLowerReference ) { |
231 |
|
- |
super( pSelected, "Between", pUpperReference, pLowerReference ); |
232 |
|
- |
} |
233 |
|
- |
|
234 |
|
- |
public static <V extends Synopsisable> Between<V> create( boolean pSelected, V pUpperReference, V pLowerReference ) { |
235 |
|
- |
return new Between<V>( pSelected, pUpperReference, pLowerReference ); |
236 |
|
- |
} |
237 |
|
- |
|
238 |
|
- |
public Between<U> copyAsSelected() { |
239 |
|
- |
return isSelected() ? this : create( true, getUpperReference(), getLowerReference() ); |
240 |
|
- |
} |
241 |
|
- |
|
242 |
|
- |
@Override |
243 |
|
- |
public boolean isBetween() { |
244 |
|
- |
return true; |
245 |
|
- |
} |
246 |
|
- |
|
247 |
|
- |
protected String addXtra() { |
248 |
|
- |
return (isSelected() ? "(?Y)" : "(?N)"); |
249 |
|
- |
} |
250 |
|
- |
|
251 |
|
- |
@Override |
252 |
|
- |
@SuppressWarnings({"EqualsWhichDoesntCheckParameterClass"}) |
253 |
|
- |
public boolean equals( Object o ) { |
254 |
|
- |
return super.equals( o ) && (this.isSelected() == ((Between) o).isSelected()); |
255 |
|
- |
} |
256 |
|
- |
} |
257 |
|
- |
|
258 |
|
- |
static class There<U extends Synopsisable> extends SelectionPointEntry<U> { |
259 |
|
- |
private There( U pUpperReference, U pLowerReference ) { |
260 |
|
- |
super( false, "There", pUpperReference, pLowerReference ); |
261 |
|
- |
} |
262 |
|
- |
|
263 |
|
- |
public static <V extends Synopsisable> There<V> create( V pUpperReference, V pLowerReference ) { |
264 |
|
- |
return new There<V>( pUpperReference, pLowerReference ); |
265 |
|
- |
} |
266 |
|
- |
} |
267 |
|
- |
|
268 |
|
- |
static class Top<U extends Synopsisable> extends SelectionPointEntry<U> { |
269 |
|
- |
private Top( U pLowerReference ) { |
270 |
|
- |
super( false, "Top\n(There)", null, pLowerReference ); |
271 |
|
- |
} |
272 |
|
- |
|
273 |
|
- |
public static <V extends Synopsisable> Top<V> create( V pLowerReference ) { |
274 |
|
- |
return new Top<V>( pLowerReference ); |
275 |
|
- |
} |
276 |
|
- |
} |
277 |
|
- |
|
278 |
|
- |
static class Bottom<U extends Synopsisable> extends SelectionPointEntry<U> { |
279 |
|
- |
private Bottom( U pUpperReference ) { |
280 |
|
- |
super( false, "Bottom\n(There)", pUpperReference, null ); |
281 |
|
- |
} |
282 |
|
- |
|
283 |
|
- |
public static <V extends Synopsisable> Bottom<V> create( V pUpperReference ) { |
284 |
|
- |
return new Bottom<V>( pUpperReference ); |
285 |
|
- |
} |
286 |
|
- |
} |
287 |
|
- |
|
288 |
|
- |
static class Reference<U extends Synopsisable> extends ViewEntry<U> { |
289 |
|
- |
private Reference( int pLines, U pReference ) { |
290 |
|
- |
super( pReference.getSynopsis( pLines ) ); |
291 |
|
- |
} |
292 |
|
- |
|
293 |
|
- |
public static <V extends Synopsisable> Reference<V> create( int pLines, V pReference ) { |
294 |
|
- |
return new Reference<V>( pLines, pReference ); |
295 |
|
- |
} |
296 |
|
- |
|
297 |
|
- |
@Override |
298 |
|
- |
public String toString() { |
299 |
|
- |
return "Ref: " + Strings.replace( getText(), '\n', "\\n" ); |
300 |
|
- |
} |
301 |
|
- |
} |
302 |
|
- |
|
303 |
|
- |
private int mSynopsisLines; |
304 |
|
- |
private List<T> mInjectIns; |
305 |
|
- |
private View<T> mView; |
306 |
|
- |
private int mCurrentEntriesVisible = -1; |
307 |
|
- |
private List<Between<T>> mSelectedBetweens = new ArrayList<Between<T>>(); |
308 |
|
- |
|
309 |
|
- |
public InjectionPointSelectorController( int pSynopsisLines, List<T> pInjectIns, View<T> pView ) { |
310 |
|
- |
mSynopsisLines = pSynopsisLines; |
311 |
|
- |
mInjectIns = pInjectIns; |
312 |
|
- |
mView = pView; |
313 |
|
- |
} |
314 |
|
- |
|
315 |
|
- |
public InjectionPointSelectorController( int pSynopsisLines, View<T> pView, T... pInjectIns ) { |
316 |
|
- |
this( pSynopsisLines, Arrays.asList( pInjectIns ), pView ); |
317 |
|
- |
} |
318 |
|
- |
|
319 |
|
- |
public void updateForEntriesVisible( int pCount ) { |
320 |
|
- |
if ( mCurrentEntriesVisible != pCount ) { |
321 |
|
- |
DrillDownSet zDrillDownSet = updateDrillDownSetWhenEntriesVisibleChanges( pCount, mSelectedBetweens ); |
322 |
|
- |
if ( zDrillDownSet == null ) { |
323 |
|
- |
mView.notEnoughVisibleEntries(); |
324 |
|
- |
return; |
325 |
|
- |
} |
326 |
|
- |
mCurrentEntriesVisible = pCount; |
327 |
|
- |
mView.show( zDrillDownSet ); |
328 |
|
- |
} |
329 |
|
- |
} |
330 |
|
- |
|
331 |
|
- |
public void homeSelected() { |
332 |
|
- |
DrillDownSet zDrillDownSet = updateDrillDownSetWhenEntriesVisibleChanges( mCurrentEntriesVisible, mSelectedBetweens ); |
333 |
|
- |
mView.show( zDrillDownSet ); |
334 |
|
- |
} |
335 |
|
- |
|
336 |
|
- |
public void previousSelected() { |
337 |
|
- |
mSelectedBetweens.remove( mSelectedBetweens.size() - 1 ); |
338 |
|
- |
DrillDownSet zDrillDownSet = updateDrillDownSetWhenSelectedBetweensChange( mCurrentEntriesVisible, mSelectedBetweens ); |
339 |
|
- |
mView.show( zDrillDownSet ); |
340 |
|
- |
} |
341 |
|
- |
|
342 |
|
- |
public void viewSelected( ViewEntry<T> pEntry ) { |
343 |
|
- |
Objects.assertNotNull( "Entry", pEntry ); |
344 |
|
- |
if ( pEntry.isBetween() ) { |
345 |
|
- |
mSelectedBetweens.add( ((Between<T>) pEntry).copyAsSelected() ); |
346 |
|
- |
DrillDownSet zDrillDownSet = updateDrillDownSetWhenSelectedBetweensChange( mCurrentEntriesVisible, mSelectedBetweens ); |
347 |
|
- |
mView.show( zDrillDownSet ); |
348 |
|
- |
return; |
349 |
|
- |
} |
350 |
|
- |
if ( pEntry.isSelectable() ) { |
351 |
|
- |
mView.injectBetween( pEntry.getLowerReference(), pEntry.getUpperReference() ); |
352 |
|
- |
return; |
353 |
|
- |
} |
354 |
|
- |
throw new IllegalArgumentException( "Can not 'viewSelected' for type '" + ClassName.simple( pEntry ) + "': " + pEntry ); |
355 |
|
- |
} |
356 |
|
- |
|
357 |
|
- |
/** |
358 |
|
- |
* Update the pLastDrillDownSet based on the new pCount (maximum Entries per ViewSet) (public for Testing) |
359 |
|
- |
* |
360 |
|
- |
* @return null means that pCount was too small! |
361 |
|
- |
*/ |
362 |
|
- |
public DrillDownSet updateDrillDownSetWhenEntriesVisibleChanges( int pCount, List<Between<T>> pSelectedBetweens ) { |
363 |
|
- |
if ( -1 == (pCount = checkIfNotEnoughVisibleEntries( makeOdd( pCount ) )) ) { |
364 |
|
- |
return null; |
365 |
|
- |
} |
366 |
|
- |
pSelectedBetweens.clear(); |
367 |
|
- |
|
368 |
|
- |
List<ViewSet> zViewSets = buildViewSets( pCount, pSelectedBetweens ); |
369 |
|
- |
return new DrillDownSet( null, false, null, zViewSets.get( 0 ) ); |
370 |
|
- |
} |
371 |
|
- |
|
372 |
|
- |
/** |
373 |
|
- |
* Update the pLastDrillDownSet based on the new pCount (maximum Entries per ViewSet) (public for Testing) |
374 |
|
- |
* |
375 |
|
- |
* @return null means that pCount was too small! |
376 |
|
- |
*/ |
377 |
|
- |
public DrillDownSet updateDrillDownSetWhenSelectedBetweensChange( int pCount, List<Between<T>> pSelectedBetweens ) { |
378 |
|
- |
List<ViewSet> zViewSets = buildViewSets( makeOdd( pCount ), pSelectedBetweens ); |
379 |
|
- |
switch ( zViewSets.size() ) { |
380 |
|
- |
case 1: |
381 |
|
- |
return new DrillDownSet( null, false, null, zViewSets.get( 0 ) ); |
382 |
|
- |
case 2: |
383 |
|
- |
return new DrillDownSet( zViewSets.get( 0 ), false, null, zViewSets.get( 1 ) ); |
384 |
|
- |
case 3: |
385 |
|
- |
return new DrillDownSet( zViewSets.get( 0 ), false, zViewSets.get( 1 ), zViewSets.get( 2 ) ); |
386 |
|
- |
default: |
387 |
|
- |
return new DrillDownSet( zViewSets.get( 0 ), true, zViewSets.get( zViewSets.size() - 2 ), zViewSets.get( zViewSets.size() - 1 ) ); |
388 |
|
- |
} |
389 |
|
- |
} |
390 |
|
- |
|
391 |
|
- |
private int checkIfNotEnoughVisibleEntries( int pCount ) { |
392 |
|
- |
return ((pCount >= 5) || // 5 is enough for anything (more is better) |
393 |
|
- |
((pCount == 3) && (mInjectIns.size() == 1))) ? // Special Case of just 1 InjectIn? |
394 |
|
- |
pCount : // pCount is OK |
395 |
|
- |
-1; // indicate pCount too small |
396 |
|
- |
} |
397 |
|
- |
|
398 |
|
- |
private int makeOdd( int pCount ) { |
399 |
|
- |
return ((pCount & 1) == 0) ? // Is Even? |
400 |
|
- |
pCount - 1 : // Even, make Odd! |
401 |
|
- |
pCount; // Already Odd |
402 |
|
- |
} |
403 |
|
- |
|
404 |
|
- |
private Between<T> getCurrentSelectedBetween( List<Between<T>> pSelectedBetweens, int pCurrentIndex ) { |
405 |
|
- |
return (pCurrentIndex < pSelectedBetweens.size()) ? pSelectedBetweens.get( pCurrentIndex ) : null; |
406 |
|
- |
} |
407 |
|
- |
|
408 |
|
- |
private boolean isSelected( Between<T> pSelectedBetween, T pLast, T pCurr ) { |
409 |
|
- |
return (pSelectedBetween != null) && (pLast == pSelectedBetween.getUpperReference()) && (pCurr == pSelectedBetween.getLowerReference()); |
410 |
|
- |
} |
411 |
|
- |
|
412 |
|
- |
private List<ViewSet> buildViewSets( int pCount, List<Between<T>> pSelectedBetweens ) { |
413 |
|
- |
List<ViewSet> zViewSets = new ArrayList<ViewSet>(); |
414 |
|
- |
|
415 |
|
- |
buildHomeViewSet( zViewSets, pCount, pSelectedBetweens ); |
416 |
|
- |
|
417 |
|
- |
return zViewSets; |
418 |
|
- |
} |
419 |
|
- |
|
420 |
|
- |
private void buildHomeViewSet( List<ViewSet> pViewSets, int pCount, List<Between<T>> pSelectedBetweens ) { |
421 |
|
- |
Between<T> zSelectedBetween = getCurrentSelectedBetween( pSelectedBetweens, 0 ); |
422 |
|
- |
|
423 |
|
- |
int zInjectInsToAdd = mInjectIns.size() - 1; |
424 |
|
- |
int zAvailableBetweenBuckets = Math.min( zInjectInsToAdd, (pCount - 3) / 2 ); |
425 |
|
- |
|
426 |
|
- |
// System.out.println( "buildHomeViewSett( " + zSelectedBetween + " ): " + // |
427 |
|
- |
// pCount + " ( " + mInjectIns.size() + " ) " + zInjectInsToAdd + " | " + zAvailableBetweenBuckets ); |
428 |
|
- |
|
429 |
|
- |
ArrayList<ViewEntry> zEntries = new ArrayList<ViewEntry>( pCount ); |
430 |
|
- |
pViewSets.add( new ViewSet( zEntries ) ); |
431 |
|
- |
|
432 |
|
- |
int zCurrNdx = 0; |
433 |
|
- |
int zThru = mInjectIns.size() - 1; |
434 |
|
- |
T zCurrT = mInjectIns.get( zCurrNdx ); |
435 |
|
- |
zEntries.add( Top.create( zCurrT ) ); |
436 |
|
- |
|
437 |
|
- |
while ( zCurrNdx < zThru ) { |
438 |
|
- |
zEntries.add( Reference.create( mSynopsisLines, zCurrT ) ); |
439 |
|
- |
int zLastNdx = zCurrNdx; |
440 |
|
- |
T zLastT = zCurrT; |
441 |
|
- |
int zHowMany = zInjectInsToAdd / zAvailableBetweenBuckets; |
442 |
|
- |
// System.out.print( " zInjectInsToAdd / zAvailableBetweenBuckets ==> " + zInjectInsToAdd + " / " + zAvailableBetweenBuckets + " = " + zHowMany ); |
443 |
|
- |
zInjectInsToAdd -= zHowMany; |
444 |
|
- |
zCurrNdx += zHowMany; |
445 |
|
- |
zCurrT = mInjectIns.get( zCurrNdx ); |
446 |
|
- |
if ( zHowMany == 1 ) { |
447 |
|
- |
// System.out.println( " Add There 1" ); |
448 |
|
- |
zEntries.add( There.create( zLastT, zCurrT ) ); |
449 |
|
- |
} else { |
450 |
|
- |
// System.out.println( " Add Between " + zHowMany ); |
451 |
|
- |
if ( isSelected( zSelectedBetween, zLastT, zCurrT ) ) { |
452 |
|
- |
zEntries.add( zSelectedBetween ); |
453 |
|
- |
buildSubsequentViewSet( pViewSets, pCount, zLastNdx, zCurrNdx, pSelectedBetweens, 1 ); |
454 |
|
- |
} else { |
455 |
|
- |
zEntries.add( Between.create( false, zLastT, zCurrT ) ); |
456 |
|
- |
} |
457 |
|
- |
} |
458 |
|
- |
zAvailableBetweenBuckets--; |
459 |
|
- |
} |
460 |
|
- |
zEntries.add( Reference.create( mSynopsisLines, zCurrT ) ); |
461 |
|
- |
zEntries.add( Bottom.create( zCurrT ) ); |
462 |
|
- |
} |
463 |
|
- |
|
464 |
|
- |
private void buildSubsequentViewSet( List<ViewSet> pViewSets, int pCount, int zUpperNdx, int zLowerNdx, List<Between<T>> pSelectedBetweens, |
465 |
|
- |
int pCurrentIndex ) { |
466 |
|
- |
Between<T> zSelectedBetween = getCurrentSelectedBetween( pSelectedBetweens, pCurrentIndex ); |
467 |
|
- |
|
468 |
|
- |
int zInjectInsToAdd = zLowerNdx - zUpperNdx; |
469 |
|
- |
int zAvailableBetweenBuckets = Math.min( zInjectInsToAdd, pCount / 2 ); |
470 |
|
- |
|
471 |
|
- |
// System.out.println( " buildSubsequentViewSet( " + pCurrentIndex + " => " + zSelectedBetween + " ): " + // |
472 |
|
- |
// pCount + " ( " + zUpperNdx + ", " + zLowerNdx + " ) " + zInjectInsToAdd + " | " + zAvailableBetweenBuckets ); |
473 |
|
- |
|
474 |
|
- |
ArrayList<ViewEntry> zEntries = new ArrayList<ViewEntry>( pCount ); |
475 |
|
- |
pViewSets.add( new ViewSet( zEntries ) ); |
476 |
|
- |
|
477 |
|
- |
int zCurrNdx = zUpperNdx; |
478 |
|
- |
int zThru = zLowerNdx; |
479 |
|
- |
T zCurrT = mInjectIns.get( zCurrNdx ); |
480 |
|
- |
|
481 |
|
- |
while ( zCurrNdx < zThru ) { |
482 |
|
- |
zEntries.add( Reference.create( mSynopsisLines, zCurrT ) ); |
483 |
|
- |
int zLastNdx = zCurrNdx; |
484 |
|
- |
T zLastT = zCurrT; |
485 |
|
- |
int zHowMany = zInjectInsToAdd / zAvailableBetweenBuckets; |
486 |
|
- |
// System.out.print( " zInjectInsToAdd / zAvailableBetweenBuckets ==> " + zInjectInsToAdd + " / " + zAvailableBetweenBuckets + " = " + zHowMany ); |
487 |
|
- |
zInjectInsToAdd -= zHowMany; |
488 |
|
- |
zCurrNdx += zHowMany; |
489 |
|
- |
zCurrT = mInjectIns.get( zCurrNdx ); |
490 |
|
- |
if ( zHowMany == 1 ) { |
491 |
|
- |
// System.out.println( " Add There 1" ); |
492 |
|
- |
zEntries.add( There.create( zLastT, zCurrT ) ); |
493 |
|
- |
} else { |
494 |
|
- |
// System.out.println( " Add Between " + zHowMany ); |
495 |
|
- |
if ( isSelected( zSelectedBetween, zLastT, zCurrT ) ) { |
496 |
|
- |
zEntries.add( zSelectedBetween ); |
497 |
|
- |
buildSubsequentViewSet( pViewSets, pCount, zLastNdx, zCurrNdx, pSelectedBetweens, pCurrentIndex + 1 ); |
498 |
|
- |
} else { |
499 |
|
- |
zEntries.add( Between.create( false, zLastT, zCurrT ) ); |
500 |
|
- |
} |
501 |
|
- |
} |
502 |
|
- |
zAvailableBetweenBuckets--; |
503 |
|
- |
} |
504 |
|
- |
zEntries.add( Reference.create( mSynopsisLines, zCurrT ) ); |
505 |
|
- |
} |
506 |
|
- |
} |
|
1 |
+ |
// This Source Code is in the Public Domain per: http://unlicense.org |
|
2 |
+ |
package org.litesoft.GWT.client.widgets.nonpublic; |
|
3 |
+ |
|
|
4 |
+ |
import org.litesoft.commonfoundation.base.*; |
|
5 |
+ |
import org.litesoft.commonfoundation.typeutils.*; |
|
6 |
+ |
import org.litesoft.core.simpletypes.*; |
|
7 |
+ |
|
|
8 |
+ |
import java.util.*; |
|
9 |
+ |
|
|
10 |
+ |
import static org.litesoft.core.simpletypes.nonpublic.EqualSupport.*; |
|
11 |
+ |
|
|
12 |
+ |
public class InjectionPointSelectorController<T extends Synopsisable> { |
|
13 |
+ |
public interface View<U extends Synopsisable> { |
|
14 |
+ |
public void injectBetween( U pLowerBound, U pUpperBound ); |
|
15 |
+ |
|
|
16 |
+ |
public void show( DrillDownSet pDrillDownSet ); |
|
17 |
+ |
|
|
18 |
+ |
public void notEnoughVisibleEntries(); |
|
19 |
+ |
} |
|
20 |
+ |
|
|
21 |
+ |
public static abstract class ViewEntry<U extends Synopsisable> { |
|
22 |
+ |
private String mText; |
|
23 |
+ |
|
|
24 |
+ |
protected ViewEntry( String pText ) { |
|
25 |
+ |
mText = Confirm.significant( "Text", pText ); |
|
26 |
+ |
} |
|
27 |
+ |
|
|
28 |
+ |
public U getUpperReference() { |
|
29 |
+ |
return null; |
|
30 |
+ |
} |
|
31 |
+ |
|
|
32 |
+ |
public U getLowerReference() { |
|
33 |
+ |
return null; |
|
34 |
+ |
} |
|
35 |
+ |
|
|
36 |
+ |
/** |
|
37 |
+ |
* If Selectable, then is NOT a reference, but one of: Between, There, Top, or Bottom |
|
38 |
+ |
*/ |
|
39 |
+ |
public boolean isSelectable() { |
|
40 |
+ |
return false; |
|
41 |
+ |
} |
|
42 |
+ |
|
|
43 |
+ |
public boolean isBetween() { |
|
44 |
+ |
return false; |
|
45 |
+ |
} |
|
46 |
+ |
|
|
47 |
+ |
public boolean isSelected() { |
|
48 |
+ |
return false; |
|
49 |
+ |
} |
|
50 |
+ |
|
|
51 |
+ |
public final String getText() { |
|
52 |
+ |
return mText; |
|
53 |
+ |
} |
|
54 |
+ |
|
|
55 |
+ |
@Override |
|
56 |
+ |
public boolean equals( Object o ) { |
|
57 |
+ |
if ( this == o ) { |
|
58 |
+ |
return true; |
|
59 |
+ |
} |
|
60 |
+ |
if ( (o == null) || !this.getClass().getName().equals( o.getClass().getName() ) ) { |
|
61 |
+ |
return false; |
|
62 |
+ |
} |
|
63 |
+ |
ViewEntry them = (ViewEntry) o; |
|
64 |
+ |
return Currently.areEqual( this.getText(), them.getText() ) && // |
|
65 |
+ |
Currently.areEqual( this.getUpperReference(), them.getUpperReference() ) && // |
|
66 |
+ |
Currently.areEqual( this.getLowerReference(), them.getLowerReference() ); |
|
67 |
+ |
} |
|
68 |
+ |
|
|
69 |
+ |
@Override |
|
70 |
+ |
public int hashCode() { |
|
71 |
+ |
return hashCodeEm( calcHashCode( getText() ), // |
|
72 |
+ |
calcHashCode( getUpperReference() ), // |
|
73 |
+ |
calcHashCode( getLowerReference() ) ); |
|
74 |
+ |
} |
|
75 |
+ |
} |
|
76 |
+ |
|
|
77 |
+ |
public static class ViewSet { |
|
78 |
+ |
private List<ViewEntry> mEntries; |
|
79 |
+ |
|
|
80 |
+ |
public ViewSet( List<ViewEntry> pEntries ) { |
|
81 |
+ |
mEntries = pEntries; |
|
82 |
+ |
} |
|
83 |
+ |
|
|
84 |
+ |
public ViewSet( ViewEntry... pEntries ) { |
|
85 |
+ |
mEntries = Arrays.asList( pEntries ); |
|
86 |
+ |
} |
|
87 |
+ |
|
|
88 |
+ |
public ViewEntry[] getEntries() { |
|
89 |
+ |
return mEntries.toArray( new ViewEntry[mEntries.size()] ); |
|
90 |
+ |
} |
|
91 |
+ |
|
|
92 |
+ |
@Override |
|
93 |
+ |
public String toString() { |
|
94 |
+ |
return mEntries.toString(); |
|
95 |
+ |
} |
|
96 |
+ |
|
|
97 |
+ |
@Override |
|
98 |
+ |
public boolean equals( Object o ) { |
|
99 |
+ |
if ( this == o ) { |
|
100 |
+ |
return true; |
|
101 |
+ |
} |
|
102 |
+ |
if ( (o == null) || !this.getClass().getName().equals( o.getClass().getName() ) ) { |
|
103 |
+ |
return false; |
|
104 |
+ |
} |
|
105 |
+ |
ViewSet them = (ViewSet) o; |
|
106 |
+ |
return Currently.areEqual( this.mEntries, them.mEntries ); |
|
107 |
+ |
} |
|
108 |
+ |
|
|
109 |
+ |
@Override |
|
110 |
+ |
public int hashCode() { |
|
111 |
+ |
return calcHashCode( mEntries ); |
|
112 |
+ |
} |
|
113 |
+ |
} |
|
114 |
+ |
|
|
115 |
+ |
public static class DrillDownSet { |
|
116 |
+ |
private ViewSet mHomeSet; |
|
117 |
+ |
private boolean mSomethingBetweenHomeAndPreviousSets; |
|
118 |
+ |
private ViewSet mPreviousSet; |
|
119 |
+ |
private ViewSet mCurrentSet; |
|
120 |
+ |
|
|
121 |
+ |
public DrillDownSet( ViewSet pHomeSet, boolean pSomethingBetweenHomeAndPreviousSets, ViewSet pPreviousSet, ViewSet pCurrentSet ) { |
|
122 |
+ |
mHomeSet = pHomeSet; |
|
123 |
+ |
mSomethingBetweenHomeAndPreviousSets = pSomethingBetweenHomeAndPreviousSets; |
|
124 |
+ |
mPreviousSet = pPreviousSet; |
|
125 |
+ |
mCurrentSet = pCurrentSet; |
|
126 |
+ |
} |
|
127 |
+ |
|
|
128 |
+ |
public ViewSet getHomeSet() { |
|
129 |
+ |
return mHomeSet; |
|
130 |
+ |
} |
|
131 |
+ |
|
|
132 |
+ |
public boolean isSomethingBetweenHomeAndPreviousSets() { |
|
133 |
+ |
return mSomethingBetweenHomeAndPreviousSets; |
|
134 |
+ |
} |
|
135 |
+ |
|
|
136 |
+ |
public ViewSet getPreviousSet() { |
|
137 |
+ |
return mPreviousSet; |
|
138 |
+ |
} |
|
139 |
+ |
|
|
140 |
+ |
public ViewSet getCurrentSet() { |
|
141 |
+ |
return mCurrentSet; |
|
142 |
+ |
} |
|
143 |
+ |
|
|
144 |
+ |
@Override |
|
145 |
+ |
public String toString() { |
|
146 |
+ |
StringBuilder sb = new StringBuilder( "DrillDownSet:" ); |
|
147 |
+ |
add( sb, "Home", mHomeSet ); |
|
148 |
+ |
if ( mSomethingBetweenHomeAndPreviousSets ) { |
|
149 |
+ |
sb.append( "\n ..." ); |
|
150 |
+ |
} |
|
151 |
+ |
add( sb, "Prev", mPreviousSet ); |
|
152 |
+ |
add( sb, "Curr", mCurrentSet ); |
|
153 |
+ |
return sb.toString(); |
|
154 |
+ |
} |
|
155 |
+ |
|
|
156 |
+ |
private void add( StringBuilder pSb, String pWhat, ViewSet pSet ) { |
|
157 |
+ |
if ( pSet != null ) { |
|
158 |
+ |
pSb.append( '\n' ).append( pWhat ).append( ": " ).append( pSet ); |
|
159 |
+ |
} |
|
160 |
+ |
} |
|
161 |
+ |
|
|
162 |
+ |
@Override |
|
163 |
+ |
public boolean equals( Object o ) { |
|
164 |
+ |
if ( this == o ) { |
|
165 |
+ |
return true; |
|
166 |
+ |
} |
|
167 |
+ |
if ( (o == null) || !this.getClass().getName().equals( o.getClass().getName() ) ) { |
|
168 |
+ |
return false; |
|
169 |
+ |
} |
|
170 |
+ |
DrillDownSet them = (DrillDownSet) o; |
|
171 |
+ |
return (this.mSomethingBetweenHomeAndPreviousSets == them.mSomethingBetweenHomeAndPreviousSets) && // |
|
172 |
+ |
Currently.areEqual( this.mHomeSet, them.mHomeSet ) && // |
|
173 |
+ |
Currently.areEqual( this.mPreviousSet, them.mPreviousSet ) && // |
|
174 |
+ |
Currently.areEqual( this.mCurrentSet, them.mCurrentSet ); |
|
175 |
+ |
} |
|
176 |
+ |
|
|
177 |
+ |
@Override |
|
178 |
+ |
public int hashCode() { |
|
179 |
+ |
return hashCodeEm( calcHashCode( mHomeSet ), // |
|
180 |
+ |
calcHashCode( mPreviousSet ), // |
|
181 |
+ |
calcHashCode( mCurrentSet ) ); |
|
182 |
+ |
} |
|
183 |
+ |
} |
|
184 |
+ |
|
|
185 |
+ |
static abstract class SelectionPointEntry<U extends Synopsisable> extends ViewEntry<U> { |
|
186 |
+ |
private boolean mSelected; |
|
187 |
+ |
private U mUpperReference; |
|
188 |
+ |
private U mLowerReference; |
|
189 |
+ |
|
|
190 |
+ |
protected SelectionPointEntry( boolean pSelected, String pText, U pUpperReference, U pLowerReference ) { |
|
191 |
+ |
super( pText ); |
|
192 |
+ |
mSelected = pSelected; |
|
193 |
+ |
mUpperReference = pUpperReference; |
|
194 |
+ |
mLowerReference = pLowerReference; |
|
195 |
+ |
} |
|
196 |
+ |
|
|
197 |
+ |
@Override |
|
198 |
+ |
public U getUpperReference() { |
|
199 |
+ |
return mUpperReference; |
|
200 |
+ |
} |
|
201 |
+ |
|
|
202 |
+ |
@Override |
|
203 |
+ |
public U getLowerReference() { |
|
204 |
+ |
return mLowerReference; |
|
205 |
+ |
} |
|
206 |
+ |
|
|
207 |
+ |
@Override |
|
208 |
+ |
public boolean isSelectable() { |
|
209 |
+ |
return true; |
|
210 |
+ |
} |
|
211 |
+ |
|
|
212 |
+ |
@Override |
|
213 |
+ |
public boolean isSelected() { |
|
214 |
+ |
return mSelected; |
|
215 |
+ |
} |
|
216 |
+ |
|
|
217 |
+ |
@Override |
|
218 |
+ |
public String toString() { |
|
219 |
+ |
return Strings.replace( getText(), '\n', "\\n" ) + ":" + addXtra(); |
|
220 |
+ |
} |
|
221 |
+ |
|
|
222 |
+ |
protected String addXtra() { |
|
223 |
+ |
return ""; |
|
224 |
+ |
} |
|
225 |
+ |
} |
|
226 |
+ |
|
|
227 |
+ |
@SuppressWarnings("EqualsAndHashcode") |
|
228 |
+ |
static class Between<U extends Synopsisable> extends SelectionPointEntry<U> { |
|
229 |
+ |
private Between( boolean pSelected, U pUpperReference, U pLowerReference ) { |
|
230 |
+ |
super( pSelected, "Between", pUpperReference, pLowerReference ); |
|
231 |
+ |
} |
|
232 |
+ |
|
|
233 |
+ |
public static <V extends Synopsisable> Between<V> create( boolean pSelected, V pUpperReference, V pLowerReference ) { |
|
234 |
+ |
return new Between<V>( pSelected, pUpperReference, pLowerReference ); |
|
235 |
+ |
} |
|
236 |
+ |
|
|
237 |
+ |
public Between<U> copyAsSelected() { |
|
238 |
+ |
return isSelected() ? this : create( true, getUpperReference(), getLowerReference() ); |
|
239 |
+ |
} |
|
240 |
+ |
|
|
241 |
+ |
@Override |
|
242 |
+ |
public boolean isBetween() { |
|
243 |
+ |
return true; |
|
244 |
+ |
} |
|
245 |
+ |
|
|
246 |
+ |
protected String addXtra() { |
|
247 |
+ |
return (isSelected() ? "(?Y)" : "(?N)"); |
|
248 |
+ |
} |
|
249 |
+ |
|
|
250 |
+ |
@Override |
|
251 |
+ |
@SuppressWarnings({"EqualsWhichDoesntCheckParameterClass"}) |
|
252 |
+ |
public boolean equals( Object o ) { |
|
253 |
+ |
return super.equals( o ) && (this.isSelected() == ((Between) o).isSelected()); |
|
254 |
+ |
} |
|
255 |
+ |
} |
|
256 |
+ |
|
|
257 |
+ |
static class There<U extends Synopsisable> extends SelectionPointEntry<U> { |
|
258 |
+ |
private There( U pUpperReference, U pLowerReference ) { |
|
259 |
+ |
super( false, "There", pUpperReference, pLowerReference ); |
|
260 |
+ |
} |
|
261 |
+ |
|
|
262 |
+ |
public static <V extends Synopsisable> There<V> create( V pUpperReference, V pLowerReference ) { |
|
263 |
+ |
return new There<V>( pUpperReference, pLowerReference ); |
|
264 |
+ |
} |
|
265 |
+ |
} |
|
266 |
+ |
|
|
267 |
+ |
static class Top<U extends Synopsisable> extends SelectionPointEntry<U> { |
|
268 |
+ |
private Top( U pLowerReference ) { |
|
269 |
+ |
super( false, "Top\n(There)", null, pLowerReference ); |
|
270 |
+ |
} |
|
271 |
+ |
|
|
272 |
+ |
public static <V extends Synopsisable> Top<V> create( V pLowerReference ) { |
|
273 |
+ |
return new Top<V>( pLowerReference ); |
|
274 |
+ |
} |
|
275 |
+ |
} |
|
276 |
+ |
|
|
277 |
+ |
static class Bottom<U extends Synopsisable> extends SelectionPointEntry<U> { |
|
278 |
+ |
private Bottom( U pUpperReference ) { |
|
279 |
+ |
super( false, "Bottom\n(There)", pUpperReference, null ); |
|
280 |
+ |
} |
|
281 |
+ |
|
|
282 |
+ |
public static <V extends Synopsisable> Bottom<V> create( V pUpperReference ) { |
|
283 |
+ |
return new Bottom<V>( pUpperReference ); |
|
284 |
+ |
} |
|
285 |
+ |
} |
|
286 |
+ |
|
|
287 |
+ |
static class Reference<U extends Synopsisable> extends ViewEntry<U> { |
|
288 |
+ |
private Reference( int pLines, U pReference ) { |
|
289 |
+ |
super( pReference.getSynopsis( pLines ) ); |
|
290 |
+ |
} |
|
291 |
+ |
|
|
292 |
+ |
public static <V extends Synopsisable> Reference<V> create( int pLines, V pReference ) { |
|
293 |
+ |
return new Reference<V>( pLines, pReference ); |
|
294 |
+ |
} |
|
295 |
+ |
|
|
296 |
+ |
@Override |
|
297 |
+ |
public String toString() { |
|
298 |
+ |
return "Ref: " + Strings.replace( getText(), '\n', "\\n" ); |
|
299 |
+ |
} |
|
300 |
+ |
} |
|
301 |
+ |
|
|
302 |
+ |
private int mSynopsisLines; |
|
303 |
+ |
private List<T> mInjectIns; |
|
304 |
+ |
private View<T> mView; |
|
305 |
+ |
private int mCurrentEntriesVisible = -1; |
|
306 |
+ |
private List<Between<T>> mSelectedBetweens = new ArrayList<Between<T>>(); |
|
307 |
+ |
|
|
308 |
+ |
public InjectionPointSelectorController( int pSynopsisLines, List<T> pInjectIns, View<T> pView ) { |
|
309 |
+ |
mSynopsisLines = pSynopsisLines; |
|
310 |
+ |
mInjectIns = pInjectIns; |
|
311 |
+ |
mView = pView; |
|
312 |
+ |
} |
|
313 |
+ |
|
|
314 |
+ |
public InjectionPointSelectorController( int pSynopsisLines, View<T> pView, T... pInjectIns ) { |
|
315 |
+ |
this( pSynopsisLines, Arrays.asList( pInjectIns ), pView ); |
|
316 |
+ |
} |
|
317 |
+ |
|
|
318 |
+ |
public void updateForEntriesVisible( int pCount ) { |
|
319 |
+ |
if ( mCurrentEntriesVisible != pCount ) { |
|
320 |
+ |
DrillDownSet zDrillDownSet = updateDrillDownSetWhenEntriesVisibleChanges( pCount, mSelectedBetweens ); |
|
321 |
+ |
if ( zDrillDownSet == null ) { |
|
322 |
+ |
mView.notEnoughVisibleEntries(); |
|
323 |
+ |
return; |
|
324 |
+ |
} |
|
325 |
+ |
mCurrentEntriesVisible = pCount; |
|
326 |
+ |
mView.show( zDrillDownSet ); |
|
327 |
+ |
} |
|
328 |
+ |
} |
|
329 |
+ |
|
|
330 |
+ |
public void homeSelected() { |
|
331 |
+ |
DrillDownSet zDrillDownSet = updateDrillDownSetWhenEntriesVisibleChanges( mCurrentEntriesVisible, mSelectedBetweens ); |
|
332 |
+ |
mView.show( zDrillDownSet ); |
|
333 |
+ |
} |
|
334 |
+ |
|
|
335 |
+ |
public void previousSelected() { |
|
336 |
+ |
mSelectedBetweens.remove( mSelectedBetweens.size() - 1 ); |
|
337 |
+ |
DrillDownSet zDrillDownSet = updateDrillDownSetWhenSelectedBetweensChange( mCurrentEntriesVisible, mSelectedBetweens ); |
|
338 |
+ |
mView.show( zDrillDownSet ); |
|
339 |
+ |
} |
|
340 |
+ |
|
|
341 |
+ |
public void viewSelected( ViewEntry<T> pEntry ) { |
|
342 |
+ |
Confirm.isNotNull( "Entry", pEntry ); |
|
343 |
+ |
if ( pEntry.isBetween() ) { |
|
344 |
+ |
mSelectedBetweens.add( ((Between<T>) pEntry).copyAsSelected() ); |
|
345 |
+ |
DrillDownSet zDrillDownSet = updateDrillDownSetWhenSelectedBetweensChange( mCurrentEntriesVisible, mSelectedBetweens ); |
|
346 |
+ |
mView.show( zDrillDownSet ); |
|
347 |
+ |
return; |
|
348 |
+ |
} |
|
349 |
+ |
if ( pEntry.isSelectable() ) { |
|
350 |
+ |
mView.injectBetween( pEntry.getLowerReference(), pEntry.getUpperReference() ); |
|
351 |
+ |
return; |
|
352 |
+ |
} |
|
353 |
+ |
throw new IllegalArgumentException( "Can not 'viewSelected' for type '" + ClassName.simple( pEntry ) + "': " + pEntry ); |
|
354 |
+ |
} |
|
355 |
+ |
|
|
356 |
+ |
/** |
|
357 |
+ |
* Update the pLastDrillDownSet based on the new pCount (maximum Entries per ViewSet) (public for Testing) |
|
358 |
+ |
* |
|
359 |
+ |
* @return null means that pCount was too small! |
|
360 |
+ |
*/ |
|
361 |
+ |
public DrillDownSet updateDrillDownSetWhenEntriesVisibleChanges( int pCount, List<Between<T>> pSelectedBetweens ) { |
|
362 |
+ |
if ( -1 == (pCount = checkIfNotEnoughVisibleEntries( makeOdd( pCount ) )) ) { |
|
363 |
+ |
return null; |
|
364 |
+ |
} |
|
365 |
+ |
pSelectedBetweens.clear(); |
|
366 |
+ |
|
|
367 |
+ |
List<ViewSet> zViewSets = buildViewSets( pCount, pSelectedBetweens ); |
|
368 |
+ |
return new DrillDownSet( null, false, null, zViewSets.get( 0 ) ); |
|
369 |
+ |
} |
|
370 |
+ |
|
|
371 |
+ |
/** |
|
372 |
+ |
* Update the pLastDrillDownSet based on the new pCount (maximum Entries per ViewSet) (public for Testing) |
|
373 |
+ |
* |
|
374 |
+ |
* @return null means that pCount was too small! |
|
375 |
+ |
*/ |
|
376 |
+ |
public DrillDownSet updateDrillDownSetWhenSelectedBetweensChange( int pCount, List<Between<T>> pSelectedBetweens ) { |
|
377 |
+ |
List<ViewSet> zViewSets = buildViewSets( makeOdd( pCount ), pSelectedBetweens ); |
|
378 |
+ |
switch ( zViewSets.size() ) { |
|
379 |
+ |
case 1: |
|
380 |
+ |
return new DrillDownSet( null, false, null, zViewSets.get( 0 ) ); |
|
381 |
+ |
case 2: |
|
382 |
+ |
return new DrillDownSet( zViewSets.get( 0 ), false, null, zViewSets.get( 1 ) ); |
|
383 |
+ |
case 3: |
|
384 |
+ |
return new DrillDownSet( zViewSets.get( 0 ), false, zViewSets.get( 1 ), zViewSets.get( 2 ) ); |
|
385 |
+ |
default: |
|
386 |
+ |
return new DrillDownSet( zViewSets.get( 0 ), true, zViewSets.get( zViewSets.size() - 2 ), zViewSets.get( zViewSets.size() - 1 ) ); |
|
387 |
+ |
} |
|
388 |
+ |
} |
|
389 |
+ |
|
|
390 |
+ |
private int checkIfNotEnoughVisibleEntries( int pCount ) { |
|
391 |
+ |
return ((pCount >= 5) || // 5 is enough for anything (more is better) |
|
392 |
+ |
((pCount == 3) && (mInjectIns.size() == 1))) ? // Special Case of just 1 InjectIn? |
|
393 |
+ |
pCount : // pCount is OK |
|
394 |
+ |
-1; // indicate pCount too small |
|
395 |
+ |
} |
|
396 |
+ |
|
|
397 |
+ |
private int makeOdd( int pCount ) { |
|
398 |
+ |
return ((pCount & 1) == 0) ? // Is Even? |
|
399 |
+ |
pCount - 1 : // Even, make Odd! |
|
400 |
+ |
pCount; // Already Odd |
|
401 |
+ |
} |
|
402 |
+ |
|
|
403 |
+ |
private Between<T> getCurrentSelectedBetween( List<Between<T>> pSelectedBetweens, int pCurrentIndex ) { |
|
404 |
+ |
return (pCurrentIndex < pSelectedBetweens.size()) ? pSelectedBetweens.get( pCurrentIndex ) : null; |
|
405 |
+ |
} |
|
406 |
+ |
|
|
407 |
+ |
private boolean isSelected( Between<T> pSelectedBetween, T pLast, T pCurr ) { |
|
408 |
+ |
return (pSelectedBetween != null) && (pLast == pSelectedBetween.getUpperReference()) && (pCurr == pSelectedBetween.getLowerReference()); |
|
409 |
+ |
} |
|
410 |
+ |
|
|
411 |
+ |
private List<ViewSet> buildViewSets( int pCount, List<Between<T>> pSelectedBetweens ) { |
|
412 |
+ |
List<ViewSet> zViewSets = new ArrayList<ViewSet>(); |
|
413 |
+ |
|
|
414 |
+ |
buildHomeViewSet( zViewSets, pCount, pSelectedBetweens ); |
|
415 |
+ |
|
|
416 |
+ |
return zViewSets; |
|
417 |
+ |
} |
|
418 |
+ |
|
|
419 |
+ |
private void buildHomeViewSet( List<ViewSet> pViewSets, int pCount, List<Between<T>> pSelectedBetweens ) { |
|
420 |
+ |
Between<T> zSelectedBetween = getCurrentSelectedBetween( pSelectedBetweens, 0 ); |
|
421 |
+ |
|
|
422 |
+ |
int zInjectInsToAdd = mInjectIns.size() - 1; |
|
423 |
+ |
int zAvailableBetweenBuckets = Math.min( zInjectInsToAdd, (pCount - 3) / 2 ); |
|
424 |
+ |
|
|
425 |
+ |
// System.out.println( "buildHomeViewSett( " + zSelectedBetween + " ): " + // |
|
426 |
+ |
// pCount + " ( " + mInjectIns.size() + " ) " + zInjectInsToAdd + " | " + zAvailableBetweenBuckets ); |
|
427 |
+ |
|
|
428 |
+ |
ArrayList<ViewEntry> zEntries = new ArrayList<ViewEntry>( pCount ); |
|
429 |
+ |
pViewSets.add( new ViewSet( zEntries ) ); |
|
430 |
+ |
|
|
431 |
+ |
int zCurrNdx = 0; |
|
432 |
+ |
int zThru = mInjectIns.size() - 1; |
|
433 |
+ |
T zCurrT = mInjectIns.get( zCurrNdx ); |
|
434 |
+ |
zEntries.add( Top.create( zCurrT ) ); |
|
435 |
+ |
|
|
436 |
+ |
while ( zCurrNdx < zThru ) { |
|
437 |
+ |
zEntries.add( Reference.create( mSynopsisLines, zCurrT ) ); |
|
438 |
+ |
int zLastNdx = zCurrNdx; |
|
439 |
+ |
T zLastT = zCurrT; |
|
440 |
+ |
int zHowMany = zInjectInsToAdd / zAvailableBetweenBuckets; |
|
441 |
+ |
// System.out.print( " zInjectInsToAdd / zAvailableBetweenBuckets ==> " + zInjectInsToAdd + " / " + zAvailableBetweenBuckets + " = " + zHowMany ); |
|
442 |
+ |
zInjectInsToAdd -= zHowMany; |
|
443 |
+ |
zCurrNdx += zHowMany; |
|
444 |
+ |
zCurrT = mInjectIns.get( zCurrNdx ); |
|
445 |
+ |
if ( zHowMany == 1 ) { |
|
446 |
+ |
// System.out.println( " Add There 1" ); |
|
447 |
+ |
zEntries.add( There.create( zLastT, zCurrT ) ); |
|
448 |
+ |
} else { |
|
449 |
+ |
// System.out.println( " Add Between " + zHowMany ); |
|
450 |
+ |
if ( isSelected( zSelectedBetween, zLastT, zCurrT ) ) { |
|
451 |
+ |
zEntries.add( zSelectedBetween ); |
|
452 |
+ |
buildSubsequentViewSet( pViewSets, pCount, zLastNdx, zCurrNdx, pSelectedBetweens, 1 ); |
|
453 |
+ |
} else { |
|
454 |
+ |
zEntries.add( Between.create( false, zLastT, zCurrT ) ); |
|
455 |
+ |
} |
|
456 |
+ |
} |
|
457 |
+ |
zAvailableBetweenBuckets--; |
|
458 |
+ |
} |
|
459 |
+ |
zEntries.add( Reference.create( mSynopsisLines, zCurrT ) ); |
|
460 |
+ |
zEntries.add( Bottom.create( zCurrT ) ); |
|
461 |
+ |
} |
|
462 |
+ |
|
|
463 |
+ |
private void buildSubsequentViewSet( List<ViewSet> pViewSets, int pCount, int zUpperNdx, int zLowerNdx, List<Between<T>> pSelectedBetweens, |
|
464 |
+ |
int pCurrentIndex ) { |
|
465 |
+ |
Between<T> zSelectedBetween = getCurrentSelectedBetween( pSelectedBetweens, pCurrentIndex ); |
|
466 |
+ |
|
|
467 |
+ |
int zInjectInsToAdd = zLowerNdx - zUpperNdx; |
|
468 |
+ |
int zAvailableBetweenBuckets = Math.min( zInjectInsToAdd, pCount / 2 ); |
|
469 |
+ |
|
|
470 |
+ |
// System.out.println( " buildSubsequentViewSet( " + pCurrentIndex + " => " + zSelectedBetween + " ): " + // |
|
471 |
+ |
// pCount + " ( " + zUpperNdx + ", " + zLowerNdx + " ) " + zInjectInsToAdd + " | " + zAvailableBetweenBuckets ); |
|
472 |
+ |
|
|
473 |
+ |
ArrayList<ViewEntry> zEntries = new ArrayList<ViewEntry>( pCount ); |
|
474 |
+ |
pViewSets.add( new ViewSet( zEntries ) ); |
|
475 |
+ |
|
|
476 |
+ |
int zCurrNdx = zUpperNdx; |
|
477 |
+ |
int zThru = zLowerNdx; |
|
478 |
+ |
T zCurrT = mInjectIns.get( zCurrNdx ); |
|
479 |
+ |
|
|
480 |
+ |
while ( zCurrNdx < zThru ) { |
|
481 |
+ |
zEntries.add( Reference.create( mSynopsisLines, zCurrT ) ); |
|
482 |
+ |
int zLastNdx = zCurrNdx; |
|
483 |
+ |
T zLastT = zCurrT; |
|
484 |
+ |
int zHowMany = zInjectInsToAdd / zAvailableBetweenBuckets; |
|
485 |
+ |
// System.out.print( " zInjectInsToAdd / zAvailableBetweenBuckets ==> " + zInjectInsToAdd + " / " + zAvailableBetweenBuckets + " = " + zHowMany ); |
|
486 |
+ |
zInjectInsToAdd -= zHowMany; |
|
487 |
+ |
zCurrNdx += zHowMany; |
|
488 |
+ |
zCurrT = mInjectIns.get( zCurrNdx ); |
|
489 |
+ |
if ( zHowMany == 1 ) { |
|
490 |
+ |
// System.out.println( " Add There 1" ); |
|
491 |
+ |
zEntries.add( There.create( zLastT, zCurrT ) ); |
|
492 |
+ |
} else { |
|
493 |
+ |
// System.out.println( " Add Between " + zHowMany ); |
|
494 |
+ |
if ( isSelected( zSelectedBetween, zLastT, zCurrT ) ) { |
|
495 |
+ |
zEntries.add( zSelectedBetween ); |
|
496 |
+ |
buildSubsequentViewSet( pViewSets, pCount, zLastNdx, zCurrNdx, pSelectedBetweens, pCurrentIndex + 1 ); |
|
497 |
+ |
} else { |
|
498 |
+ |
zEntries.add( Between.create( false, zLastT, zCurrT ) ); |
|
499 |
+ |
} |
|
500 |
+ |
} |
|
501 |
+ |
zAvailableBetweenBuckets--; |
|
502 |
+ |
} |
|
503 |
+ |
zEntries.add( Reference.create( mSynopsisLines, zCurrT ) ); |
|
504 |
+ |
} |
|
505 |
+ |
} |