org.eclipse.swt.widgets.FontDialog.java Source code

Java tutorial

Introduction

Here is the source code for org.eclipse.swt.widgets.FontDialog.java

Source

/*******************************************************************************
 * 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();
    }

}