Skip to main content

[Date Prev][Date Next][Thread Prev][Thread Next][Date Index][Thread Index] [List Home]
[albireo-dev] Font and color propagation

I've updated albireo.core with SAS and ILOG contributions to control embedded component color and font.

The font code needs work. It propagates only the system default font to embedded components (The override to Control.setFont is not yet implemented.) It does not yet work under Vista, and it probably doesn't work yet under non-Windows OS.

Re the color code, I added these things to the ILOG contribution:

1) Propagation of foreground color as well as background.
2) Setting the color only when necessary

The color code also needs work to properly respect the look and feel and settings changes.

The color/font propagation should be optional. I'll work on that.

There are two separate text files attached with the diffs for these changes.
### Eclipse Workspace Patch 1.0
#P org.eclipse.albireo.core
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.11
diff -u -r1.11 SwingControl.java
--- src/org/eclipse/albireo/core/SwingControl.java	27 Jan 2008 02:41:13 -0000	1.11
+++ src/org/eclipse/albireo/core/SwingControl.java	27 Jan 2008 06:33:24 -0000
@@ -28,6 +28,7 @@
 import org.eclipse.swt.SWT;
 import org.eclipse.swt.SWTException;
 import org.eclipse.swt.awt.SWT_AWT;
+import org.eclipse.swt.graphics.Color;
 import org.eclipse.swt.graphics.Font;
 import org.eclipse.swt.graphics.FontData;
 import org.eclipse.swt.graphics.Point;
