/******************************************************************************* * Copyright (c) 2010 EclipseSource and others. All rights reserved. * This program and the accompanying materials are made available under the * terms of the Eclipse Public License v1.0 which accompanies this distribution, * and is available at http://www.eclipse.org/legal/epl-v10.html * * Contributors: * Ralf Zahn (ARS) - initial API and implementation ******************************************************************************/ package org.eclipse.swt.widgets; import java.util.*; import org.eclipse.rwt.graphics.Graphics; import org.eclipse.rwt.internal.RWTMessages; import org.eclipse.swt.SWT; import org.eclipse.swt.SWTException; import org.eclipse.swt.events.*; import org.eclipse.swt.graphics.*; import org.eclipse.swt.layout.GridData; import org.eclipse.swt.layout.GridLayout; /** * Instances of this class allow the user to select a font from all available * fonts in the system. * <dl> * <dt><b>Styles:</b></dt> * <dd>(none)</dd> * <dt><b>Events:</b></dt> * <dd>(none)</dd> * </dl> * <p> * IMPORTANT: This class is intended to be subclassed <em>only</em> within the * SWT implementation. * </p> * * @since 1.3 */ public class FontDialog extends Dialog { private static final int BUTTON_WIDTH = 60; private Shell shell; private FontData fontData; private RGB rgb; private boolean committed; private Text fontFamilyText; private List fontFamilyList; private Spinner fontSizeSpinner; private Button boldCheckbox; private Button italicCheckbox; private Label colorLabel; private Label previewLabel; /** * Constructs a new instance of this class given only its parent. * * @param parent a shell which will be the parent of the new instance * @exception IllegalArgumentException <ul> * <li>ERROR_NULL_ARGUMENT - if the parent is null</li> * </ul> * @exception SWTException <ul> * <li>ERROR_THREAD_INVALID_ACCESS - if not called from the * thread that created the parent</li> * <li>ERROR_INVALID_SUBCLASS - if this class is not an allowed * subclass</li> * </ul> */ public FontDialog( final Shell parent ) { this( parent, SWT.APPLICATION_MODAL ); } /** * Constructs a new instance of this class given its parent and a style value * describing its behavior and appearance. * <p> * The style value is either one of the style constants defined in class * <code>SWT</code> which is applicable to instances of this class, or must be * built by <em>bitwise OR</em>'ing together (that is, using the * <code>int</code> "|" operator) two or more of those <code>SWT</code> style * constants. The class description lists the style constants that are * applicable to the class. Style bits are also inherited from superclasses. * </p> * * @param parent a shell which will be the parent of the new instance * @param style the style of dialog to construct * @exception IllegalArgumentException <ul> * <li>ERROR_NULL_ARGUMENT - if the parent is null</li> * </ul> * @exception SWTException <ul> * <li>ERROR_THREAD_INVALID_ACCESS - if not called from the * thread that created the parent</li> * <li>ERROR_INVALID_SUBCLASS - if this class is not an allowed * subclass</li> * </ul> */ public FontDialog( final Shell parent, final int style ) { super( parent, checkStyle( parent, style ) ); checkSubclass(); setText( RWTMessages.getMessage( "RWT_FontDialogTitle" ) ); } /** * Returns a FontData set describing the font that was selected in the dialog, * or null if none is available. * * @return the FontData for the selected font, or null */ public FontData[] getFontList() { FontData[] result = null; if( fontData != null ) { result = new FontData[ 1 ]; result[ 0 ] = fontData; } return result; } /** * Sets the set of FontData objects describing the font to be selected by * default in the dialog, or null to let the platform choose one. * * @param fontData the set of FontData objects to use initially, or null to * let the platform select a default when open() is called * @see Font#getFontData */ public void setFontList( final FontData[] fontData ) { if( fontData != null && fontData.length > 0 ) { this.fontData = fontData[ 0 ]; } else { this.fontData = null; } } /** * Returns an RGB describing the color that was selected in the dialog, or * null if none is available. * * @return the RGB value for the selected color, or null * @see PaletteData#getRGBs */ public RGB getRGB() { return rgb; } /** * Sets the RGB describing the color to be selected by default in the dialog, * or null to let the platform choose one. * * @param rgb the RGB value to use initially, or null to let the platform * select a default when open() is called * @see PaletteData#getRGBs */ public void setRGB( final RGB rgb ) { this.rgb = rgb; } /** * Makes the dialog visible and brings it to the front of the display. * * @return a FontData object describing the font that was selected, or null if * the dialog was cancelled or an error occurred * @exception SWTException <ul> * <li>ERROR_WIDGET_DISPOSED - if the dialog has been disposed</li> * <li>ERROR_THREAD_INVALID_ACCESS - if not called from the * thread that created the dialog</li> * </ul> */ public FontData open() { initializeDefaults(); createShell(); createControls(); updateControls(); addChangeListeners(); layoutAndCenterShell(); openShell(); return fontData; } private void initializeDefaults() { if( fontData == null ) { Display display = parent.getDisplay(); FontData systemFontData = display.getSystemFont().getFontData()[ 0 ]; String fontName = getFirstFontName( systemFontData.getName() ); int fontHeight = systemFontData.getHeight(); int fontStyle = systemFontData.getStyle(); fontData = new FontData( fontName, fontHeight, fontStyle ); } if( rgb == null ) { rgb = new RGB( 0, 0, 0 ); } } static String getFirstFontName( final String fontName ) { String result = fontName; int index = result.indexOf( ',' ); if( index != -1 ) { result = result.substring( 0, index ); } result = result.trim(); if( result.length() > 2 ) { char firstChar = result.charAt( 0 ); char lastChar = result.charAt( result.length() - 1 ); boolean isQuoted = ( firstChar == '\'' && lastChar == '\'' ) || ( firstChar == '"' && lastChar == '"' ); if( isQuoted ) { result = result.substring( 1, result.length() - 1 ); } } return result; } private void createShell() { int style = SWT.TITLE | SWT.BORDER | SWT.APPLICATION_MODAL; shell = new Shell( parent, style ); shell.setText( getText() ); shell.addShellListener( new ShellAdapter() { public void shellClosed( final ShellEvent e ) { handleShellClose(); } } ); } private void layoutAndCenterShell() { Point prefSize = shell.computeSize( SWT.DEFAULT, SWT.DEFAULT ); // leave some space in preview area for larger fonts prefSize.y += 50; shell.setSize( prefSize ); Rectangle parentSize = parent.getBounds(); int locationX = ( parentSize.width - prefSize.x ) / 2 + parentSize.x; int locationY = ( parentSize.height - prefSize.y ) / 2 + parentSize.y; shell.setLocation( locationX, locationY ); } private void openShell() { shell.open(); Display display = parent.getDisplay(); while( !shell.isDisposed() ) { if( !display.readAndDispatch() ) { display.sleep(); } } shell = null; } private void createControls() { GridLayout mainLayout = new GridLayout( 2, true ); mainLayout.marginWidth = 10; mainLayout.marginHeight = 10; mainLayout.horizontalSpacing = 10; mainLayout.verticalSpacing = 10; shell.setLayout( mainLayout ); createLeftArea( shell ); createRightArea( shell ); createPreviewArea( shell ); createButtonArea( shell ); fillAvailableFonts(); } private void createLeftArea( final Composite parent ) { Composite leftArea = createVerticalArea( parent ); createFontFamilyGroup( leftArea ); } private void createRightArea( final Composite parent ) { Composite rightArea = createVerticalArea( parent ); createFontSizeGroup( rightArea ); createFontStyleGroup( rightArea ); createFontColorGroup( rightArea ); } private Composite createVerticalArea( final Composite parent ) { Composite result = new Composite( parent, SWT.NONE ); result.setLayoutData( new GridData( SWT.FILL, SWT.FILL, true, false ) ); GridLayout layout = new GridLayout(); layout.marginWidth = 0; layout.marginHeight = 0; result.setLayout( layout ); return result; } private void createFontFamilyGroup( final Composite parent ) { Group result = new Group( parent, SWT.NONE ); result.setLayoutData( new GridData( SWT.FILL, SWT.FILL, true, true ) ); result.setText( RWTMessages.getMessage( "RWT_FontDialogFontFamilyTitle" ) ); result.setLayout( new GridLayout() ); fontFamilyText = new Text( result, SWT.BORDER ); GridData textData = new GridData( SWT.FILL, SWT.CENTER, true, false ); fontFamilyText.setLayoutData( textData ); fontFamilyList = new List( result, SWT.SINGLE | SWT.V_SCROLL | SWT.BORDER ); GridData listData = new GridData( SWT.FILL, SWT.FILL, true, true ); fontFamilyList.setLayoutData( listData ); fontFamilyList.addSelectionListener( new SelectionAdapter() { public void widgetSelected( final SelectionEvent e ) { int selectionIndex = fontFamilyList.getSelectionIndex(); if( selectionIndex != -1 ) { fontFamilyText.setText( fontFamilyList.getItem( selectionIndex ) ); } } } ); } private void createFontSizeGroup( final Composite parent ) { Group result = new Group( parent, SWT.NONE ); result.setLayoutData( new GridData( SWT.FILL, SWT.FILL, true, false ) ); result.setText( RWTMessages.getMessage( "RWT_FontDialogFontSizeTitle" ) ); result.setLayout( new GridLayout() ); fontSizeSpinner = new Spinner( result, SWT.BORDER ); fontSizeSpinner.setDigits( 0 ); fontSizeSpinner.setMinimum( 0 ); fontSizeSpinner.setMaximum( 200 ); GridData spinnerData = new GridData( SWT.FILL, SWT.FILL, true, true ); fontSizeSpinner.setLayoutData( spinnerData ); } private void createFontStyleGroup( final Composite parent ) { Group result = new Group( parent, SWT.NONE ); result.setLayoutData( new GridData( SWT.FILL, SWT.FILL, true, true ) ); result.setText( RWTMessages.getMessage( "RWT_FontDialogFontStyleTitle" ) ); GridLayout layout = new GridLayout(); layout.marginWidth = 0; layout.marginHeight = 0; result.setLayout( layout ); boldCheckbox = new Button( result, SWT.CHECK ); String bold = RWTMessages.getMessage( "RWT_FontDialogFontStyleBold" ); boldCheckbox.setText( bold ); FontData normalFont = boldCheckbox.getFont().getFontData()[ 0 ]; boldCheckbox.setFont( Graphics.getFont( normalFont.getName(), normalFont.getHeight(), SWT.BOLD ) ); italicCheckbox = new Button( result, SWT.CHECK ); String italic = RWTMessages.getMessage( "RWT_FontDialogFontStyleItalic" ); italicCheckbox.setText( italic ); italicCheckbox.setFont( Graphics.getFont( normalFont.getName(), normalFont.getHeight(), SWT.ITALIC ) ); } private void createFontColorGroup( final Composite parent ) { Group result = new Group( parent, SWT.NONE ); result.setLayoutData( new GridData( SWT.FILL, SWT.FILL, true, false ) ); result.setText( RWTMessages.getMessage( "RWT_FontDialogFontColorTitle" ) ); result.setLayout( new GridLayout( 2, false ) ); colorLabel = new Label( result, SWT.BORDER ); colorLabel.setLayoutData( new GridData( 20, 20 ) ); Button changeColorButton = new Button( result, SWT.PUSH ); String text = RWTMessages.getMessage( "RWT_FontDialogFontColorSelect" ); changeColorButton.setText( text ); changeColorButton.addSelectionListener( new SelectionAdapter() { public void widgetSelected( final SelectionEvent e ) { openColorDialog(); } } ); } private void openColorDialog() { ColorDialog dialog = new ColorDialog( shell ); dialog.setRGB( rgb ); RGB selected = dialog.open(); if( selected != null ) { rgb = selected; updateControls(); } } private void addChangeListeners() { SelectionListener selectionListener = new SelectionAdapter() { public void widgetSelected( final SelectionEvent e ) { updateFontData(); } }; fontSizeSpinner.addSelectionListener( selectionListener ); boldCheckbox.addSelectionListener( selectionListener ); italicCheckbox.addSelectionListener( selectionListener ); fontFamilyText.addModifyListener( new ModifyListener() { public void modifyText( final ModifyEvent event ) { String text = fontFamilyText.getText(); selectFontFamilyInList( text ); updateFontData(); } } ); } private void createPreviewArea( final Composite parent ) { Composite previewArea = new Composite( parent, SWT.BORDER ); GridData areaData = new GridData( SWT.FILL, SWT.FILL, true, true ); areaData.minimumWidth = 300; areaData.horizontalSpan = 2; previewArea.setLayoutData( areaData ); previewArea.setLayout( new GridLayout() ); previewLabel = new Label( previewArea, SWT.CENTER ); GridData labelData = new GridData( SWT.FILL, SWT.CENTER, true, true ); previewLabel.setLayoutData( labelData ); String previewText = RWTMessages.getMessage( "RWT_FontDialogPreviewText" ); previewLabel.setText( previewText ); Display display = parent.getDisplay(); Color bgColor = display.getSystemColor( SWT.COLOR_LIST_BACKGROUND ); previewArea.setBackground( bgColor ); previewArea.setBackgroundMode( SWT.INHERIT_DEFAULT ); } private void createButtonArea( final Composite parent ) { Composite buttonComposite = new Composite( parent, SWT.NONE ); GridData layoutData = new GridData( SWT.RIGHT, SWT.CENTER, false, false ); layoutData.horizontalSpan = 2; buttonComposite.setLayoutData( layoutData ); GridLayout buttonCompLayout = new GridLayout( 2, true ); buttonCompLayout.marginWidth = 0; buttonCompLayout.marginHeight = 0; buttonComposite.setLayout( buttonCompLayout ); String okText = SWT.getMessage( "SWT_OK" ); Button okButton = createButton( buttonComposite, okText ); parent.getShell().setDefaultButton( okButton ); okButton.forceFocus(); String cancelText = SWT.getMessage( "SWT_Cancel" ); Button cancelButton = createButton( buttonComposite, cancelText ); okButton.addSelectionListener( new SelectionAdapter() { public void widgetSelected( final SelectionEvent e ) { committed = true; shell.close(); } } ); cancelButton.addSelectionListener( new SelectionAdapter() { public void widgetSelected( final SelectionEvent e ) { shell.close(); } } ); } private Button createButton( final Composite parent, final String text ) { Button result = new Button( parent, SWT.PUSH ); result.setText( text ); GridData data = new GridData( GridData.HORIZONTAL_ALIGN_FILL ); int widthHint = convertHorizontalDLUsToPixels( result, BUTTON_WIDTH ); Point minSize = result.computeSize( SWT.DEFAULT, SWT.DEFAULT ); data.widthHint = Math.max( widthHint, minSize.x ); result.setLayoutData( data ); return result; } private void handleShellClose() { if( !committed ) { fontData = null; rgb = null; } committed = false; } private void fillAvailableFonts() { Collection fontFamilies = new HashSet(); FontData[] fontList = parent.getDisplay().getFontList( null, true ); if( fontList != null ) { for( int i = 0; i < fontList.length; i++ ) { fontFamilies.add( fontList[ i ].getName() ); } } String[] availableFontNames = new String[ fontFamilies.size() ]; fontFamilies.toArray( availableFontNames ); Arrays.sort( availableFontNames ); fontFamilyList.setItems( availableFontNames ); } private void updateControls() { String fontName = fontData.getName(); if( !fontFamilyText.getText().equals( fontName ) ) { fontFamilyText.setText( fontName ); } selectFontFamilyInList( fontName ); fontSizeSpinner.setSelection( fontData.getHeight() ); boldCheckbox.setSelection( ( fontData.getStyle() & SWT.BOLD ) != 0 ); italicCheckbox.setSelection( ( fontData.getStyle() & SWT.ITALIC ) != 0 ); updatePreview(); } private void selectFontFamilyInList( final String fontFamily ) { fontFamilyList.deselectAll(); String[] items = fontFamilyList.getItems(); for( int i = 0; i < items.length; i++ ) { String item = items[ i ]; if( fontFamily.toLowerCase().equals( item.toLowerCase() ) ) { fontFamilyList.select( i ); } } } private void updatePreview() { if( previewLabel != null ) { Font font = Graphics.getFont( fontData ); previewLabel.setFont( font ); Color color = Graphics.getColor( rgb ); previewLabel.setForeground( color ); colorLabel.setBackground( color ); previewLabel.getParent().layout( true ); } } private void updateFontData() { String name = fontData.getName(); if( fontFamilyText.getText().length() > 0 ) { name = fontFamilyText.getText(); } int height = fontSizeSpinner.getSelection(); int style = SWT.NORMAL; if( boldCheckbox.getSelection() ) { style |= SWT.BOLD; } if( italicCheckbox.getSelection() ) { style |= SWT.ITALIC; } fontData = new FontData( name, height, style ); updateControls(); } }