[
Date Prev][
Date Next][
Thread Prev][
Thread Next][
Date Index][
Thread Index]
[
List Home]
Re: [albireo-dev] size/layout management
|
Hi Gordon,
> I made this change and marked the populate method protected.
Thanks, it's good that, as an API user, one doesn't have to think of
this populate method any more.
> I wanted to make sure that this would not break the size and layout
> management code that is in both contributions, so I have now merged that
> code into albireo.core too.
Good. I added some comments and made the getCachedAWTSizes method more
self-contained. (Before, this method was marked 'protected', but it
was only safe to be called when cachedSizesInitialized = true - which
is private. Also, it's safer to evaluate cachedSizesInitialized
in the same 'synchronized(this)' block as the three cache variables.)
Still, I haven't understood the handleSetBounds and setAWTSize methods.
Also, is the 'computeSizeDefault' variable really needed? Why not use
'!cachedSizesInitialized' instead? Or equivalently, why is the initial
value of 'computeSizeDefault' false?
> There is one addition from the SAS contribution. AWT components are not
> initially set to a hard coded size. Instead, we wait for the AWT
> component to cache a size, and then we re-layout the SwingControl.
Sure, there's no other way to implement the bottom-up size propagation,
since the Swing component's creation is delayed.
> AWT min, max, and preferred sizes are cached in SwingControl, so that
> size can be managed without breaking the threading rules. As in the
> original ILOG contribution, the cache is updated by hooking
> validateTree() and invalidate() methods in the AWT component.
> ...
> The SAS contribution has a different way to update the cached sizes that
> uses a RepaintManager. Since there was some disagreement about this
> approach (pre-project-creation), I have left it out for now.
Yes, I recall the arguments. Basically, the RepaintManager is the hook
for paint() and redraw(), whereas validate()/invalidate() are the hooks
for size management.
Bruno
Index: src/org/eclipse/albireo/core/SwingControl.java
===================================================================
RCS file: /cvsroot/technology/org.eclipse.albireo/org.eclipse.albireo.core/src/org/eclipse/albireo/core/SwingControl.java,v
retrieving revision 1.15
diff -c -3 -r1.15 SwingControl.java
*** src/org/eclipse/albireo/core/SwingControl.java 29 Jan 2008 20:50:33 -0000 1.15
--- src/org/eclipse/albireo/core/SwingControl.java 1 Feb 2008 20:52:59 -0000
***************
*** 49,64 ****
}
};
private Display display;
private Frame frame;
private JComponent swingComponent;
private boolean populated = false;
- private boolean computeSizeDefault = false;
- private Dimension cachedMinSize = new Dimension(0,0);
- private Dimension cachedPrefSize = new Dimension(0,0);
- private Dimension cachedMaxSize = new Dimension(0,0);
- private boolean cachedSizesInitialized = false;
- private Font currentSystemFont;
- private RootPaneContainer rootPaneContainer;
// ========================================================================
// Constructors
--- 49,59 ----
}
};
private Display display;
+
private Frame frame;
+ private RootPaneContainer rootPaneContainer;
private JComponent swingComponent;
private boolean populated = false;
// ========================================================================
// Constructors
***************
*** 322,330 ****
// ========================================================================
// Size management
! // The min/max/preferred sizes are changed and accessed atomically so that they are always
! // consistent with each other.
protected void updateCachedAWTSizes(Dimension min, Dimension pref, Dimension max) {
// System.out.println("Updated component sizes from AWT: " + min + " <= " + pref + " <= " + max);
boolean firstSizeUpdate = !cachedSizesInitialized;
--- 317,353 ----
// ========================================================================
// Size management
! // Outside this control (on the SWT side) the size management protocol
! // consists of the computeSize() method (bottom-up size propagation)
! // and of the two setBounds() methods (top-down size propagation).
! //
! // Inside this control (on the AWT side) the size management protocol
! // consists of the getPreferredSize(), getMinimumSize(), getMaximumSize()
! // methods (bottom-up size propagation) and of the layout() method
! // (top-down size propagation).
! //
! // We connect these two protocols.
! //
! // One cannot call swingComponent.getPreferredSize()/getMinimumSize()/
! // getMaximumSize() outside the AWT event thread - this would lead to
! // deadlocks. Therefore we use a cache of their values; this cache
! // can be accessed from any thread (with 'synchronized', of course).
! //
! // We change and access the three sizes atomically at once, so that
! // they are consistent with each other.
!
! private Dimension cachedMinSize = new Dimension(0,0);
! private Dimension cachedPrefSize = new Dimension(0,0);
! private Dimension cachedMaxSize = new Dimension(0,0);
! private boolean cachedSizesInitialized = false;
!
! /**
! * Given the minimum, preferred, and maximum sizes of the Swing
! * component, this method stores them in the cache and updates
! * this control accordingly.
! */
protected void updateCachedAWTSizes(Dimension min, Dimension pref, Dimension max) {
+ assert EventQueue.isDispatchThread(); // On AWT event thread
// System.out.println("Updated component sizes from AWT: " + min + " <= " + pref + " <= " + max);
boolean firstSizeUpdate = !cachedSizesInitialized;
***************
*** 336,343 ****
}
if (firstSizeUpdate) {
! // Preferred (and min/max) sizes are available for the AWT component for the first time. Layout the
! // composite so that those sizes can be taken into account
ThreadingHandler.getInstance().asyncExec(display, new Runnable() {
public void run() {
// System.out.println("Laying out after first size update");
--- 359,367 ----
}
if (firstSizeUpdate) {
! // Preferred (and min/max) sizes are available for the AWT
! // component for the first time. Layout the composite so that those
! // sizes can be taken into account.
ThreadingHandler.getInstance().asyncExec(display, new Runnable() {
public void run() {
// System.out.println("Laying out after first size update");
***************
*** 349,362 ****
}
}
! protected void getCachedAWTSizes(Dimension min, Dimension pref, Dimension max) {
synchronized(this) {
! min.setSize(cachedMinSize);
! pref.setSize(cachedPrefSize);
! max.setSize(cachedMaxSize);
}
}
protected void setAWTSize(final int width, final int height) {
// System.out.println("Setting size from SWT: " + width + " x " + height + " for " + swingComponent);
EventQueue.invokeLater(
--- 373,408 ----
}
}
! /**
! * Retrieves the minimum, preferred, and maximum sizes of the Swing
! * component, if they are already available.
! * @param min Output parameter for the Swing component's minimum size.
! * @param pref Output parameter for the Swing component's preferred size.
! * @param max Output parameter for the Swing component's maximum size.
! * @return true if the sizes were available and the output parameters are
! * filled
! */
! protected boolean getCachedAWTSizes(Dimension min, Dimension pref, Dimension max) {
synchronized(this) {
! if (cachedSizesInitialized) {
! min.setSize(cachedMinSize);
! pref.setSize(cachedPrefSize);
! max.setSize(cachedMaxSize);
! return true;
! } else {
! return false;
! }
}
}
+ // Since the swingComponent is not already initialized in the constructor,
+ // this control initially has no notion of what its preferred size could
+ // be.
+ // This variable is true when computeSize() should use the default
+ // implementation from the superclass, and is false once computeSize()
+ // can use the cached sizes, coming from the swingComponent.
+ private boolean computeSizeDefault = false;
+
protected void setAWTSize(final int width, final int height) {
// System.out.println("Setting size from SWT: " + width + " x " + height + " for " + swingComponent);
EventQueue.invokeLater(
***************
*** 370,376 ****
--- 416,426 ----
});
}
+ /**
+ * Called when the SWT layout assigns a size and position to this Control.
+ */
protected void handleSetBounds(int width, int height) {
+ assert Display.getCurrent() != null; // On SWT event thread
checkPopulated();
if (!computeSizeDefault) {
setAWTSize(width, height);
***************
*** 378,397 ****
computeSizeDefault = false;
}
public Point computeSize(int widthHint, int heightHint, boolean changed) {
! assert Display.getCurrent() != null;
! computeSizeDefault = !cachedSizesInitialized;
if (computeSizeDefault) {
// System.out.println("Uninitialized AWT sizes for " + swingComponent);
return super.computeSize(widthHint, heightHint, changed);
} else {
- Dimension min = new Dimension();
- Dimension pref = new Dimension();
- Dimension max = new Dimension();
- getCachedAWTSizes(min, pref, max);
-
int width =
(widthHint == SWT.DEFAULT ? pref.width :
widthHint < min.width ? min.width :
--- 428,453 ----
computeSizeDefault = false;
}
+ // This is called by the layout when it wants to know the size preferences
+ // of this control.
+ /**
+ * Overridden to use the preferred, minimum, and maxiomum sizes of
+ * the embedded Swing component.
+ */
public Point computeSize(int widthHint, int heightHint, boolean changed) {
! assert Display.getCurrent() != null; // On SWT event thread
! Dimension min = new Dimension();
! Dimension pref = new Dimension();
! Dimension max = new Dimension();
! boolean initialized = getCachedAWTSizes(min, pref, max);
!
! computeSizeDefault = !initialized;
if (computeSizeDefault) {
// System.out.println("Uninitialized AWT sizes for " + swingComponent);
return super.computeSize(widthHint, heightHint, changed);
} else {
int width =
(widthHint == SWT.DEFAULT ? pref.width :
widthHint < min.width ? min.width :
***************
*** 410,423 ****
// This is called by the layout when it assigns a size and position to this
// Control.
/**
! * Overridden.
*/
public void setBounds(Rectangle rect) {
handleSetBounds(rect.width, rect.height);
super.setBounds(rect);
}
/**
! * Overridden.
*/
public void setBounds(int x, int y, int width, int height) {
handleSetBounds(width, height);
--- 466,479 ----
// This is called by the layout when it assigns a size and position to this
// Control.
/**
! * Overridden to propagate the size to the embedded Swing component.
*/
public void setBounds(Rectangle rect) {
handleSetBounds(rect.width, rect.height);
super.setBounds(rect);
}
/**
! * Overridden to propagate the size to the embedded Swing component.
*/
public void setBounds(int x, int y, int width, int height) {
handleSetBounds(width, height);
***************
*** 428,433 ****
--- 484,490 ----
// ========================================================================
// Font management
+ private Font currentSystemFont;
public void setFont(Font font) {
super.setFont(font);
***************
*** 573,578 ****
--- 630,637 ----
}
protected void setComponentColors(Color foreground, Color background) {
+ // TODO: on which thread?
+
java.awt.Color bg = convertColor(background);
java.awt.Color fg = convertColor(foreground);