Subversion Repository Public Repository

litesoft

Diff Revisions 949 vs 950 for /trunk/Java/GWT/OldClient/src/org/litesoft/GWT/client/widgets/SizeableFloatableContainerPanel.java

Diff revisions: vs.
  @@ -1,603 +1,603 @@
1 - // This Source Code is in the Public Domain per: http://unlicense.org
2 - package org.litesoft.GWT.client.widgets;
3 -
4 - import org.litesoft.GWT.client.widgets.nonpublic.*;
5 - import org.litesoft.commonfoundation.base.*;
6 -
7 - import com.google.gwt.user.client.*;
8 - import com.google.gwt.user.client.ui.*;
9 -
10 - import java.util.*;
11 -
12 - public class SizeableFloatableContainerPanel extends AbstractSizeableComplexPanel implements IndexedPanel,
13 - FloatablesCarrier {
14 - private static int INITIAL_Z_INDEX = 1000;
15 - private static int MAX_ALLOWED_Z_INDEX = 9999;
16 - private SizeableFloater mActive = null;
17 -
18 - private FloatableContainerListener mFloatableContainerListener;
19 -
20 - public SizeableFloatableContainerPanel() {
21 - initializeElements( getHelper().create_OeSeIeOverflowHiddenSingleDivSandwich(),
22 - "litesoft-NoSizeAffectingCSS-FloatablesCarrier" );
23 - LLstretchable();
24 - Element containerElement = getContainerElement();
25 -
26 - /*
27 - * Establish a local stacking context. This keeps the menus and dialogs
28 - * above the internal windows.
29 - * http://code.google.com/p/google-web-toolkit/issues/detail?id=1288
30 - */
31 - DOM.setStyleAttribute( containerElement, "position", "relative" );
32 - DOM.setIntStyleAttribute( containerElement, "zIndex", 0 );
33 - }
34 -
35 - private boolean setActive( SizeableFloater pActive ) {
36 - if ( pActive != mActive ) {
37 - if ( mActive != null ) {
38 - mActive.setActive( false );
39 - if ( mFloatableContainerListener != null ) {
40 - mFloatableContainerListener.clearActive( mActive );
41 - }
42 - }
43 - mActive = pActive;
44 - if ( mActive != null ) {
45 - mActive.setActive( true );
46 - if ( mFloatableContainerListener != null ) {
47 - mFloatableContainerListener.setActive( mActive );
48 - }
49 - }
50 - return true;
51 - }
52 - return false;
53 - }
54 -
55 - public void undoCascade() {
56 - if ( !mStackOfFloatersPositionState.isEmpty() ) {
57 - SizeableFloater[] floaters = getFloatersSortedByZindex();
58 -
59 - if ( floaters.length == 0 ) {
60 - mStackOfFloatersPositionState.clear();
61 - } else {
62 - FloatersPositionState zFPS = mStackOfFloatersPositionState.pop();
63 -
64 - setActive( zFPS.restoreFloaters( floaters ) );
65 - }
66 - }
67 - }
68 -
69 - private Stack<FloatersPositionState> mStackOfFloatersPositionState = new Stack<FloatersPositionState>();
70 -
71 - public void cascade() {
72 - SizeableFloater[] floaters = getFloatersSortedByZindex();
73 - if ( floaters.length == 0 ) {
74 - mStackOfFloatersPositionState.clear();
75 - } else {
76 - FloatersPositionState zFPS = new FloatersPositionState();
77 -
78 - SizeableFloater floater = zFPS.cascadeFloaters( floaters );
79 -
80 - if ( floater != null ) {
81 - setActive( floater );
82 -
83 - if ( floater.getZindex() > MAX_ALLOWED_Z_INDEX ) {
84 - reZindex();
85 - }
86 -
87 - if ( zFPS.isChanged() ) {
88 - mStackOfFloatersPositionState.push( zFPS );
89 - }
90 - }
91 - }
92 - }
93 -
94 - private SizeableFloater[] getArrayOfChildren() {
95 - WidgetCollection wc = getChildren();
96 - int count = wc.size();
97 - if ( count == 0 ) {
98 - return SizeableFloater.EMPTY_ARRAY;
99 - }
100 - SizeableFloater[] floaters = new SizeableFloater[count];
101 - for ( int i = 0; i < floaters.length; i++ ) {
102 - floaters[i] = (SizeableFloater) wc.get( i );
103 - }
104 - return floaters;
105 - }
106 -
107 - public Widget getWidget( int index ) {
108 - return getChildren().get( index );
109 - }
110 -
111 - public int getWidgetCount() {
112 - return getChildren().size();
113 - }
114 -
115 - public int getWidgetIndex( Widget child ) {
116 - return getChildren().indexOf( child );
117 - }
118 -
119 - public boolean remove( int index ) {
120 - return remove( getWidget( index ) );
121 - }
122 -
123 - /**
124 - * Adds a floater to the panel and makes it the top floater.
125 - *
126 - * @param w the widget to be added
127 - */
128 - public void add( Widget w ) {
129 - if ( !(w instanceof SizeableFloater) ) {
130 - throw new IllegalArgumentException( "Only a 'SizeableFloater' can be added" );
131 - }
132 - SizeableFloater floater = (SizeableFloater) w;
133 -
134 - floater.setZindex( calcTemporaryNewZindex() );
135 -
136 - int zTop = 0;
137 - int zLeft = 0;
138 - int count = 0;
139 -
140 - SizeableFloater[] floaters = getArrayOfChildren();
141 -
142 - if ( floaters.length != 0 ) {
143 - int delta = Math.max( floaters[0].getTitleBarHeight(), 25 );
144 -
145 - int doubleDelta = (delta * 2);
146 - int maxWidth = getOffsetWidth() - doubleDelta;
147 - int maxHeight = getOffsetHeight() - doubleDelta;
148 - boolean checkOverflow = (maxWidth > doubleDelta && maxHeight > doubleDelta);
149 -
150 - while ( anyAt( floaters, delta, zTop, zLeft ) ) {
151 - // safety valve -- if things get too jammed, just start plopping stuff at the top left
152 - if ( count++ > 80 ) {
153 - zTop = zLeft = 0;
154 - break;
155 - }
156 -
157 - zTop += delta;
158 - zLeft += delta;
159 -
160 - // if we roll off the bottom or right, start over with a smaller delta
161 - if ( checkOverflow && (zTop > maxHeight || zLeft > maxWidth) ) {
162 - delta /= 2;
163 - if ( delta < 2 ) {
164 - delta = 2;
165 - }
166 - zTop = delta;
167 - zLeft = delta;
168 - }
169 - }
170 - }
171 -
172 - add( w, getContainerElement() );
173 - floater.initializeSize();
174 - floater.setPosition( zLeft, zTop );
175 - floaterAdded( floater );
176 - makeTop( floater );
177 - }
178 -
179 - public boolean remove( Widget w ) {
180 - if ( super.remove( w ) ) {
181 - setActive( (getChildren().size() > 0) ? getCurrentMaxZindexChild() : null );
182 - if ( w instanceof SizeableFloater ) {
183 - floaterRemoved( (SizeableFloater) w );
184 - }
185 - return true;
186 - }
187 - return false;
188 - }
189 -
190 - private boolean anyAt( SizeableFloater[] pFloaters, int pDelta, int pTop, int pLeft ) {
191 - //noinspection ForLoopReplaceableByForEach
192 - for ( int i = 0; i < pFloaters.length; i++ ) {
193 - SizeableFloater floater = pFloaters[i];
194 - if ( within( pDelta, pTop, floater.getPosTop() ) ||
195 - within( pDelta, pLeft, floater.getPosLeft() ) ) {
196 - return true;
197 - }
198 - }
199 - return false;
200 - }
201 -
202 - private boolean within( int pDelta, int pPos1, int pPos2 ) {
203 - return Math.abs( pPos1 - pPos2 ) < pDelta;
204 - }
205 -
206 - public SizeableFloater[] getFloatersSortedByTitle() {
207 - return getFloatersSortedBy( TitleComparator.INSTANCE );
208 - }
209 -
210 - public SizeableFloater[] getFloatersSortedByZindex() {
211 - return getFloatersSortedBy( ZindexComparator.INSTANCE );
212 - }
213 -
214 - private SizeableFloater[] getFloatersSortedBy( Comparator pComparator ) {
215 - SizeableFloater[] floaters = getArrayOfChildren();
216 - return sort( floaters, pComparator );
217 - }
218 -
219 - private static SizeableFloater[] sort( SizeableFloater[] pFloaters, Comparator pComparator ) {
220 - if ( pFloaters.length != 0 ) {
221 - //noinspection unchecked
222 - Arrays.sort( pFloaters, pComparator );
223 - }
224 - return pFloaters;
225 - }
226 -
227 - private void reZindex() {
228 - reZindex( getFloatersSortedByZindex() );
229 - }
230 -
231 - private static void reZindex( SizeableFloater[] pFloaters ) {
232 - int zIndex = INITIAL_Z_INDEX;
233 - //noinspection ForLoopReplaceableByForEach
234 - for ( int i = 0; i < pFloaters.length; i++ ) {
235 - pFloaters[i].setZindex( ++zIndex );
236 - }
237 - }
238 -
239 - private SizeableFloater getCurrentMaxZindexChild() {
240 - WidgetCollection wc = getChildren();
241 - int count = wc.size();
242 -
243 - if ( count == 0 ) {
244 - return null;
245 - }
246 - SizeableFloater maxChild = (SizeableFloater) wc.get( 0 );
247 - int maxZ = maxChild.getZindex();
248 -
249 - for ( int i = 1; i < count; i++ ) {
250 - SizeableFloater floater = (SizeableFloater) wc.get( i );
251 - int zindex = floater.getZindex();
252 - if ( zindex > maxZ ) {
253 - maxChild = floater;
254 - maxZ = zindex;
255 - }
256 - }
257 - return maxChild;
258 - }
259 -
260 - /**
261 - * ONLY called by a current child!
262 - */
263 - public void makeTop( SizeableFloater pChild ) {
264 - SizeableFloatingPanel zFloater = ((SizeableFloatingPanel) pChild);
265 -
266 - if ( zFloater.isHidden() ) {
267 - // zFloater.setActive( true );
268 - zFloater.showFloater();
269 - }
270 -
271 - if ( pChild != mActive ) {
272 - int zindex = calcTemporaryNewZindex();
273 - pChild.setZindex( zindex );
274 - if ( zindex > MAX_ALLOWED_Z_INDEX ) {
275 - reZindex();
276 - }
277 - setActive( pChild );
278 - }
279 - }
280 -
281 - private int calcTemporaryNewZindex() {
282 - return 1 + ((mActive == null) ? INITIAL_Z_INDEX : mActive.getZindex());
283 - }
284 -
285 - //****** Implementation Code Block to support delegation to AbsoluteSizeHelper
286 -
287 - public SizeableFloatableContainerPanel width( int pPixels ) {
288 - setWidth( "" + pPixels );
289 - return this;
290 - }
291 -
292 - public SizeableFloatableContainerPanel height( int pPixels ) {
293 - setHeight( "" + pPixels );
294 - return this;
295 - }
296 -
297 - public void setRenderedDeferredCommand( Command pCommand ) {
298 - mRDCHelper.setRenderedDeferredCommand( pCommand );
299 - }
300 -
301 - public void setWidth( String width ) {
302 - super.setWidth( width );
303 - mRDCHelper.chkWidth( width );
304 - }
305 -
306 - public void setHeight( String height ) {
307 - super.setHeight( height );
308 - mRDCHelper.chkHeight( height );
309 - }
310 -
311 - private RenderedDeferredCommandHelper mRDCHelper = new RenderedDeferredCommandHelper( this );
312 -
313 - protected void distributeToChildrenChangedWidth() {
314 - getHelper().forceAdjustDimensionOnChild( getHelper().getInnerElement(), getWidthHelper() );
315 - for ( int i = 0; i < getWidgetCount(); i++ ) {
316 - SizeableFloater floater = (SizeableFloater) getWidget( i );
317 - floater.initializeWidth();
318 - if ( floater.isPositionLocked() ) {
319 - floater.changedContainerWidth();
320 - }
321 - }
322 - }
323 -
324 - protected void distributeToChildrenChangedHeight() {
325 - getHelper().forceAdjustDimensionOnChild( getHelper().getInnerElement(), getHeightHelper() );
326 - for ( int i = 0; i < getWidgetCount(); i++ ) {
327 - SizeableFloater floater = (SizeableFloater) getWidget( i );
328 - floater.initializeHeight();
329 - if ( floater.isPositionLocked() ) {
330 - floater.changedContainerHeight();
331 - }
332 - }
333 - }
334 -
335 - public void setFloatableContainerListener( FloatableContainerListener pFloatableContainerListener ) {
336 - mFloatableContainerListener = pFloatableContainerListener;
337 - }
338 -
339 - private void floaterAdded( SizeableFloater pFloater ) {
340 - if ( mFloatableContainerListener != null ) {
341 - mFloatableContainerListener.floaterAdded( pFloater );
342 - }
343 - }
344 -
345 - private void floaterRemoved( SizeableFloater pFloater ) {
346 - if ( mFloatableContainerListener != null ) {
347 - mFloatableContainerListener.floaterRemoved( pFloater );
348 - }
349 - }
350 -
351 - private static class ZindexComparator implements Comparator {
352 - public static final Comparator INSTANCE = new ZindexComparator();
353 -
354 - public int compare( Object o1, Object o2 ) {
355 - return compare( (SizeableFloater) o1, (SizeableFloater) o2 );
356 - }
357 -
358 - /**
359 - * @return a negative integer, zero, or a positive integer as pThis object
360 - * is less than, equal to, or greater than the pThem object.
361 - */
362 - public int compare( SizeableFloater pThis, SizeableFloater pThem ) {
363 - return pThis.getZindex() - pThem.getZindex();
364 - }
365 - }
366 -
367 - private static class AreaComparator implements Comparator<SizeableFloater> {
368 - public static final AreaComparator INSTANCE = new AreaComparator();
369 -
370 - /**
371 - * @return a negative integer, zero, or a positive integer as pThis object
372 - * is less than, equal to, or greater than the pThem object.
373 - */
374 - public int compare( SizeableFloater pThis, SizeableFloater pThem ) {
375 - // return pThis.getArea() - pThem.getArea();
376 - return pThem.getArea() - pThis.getArea(); // reverse! (Bigger to Smaller)
377 - }
378 - }
379 -
380 - private static class TitleComparator implements Comparator {
381 - public static final Comparator INSTANCE = new TitleComparator();
382 -
383 - public int compare( Object o1, Object o2 ) {
384 - return compare( (SizeableFloater) o1, (SizeableFloater) o2 );
385 - }
386 -
387 - /**
388 - * @return a negative integer, zero, or a positive integer as pThis object
389 - * is less than, equal to, or greater than the pThem object.
390 - */
391 - public int compare( SizeableFloater pThis, SizeableFloater pThem ) {
392 - return Compare.nullsOK( pThem.getTitle(), pThis.getTitle() );
393 - }
394 - }
395 -
396 - private static class FloaterPosition implements Cascadable {
397 - private int mCascadeUniqueID, mPosLeft, mPosTop;
398 -
399 - public FloaterPosition( SizeableFloater pFloater ) {
400 - mCascadeUniqueID = pFloater.getCascadeUniqueID();
401 - mPosLeft = pFloater.getPosLeft();
402 - mPosTop = pFloater.getPosTop();
403 - }
404 -
405 - public boolean isPositionLocked() {
406 - return true;
407 - }
408 -
409 - public int getCascadeUniqueID() {
410 - return mCascadeUniqueID;
411 - }
412 -
413 - public int getPosLeft() {
414 - return mPosLeft;
415 - }
416 -
417 - public int getPosTop() {
418 - return mPosTop;
419 - }
420 -
421 - public int getOffsetWidth() {
422 - throw new UnsupportedOperationException();
423 - }
424 -
425 - public int getOffsetHeight() {
426 - throw new UnsupportedOperationException();
427 - }
428 -
429 - public int minPosLeft() {
430 - throw new UnsupportedOperationException();
431 - }
432 -
433 - public int minPosTop() {
434 - throw new UnsupportedOperationException();
435 - }
436 -
437 - public int maxPosLeft() {
438 - throw new UnsupportedOperationException();
439 - }
440 -
441 - public int maxPosTop() {
442 - throw new UnsupportedOperationException();
443 - }
444 -
445 - public void setPosition( int pLeft, int pTop ) {
446 - throw new UnsupportedOperationException();
447 - }
448 -
449 - public void setPosLeft( int pPosLeft ) {
450 - throw new UnsupportedOperationException();
451 - }
452 -
453 - public void setPosTop( int pPosTop ) {
454 - throw new UnsupportedOperationException();
455 - }
456 -
457 - /**
458 - * Like equals(), but with the contract
459 - *
460 - * @param them !null
461 - */
462 - public boolean isEquivalent( Cascadable them ) {
463 - return (this.getCascadeUniqueID() == them.getCascadeUniqueID()) //
464 - && (this.getPosLeft() == them.getPosLeft()) //
465 - && (this.getPosTop() == them.getPosTop()) //
466 - ;
467 - }
468 -
469 - public boolean shouldMove( int pDesiredLeft, int pDesiredTop ) {
470 - return (mPosLeft != pDesiredLeft) || (mPosTop != pDesiredTop);
471 - }
472 - }
473 -
474 - private static class FloatersPositionState {
475 - private boolean mChanged = false;
476 - private FloaterPosition[] mFloaterPositions;
477 -
478 - /**
479 - * @param pFloaters - current floaters sorted in Current Z-Order Back to Front,
480 - * Array is !null, !empty, & safe to mutate
481 - *
482 - * @return - Floater to make Active
483 - */
484 - public SizeableFloater restoreFloaters( SizeableFloater[] pFloaters ) {
485 - SizeableFloater floater = null;
486 -
487 - SizeableFloater[] zNewOrder = new SizeableFloater[pFloaters.length];
488 -
489 - int ndxTo = 0;
490 - for ( int ndxFrom = 0; ndxFrom < mFloaterPositions.length; ndxFrom++ ) {
491 - FloaterPosition zPosition = mFloaterPositions[ndxFrom];
492 - int zAt = locate( zPosition.getCascadeUniqueID(), pFloaters );
493 - if ( zAt != -1 ) {
494 - floater = zNewOrder[ndxTo++] = pFloaters[zAt];
495 - pFloaters[zAt] = null;
496 - if ( !floater.isPositionLocked() ) {
497 - floater.setPosition( zPosition.getPosLeft(), zPosition.getPosTop() );
498 - }
499 - }
500 - }
501 - for ( int i = 0; i < pFloaters.length; i++ ) {
502 - SizeableFloater zFloater = pFloaters[i];
503 - if ( zFloater != null ) {
504 - floater = zNewOrder[ndxTo++] = zFloater;
505 - }
506 - }
507 -
508 - reZindex( zNewOrder );
509 -
510 - return floater;
511 - }
512 -
513 - private int locate( int pCascadeUniqueID, SizeableFloater[] pFloaters ) {
514 - int i = pFloaters.length;
515 - while ( --i >= 0 ) {
516 - SizeableFloater zFloater = pFloaters[i];
517 - if ( (zFloater != null) && (zFloater.getCascadeUniqueID() == pCascadeUniqueID) ) {
518 - return i;
519 - }
520 - }
521 - return i;
522 - }
523 -
524 - private SizeableFloater populate( SizeableFloater[] pFloaters,
525 - List<SizeableFloater> pNonLockedFloaters ) {
526 - mFloaterPositions = new FloaterPosition[pFloaters.length];
527 -
528 - SizeableFloater zFloater = null;
529 - for ( int i = 0; i < pFloaters.length; i++ ) {
530 - zFloater = pFloaters[i];
531 - mFloaterPositions[i] = new FloaterPosition( zFloater );
532 - if ( !zFloater.isPositionLocked() ) {
533 - pNonLockedFloaters.add( zFloater );
534 - }
535 - }
536 - return pNonLockedFloaters.isEmpty() ? null : zFloater;
537 - }
538 -
539 - /**
540 - * @param pFloaters - current floaters sorted in Current Z-Order Back to Front,
541 - * Array is !null, !empty, & safe to mutate
542 - *
543 - * @return - Floater to make Active
544 - */
545 - public SizeableFloater cascadeFloaters( SizeableFloater[] pFloaters ) {
546 - List<SizeableFloater> zNonLockedFloaters = new ArrayList<SizeableFloater>( pFloaters.length );
547 -
548 - SizeableFloater zFloater = populate( pFloaters, zNonLockedFloaters );
549 -
550 - if ( zFloater == null ) {
551 - return null;
552 - }
553 - Collections.sort( zNonLockedFloaters, AreaComparator.INSTANCE );
554 -
555 - int pMaxZindex = zFloater.getZindex();
556 -
557 - int zTop = 0;
558 - int zLeft = 0;
559 -
560 - SizeableFloater floater = cascadeFloater( zNonLockedFloaters, pMaxZindex, 0, zTop, zLeft );
561 -
562 - int delta = Math.max( floater.getTitleBarHeight(), 25 );
563 -
564 - for ( int i = 1; i < zNonLockedFloaters.size(); i++ ) {
565 - floater = cascadeFloater( zNonLockedFloaters, pMaxZindex, i, zLeft += delta, zTop += delta );
566 - }
567 - return floater;
568 - }
569 -
570 - private SizeableFloater cascadeFloater( List<SizeableFloater> pFloaters, int pMaxZindex, int pIndex,
571 - int pTop, int pLeft ) {
572 - SizeableFloater floater = pFloaters.get( pIndex );
573 -
574 - floater.setPosition( pLeft, pTop );
575 - floater.setZindex( pMaxZindex + pIndex + 1 );
576 -
577 - mChanged |= !mFloaterPositions[pIndex].isEquivalent( floater );
578 -
579 - return floater;
580 - }
581 -
582 - public boolean isChanged() {
583 - return mChanged;
584 - }
585 - }
586 -
587 - // vvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvv No Additional Style Support vvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvv
588 - public void setStylePrimaryName( String style ) {
589 - throw new IllegalStateException( "No Style Support" );
590 - }
591 -
592 - public void addStyleDependentName( String styleSuffix ) {
593 - throw new IllegalStateException( "No Style Support" );
594 - }
595 -
596 - public void addStyleName( String style ) {
597 - throw new IllegalStateException( "No Style Support" );
598 - }
599 -
600 - protected Element getStyleElement() {
601 - throw new IllegalStateException( "No Style Support" );
602 - }
603 - }
1 + // This Source Code is in the Public Domain per: http://unlicense.org
2 + package org.litesoft.GWT.client.widgets;
3 +
4 + import org.litesoft.GWT.client.widgets.nonpublic.*;
5 + import org.litesoft.commonfoundation.base.*;
6 +
7 + import com.google.gwt.user.client.*;
8 + import com.google.gwt.user.client.ui.*;
9 +
10 + import java.util.*;
11 +
12 + public class SizeableFloatableContainerPanel extends AbstractSizeableComplexPanel implements IndexedPanel,
13 + FloatablesCarrier {
14 + private static int INITIAL_Z_INDEX = 1000;
15 + private static int MAX_ALLOWED_Z_INDEX = 9999;
16 + private SizeableFloater mActive = null;
17 +
18 + private FloatableContainerListener mFloatableContainerListener;
19 +
20 + public SizeableFloatableContainerPanel() {
21 + initializeElements( getHelper().create_OeSeIeOverflowHiddenSingleDivSandwich(),
22 + "litesoft-NoSizeAffectingCSS-FloatablesCarrier" );
23 + LLstretchable();
24 + Element containerElement = getContainerElement();
25 +
26 + /*
27 + * Establish a local stacking context. This keeps the menus and dialogs
28 + * above the internal windows.
29 + * http://code.google.com/p/google-web-toolkit/issues/detail?id=1288
30 + */
31 + DOM.setStyleAttribute( containerElement, "position", "relative" );
32 + DOM.setIntStyleAttribute( containerElement, "zIndex", 0 );
33 + }
34 +
35 + private boolean setActive( SizeableFloater pActive ) {
36 + if ( pActive != mActive ) {
37 + if ( mActive != null ) {
38 + mActive.setActive( false );
39 + if ( mFloatableContainerListener != null ) {
40 + mFloatableContainerListener.clearActive( mActive );
41 + }
42 + }
43 + mActive = pActive;
44 + if ( mActive != null ) {
45 + mActive.setActive( true );
46 + if ( mFloatableContainerListener != null ) {
47 + mFloatableContainerListener.setActive( mActive );
48 + }
49 + }
50 + return true;
51 + }
52 + return false;
53 + }
54 +
55 + public void undoCascade() {
56 + if ( !mStackOfFloatersPositionState.isEmpty() ) {
57 + SizeableFloater[] floaters = getFloatersSortedByZindex();
58 +
59 + if ( floaters.length == 0 ) {
60 + mStackOfFloatersPositionState.clear();
61 + } else {
62 + FloatersPositionState zFPS = mStackOfFloatersPositionState.pop();
63 +
64 + setActive( zFPS.restoreFloaters( floaters ) );
65 + }
66 + }
67 + }
68 +
69 + private Stack<FloatersPositionState> mStackOfFloatersPositionState = new Stack<FloatersPositionState>();
70 +
71 + public void cascade() {
72 + SizeableFloater[] floaters = getFloatersSortedByZindex();
73 + if ( floaters.length == 0 ) {
74 + mStackOfFloatersPositionState.clear();
75 + } else {
76 + FloatersPositionState zFPS = new FloatersPositionState();
77 +
78 + SizeableFloater floater = zFPS.cascadeFloaters( floaters );
79 +
80 + if ( floater != null ) {
81 + setActive( floater );
82 +
83 + if ( floater.getZindex() > MAX_ALLOWED_Z_INDEX ) {
84 + reZindex();
85 + }
86 +
87 + if ( zFPS.isChanged() ) {
88 + mStackOfFloatersPositionState.push( zFPS );
89 + }
90 + }
91 + }
92 + }
93 +
94 + private SizeableFloater[] getArrayOfChildren() {
95 + WidgetCollection wc = getChildren();
96 + int count = wc.size();
97 + if ( count == 0 ) {
98 + return SizeableFloater.EMPTY_ARRAY;
99 + }
100 + SizeableFloater[] floaters = new SizeableFloater[count];
101 + for ( int i = 0; i < floaters.length; i++ ) {
102 + floaters[i] = (SizeableFloater) wc.get( i );
103 + }
104 + return floaters;
105 + }
106 +
107 + public Widget getWidget( int index ) {
108 + return getChildren().get( index );
109 + }
110 +
111 + public int getWidgetCount() {
112 + return getChildren().size();
113 + }
114 +
115 + public int getWidgetIndex( Widget child ) {
116 + return getChildren().indexOf( child );
117 + }
118 +
119 + public boolean remove( int index ) {
120 + return remove( getWidget( index ) );
121 + }
122 +
123 + /**
124 + * Adds a floater to the panel and makes it the top floater.
125 + *
126 + * @param w the widget to be added
127 + */
128 + public void add( Widget w ) {
129 + if ( !(w instanceof SizeableFloater) ) {
130 + throw new IllegalArgumentException( "Only a 'SizeableFloater' can be added" );
131 + }
132 + SizeableFloater floater = (SizeableFloater) w;
133 +
134 + floater.setZindex( calcTemporaryNewZindex() );
135 +
136 + int zTop = 0;
137 + int zLeft = 0;
138 + int count = 0;
139 +
140 + SizeableFloater[] floaters = getArrayOfChildren();
141 +
142 + if ( floaters.length != 0 ) {
143 + int delta = Math.max( floaters[0].getTitleBarHeight(), 25 );
144 +
145 + int doubleDelta = (delta * 2);
146 + int maxWidth = getOffsetWidth() - doubleDelta;
147 + int maxHeight = getOffsetHeight() - doubleDelta;
148 + boolean checkOverflow = (maxWidth > doubleDelta && maxHeight > doubleDelta);
149 +
150 + while ( anyAt( floaters, delta, zTop, zLeft ) ) {
151 + // safety valve -- if things get too jammed, just start plopping stuff at the top left
152 + if ( count++ > 80 ) {
153 + zTop = zLeft = 0;
154 + break;
155 + }
156 +
157 + zTop += delta;
158 + zLeft += delta;
159 +
160 + // if we roll off the bottom or right, start over with a smaller delta
161 + if ( checkOverflow && (zTop > maxHeight || zLeft > maxWidth) ) {
162 + delta /= 2;
163 + if ( delta < 2 ) {
164 + delta = 2;
165 + }
166 + zTop = delta;
167 + zLeft = delta;
168 + }
169 + }
170 + }
171 +
172 + add( w, getContainerElement() );
173 + floater.initializeSize();
174 + floater.setPosition( zLeft, zTop );
175 + floaterAdded( floater );
176 + makeTop( floater );
177 + }
178 +
179 + public boolean remove( Widget w ) {
180 + if ( super.remove( w ) ) {
181 + setActive( (getChildren().size() > 0) ? getCurrentMaxZindexChild() : null );
182 + if ( w instanceof SizeableFloater ) {
183 + floaterRemoved( (SizeableFloater) w );
184 + }
185 + return true;
186 + }
187 + return false;
188 + }
189 +
190 + private boolean anyAt( SizeableFloater[] pFloaters, int pDelta, int pTop, int pLeft ) {
191 + //noinspection ForLoopReplaceableByForEach
192 + for ( int i = 0; i < pFloaters.length; i++ ) {
193 + SizeableFloater floater = pFloaters[i];
194 + if ( within( pDelta, pTop, floater.getPosTop() ) ||
195 + within( pDelta, pLeft, floater.getPosLeft() ) ) {
196 + return true;
197 + }
198 + }
199 + return false;
200 + }
201 +
202 + private boolean within( int pDelta, int pPos1, int pPos2 ) {
203 + return Math.abs( pPos1 - pPos2 ) < pDelta;
204 + }
205 +
206 + public SizeableFloater[] getFloatersSortedByTitle() {
207 + return getFloatersSortedBy( TitleComparator.INSTANCE );
208 + }
209 +
210 + public SizeableFloater[] getFloatersSortedByZindex() {
211 + return getFloatersSortedBy( ZindexComparator.INSTANCE );
212 + }
213 +
214 + private SizeableFloater[] getFloatersSortedBy( Comparator pComparator ) {
215 + SizeableFloater[] floaters = getArrayOfChildren();
216 + return sort( floaters, pComparator );
217 + }
218 +
219 + private static SizeableFloater[] sort( SizeableFloater[] pFloaters, Comparator pComparator ) {
220 + if ( pFloaters.length != 0 ) {
221 + //noinspection unchecked
222 + Arrays.sort( pFloaters, pComparator );
223 + }
224 + return pFloaters;
225 + }
226 +
227 + private void reZindex() {
228 + reZindex( getFloatersSortedByZindex() );
229 + }
230 +
231 + private static void reZindex( SizeableFloater[] pFloaters ) {
232 + int zIndex = INITIAL_Z_INDEX;
233 + //noinspection ForLoopReplaceableByForEach
234 + for ( int i = 0; i < pFloaters.length; i++ ) {
235 + pFloaters[i].setZindex( ++zIndex );
236 + }
237 + }
238 +
239 + private SizeableFloater getCurrentMaxZindexChild() {
240 + WidgetCollection wc = getChildren();
241 + int count = wc.size();
242 +
243 + if ( count == 0 ) {
244 + return null;
245 + }
246 + SizeableFloater maxChild = (SizeableFloater) wc.get( 0 );
247 + int maxZ = maxChild.getZindex();
248 +
249 + for ( int i = 1; i < count; i++ ) {
250 + SizeableFloater floater = (SizeableFloater) wc.get( i );
251 + int zindex = floater.getZindex();
252 + if ( zindex > maxZ ) {
253 + maxChild = floater;
254 + maxZ = zindex;
255 + }
256 + }
257 + return maxChild;
258 + }
259 +
260 + /**
261 + * ONLY called by a current child!
262 + */
263 + public void makeTop( SizeableFloater pChild ) {
264 + SizeableFloatingPanel zFloater = ((SizeableFloatingPanel) pChild);
265 +
266 + if ( zFloater.isHidden() ) {
267 + // zFloater.setActive( true );
268 + zFloater.showFloater();
269 + }
270 +
271 + if ( pChild != mActive ) {
272 + int zindex = calcTemporaryNewZindex();
273 + pChild.setZindex( zindex );
274 + if ( zindex > MAX_ALLOWED_Z_INDEX ) {
275 + reZindex();
276 + }
277 + setActive( pChild );
278 + }
279 + }
280 +
281 + private int calcTemporaryNewZindex() {
282 + return 1 + ((mActive == null) ? INITIAL_Z_INDEX : mActive.getZindex());
283 + }
284 +
285 + //****** Implementation Code Block to support delegation to AbsoluteSizeHelper
286 +
287 + public SizeableFloatableContainerPanel width( int pPixels ) {
288 + setWidth( "" + pPixels );
289 + return this;
290 + }
291 +
292 + public SizeableFloatableContainerPanel height( int pPixels ) {
293 + setHeight( "" + pPixels );
294 + return this;
295 + }
296 +
297 + public void setRenderedDeferredCommand( Command pCommand ) {
298 + mRDCHelper.setRenderedDeferredCommand( pCommand );
299 + }
300 +
301 + public void setWidth( String width ) {
302 + super.setWidth( width );
303 + mRDCHelper.chkWidth( width );
304 + }
305 +
306 + public void setHeight( String height ) {
307 + super.setHeight( height );
308 + mRDCHelper.chkHeight( height );
309 + }
310 +
311 + private RenderedDeferredCommandHelper mRDCHelper = new RenderedDeferredCommandHelper( this );
312 +
313 + protected void distributeToChildrenChangedWidth() {
314 + getHelper().forceAdjustDimensionOnChild( getHelper().getInnerElement(), getWidthHelper() );
315 + for ( int i = 0; i < getWidgetCount(); i++ ) {
316 + SizeableFloater floater = (SizeableFloater) getWidget( i );
317 + floater.initializeWidth();
318 + if ( floater.isPositionLocked() ) {
319 + floater.changedContainerWidth();
320 + }
321 + }
322 + }
323 +
324 + protected void distributeToChildrenChangedHeight() {
325 + getHelper().forceAdjustDimensionOnChild( getHelper().getInnerElement(), getHeightHelper() );
326 + for ( int i = 0; i < getWidgetCount(); i++ ) {
327 + SizeableFloater floater = (SizeableFloater) getWidget( i );
328 + floater.initializeHeight();
329 + if ( floater.isPositionLocked() ) {
330 + floater.changedContainerHeight();
331 + }
332 + }
333 + }
334 +
335 + public void setFloatableContainerListener( FloatableContainerListener pFloatableContainerListener ) {
336 + mFloatableContainerListener = pFloatableContainerListener;
337 + }
338 +
339 + private void floaterAdded( SizeableFloater pFloater ) {
340 + if ( mFloatableContainerListener != null ) {
341 + mFloatableContainerListener.floaterAdded( pFloater );
342 + }
343 + }
344 +
345 + private void floaterRemoved( SizeableFloater pFloater ) {
346 + if ( mFloatableContainerListener != null ) {
347 + mFloatableContainerListener.floaterRemoved( pFloater );
348 + }
349 + }
350 +
351 + private static class ZindexComparator implements Comparator {
352 + public static final Comparator INSTANCE = new ZindexComparator();
353 +
354 + public int compare( Object o1, Object o2 ) {
355 + return compare( (SizeableFloater) o1, (SizeableFloater) o2 );
356 + }
357 +
358 + /**
359 + * @return a negative integer, zero, or a positive integer as pThis object
360 + * is less than, equal to, or greater than the pThem object.
361 + */
362 + public int compare( SizeableFloater pThis, SizeableFloater pThem ) {
363 + return pThis.getZindex() - pThem.getZindex();
364 + }
365 + }
366 +
367 + private static class AreaComparator implements Comparator<SizeableFloater> {
368 + public static final AreaComparator INSTANCE = new AreaComparator();
369 +
370 + /**
371 + * @return a negative integer, zero, or a positive integer as pThis object
372 + * is less than, equal to, or greater than the pThem object.
373 + */
374 + public int compare( SizeableFloater pThis, SizeableFloater pThem ) {
375 + // return pThis.getArea() - pThem.getArea();
376 + return pThem.getArea() - pThis.getArea(); // reverse! (Bigger to Smaller)
377 + }
378 + }
379 +
380 + private static class TitleComparator implements Comparator {
381 + public static final Comparator INSTANCE = new TitleComparator();
382 +
383 + public int compare( Object o1, Object o2 ) {
384 + return compare( (SizeableFloater) o1, (SizeableFloater) o2 );
385 + }
386 +
387 + /**
388 + * @return a negative integer, zero, or a positive integer as pThis object
389 + * is less than, equal to, or greater than the pThem object.
390 + */
391 + public int compare( SizeableFloater pThis, SizeableFloater pThem ) {
392 + return Compare.nullsOK( pThem.getTitle(), pThis.getTitle() );
393 + }
394 + }
395 +
396 + private static class FloaterPosition implements Cascadable {
397 + private int mCascadeUniqueID, mPosLeft, mPosTop;
398 +
399 + public FloaterPosition( SizeableFloater pFloater ) {
400 + mCascadeUniqueID = pFloater.getCascadeUniqueID();
401 + mPosLeft = pFloater.getPosLeft();
402 + mPosTop = pFloater.getPosTop();
403 + }
404 +
405 + public boolean isPositionLocked() {
406 + return true;
407 + }
408 +
409 + public int getCascadeUniqueID() {
410 + return mCascadeUniqueID;
411 + }
412 +
413 + public int getPosLeft() {
414 + return mPosLeft;
415 + }
416 +
417 + public int getPosTop() {
418 + return mPosTop;
419 + }
420 +
421 + public int getOffsetWidth() {
422 + throw new UnsupportedOperationException();
423 + }
424 +
425 + public int getOffsetHeight() {
426 + throw new UnsupportedOperationException();
427 + }
428 +
429 + public int minPosLeft() {
430 + throw new UnsupportedOperationException();
431 + }
432 +
433 + public int minPosTop() {
434 + throw new UnsupportedOperationException();
435 + }
436 +
437 + public int maxPosLeft() {
438 + throw new UnsupportedOperationException();
439 + }
440 +
441 + public int maxPosTop() {
442 + throw new UnsupportedOperationException();
443 + }
444 +
445 + public void setPosition( int pLeft, int pTop ) {
446 + throw new UnsupportedOperationException();
447 + }
448 +
449 + public void setPosLeft( int pPosLeft ) {
450 + throw new UnsupportedOperationException();
451 + }
452 +
453 + public void setPosTop( int pPosTop ) {
454 + throw new UnsupportedOperationException();
455 + }
456 +
457 + /**
458 + * Like equals(), but with the contract
459 + *
460 + * @param them !null
461 + */
462 + public boolean isEquivalent( Cascadable them ) {
463 + return (this.getCascadeUniqueID() == them.getCascadeUniqueID()) //
464 + && (this.getPosLeft() == them.getPosLeft()) //
465 + && (this.getPosTop() == them.getPosTop()) //
466 + ;
467 + }
468 +
469 + public boolean shouldMove( int pDesiredLeft, int pDesiredTop ) {
470 + return (mPosLeft != pDesiredLeft) || (mPosTop != pDesiredTop);
471 + }
472 + }
473 +
474 + private static class FloatersPositionState {
475 + private boolean mChanged = false;
476 + private FloaterPosition[] mFloaterPositions;
477 +
478 + /**
479 + * @param pFloaters - current floaters sorted in Current Z-Order Back to Front,
480 + * Array is !null, !empty, & safe to mutate
481 + *
482 + * @return - Floater to make Active
483 + */
484 + public SizeableFloater restoreFloaters( SizeableFloater[] pFloaters ) {
485 + SizeableFloater floater = null;
486 +
487 + SizeableFloater[] zNewOrder = new SizeableFloater[pFloaters.length];
488 +
489 + int ndxTo = 0;
490 + for ( int ndxFrom = 0; ndxFrom < mFloaterPositions.length; ndxFrom++ ) {
491 + FloaterPosition zPosition = mFloaterPositions[ndxFrom];
492 + int zAt = locate( zPosition.getCascadeUniqueID(), pFloaters );
493 + if ( zAt != -1 ) {
494 + floater = zNewOrder[ndxTo++] = pFloaters[zAt];
495 + pFloaters[zAt] = null;
496 + if ( !floater.isPositionLocked() ) {
497 + floater.setPosition( zPosition.getPosLeft(), zPosition.getPosTop() );
498 + }
499 + }
500 + }
501 + for ( int i = 0; i < pFloaters.length; i++ ) {
502 + SizeableFloater zFloater = pFloaters[i];
503 + if ( zFloater != null ) {
504 + floater = zNewOrder[ndxTo++] = zFloater;
505 + }
506 + }
507 +
508 + reZindex( zNewOrder );
509 +
510 + return floater;
511 + }
512 +
513 + private int locate( int pCascadeUniqueID, SizeableFloater[] pFloaters ) {
514 + int i = pFloaters.length;
515 + while ( --i >= 0 ) {
516 + SizeableFloater zFloater = pFloaters[i];
517 + if ( (zFloater != null) && (zFloater.getCascadeUniqueID() == pCascadeUniqueID) ) {
518 + return i;
519 + }
520 + }
521 + return i;
522 + }
523 +
524 + private SizeableFloater populate( SizeableFloater[] pFloaters,
525 + List<SizeableFloater> pNonLockedFloaters ) {
526 + mFloaterPositions = new FloaterPosition[pFloaters.length];
527 +
528 + SizeableFloater zFloater = null;
529 + for ( int i = 0; i < pFloaters.length; i++ ) {
530 + zFloater = pFloaters[i];
531 + mFloaterPositions[i] = new FloaterPosition( zFloater );
532 + if ( !zFloater.isPositionLocked() ) {
533 + pNonLockedFloaters.add( zFloater );
534 + }
535 + }
536 + return pNonLockedFloaters.isEmpty() ? null : zFloater;
537 + }
538 +
539 + /**
540 + * @param pFloaters - current floaters sorted in Current Z-Order Back to Front,
541 + * Array is !null, !empty, & safe to mutate
542 + *
543 + * @return - Floater to make Active
544 + */
545 + public SizeableFloater cascadeFloaters( SizeableFloater[] pFloaters ) {
546 + List<SizeableFloater> zNonLockedFloaters = new ArrayList<SizeableFloater>( pFloaters.length );
547 +
548 + SizeableFloater zFloater = populate( pFloaters, zNonLockedFloaters );
549 +
550 + if ( zFloater == null ) {
551 + return null;
552 + }
553 + Collections.sort( zNonLockedFloaters, AreaComparator.INSTANCE );
554 +
555 + int pMaxZindex = zFloater.getZindex();
556 +
557 + int zTop = 0;
558 + int zLeft = 0;
559 +
560 + SizeableFloater floater = cascadeFloater( zNonLockedFloaters, pMaxZindex, 0, zTop, zLeft );
561 +
562 + int delta = Math.max( floater.getTitleBarHeight(), 25 );
563 +
564 + for ( int i = 1; i < zNonLockedFloaters.size(); i++ ) {
565 + floater = cascadeFloater( zNonLockedFloaters, pMaxZindex, i, zLeft += delta, zTop += delta );
566 + }
567 + return floater;
568 + }
569 +
570 + private SizeableFloater cascadeFloater( List<SizeableFloater> pFloaters, int pMaxZindex, int pIndex,
571 + int pTop, int pLeft ) {
572 + SizeableFloater floater = pFloaters.get( pIndex );
573 +
574 + floater.setPosition( pLeft, pTop );
575 + floater.setZindex( pMaxZindex + pIndex + 1 );
576 +
577 + mChanged |= !mFloaterPositions[pIndex].isEquivalent( floater );
578 +
579 + return floater;
580 + }
581 +
582 + public boolean isChanged() {
583 + return mChanged;
584 + }
585 + }
586 +
587 + // vvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvv No Additional Style Support vvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvv
588 + public void setStylePrimaryName( String style ) {
589 + throw new IllegalStateException( "No Style Support" );
590 + }
591 +
592 + public void addStyleDependentName( String styleSuffix ) {
593 + throw new IllegalStateException( "No Style Support" );
594 + }
595 +
596 + public void addStyleName( String style ) {
597 + throw new IllegalStateException( "No Style Support" );
598 + }
599 +
600 + protected Element getStyleElement() {
601 + throw new IllegalStateException( "No Style Support" );
602 + }
603 + }