/******************************************************************************* * Copyright (c) 2010, 2016 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 * EclipseSource - ongoing development ******************************************************************************/ package org.eclipse.swt.widgets; import java.util.Arrays; import java.util.Collection; import java.util.HashSet; import java.util.Locale; import org.eclipse.rap.rwt.internal.RWTMessages; import org.eclipse.rap.rwt.widgets.DialogCallback; import org.eclipse.swt.SWT; import org.eclipse.swt.SWTException; import org.eclipse.swt.events.ModifyEvent; import org.eclipse.swt.events.ModifyListener; import org.eclipse.swt.events.SelectionAdapter; import org.eclipse.swt.events.SelectionEvent; import org.eclipse.swt.events.SelectionListener; import org.eclipse.swt.events.ShellAdapter; import org.eclipse.swt.events.ShellEvent; import org.eclipse.swt.graphics.Color; import org.eclipse.swt.graphics.Font; import org.eclipse.swt.graphics.FontData; import org.eclipse.swt.graphics.PaletteData; import org.eclipse.swt.graphics.Point; import org.eclipse.swt.graphics.RGB; import org.eclipse.swt.graphics.Rectangle; 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 FontData fontData; private RGB rgb; private Text txtFontFamily; private List lstFontFamily; private Spinner spFontSize; private Button cbBold; private Button cbItalic; private Label lblColor; private Label lblPreview; /** * 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( 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( Shell parent, 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( 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( RGB rgb ) { this.rgb = rgb; } /** * Makes the dialog visible and brings it to the front of the display. * * <!-- Begin RAP specific --> * <p><strong>RAP Note:</strong> This method is not supported when running the application in * JEE_COMPATIBILITY mode. Use <code>Dialog#open(DialogCallback)</code> instead.</p> * <!-- End RAP specific --> * * @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> * @exception UnsupportedOperationException when running the application in JEE_COMPATIBILITY mode * * @see org.eclipse.rap.rwt.application.Application.OperationMode * @see #open(DialogCallback) */ public FontData open() { checkOperationMode(); prepareOpen(); runEventLoop( shell ); return fontData; } @Override protected void prepareOpen() { initializeDefaults(); createShell(); createControls(); updateControls(); addChangeListeners(); layoutAndCenterShell(); } private void initializeDefaults() { if( fontData == null ) { FontData systemFontData = getDisplay().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( 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() { shell = new Shell( parent, SWT.TITLE | SWT.BORDER | SWT.APPLICATION_MODAL ); shell.setText( getText() ); shell.addShellListener( new ShellAdapter() { @Override public void shellClosed( ShellEvent event ) { 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 displaySize = parent.getDisplay().getBounds(); int locationX = ( displaySize.width - prefSize.x ) / 2 + displaySize.x; int locationY = ( displaySize.height - prefSize.y ) / 2 + displaySize.y; shell.setLocation( locationX, locationY ); } 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( Composite parent ) { Composite leftArea = createVerticalArea( parent ); createFontFamilyGroup( leftArea ); } private void createRightArea( Composite parent ) { Composite rightArea = createVerticalArea( parent ); createFontSizeGroup( rightArea ); createFontStyleGroup( rightArea ); createFontColorGroup( rightArea ); } private static Composite createVerticalArea( 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( 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() ); txtFontFamily = new Text( result, SWT.BORDER ); GridData textData = new GridData( SWT.FILL, SWT.CENTER, true, false ); txtFontFamily.setLayoutData( textData ); lstFontFamily = new List( result, SWT.SINGLE | SWT.V_SCROLL | SWT.BORDER ); GridData listData = new GridData( SWT.FILL, SWT.FILL, true, true ); lstFontFamily.setLayoutData( listData ); lstFontFamily.addSelectionListener( new SelectionAdapter() { @Override public void widgetSelected( SelectionEvent event ) { int selectionIndex = lstFontFamily.getSelectionIndex(); if( selectionIndex != -1 ) { txtFontFamily.setText( lstFontFamily.getItem( selectionIndex ) ); } } } ); } private void createFontSizeGroup( 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() ); spFontSize = new Spinner( result, SWT.BORDER ); spFontSize.setDigits( 0 ); spFontSize.setMinimum( 0 ); spFontSize.setMaximum( 200 ); GridData spinnerData = new GridData( SWT.FILL, SWT.FILL, true, true ); spFontSize.setLayoutData( spinnerData ); } private void createFontStyleGroup( Composite parent ) { Display display = getDisplay(); 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 ); cbBold = new Button( result, SWT.CHECK ); cbBold.setText( RWTMessages.getMessage( "RWT_FontDialogFontStyleBold" ) ); FontData normalFont = cbBold.getFont().getFontData()[ 0 ]; Font boldFont = new Font( display, normalFont.getName(), normalFont.getHeight(), SWT.BOLD ); cbBold.setFont( boldFont ); cbItalic = new Button( result, SWT.CHECK ); cbItalic.setText( RWTMessages.getMessage( "RWT_FontDialogFontStyleItalic" ) ); Font italicFont = new Font( display, normalFont.getName(), normalFont.getHeight(), SWT.ITALIC ); cbItalic.setFont( italicFont ); } private void createFontColorGroup( 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 ) ); lblColor = new Label( result, SWT.BORDER ); lblColor.setLayoutData( new GridData( 20, 20 ) ); Button changeColorButton = new Button( result, SWT.PUSH ); changeColorButton.setText( RWTMessages.getMessage( "RWT_FontDialogFontColorSelect" ) ); changeColorButton.addSelectionListener( new SelectionAdapter() { @Override public void widgetSelected( SelectionEvent event ) { openColorDialog(); } } ); } private void openColorDialog() { final ColorDialog dialog = new ColorDialog( shell ); dialog.setRGB( rgb ); dialog.open( new DialogCallback() { @Override public void dialogClosed( int returnCode ) { RGB selected = dialog.getRGB(); if( selected != null ) { rgb = selected; updateControls(); } } } ); } private void addChangeListeners() { SelectionListener selectionListener = new SelectionAdapter() { @Override public void widgetSelected( SelectionEvent event ) { updateFontData(); } }; spFontSize.addSelectionListener( selectionListener ); cbBold.addSelectionListener( selectionListener ); cbItalic.addSelectionListener( selectionListener ); txtFontFamily.addModifyListener( new ModifyListener() { @Override public void modifyText( ModifyEvent event ) { String text = txtFontFamily.getText(); selectFontFamilyInList( text ); updateFontData(); } } ); } private void createPreviewArea( Composite parent ) { Composite previewArea = new Composite( parent, SWT.BORDER ); GridData gridData = new GridData( SWT.FILL, SWT.FILL, true, true, 2, 1 ); gridData.minimumWidth = 300; previewArea.setLayoutData( gridData ); previewArea.setLayout( new GridLayout() ); lblPreview = new Label( previewArea, SWT.CENTER ); GridData labelData = new GridData( SWT.FILL, SWT.CENTER, true, true ); lblPreview.setLayoutData( labelData ); lblPreview.setText( RWTMessages.getMessage( "RWT_FontDialogPreviewText" ) ); Color bgColor = getDisplay().getSystemColor( SWT.COLOR_LIST_BACKGROUND ); previewArea.setBackground( bgColor ); previewArea.setBackgroundMode( SWT.INHERIT_DEFAULT ); } private void createButtonArea( Composite parent ) { Composite composite = new Composite( parent, SWT.NONE ); GridData layoutData = new GridData( SWT.RIGHT, SWT.CENTER, false, false, 2, 1 ); composite.setLayoutData( layoutData ); GridLayout layout = new GridLayout( 2, true ); layout.marginWidth = 0; layout.marginHeight = 0; composite.setLayout( layout ); Button okButton = createButton( composite, SWT.getMessage( "SWT_OK" ), SWT.OK ); okButton.getShell().setDefaultButton( okButton ); okButton.forceFocus(); createButton( composite, SWT.getMessage( "SWT_Cancel" ), SWT.CANCEL ); } private Button createButton( Composite parent, String text, final int returnCode ) { 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 ); result.addSelectionListener( new SelectionAdapter() { @Override public void widgetSelected( SelectionEvent event ) { FontDialog.this.returnCode = returnCode; shell.close(); } } ); return result; } private void handleShellClose() { if( returnCode != SWT.OK ) { fontData = null; rgb = null; } } private void fillAvailableFonts() { Collection<String> fontFamilies = new HashSet<>(); FontData[] fontList = getDisplay().getFontList( null, true ); if( fontList != null ) { for( int i = 0; i < fontList.length; i++ ) { fontFamilies.add( fontList[ i ].getName() ); } } String[] availableFontNames = fontFamilies.toArray( new String[ fontFamilies.size() ] ); Arrays.sort( availableFontNames ); lstFontFamily.setItems( availableFontNames ); } private void updateControls() { String fontName = fontData.getName(); if( !txtFontFamily.getText().equals( fontName ) ) { txtFontFamily.setText( fontName ); } selectFontFamilyInList( fontName ); spFontSize.setSelection( fontData.getHeight() ); cbBold.setSelection( ( fontData.getStyle() & SWT.BOLD ) != 0 ); cbItalic.setSelection( ( fontData.getStyle() & SWT.ITALIC ) != 0 ); updatePreview(); } private void selectFontFamilyInList( String fontFamily ) { lstFontFamily.deselectAll(); String[] items = lstFontFamily.getItems(); for( int i = 0; i < items.length; i++ ) { String item = items[ i ].toLowerCase( Locale.ENGLISH ); if( fontFamily.toLowerCase( Locale.ENGLISH ).equals( item ) ) { lstFontFamily.select( i ); } } } private void updatePreview() { if( lblPreview != null ) { Display display = getDisplay(); Font font = new Font( display, fontData ); lblPreview.setFont( font ); Color color = new Color( display, rgb ); lblPreview.setForeground( color ); lblColor.setBackground( color ); lblPreview.getParent().layout( true ); } } private void updateFontData() { String name = txtFontFamily.getText(); int height = spFontSize.getSelection(); int style = SWT.NORMAL; if( cbBold.getSelection() ) { style |= SWT.BOLD; } if( cbItalic.getSelection() ) { style |= SWT.ITALIC; } fontData = new FontData( name, height, style ); updateControls(); } private Display getDisplay() { return parent.getDisplay(); } }