@@ -41,6 +42,11 @@
 
 public abstract class SwingControl extends Composite {
 
+    private Listener settingsListener = new Listener() {
+        public void handleEvent(Event event) {
+            handleSettingsChange();
+        }
+    };
     private Display display;
     private Frame frame;
     private JComponent swingComponent;
@@ -51,12 +57,7 @@
     private Dimension cachedMaxSize = new Dimension(0,0);
     private boolean cachedSizesInitialized = false;
     private Font currentSystemFont;
-
-    private Listener settingsListener = new Listener() {
-        public void handleEvent(Event event) {
-            handleSettingsChange();
-        }
-    };
+    private RootPaneContainer rootPaneContainer;
     
     // ========================================================================
     // Constructors
@@ -159,14 +160,18 @@
     protected void scheduleComponentCreation() {
         assert frame != null;
         
+        final Color foreground = getForeground();
+        final Color background = getBackground();
+        
         // Create AWT/Swing components on the AWT thread. This is 
         // especially necessary to avoid an AWT leak bug (Sun bug 6411042).
         EventQueue.invokeLater(new Runnable() {
             public void run() {
-                RootPaneContainer container = addRootPaneContainer(frame);
+                rootPaneContainer = addRootPaneContainer(frame);
                 swingComponent = createSwingComponent();
-                container.getRootPane().getContentPane().add(swingComponent);
+                rootPaneContainer.getRootPane().getContentPane().add(swingComponent);
                 setComponentFont();
+                setComponentColors(foreground, background);
                 // Invoke hooks, for use by the application.
                 afterComponentCreatedAWTThread();
                 try {
@@ -419,6 +424,13 @@
 
     // ========================================================================
     // Font management
+    
+
+    public void setFont(Font font) {
+        super.setFont(font);
+        // TODO Convert font to AWT. Currently we pass on the system font and don't propagate any sets through this method
+    }
+    
 
     private void setComponentFont() {
         assert currentSystemFont != null;
@@ -519,4 +531,67 @@
         display.removeListener(SWT.Settings, settingsListener);
     }
 
+    // ============================= Painting =============================
+
+    /**
+     * Converts a color from SWT to Swing.
+     * The argument Color remains owned by the caller.
+     */
+    public static java.awt.Color convertColor(Color c) {
+        return new java.awt.Color(c.getRed(), c.getGreen(), c.getBlue());
+    }
+
+    /**
+     * Overridden to propagate the background color change to the embedded AWT
+     * component.
+     */
+    public void setBackground(final Color background) {
+        super.setBackground(background);
+        
+        ThreadingHandler.getInstance().asyncExec(display, new Runnable() {
+            public void run() {
+                setComponentColors(getForeground(), background);
+            }
+        });
+    }
+
+    /**
+     * Overridden to propagate the foreground color change to the embedded AWT
+     * component.
+     */
+    public void setForeground(final Color foreground) {
+        super.setForeground(foreground);
+        
+        ThreadingHandler.getInstance().asyncExec(display, new Runnable() {
+            public void run() {
+                setComponentColors(foreground, getBackground());
+            }
+        });
+    }
+
+    protected void setComponentColors(Color foreground, Color background) {
+        java.awt.Color bg = convertColor(background);
+        java.awt.Color fg = convertColor(foreground);
+
+        // The color of the content Pane is visible permanently.
+        if (rootPaneContainer != null) {
+            Container contentPane = rootPaneContainer.getContentPane();
+            if (!contentPane.getBackground().equals(bg)) {
+                contentPane.setBackground(bg);
+            }
+            if (!contentPane.getForeground().equals(fg)) {
+                contentPane.setForeground(fg);
+            }
+        }
+        // The color of the frame is visible during redraws. Use the
+        // same color, to reduce flickering.
+        if (frame != null) {
+            if (!frame.getBackground().equals(bg)) {
+                frame.setBackground(bg);
+            }
+            if (!frame.getBackground().equals(bg)) {
+                frame.setForeground(fg);
+            }
+        }
+    }
 }
#P org.eclipse.albireo.examples.plugin
Index: src/org/eclipse/albireo/examples/plugin/views/EmbeddedJTableView.java
===================================================================
RCS file: /cvsroot/technology/org.eclipse.albireo/org.eclipse.albireo.examples.plugin/src/org/eclipse/albireo/examples/plugin/views/EmbeddedJTableView.java,v
retrieving revision 1.3
diff -u -r1.3 EmbeddedJTableView.java
--- src/org/eclipse/albireo/examples/plugin/views/EmbeddedJTableView.java	27 Jan 2008 00:56:11 -0000	1.3
+++ src/org/eclipse/albireo/examples/plugin/views/EmbeddedJTableView.java	27 Jan 2008 06:33:25 -0000
@@ -3,13 +3,18 @@
 import java.util.Vector;
 
 import javax.swing.JComponent;
+import javax.swing.JPanel;
 import javax.swing.JScrollPane;
 import javax.swing.JTable;
 import javax.swing.border.EmptyBorder;
 
 import org.eclipse.albireo.core.SwingControl;
 import org.eclipse.swt.SWT;
+import org.eclipse.swt.layout.GridData;
 import org.eclipse.swt.widgets.Composite;
+import org.eclipse.swt.widgets.Control;
+import org.eclipse.swt.widgets.Display;
+import org.eclipse.ui.PlatformUI;
 import org.eclipse.ui.part.ViewPart;
 
 /**
@@ -41,12 +46,20 @@
                 table.setAutoResizeMode(JTable.AUTO_RESIZE_OFF);
                 table.createDefaultColumnsFromModel();
                 
+                table.setOpaque(true);
+                table.setBackground(getAWTHierarchyRoot().getBackground());
+                
                 JScrollPane scrollPane = new JScrollPane(table);
                 scrollPane.setBorder(new EmptyBorder(0,0,0,0));
                 
                 return scrollPane;
             }
         };
+        Display display = PlatformUI.getWorkbench().getDisplay();
+        swingControl.setBackground(display.getSystemColor(SWT.COLOR_YELLOW));
+        swingControl.setForeground(display.getSystemColor(SWT.COLOR_DARK_RED));
+        
+        
     }
 
     public void setFocus() {
### Eclipse Workspace Patch 1.0
#P org.eclipse.albireo.core
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.10
diff -u -r1.10 SwingControl.java
--- src/org/eclipse/albireo/core/SwingControl.java	27 Jan 2008 01:50:53 -0000	1.10
+++ src/org/eclipse/albireo/core/SwingControl.java	27 Jan 2008 02:38:30 -0000
@@ -15,24 +15,33 @@
 import java.awt.Dimension;
 import java.awt.EventQueue;
 import java.awt.Frame;
+import java.awt.Toolkit;
 
 import javax.swing.JApplet;
 import javax.swing.JComponent;
 import javax.swing.RootPaneContainer;
+import javax.swing.SwingUtilities;
+import javax.swing.UIManager;
+import javax.swing.plaf.FontUIResource;
 
 import org.eclipse.albireo.internal.Platform;
 import org.eclipse.swt.SWT;
 import org.eclipse.swt.SWTException;
 import org.eclipse.swt.awt.SWT_AWT;
+import org.eclipse.swt.graphics.Font;
+import org.eclipse.swt.graphics.FontData;
 import org.eclipse.swt.graphics.Point;
 import org.eclipse.swt.graphics.Rectangle;
 import org.eclipse.swt.layout.FillLayout;
 import org.eclipse.swt.widgets.Composite;
 import org.eclipse.swt.widgets.Display;
+import org.eclipse.swt.widgets.Event;
+import org.eclipse.swt.widgets.Listener;
 import org.eclipse.swt.widgets.Widget;
 
 public abstract class SwingControl extends Composite {
 
+    private Display display;
     private Frame frame;
     private JComponent swingComponent;
     private boolean populated = false;
@@ -41,8 +50,14 @@
     private Dimension cachedPrefSize = new Dimension(0,0);
     private Dimension cachedMaxSize = new Dimension(0,0);
     private boolean cachedSizesInitialized = false;
-    private Display display;
+    private Font currentSystemFont;
 
+    private Listener settingsListener = new Listener() {
+        public void handleEvent(Event event) {
+            handleSettingsChange();
+        }
+    };
+    
     // ========================================================================
     // Constructors
 
@@ -80,7 +95,16 @@
         super(parent, style | SWT.EMBEDDED | SWT.NO_BACKGROUND);
         setLayout(new FillLayout());
         display = getDisplay();
+        currentSystemFont = getFont();
         
+        display.addListener(SWT.Settings, settingsListener);
+
+        // Clean up on dispose
+        addListener(SWT.Dispose, new Listener() {
+            public void handleEvent(Event event) {
+                handleDispose();
+            }
+        });
         // This listener clears garbage during resizing, making it looker much cleaner. The garbage
         // is due to use of the sun.awt.noerasebackground property, so this is done only under Windows. 
         if (Platform.isWin32()) {
@@ -142,6 +166,7 @@
                 RootPaneContainer container = addRootPaneContainer(frame);
                 swingComponent = createSwingComponent();
                 container.getRootPane().getContentPane().add(swingComponent);
+                setComponentFont();
                 // Invoke hooks, for use by the application.
                 afterComponentCreatedAWTThread();
                 try {
@@ -393,4 +418,105 @@
 
 
     // ========================================================================
+    // Font management
+
+    private void setComponentFont() {
+        assert currentSystemFont != null;
+        assert EventQueue.isDispatchThread();    // On AWT event thread
+        
+        if ((swingComponent != null) && !currentSystemFont.getDevice().isDisposed()) {
+            FontData fontData = currentSystemFont.getFontData()[0];
+            
+            // AWT font sizes assume a 72 dpi resolution, always. The true screen resolution must be 
+            // used to convert the platform font size into an AWT point size that matches when displayed. 
+            int resolution = Toolkit.getDefaultToolkit().getScreenResolution();
+            int awtFontSize = (int)Math.round((double)fontData.getHeight() * resolution / 72.0);
+            
+            // The style constants for SWT and AWT map exactly, and since they are int constants, they should
+            // never change. So, the SWT style is passed through as the AWT style. 
+            java.awt.Font awtFont = new java.awt.Font(fontData.getName(), fontData.getStyle(), awtFontSize);
+
+            // Update the look and feel defaults to use new font.
+            updateLookAndFeel(awtFont);
+
+            // Allow subclasses to react to font change if necessary. 
+            updateAwtFont(awtFont);
+
+            // Allow components to update their UI based on new font 
+            // TODO: should the update method be called on the root pane instead?
+            Container contentPane = swingComponent.getRootPane().getContentPane();
+            SwingUtilities.updateComponentTreeUI(contentPane);
+        }
+    }
+    
+    /**
+     * Performs custom updates to newly set fonts. This method is called whenever a change
+     * to the system font through the system settings (i.e. control panel) is detected.
+     * <p>
+     * This method is called from the AWT event thread.  
+     * <p>
+     * In most cases it is not necessary to override this method.  Normally, the implementation
+     * of this class will automatically propogate font changes to the embedded Swing components 
+     * through Swing's Look and Feel support. However, if additional 
+     * special processing is necessary, it can be done inside this method. 
+     *    
+     * @param newFont New AWT font
+     */
+    protected void updateAwtFont(java.awt.Font newFont) {
+        // Do nothing by default; subclasses can override to insert behavior
+    }
+
+    private void updateLookAndFeel(java.awt.Font awtFont) {
+        assert awtFont != null;
+        assert EventQueue.isDispatchThread();    // On AWT event thread
+        
+        // The FontUIResource class marks the font as replaceable by the look and feel 
+        // implementation if font settings are later changed. 
+        FontUIResource fontResource = new FontUIResource(awtFont);
+
+        // Assign the new font to the relevant L&F font properties. These are 
+        // the properties that are initially assigned to the system font
+        // under the Windows look and feel. 
+        // TODO: It's possible that other platforms will need other assignments.
+        // TODO: This does not handle fonts other than the "system" font. 
+        // TODO: Font not properly set when running under Vista
+        // Other fonts may change, and the Swing L&F may not be adjusting.
+        
+        UIManager.put("Button.font", fontResource); //$NON-NLS-1$
+        UIManager.put("CheckBox.font", fontResource); //$NON-NLS-1$
+        UIManager.put("ComboBox.font", fontResource); //$NON-NLS-1$
+        UIManager.put("EditorPane.font", fontResource); //$NON-NLS-1$
+        UIManager.put("Label.font", fontResource); //$NON-NLS-1$
+        UIManager.put("List.font", fontResource); //$NON-NLS-1$
+        UIManager.put("Panel.font", fontResource); //$NON-NLS-1$
+        UIManager.put("ProgressBar.font", fontResource); //$NON-NLS-1$
+        UIManager.put("RadioButton.font", fontResource); //$NON-NLS-1$
+        UIManager.put("ScrollPane.font", fontResource); //$NON-NLS-1$
+        UIManager.put("TabbedPane.font", fontResource); //$NON-NLS-1$
+        UIManager.put("Table.font", fontResource); //$NON-NLS-1$
+        UIManager.put("TableHeader.font", fontResource); //$NON-NLS-1$
+        UIManager.put("TextField.font", fontResource); //$NON-NLS-1$
+        UIManager.put("TextPane.font", fontResource); //$NON-NLS-1$
+        UIManager.put("TitledBorder.font", fontResource); //$NON-NLS-1$
+        UIManager.put("ToggleButton.font", fontResource); //$NON-NLS-1$
+        UIManager.put("TreeFont.font", fontResource); //$NON-NLS-1$
+        UIManager.put("ViewportFont.font", fontResource); //$NON-NLS-1$
+    }
+
+    private void handleSettingsChange() {
+        Font newFont = getDisplay().getSystemFont();
+        if (!newFont.equals(currentSystemFont)) { 
+            currentSystemFont = newFont;
+            EventQueue.invokeLater(new Runnable() {
+                public void run() {
+                    setComponentFont();
+                }
+            });            
+        }
+    }
+    
+    private void handleDispose() {
+        display.removeListener(SWT.Settings, settingsListener);
+    }
+
 }

Back to the top