diff options
Diffstat (limited to 'bundles/org.eclipse.swt/Eclipse SWT/motif/org/eclipse/swt/widgets/FontDialog.java')
-rwxr-xr-x | bundles/org.eclipse.swt/Eclipse SWT/motif/org/eclipse/swt/widgets/FontDialog.java | 1176 |
1 files changed, 1176 insertions, 0 deletions
diff --git a/bundles/org.eclipse.swt/Eclipse SWT/motif/org/eclipse/swt/widgets/FontDialog.java b/bundles/org.eclipse.swt/Eclipse SWT/motif/org/eclipse/swt/widgets/FontDialog.java new file mode 100755 index 0000000000..7107e8e7f6 --- /dev/null +++ b/bundles/org.eclipse.swt/Eclipse SWT/motif/org/eclipse/swt/widgets/FontDialog.java @@ -0,0 +1,1176 @@ +/******************************************************************************* + * Copyright (c) 2000, 2009 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); +} + +} |