blob: 340e174679a9106db920b3b617a27086d4fb4ffa [file] [log] [blame]
/*******************************************************************************
* Copyright (c) 2000, 2008 IBM Corporation 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:
* IBM Corporation - initial API and implementation
*******************************************************************************/
package org.eclipse.swt.widgets;
import org.eclipse.swt.*;
import org.eclipse.swt.graphics.*;
import org.eclipse.swt.layout.*;
import java.util.*;
/**
* 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>
*
* @see <a href="http://www.eclipse.org/swt/examples.php">SWT Example: ControlExample, Dialog tab</a>
* @see <a href="http://www.eclipse.org/swt/">Sample code and further information</a>
* @noextend This class is not intended to be subclassed by clients.
*/
public class FontDialog extends Dialog {
private FontData [] fontData;
private FontData currentFontData;
private Font sampleFont; // the displayed sample font
private Color sampleColor; // the displayed sample color
private RGB rgb;
private boolean okSelected = false;
private boolean ignoreEvents = false;
/*
* Table containing all available fonts as FontData objects.
* The table is structured as a series of embedded Hashtables as follows:
* <br>characterRegistryName -> faceName -> extendedStyle -> size -> style
*/
private Hashtable characterSets = new Hashtable ();
// widgets
private Shell shell;
private List fontSetList;
private List charSetList, faceNameList, extStyleList;
private List fontStyleList, fontSizeList;
private Label sampleLabel;
private Button upButton, downButton, newButton, removeButton;
private Button okButton, cancelButton, colorButton;
// constants
private static final String TEXT_SAMPLE = "AaBbYyZz";
private static String SCALABLE_SIZES [];
private static final int DEFAULT_SIZE = 14;
private static final String DEFAULT_STYLE = "medium";
private static final Integer SCALABLE_KEY = new Integer (0);
private static final int LIST_WIDTH = 200;
private static final int EXTSTYLE_WIDTH = 150;
private static final int LIST_HEIGHT = 150;
private static final int SAMPLE_HEIGHT = 75;
private static final String PREFIX_ISO8859 = "iso8859";
private static final String PREFIX_ISO646 = "iso646";
private static final String PREFIX_UNICODE = "ucs";
private static final String PREFIX_JAPANESE = "jis";
private static final String PREFIX_SIMPLIFIEDCHINESE = "gb";
private static final String PREFIX_TRADITIONALCHINESE = "cns";
private static final String PREFIX_KOREAN = "ks";
private static final String [] ISO_CHARSETS = new String [] {
"", // 0 undefined
SWT.getMessage ("SWT_Charset_Western"),
SWT.getMessage ("SWT_Charset_EastEuropean"),
SWT.getMessage ("SWT_Charset_SouthEuropean"),
SWT.getMessage ("SWT_Charset_NorthEuropean"),
SWT.getMessage ("SWT_Charset_Cyrillic"),
SWT.getMessage ("SWT_Charset_Arabic"),
SWT.getMessage ("SWT_Charset_Greek"),
SWT.getMessage ("SWT_Charset_Hebrew"),
SWT.getMessage ("SWT_Charset_Turkish"),
SWT.getMessage ("SWT_Charset_Nordic"),
SWT.getMessage ("SWT_Charset_Thai"),
"", // 12 undefined
SWT.getMessage ("SWT_Charset_BalticRim"),
SWT.getMessage ("SWT_Charset_Celtic"),
SWT.getMessage ("SWT_Charset_Euro"),
SWT.getMessage ("SWT_Charset_Romanian")
};
static {
SCALABLE_SIZES = new String [69];
for (int i = 0; i < 69; i++) {
SCALABLE_SIZES [i] = String.valueOf (i + 4);
}
}
/**
* 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 ();
}
/**
* Add the fonts found in 'fonts' to the list of fonts.
* Fonts are stored by character set and face name. For each character
* set/face name combination there is one FontExtStyles object that
* captures the different extended styles and the sizes and styles
* available for that extended style.
*/
void addFonts (FontData fonts []) {
for (int i = 0; i < fonts.length; i++) {
FontData font = fonts [i];
String charSetName = getTranslatedCharSet (font, true);
Hashtable charSet = (Hashtable) characterSets.get (charSetName);
if (charSet == null) {
charSet = new Hashtable (9);
characterSets.put (charSetName, charSet);
}
String faceName = getTranslatedFaceName (font);
Hashtable faceSet = (Hashtable) charSet.get (faceName);
if (faceSet == null) {
faceSet = new Hashtable (9);
charSet.put (faceName, faceSet);
}
String extStyleName = font.addStyle;
Hashtable extStyleSet = (Hashtable) faceSet.get (extStyleName);
if (extStyleSet == null) {
extStyleSet = new Hashtable (9);
faceSet.put (extStyleName, extStyleSet);
}
Integer sizeValue = new Integer (font.getHeight ());
Hashtable sizeSet = (Hashtable) extStyleSet.get (sizeValue);
if (sizeSet == null) {
sizeSet = new Hashtable (9);
extStyleSet.put (sizeValue, sizeSet);
}
String style = font.weight;
sizeSet.put (style,font);
}
}
void centerListIndex (List list, int index) {
int visibleItems = list.getSize ().y / list.getItemHeight ();
int topIndex = Math.max (0, index - visibleItems / 2);
list.setTopIndex (topIndex);
}
FontData copyFontData (FontData data) {
FontData result = new FontData ();
result.addStyle = data.addStyle;
result.averageWidth = data.averageWidth;
result.characterSetName = data.characterSetName;
result.characterSetRegistry = data.characterSetRegistry;
result.fontFamily = data.fontFamily;
result.foundry = data.foundry;
result.horizontalResolution = data.horizontalResolution;
result.pixels = data.pixels;
result.points = data.points;
result.setWidth = data.setWidth;
result.slant = data.slant;
result.spacing = data.spacing;
result.verticalResolution = data.verticalResolution;
result.weight = data.weight;
return result;
}
void createButtons (Composite parent) {
int buttonAlignment = GridData.FILL_HORIZONTAL | GridData.VERTICAL_ALIGN_BEGINNING;
okButton = new Button (parent, SWT.PUSH);
okButton.setText (SWT.getMessage ("SWT_OK"));
okButton.setLayoutData (new GridData (buttonAlignment));
shell.setDefaultButton (okButton);
cancelButton = new Button (parent, SWT.PUSH);
cancelButton.setText (SWT.getMessage ("SWT_Cancel"));
cancelButton.setLayoutData (new GridData (buttonAlignment));
colorButton = new Button (parent, SWT.PUSH);
colorButton.setText (SWT.getMessage ("SWT_Color"));
colorButton.setLayoutData (new GridData (buttonAlignment));
}
void createControls (Composite parent) {
Composite composite = new Composite (parent, SWT.NONE);
GridLayout layout = new GridLayout ();
layout.numColumns = 2;
composite.setLayout (layout);
Composite controls = new Composite (composite, SWT.NONE);
layout = new GridLayout ();
layout.marginHeight = layout.marginWidth = 0;
layout.numColumns = 3;
controls.setLayout (layout);
// labels row (1)
new Label (controls, SWT.NONE).setText (SWT.getMessage ("SWT_Character_set") + ":");
new Label (controls, SWT.NONE).setText (SWT.getMessage ("SWT_Font") + ":");
new Label (controls, SWT.NONE).setText (SWT.getMessage ("SWT_Extended_style") + ":");
// lists row (2)
charSetList = new List (controls, SWT.V_SCROLL | SWT.BORDER);
GridData gridData = new GridData (GridData.FILL_HORIZONTAL);
gridData.heightHint = LIST_HEIGHT;
gridData.widthHint = LIST_WIDTH;
charSetList.setLayoutData (gridData);
faceNameList = new List (controls, SWT.V_SCROLL | SWT.BORDER);
gridData = new GridData (GridData.FILL_HORIZONTAL);
gridData.heightHint = LIST_HEIGHT;
gridData.widthHint = LIST_WIDTH;
faceNameList.setLayoutData (gridData);
extStyleList = new List (controls, SWT.V_SCROLL | SWT.MULTI | SWT.BORDER);
gridData = new GridData (GridData.FILL_HORIZONTAL);
gridData.heightHint = LIST_HEIGHT;
gridData.widthHint = EXTSTYLE_WIDTH;
extStyleList.setLayoutData (gridData);
// labels row (3)
new Label (controls, SWT.NONE).setText (SWT.getMessage ("SWT_Size") + ":");
new Label (controls, SWT.NONE).setText (SWT.getMessage ("SWT_Style") + ":");
new Label (controls, SWT.NONE); // filler
// lists row (4)
fontSizeList = new List (controls, SWT.V_SCROLL | SWT.BORDER);
gridData = new GridData (GridData.FILL_HORIZONTAL);
gridData.heightHint = LIST_HEIGHT;
gridData.widthHint = LIST_WIDTH;
fontSizeList.setLayoutData (gridData);
fontStyleList = new List (controls, SWT.V_SCROLL | SWT.BORDER);
gridData = new GridData (GridData.FILL_HORIZONTAL);
gridData.heightHint = LIST_HEIGHT;
gridData.widthHint = LIST_WIDTH;
fontStyleList.setLayoutData (gridData);
new Label (controls, SWT.NONE); // filler
// font sets group
Group fontSetGroup = new Group (controls, SWT.NONE);
fontSetGroup.setText(SWT.getMessage ("SWT_FontSet"));
layout = new GridLayout ();
layout.numColumns = 2;
fontSetGroup.setLayout (layout);
GridData data = new GridData (GridData.FILL_BOTH);
data.horizontalSpan = 3;
fontSetGroup.setLayoutData (data);
fontSetList = new List (fontSetGroup, SWT.V_SCROLL | SWT.BORDER);
data = new GridData (GridData.FILL_BOTH);
data.grabExcessHorizontalSpace = true;
fontSetList.setLayoutData (data);
Composite buttonsGroup = new Composite (fontSetGroup, SWT.NONE);
layout = new GridLayout ();
layout.numColumns = 3;
layout.makeColumnsEqualWidth = false;
layout.marginHeight = layout.marginWidth = 0;
layout.horizontalSpacing = layout.verticalSpacing = 0;
buttonsGroup.setLayout (layout);
Composite upDownButtonsGroup = new Composite (buttonsGroup, SWT.NONE);
layout = new GridLayout ();
layout.marginHeight = layout.marginWidth = 0;
layout.horizontalSpacing = layout.verticalSpacing = 0;
upDownButtonsGroup.setLayout(layout);
int buttonAlignment = GridData.FILL_HORIZONTAL | GridData.VERTICAL_ALIGN_BEGINNING;
upButton = new Button (upDownButtonsGroup, SWT.PUSH);
upButton.setLayoutData (new GridData (buttonAlignment));
upButton.setText (SWT.getMessage ("SWT_Up"));
downButton = new Button (upDownButtonsGroup, SWT.PUSH);
downButton.setLayoutData (new GridData (buttonAlignment));
downButton.setText (SWT.getMessage ("SWT_Down"));
new Label (buttonsGroup, SWT.SEPARATOR | SWT.VERTICAL);
Composite newRemoveButtonsGroup = new Composite (buttonsGroup, SWT.NONE);
layout = new GridLayout ();
layout.marginHeight = layout.marginWidth = 0;
layout.horizontalSpacing = layout.verticalSpacing = 0;
newRemoveButtonsGroup.setLayout(layout);
newButton = new Button (newRemoveButtonsGroup, SWT.PUSH);
newButton.setLayoutData (new GridData (buttonAlignment));
newButton.setText (SWT.getMessage ("SWT_NewFont"));
removeButton = new Button (newRemoveButtonsGroup, SWT.PUSH);
removeButton.setLayoutData (new GridData (buttonAlignment));
removeButton.setText (SWT.getMessage ("SWT_Remove"));
// font sample group
Group sampleGroup = new Group (controls, SWT.NONE);
sampleGroup.setText (SWT.getMessage ("SWT_Sample"));
gridData = new GridData ();
gridData.heightHint = SAMPLE_HEIGHT;
gridData.horizontalSpan = 3;
gridData.horizontalAlignment = GridData.FILL;
sampleGroup.setLayoutData (gridData);
layout = new GridLayout ();
layout.marginWidth = 10;
layout.marginHeight = 10;
sampleGroup.setLayout (layout);
sampleLabel = new Label (sampleGroup, SWT.CENTER);
sampleLabel.setText (TEXT_SAMPLE);
gridData = new GridData ();
gridData.grabExcessHorizontalSpace = true;
gridData.grabExcessVerticalSpace = true;
gridData.verticalAlignment = GridData.FILL;
gridData.horizontalAlignment = GridData.FILL;
sampleLabel.setLayoutData (gridData);
Composite okCancelGroup = new Composite (composite, SWT.NONE);
layout = new GridLayout ();
layout.marginHeight = layout.marginWidth = layout.verticalSpacing = 0;
okCancelGroup.setLayout (layout);
okCancelGroup.setLayoutData (new GridData (GridData.VERTICAL_ALIGN_BEGINNING));
createButtons (okCancelGroup);
}
Hashtable getExtStyles (String charsetName, String faceName) {
Hashtable faces = getFaces (charsetName);
if (faces == null) return null;
return (Hashtable) faces.get (faceName);
}
Hashtable getFaces (String charsetName) {
return (Hashtable) getFonts ().get (charsetName);
}
/**
* Returns a FontData object describing the font that was
* selected in the dialog, or null if none is available.
*
* @return the FontData for the selected font, or null
* @deprecated use #getFontList ()
*/
public FontData getFontData () {
if (fontData != null && fontData.length > 0) {
return fontData [0];
}
return null;
}
FontData getFontData (String charsetName, String faceName, String extStyle, int size, String style) {
Hashtable styles = getStyles (charsetName, faceName, extStyle, size);
if (styles == null) return null;
return (FontData) styles.get (style);
}
/**
* 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
* @since 2.1.1
*/
public FontData [] getFontList () {
return fontData;
}
/**
* Returns the collection of fonts that are displayed by the
* receiver.
* See the class definition for an explanation of the structure
* of the returned Hashtable.
*/
Hashtable getFonts () {
return characterSets;
}
String getListSelection (List list) {
String [] selection = list.getSelection ();
if (selection.length > 0) return selection [0];
return "";
}
/**
* 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
*
* @since 2.1
*/
public RGB getRGB () {
return rgb;
}
/**
* Returns a FontData object that can be used to load the selected
* font.
*/
FontData getSelectionFontData () {
String charSetName = getListSelection (charSetList);
String faceName = getListSelection (faceNameList);
String extStyle = getListSelection (extStyleList);
int size = DEFAULT_SIZE;
try {
size = Integer.valueOf (getListSelection (fontSizeList)).intValue ();
if (size < 1) size = DEFAULT_SIZE;
} catch (NumberFormatException e) {
/*
* This block is purposely left empty since a default
* value is already specified above.
*/
}
String style = getListSelection (fontStyleList);
FontData result = getFontData (charSetName, faceName, extStyle, size, style);
if (result != null) {
result = copyFontData (result);
} else {
/*
* One or more of the dialog's widgets contain custom typed values.
* Create a FontData that mirrors these values so that the Font created
* below will try to find the best match.
*/
result = new FontData ();
result.characterSetRegistry = charSetName;
result.setName (faceName);
result.addStyle = extStyle;
result.weight = style;
}
result.setHeight (size);
return result;
}
Hashtable getSizes (String charsetName, String faceName, String extStyle) {
Hashtable extStyles = getExtStyles (charsetName, faceName);
if (extStyles == null) return null;
return (Hashtable) extStyles.get (extStyle);
}
Hashtable getStyles (String charsetName, String faceName, String extStyle, int size) {
Hashtable sizes = getSizes (charsetName, faceName, extStyle);
if (sizes == null) return null;
Hashtable result = (Hashtable) sizes.get (new Integer (size));
if (result == null)
result = (Hashtable) sizes.get (SCALABLE_KEY);
return result;
}
/**
* Returns the character set found in 'fontData' prefixed
* with a string explaining the character set.
*/
String getTranslatedCharSet (FontData fontData, boolean includeDescription) {
String characterSet = fontData.characterSetRegistry;
String translatedCharSet = null;
if (characterSet.startsWith (PREFIX_ISO8859)) {
int charSetName = 1;
try {
charSetName = Integer.valueOf (fontData.characterSetName).intValue ();
} catch (NumberFormatException e) {
/*
* This block is purposely left empty since a default
* value is already specified above.
*/
}
characterSet = PREFIX_ISO8859 + "-" + charSetName;
if (charSetName < ISO_CHARSETS.length) {
translatedCharSet = ISO_CHARSETS [charSetName];
}
}
else
if (characterSet.startsWith (PREFIX_ISO646)) {
translatedCharSet = SWT.getMessage("SWT_Charset_ASCII");
}
else
if (characterSet.startsWith (PREFIX_UNICODE)) {
translatedCharSet = SWT.getMessage("SWT_Charset_Unicode");
}
else
if (characterSet.startsWith (PREFIX_JAPANESE)) {
translatedCharSet = SWT.getMessage("SWT_Charset_Japanese");
}
else
if (characterSet.startsWith (PREFIX_SIMPLIFIEDCHINESE)) {
translatedCharSet = SWT.getMessage("SWT_Charset_SimplifiedChinese");
}
else
if (characterSet.startsWith (PREFIX_TRADITIONALCHINESE)) {
translatedCharSet = SWT.getMessage("SWT_Charset_TraditionalChinese");
}
else
if (characterSet.startsWith (PREFIX_KOREAN)) {
translatedCharSet = SWT.getMessage("SWT_Charset_Korean");
}
if (includeDescription && translatedCharSet != null) {
translatedCharSet = characterSet + " (" + translatedCharSet + ')';
}
else {
translatedCharSet = characterSet;
}
return translatedCharSet;
}
/**
* Returns the face name as specified in FontData.familyName followed by
* the foundry set in parantheses if available.
* We display the face name first so that the list sorts the fonts by
* face name, not by foundry. Users generally want to select fonts based
* on the face name and not by foundry. Once they've found the desired
* face name in the list they can compare the font variations from
* different foundries if available.
*/
String getTranslatedFaceName (FontData fontData) {
StringBuffer faceNameBuffer;
if (fontData.foundry != null && fontData.foundry.length () > 0) {
faceNameBuffer = new StringBuffer (fontData.fontFamily);
faceNameBuffer.append (" (");
faceNameBuffer.append (fontData.foundry);
faceNameBuffer.append (')');
}
else {
faceNameBuffer = new StringBuffer (fontData.getName ());
}
return faceNameBuffer.toString ();
}
/**
* Handle the events the receiver is listening to.
* List selections cause the downstream lists to be initialized
* with font data and the sample text to be updated.
*/
void handleEvent (Event event) {
if (ignoreEvents) return;
if (event.widget instanceof List) {
List list = (List) event.widget;
String text = getListSelection (list);
int oldSelectIndex = ((Integer)list.getData ()).intValue ();
int newSelectIndex = list.indexOf (text);
if (oldSelectIndex != newSelectIndex || newSelectIndex == -1) {
ignoreEvents = true;
if (list == charSetList) initFaceNameList ();
else if (list == faceNameList) initExtStyleList ();
else if (list == extStyleList) initSizeList ();
else if (list == fontSizeList) initStyleList ();
else if (event.widget == fontSetList) {
currentFontData = fontData [fontSetList.getSelectionIndex ()];
setFontControls (currentFontData);
updateButtonEnablements ();
}
updateSampleFont ();
updateFontList ();
list.setData (new Integer (newSelectIndex));
if (newSelectIndex != -1) {
list.select (newSelectIndex);
}
ignoreEvents = false;
}
return;
}
if (event.widget instanceof Button) {
if (event.widget == okButton) {
okSelected = true;
shell.close ();
}
else if (event.widget == cancelButton) {
okSelected = false;
shell.close ();
}
else if (event.widget == colorButton) {
ColorDialog colorDialog = new ColorDialog (shell, SWT.NONE);
colorDialog.setRGB (rgb);
RGB newRgb = colorDialog.open ();
if (newRgb != null) {
rgb = newRgb;
updateSampleColor ();
}
}
else if (event.widget == newButton) {
FontData [] newFontData = new FontData [fontData.length + 1];
System.arraycopy (fontData, 0, newFontData, 0, fontData.length);
FontData source = fontData [fontSetList.getSelectionIndex ()];
FontData newFd = copyFontData (source);
newFontData [newFontData.length - 1] = newFd;
this.fontData = newFontData;
updateFontList ();
fontSetList.select (newFontData.length - 1);
fontSetList.setData (new Integer (newFontData.length - 1));
fontSetList.showSelection();
updateButtonEnablements ();
}
else if (event.widget == removeButton) {
int selectionIndex = fontSetList.getSelectionIndex ();
FontData [] newFontData = new FontData [fontData.length - 1];
System.arraycopy (fontData, 0, newFontData, 0, selectionIndex);
System.arraycopy (fontData, selectionIndex + 1, newFontData, selectionIndex, newFontData.length - selectionIndex);
fontData = newFontData;
updateFontList ();
updateButtonEnablements ();
setFontControls (fontData [fontSetList.getSelectionIndex ()]);
}
else if (event.widget == upButton) {
int selectionIndex = fontSetList.getSelectionIndex ();
FontData temp = fontData [selectionIndex];
fontData [selectionIndex] = fontData [selectionIndex - 1];
fontData [selectionIndex - 1] = temp;
fontSetList.select (selectionIndex - 1);
fontSetList.setData (new Integer (selectionIndex - 1));
updateFontList ();
updateButtonEnablements ();
}
else if (event.widget == downButton) {
int selectionIndex = fontSetList.getSelectionIndex ();
FontData temp = fontData [selectionIndex];
fontData [selectionIndex] = fontData [selectionIndex + 1];
fontData [selectionIndex + 1] = temp;
fontSetList.select (selectionIndex + 1);
fontSetList.setData (new Integer (selectionIndex + 1));
updateFontList ();
updateButtonEnablements ();
}
}
}
void hookListeners () {
Listener listener = new Listener () {
public void handleEvent (Event event) {
FontDialog.this.handleEvent (event);
}
};
okButton.addListener (SWT.Selection, listener);
cancelButton.addListener (SWT.Selection, listener);
colorButton.addListener (SWT.Selection, listener);
charSetList.addListener (SWT.Selection, listener);
faceNameList.addListener (SWT.Selection, listener);
fontStyleList.addListener (SWT.Selection, listener);
extStyleList.addListener (SWT.Selection, listener);
fontSizeList.addListener (SWT.Selection, listener);
newButton.addListener (SWT.Selection, listener);
removeButton.addListener (SWT.Selection, listener);
upButton.addListener (SWT.Selection, listener);
downButton.addListener (SWT.Selection, listener);
fontSetList.addListener (SWT.Selection, listener);
}
/**
* Initialize the extended styles list with the extended styles
* available for the selected font.
* Downstream lists are initialized as well (style and size).
*/
void initExtStyleList () {
String oldSelect = getListSelection (extStyleList);
extStyleList.removeAll ();
String characterSet = getListSelection (charSetList);
String faceName = getListSelection (faceNameList);
Hashtable extStyles = getExtStyles (characterSet, faceName);
setItemsSorted (extStyleList, extStyles);
int selectIndex = extStyleList.indexOf (oldSelect);
extStyleList.select (selectIndex);
extStyleList.setData (new Integer (selectIndex));
centerListIndex (extStyleList, selectIndex);
initSizeList ();
}
/**
* Initialize the face name list with all font names
* available in the selected character set.
* Downstream lists are initialized as well (extended style).
*/
void initFaceNameList () {
String oldSelect = getListSelection (faceNameList);
faceNameList.removeAll ();
String charSetText = getListSelection (charSetList);
if (charSetText.length () == 0) return;
Hashtable faceNames = getFaces (charSetText);
setItemsSorted (faceNameList, faceNames);
int selectIndex = faceNameList.indexOf (oldSelect);
selectIndex = Math.max (0, selectIndex);
faceNameList.select (selectIndex);
faceNameList.setData (new Integer (selectIndex));
centerListIndex (faceNameList, selectIndex);
initExtStyleList ();
}
/**
* Initialize the widgets of the receiver with the data of
* all installed fonts. If the user specified a default font
* preselect that font in the lists.
*/
void initFonts () {
Display display = shell.display;
// get all fonts available on the current display
addFonts (display.getFontList (null, false));
addFonts (display.getFontList (null, true));
setItemsSorted (charSetList, getFonts ());
if (fontData != null) {
// verify that the initial font data is a valid font
Font font = new Font (display, fontData);
fontData = font.getFontData ();
currentFontData = fontData [0];
font.dispose ();
} else {
fontData = display.textFont.getFontData ();
currentFontData = fontData [0];
}
}
/**
* Initialize the size list with the sizes the selected font
* is available in. If the selected font is scalable a selection
* of preset sizes is used.
*/
void initSizeList () {
String oldSelect = getListSelection (fontSizeList);
fontSizeList.removeAll ();
String characterSet = getListSelection (charSetList);
String faceName = getListSelection (faceNameList);
String extStyle = getListSelection (extStyleList);
Hashtable sizes = getSizes (characterSet, faceName, extStyle);
if (sizes != null) {
if (sizes.get (SCALABLE_KEY) == null) {
/*
* Font is not scalable so just present the provided sizes.
*/
setSizeItemsSorted (sizes.keys ());
} else {
/*
* Font is scalable so present the provided sizes and scalable
* sizes for selection.
*/
Vector allSizes = new Vector ();
/*
* Add the scalable sizes.
*/
for (int i = 0; i < SCALABLE_SIZES.length; i++) {
allSizes.addElement (Integer.valueOf (SCALABLE_SIZES [i]));
}
/*
* Add the provided sizes.
*/
Enumeration providedSizes = sizes.keys ();
while (providedSizes.hasMoreElements ()) {
Integer size = (Integer) providedSizes.nextElement ();
if (!size.equals (SCALABLE_KEY) && !allSizes.contains (size)) {
allSizes.addElement (size);
}
}
setSizeItemsSorted (allSizes.elements ());
}
}
int selectIndex = fontSizeList.indexOf (oldSelect);
if (selectIndex == -1) {
selectIndex = fontSizeList.indexOf (String.valueOf (DEFAULT_SIZE));
}
selectIndex = Math.max (0, selectIndex);
fontSizeList.select (selectIndex);
fontSizeList.setData (new Integer (selectIndex));
centerListIndex (fontSizeList, selectIndex);
initStyleList ();
}
/**
* Initialize the styles list with the styles the selected font
* is available in.
*/
void initStyleList () {
String oldSelect = getListSelection (fontStyleList);
fontStyleList.removeAll ();
String characterSet = getListSelection (charSetList);
String faceName = getListSelection (faceNameList);
String extStyle = getListSelection (extStyleList);
try {
int size = Integer.valueOf (getListSelection (fontSizeList)).intValue ();
if (size > 0) {
Hashtable styles = getStyles (characterSet, faceName, extStyle, size);
setItemsSorted (fontStyleList, styles);
}
} catch (NumberFormatException e) {
// fall through
}
int selectIndex = fontStyleList.indexOf (oldSelect);
if (selectIndex == -1) {
selectIndex = fontStyleList.indexOf (String.valueOf (DEFAULT_STYLE));
}
selectIndex = Math.max (0, selectIndex);
fontStyleList.select (selectIndex);
fontStyleList.setData (new Integer (selectIndex));
centerListIndex (fontStyleList, selectIndex);
}
/**
* 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 () {
shell = new Shell (getParent (), getStyle () | SWT.TITLE | SWT.BORDER | SWT.APPLICATION_MODAL);
shell.setLayout (new GridLayout ());
createControls (shell);
FontData [] originalFontData = fontData;
RGB originalRGB = rgb;
initFonts ();
openDialog ();
setFontControls (currentFontData);
updateSampleFont ();
updateSampleColor ();
updateFontList ();
fontSetList.select (0);
fontSetList.setData (new Integer (0));
updateButtonEnablements ();
hookListeners ();
Display display = shell.display;
while (!shell.isDisposed ()) {
if (!display.readAndDispatch ()) display.sleep ();
}
FontData result = null;
if (okSelected) {
result = fontData [0];
} else {
fontData = originalFontData;
rgb = originalRGB;
}
if (sampleFont != null) sampleFont.dispose ();
sampleFont = null;
if (sampleColor != null) sampleColor.dispose ();
sampleColor = null;
return result;
}
/**
* Open the receiver and set its size to the size calculated by
* the layout manager.
*/
void openDialog () {
// Start everything off by setting the shell size to its computed size.
Point pt = shell.computeSize (SWT.DEFAULT, SWT.DEFAULT, false);
// Ensure that the width of the shell fits the display.
Display display = shell.display;
Rectangle displayRect = display.getBounds ();
int widthLimit = displayRect.width * 7 / 8;
int heightLimit = displayRect.height * 7 / 8;
if (pt.x > widthLimit) {
pt = shell.computeSize (widthLimit, SWT.DEFAULT, false);
}
/*
* If the parent is visible then center this dialog on it,
* otherwise center this dialog on the parent's monitor
*/
Rectangle parentBounds = null;
if (parent.isVisible ()) {
parentBounds = getParent ().getBounds ();
} else {
parentBounds = parent.getMonitor ().getBounds ();
}
int originX = (parentBounds.width - pt.x) / 2 + parentBounds.x;
originX = Math.max (originX, 0);
originX = Math.min (originX, widthLimit - pt.x);
int originY = (parentBounds.height - pt.y) / 2 + parentBounds.y;
originY = Math.max (originY, 0);
originY = Math.min (originY, heightLimit - pt.y);
shell.setBounds (originX, originY, pt.x, pt.y);
String title = getText ();
if (title.length () == 0) title = SWT.getMessage ("SWT_FontDialog_Title");
shell.setText (title);
// Open the window.
shell.open ();
}
/**
* Initialize the lists with the data of the preselected
* font specified by the user.
*/
void setFontControls (FontData fontData) {
ignoreEvents = true;
String characterSet = getTranslatedCharSet (fontData, true);
String faceName = getTranslatedFaceName (fontData);
charSetList.select (new String[] {characterSet});
int index = charSetList.indexOf (characterSet);
charSetList.setData (new Integer (index));
if (index != -1) centerListIndex (charSetList, index);
initFaceNameList ();
faceNameList.select (new String[] {faceName});
index = faceNameList.indexOf (faceName);
faceNameList.setData (new Integer (index));
if (index != -1) centerListIndex (faceNameList, index);
initExtStyleList ();
extStyleList.select (new String[] {fontData.addStyle});
index = extStyleList.indexOf (fontData.addStyle);
extStyleList.setData (new Integer (index));
if (index != -1) centerListIndex (extStyleList, index);
initSizeList ();
String value = String.valueOf (fontData.getHeight ());
fontSizeList.select (new String[] {value});
index = fontSizeList.indexOf (value);
fontSizeList.setData (new Integer (index));
if (index != -1) centerListIndex (fontSizeList, index);
initStyleList ();
fontStyleList.select (new String[] {fontData.weight});
index = fontStyleList.indexOf (fontData.weight);
fontStyleList.setData (new Integer (index));
if (index != -1) centerListIndex (fontStyleList, index);
ignoreEvents = false;
}
/**
* Sets a FontData object describing the font to be
* selected by default in the dialog, or null to let
* the platform choose one.
*
* @param fontData the FontData to use initially, or null
* @deprecated use #setFontList (FontData [])
*/
public void setFontData (FontData fontData) {
if (fontData == null) {
this.fontData = null;
} else {
this.fontData = new FontData [1];
this.fontData [0] = fontData;
}
}
/**
* 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
*
* @since 2.1.1
*/
public void setFontList (FontData [] fontData) {
this.fontData = fontData;
}
/**
* Set the contents of 'list' to the keys of 'items'.
* Keys are sorted in ascending order first and have to be Strings.
*/
void setItemsSorted (List list, Hashtable items) {
if (items == null) return;
Enumeration itemKeys = items.keys ();
String [] sortedItems = new String [items.size ()];
int index = 0;
while (itemKeys.hasMoreElements ()) {
String item = (String) itemKeys.nextElement ();
if (item.length () != 0) sortedItems [index++] = item;
}
if (index != sortedItems.length) {
String [] newItems = new String [index];
System.arraycopy (sortedItems, 0, newItems, 0, index);
sortedItems = newItems;
}
sort (sortedItems);
list.setItems (sortedItems);
}
/**
* 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
*
* @since 2.1
*/
public void setRGB (RGB rgb) {
this.rgb = rgb;
}
/**
* Set the contents of the size list to the keys of 'items'.
* Keys are sorted in ascending order first and have to be Integers.
*/
void setSizeItemsSorted (Enumeration itemsEnum) {
Vector items = new Vector ();
while (itemsEnum.hasMoreElements ()) {
items.addElement (itemsEnum.nextElement ());
}
Integer [] sortedItems = new Integer [items.size ()];
items.copyInto (sortedItems);
sort (sortedItems);
String [] sortedItemStrings = new String [items.size ()];
for (int i = 0; i < sortedItemStrings.length; i++) {
sortedItemStrings [i] = String.valueOf (sortedItems [i].intValue ());
}
fontSizeList.setItems (sortedItemStrings);
}
/**
* Sort 'items' in ascending order.
*/
void sort (Integer [] items) {
/* Shell Sort from K&R, pg 108 */
int length = items.length;
for (int gap = length / 2; gap > 0; gap /= 2) {
for (int i = gap; i < length; i++) {
for (int j = i - gap; j >= 0; j -= gap) {
if (items [j].intValue () > items [j + gap].intValue ()) {
Integer swap = items [j];
items [j] = items [j + gap];
items [j + gap] = swap;
}
}
}
}
}
/**
* Sort 'items' in ascending order.
*/
void sort (String items []) {
/* Shell Sort from K&R, pg 108 */
int length = items.length;
for (int gap = length / 2; gap > 0; gap /= 2) {
for (int i = gap; i < length; i++) {
for (int j = i - gap; j >= 0; j -= gap) {
if (items [j].compareTo (items [j + gap]) > 0) {
String swap = items [j];
items [j] = items [j + gap];
items [j + gap] = swap;
}
}
}
}
}
void updateButtonEnablements () {
removeButton.setEnabled (fontSetList.getItemCount () > 1);
upButton.setEnabled (fontSetList.getSelectionIndex () > 0);
downButton.setEnabled (fontSetList.getSelectionIndex () < fontSetList.getItemCount () - 1);
}
void updateFontList () {
int selectionIndex = fontSetList.getSelectionIndex ();
int topIndex = Math.max (0, fontSetList.getTopIndex ());
String [] items = new String [fontData.length];
for (int i = 0; i < fontData.length; i++) {
StringBuffer buffer = new StringBuffer ();
buffer.append (i);
buffer.append (": ");
buffer.append (getTranslatedCharSet (fontData [i], false));
buffer.append ("-");
buffer.append (getTranslatedFaceName (fontData [i]));
buffer.append ("-");
if (!fontData [i].addStyle.equals ("")) {
buffer.append (fontData [i].addStyle);
buffer.append ("-");
}
buffer.append (fontData [i].getHeight ());
buffer.append ("-");
buffer.append (fontData [i].weight);
items [i] = buffer.toString ();
}
fontSetList.setItems (items);
if (selectionIndex >= items.length) selectionIndex--;
fontSetList.select (selectionIndex);
fontSetList.setData (new Integer (selectionIndex));
fontSetList.setTopIndex (topIndex);
fontSetList.showSelection ();
}
void updateSampleColor () {
if (rgb == null) {
rgb = new RGB (0, 0, 0);
}
if (sampleColor != null) {
if (sampleColor.getRGB ().equals (rgb)) return;
sampleColor.dispose ();
}
sampleColor = new Color (parent.display, rgb);
sampleLabel.setForeground (sampleColor);
}
/**
* Set the font of the sample text to the selected font.
* Display an error in place of the sample text if the selected
* font could not be loaded.
*/
void updateSampleFont () {
FontData selectionFontData = getSelectionFontData ();
/*
* sampleFont may not be the same as the one specified in selectionFontData.
* This happens when selectionFontData specifies a font alias.
*/
if (sampleFont != null) sampleFont.dispose ();
int selectionIndex = Math.max (0, fontSetList.getSelectionIndex ());
fontData [selectionIndex] = selectionFontData;
sampleFont = new Font (shell.display, selectionFontData);
sampleLabel.setFont (sampleFont);
}
}