[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);