From 3892bfc7bda026dfc5c7718a9f52e94c73ada5c0 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Andre=CC=81=20Berg?= Date: Fri, 10 May 2013 20:48:08 +0200 Subject: [PATCH 1/2] Bug-fix: code font unreadable on OS X for Aptana Themes Python scopes help text. Switch to using FontUtils and IFontUsage which were introduced earlier when similar problems erupted for specific dialogs on OS X. Doesn't change anything on Linux and Windows actually, but makes it so the desired intent is mirrored on OS X. FontUtils version bumped to 0.2 --- .../src/org/python/pydev/core/FontUtils.java | 232 ++++++++++-------- .../src/org/python/pydev/core/IFontUsage.java | 97 ++++---- .../pydev/red_core/AddRedCorePreferences.java | 4 +- 3 files changed, 183 insertions(+), 150 deletions(-) diff --git a/plugins/org.python.pydev.core/src/org/python/pydev/core/FontUtils.java b/plugins/org.python.pydev.core/src/org/python/pydev/core/FontUtils.java index 12d894d71..216da9352 100644 --- a/plugins/org.python.pydev.core/src/org/python/pydev/core/FontUtils.java +++ b/plugins/org.python.pydev.core/src/org/python/pydev/core/FontUtils.java @@ -1,103 +1,129 @@ -/** - * Copyright (c) 2005-2011 by Appcelerator, Inc. All Rights Reserved. - * Licensed under the terms of the Eclipse Public License (EPL). - * Please see the license.txt included with this distribution for details. - * Any modifications to this file must keep this entire header intact. - */ -package org.python.pydev.core; - -import org.eclipse.core.runtime.Platform; -import org.eclipse.jface.resource.JFaceResources; -import org.eclipse.osgi.service.environment.Constants; -import org.eclipse.swt.SWT; -import org.eclipse.swt.graphics.FontData; - -import com.aptana.shared_core.structure.Tuple; - -/** - *

FontUtils provides helper methods dealing with - * Fonts.

- * - * @author André Berg - * @version 0.1 - */ -public class FontUtils { - - /** - * Selects a proper font name and height for various usage cases of monospaced fonts throughout Pydev. - * - * @param usage intended usage. See {@link IFontUsage} for valid values. - * @return a {@link Tuple} containing the font name as {@link String} and the base height as {@link Integer}. - * @throws IllegalArgumentException if usage is not found in {@link IFontUsage}. - */ - private static Tuple getCodeFontNameAndHeight(int usage) throws IllegalArgumentException { - String fontName = "Courier New"; - int fontHeight = 10; - if (Platform.getOS().equals(Constants.OS_MACOSX)) { - switch (usage) { - case IFontUsage.STYLED: - fontName = "Monaco"; - fontHeight = 11; - break; - case IFontUsage.DIALOG: - // on OS X we need a different font because - // under Mac SWT the bitmap font rasterizer - // doesn't take hinting into account and thus - // makes small fonts rendered as bitmaps unreadable - // see http://aptanastudio.tenderapp.com/discussions/problems/2052-some-dialogs-have-unreadable-small-font-size - fontName = "Courier"; - fontHeight = 11; - break; - case IFontUsage.WIDGET: - fontName = "Monaco"; - fontHeight = 9; - break; - case IFontUsage.IMAGECACHE: - fontName = "Monaco"; - fontHeight = 11; - break; - - default: - throw new IllegalArgumentException( - "Invalid usage. See org.python.pydev.core.IFontUsage for valid values."); - } - } else { - switch (usage) { - case IFontUsage.STYLED: - fontName = "Courier New"; - fontHeight = 10; - break; - case IFontUsage.DIALOG: - fontName = "Courier New"; - fontHeight = 8; - break; - case IFontUsage.WIDGET: - fontName = "Courier New"; - fontHeight = 10; - break; - case IFontUsage.IMAGECACHE: - fontName = "Courier New"; - fontHeight = 9; - break; - - default: - throw new IllegalArgumentException( - "Invalid usage. See org.python.pydev.core.IFontUsage for valid values."); - } - } - return new Tuple(fontName, fontHeight); - } - - public static FontData getFontData(int usage, boolean useDefaultJFaceFontIfPossible) { - if (useDefaultJFaceFontIfPossible) { - FontData[] textFontData = JFaceResources.getTextFont().getFontData(); - if (textFontData.length == 1) { - return textFontData[0]; - } - } - Tuple codeFontDetails = FontUtils.getCodeFontNameAndHeight(IFontUsage.IMAGECACHE); - String fontName = codeFontDetails.o1; - int base = codeFontDetails.o2.intValue(); - return new FontData(fontName, base, SWT.BOLD); - } -} +/** + * Copyright (c) 2005-2011 by Appcelerator, Inc. All Rights Reserved. + * Licensed under the terms of the Eclipse Public License (EPL). + * Please see the license.txt included with this distribution for details. + * Any modifications to this file must keep this entire header intact. + */ +package org.python.pydev.core; + +import org.eclipse.core.runtime.Platform; +import org.eclipse.jface.resource.JFaceResources; +import org.eclipse.osgi.service.environment.Constants; +import org.eclipse.swt.SWT; +import org.eclipse.swt.graphics.FontData; + +import com.aptana.shared_core.structure.Tuple; + +/** + *

FontUtils provides helper methods dealing with + * Fonts.

+ * + * @author André Berg + * @version 0.2 + */ +public class FontUtils { + + /** + * Selects a proper font name and height for various usage cases of monospaced fonts throughout Pydev. + * + * @param usage intended usage. See {@link IFontUsage} for valid values. + * @return a {@link Tuple} containing the font name as {@link String} and the base height as {@link Integer}. + * @throws IllegalArgumentException if usage is not found in {@link IFontUsage}. + */ + private static Tuple getCodeFontNameAndHeight(int usage) throws IllegalArgumentException { + String fontName = "Courier New"; + int fontHeight = 10; + if (Platform.getOS().equals(Constants.OS_MACOSX)) { + switch (usage) { + case IFontUsage.STYLED: + fontName = "Monaco"; + fontHeight = 11; + break; + case IFontUsage.DIALOG: + // on OS X we need a different font because + // under Mac SWT the bitmap font rasterizer + // doesn't take hinting into account and thus + // makes small fonts rendered as bitmaps unreadable + // see http://aptanastudio.tenderapp.com/discussions/problems/2052-some-dialogs-have-unreadable-small-font-size + fontName = "Courier"; + fontHeight = 11; + break; + case IFontUsage.WIDGET: + fontName = "Monaco"; + fontHeight = 9; + break; + case IFontUsage.IMAGECACHE: + fontName = "Monaco"; + fontHeight = 11; + break; + case IFontUsage.SMALLUI: + fontName = "Monaco"; + fontHeight = 9; + break; + + default: + throw new IllegalArgumentException( + "Invalid usage. See org.python.pydev.core.IFontUsage for valid values."); + } + } else { + switch (usage) { + case IFontUsage.STYLED: + fontName = "Courier New"; + fontHeight = 10; + break; + case IFontUsage.DIALOG: + fontName = "Courier New"; + fontHeight = 8; + break; + case IFontUsage.WIDGET: + fontName = "Courier New"; + fontHeight = 10; + break; + case IFontUsage.IMAGECACHE: + fontName = "Courier New"; + fontHeight = 9; + break; + case IFontUsage.SMALLUI: + fontName = "Courier New"; + fontHeight = 8; + break; + + default: + throw new IllegalArgumentException( + "Invalid usage. See org.python.pydev.core.IFontUsage for valid values."); + } + } + return new Tuple(fontName, fontHeight); + } + + + /** + * Calls {@link #getFontData(int, boolean)} with {@link SWT#NONE} for the style param. + * @see {@link #getFontData(int, int, boolean)} + */ + public static FontData getFontData(int usage, boolean useDefaultJFaceFontIfPossible) { + return getFontData(usage, SWT.NONE, useDefaultJFaceFontIfPossible); + } + + /** + * Select a monospaced font based on intended usage. + * Can be used to provide a consistend code font size between platforms. + * + * @param usage intended usage. See {@link IFontUsage} for valid values. + * @param style SWT style constants mask + * @param useDefaultJFaceFontIfPossible + * @return {@link FontData} object + */ + public static FontData getFontData(int usage, int style, boolean useDefaultJFaceFontIfPossible) { + if (useDefaultJFaceFontIfPossible) { + FontData[] textFontData = JFaceResources.getTextFont().getFontData(); + if (textFontData.length == 1) { + return textFontData[0]; + } + } + Tuple codeFontDetails = FontUtils.getCodeFontNameAndHeight(usage); + String fontName = codeFontDetails.o1; + int base = codeFontDetails.o2.intValue(); + return new FontData(fontName, base, style); + } +} diff --git a/plugins/org.python.pydev.core/src/org/python/pydev/core/IFontUsage.java b/plugins/org.python.pydev.core/src/org/python/pydev/core/IFontUsage.java index 1de25c30d..7fd1c9af1 100644 --- a/plugins/org.python.pydev.core/src/org/python/pydev/core/IFontUsage.java +++ b/plugins/org.python.pydev.core/src/org/python/pydev/core/IFontUsage.java @@ -1,46 +1,51 @@ -/** - * Copyright (c) 2005-2011 by Appcelerator, Inc. All Rights Reserved. - * Licensed under the terms of the Eclipse Public License (EPL). - * Please see the license.txt included with this distribution for details. - * Any modifications to this file must keep this entire header intact. - */ -package org.python.pydev.core; - -/** - * IFontUsage is an enum-like interface describing usage cases - * for fonts used throughout Pydev. - *

- * It is used primarily by {@link FontUtils} to have all font usages - * in a central place to ease future edits. - *

- *

- * - * - * - * - * - * - *
valueused for
STYLEDstyled text widgets (ex. Editor prefs)
DIALOGmodal dialogs (ex. Py2To3)
WIDGETother widgets (ex. Code Coverage view or Comment Blocks prefs)
IMAGECACHEoverlaying monospaced text onto images
- *

- * - * @author André Berg - * @version 0.1 - */ -public interface IFontUsage { - /** - * used for styled text widgets (ex. Editor prefs) - */ - public static final int STYLED = 0; - /** - * used for modal dialogs (ex. Py2To3 dialog) - */ - public static final int DIALOG = 1; - /** - * used for other widgets (ex. Code Coverage view or Comment Blocks prefs) - */ - public static final int WIDGET = 2; - /** - * used in {@link org.python.pydev.core.bundle.ImageCache ImageCache} for overlaying code text onto images - */ - public static final int IMAGECACHE = 3; -} +/** + * Copyright (c) 2005-2011 by Appcelerator, Inc. All Rights Reserved. + * Licensed under the terms of the Eclipse Public License (EPL). + * Please see the license.txt included with this distribution for details. + * Any modifications to this file must keep this entire header intact. + */ +package org.python.pydev.core; + +/** + * IFontUsage is an enum-like interface describing usage cases + * for fonts used throughout Pydev. + *

+ * It is used primarily by {@link FontUtils} to have all font usages + * in a central place to ease future edits. + *

+ *

+ * + * + * + * + * + * + * + *
valueused for
STYLEDstyled text widgets (ex. Editor prefs)
DIALOGmodal dialogs (ex. Py2To3)
WIDGETother widgets (ex. Code Coverage view or Comment Blocks prefs)
IMAGECACHEoverlaying monospaced text onto images
SMALLUIfor UI layouts where space is at a premium
+ *

+ * + * @author André Berg + * @version 0.2 + */ +public interface IFontUsage { + /** + * used for styled text widgets (ex. Editor prefs) + */ + public static final int STYLED = 0; + /** + * used for modal dialogs (ex. Py2To3 dialog) + */ + public static final int DIALOG = 1; + /** + * used for other widgets (ex. Code Coverage view or Comment Blocks prefs) + */ + public static final int WIDGET = 2; + /** + * used in {@link org.python.pydev.core.bundle.ImageCache ImageCache} for overlaying code text onto images + */ + public static final int IMAGECACHE = 3; + /** + * used for UI layouts where space is at a premium + */ + public static final int SMALLUI = 4; +} diff --git a/plugins/org.python.pydev.red_core/src/org/python/pydev/red_core/AddRedCorePreferences.java b/plugins/org.python.pydev.red_core/src/org/python/pydev/red_core/AddRedCorePreferences.java index a39e2f5d2..bd4a0480a 100644 --- a/plugins/org.python.pydev.red_core/src/org/python/pydev/red_core/AddRedCorePreferences.java +++ b/plugins/org.python.pydev.red_core/src/org/python/pydev/red_core/AddRedCorePreferences.java @@ -26,6 +26,8 @@ import org.python.pydev.red_core.preferences.PydevRedCorePreferencesInitializer; import org.python.pydev.utils.LabelFieldEditor; import org.python.pydev.utils.LinkFieldEditor; +import org.python.pydev.core.FontUtils; +import org.python.pydev.core.IFontUsage; import com.aptana.editor.common.CommonEditorPlugin; import com.aptana.theme.IThemeManager; @@ -225,7 +227,7 @@ public void widgetDefaultSelected(SelectionEvent e) { "Prompt: console.prompt\n" + "", appearanceComposite); Label labelControl = labelFieldEditor.getLabelControl(appearanceComposite); try { - FontData labelFontData = new FontData("Courier New", 8, SWT.NONE); + FontData labelFontData = FontUtils.getFontData(IFontUsage.SMALLUI, false); labelControl.setFont(new Font(labelControl.getDisplay(), labelFontData)); } catch (Throwable e) { //ignore From 2f0fe201692c813913d5c2e189b6dab7d37ea131 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Andre=CC=81=20Berg?= Date: Fri, 10 May 2013 20:53:08 +0200 Subject: [PATCH 2/2] New feature: PyEditor save actions. First action updates a module level date field. --- .../org/python/pydev/core/SystemUtils.java | 62 +++++ plugins/org.python.pydev/plugin.xml | 6 + .../src/org/python/pydev/editor/PyEdit.java | 46 ++++ .../saveactions/PydevDateFieldNameEditor.java | 39 +++ .../saveactions/PydevSaveActionsPrefPage.java | 231 ++++++++++++++++++ 5 files changed, 384 insertions(+) create mode 100644 plugins/org.python.pydev.core/src/org/python/pydev/core/SystemUtils.java create mode 100755 plugins/org.python.pydev/src/org/python/pydev/editor/saveactions/PydevDateFieldNameEditor.java create mode 100755 plugins/org.python.pydev/src/org/python/pydev/editor/saveactions/PydevSaveActionsPrefPage.java diff --git a/plugins/org.python.pydev.core/src/org/python/pydev/core/SystemUtils.java b/plugins/org.python.pydev.core/src/org/python/pydev/core/SystemUtils.java new file mode 100644 index 000000000..c435cc47f --- /dev/null +++ b/plugins/org.python.pydev.core/src/org/python/pydev/core/SystemUtils.java @@ -0,0 +1,62 @@ +package org.python.pydev.core; + +import java.awt.Desktop; +import java.net.URI; +import java.net.URISyntaxException; +import java.net.URL; + +import org.eclipse.ui.PartInitException; +import org.eclipse.ui.PlatformUI; +import org.eclipse.ui.browser.IWebBrowser; +import org.python.pydev.core.log.Log; + +/** + * Utils operating system functionality. + * + * @author André Berg + * @version 0.1 + */ +public class SystemUtils { + + /** + * Open webpage given by URI with the default system browser. + */ + public static void openWebpage(URI uri) { + Desktop desktop = Desktop.isDesktopSupported() ? Desktop.getDesktop() : null; + if (desktop != null && desktop.isSupported(Desktop.Action.BROWSE)) { + try { + desktop.browse(uri); + } catch (Exception e) { + e.printStackTrace(); + } + } + } + + /** + * Open webpage given by URL with the default system browser. + */ + public static void openWebpage(URL url) { + try { + openWebpage(url.toURI()); + } catch (URISyntaxException e) { + e.printStackTrace(); + } + } + + /** + * Open a webpage in Eclipse's default browser. + * + * @param url URL address of the webpage + * @param id String id for the newly created browser view + */ + public static void openWebpageInEclipse(URL url, String id) { + IWebBrowser browser; + try { + browser = PlatformUI.getWorkbench().getBrowserSupport().createBrowser(id); + browser.openURL(url); + } catch (PartInitException e) { + Log.log(e); + } + } +} + diff --git a/plugins/org.python.pydev/plugin.xml b/plugins/org.python.pydev/plugin.xml index 6c7f1e0b9..5d9636b28 100644 --- a/plugins/org.python.pydev/plugin.xml +++ b/plugins/org.python.pydev/plugin.xml @@ -364,6 +364,12 @@ id="org.python.pydev.editor.codefolding.PyDevCodeFoldingPrefPage" name="Code Folding"> + + Supported tokens", p, + new PydevSaveActionsPrefPage.PydevSaveActionsPageLinkListener(), + dateFormatHelpLinkTooltip, tooltipPresenter); + addField(dateFormatHelpLinkEditor); + + } + + public void init(IWorkbench workbench) { + } + + public static boolean getDateFieldActionEnabled() { + return PydevPrefs.getPreferences().getBoolean(ENABLE_DATE_FIELD_ACTION); + } + + public static String getDateFieldName() { + final String fieldName = PydevPrefs.getPreferences().getString(DATE_FIELD_NAME); + if (fieldName.isEmpty()) { + return DEFAULT_DATE_FIELD_NAME; + } + return fieldName; + } + + public static String getDateFieldFormat() { + final String fieldName = PydevPrefs.getPreferences().getString(DATE_FIELD_FORMAT); + if (fieldName.isEmpty()) { + return DEFAULT_DATE_FIELD_FORMAT; + } + return fieldName; } + + protected void performDefaults() { + final Composite p = getFieldEditorParent(); + enableDateFieldActionEditor.loadDefault(); + dateFormatEditor.loadDefault(); + fieldNameEditor.loadDefault(); + dateFormatEditor.setEnabled(false, p); + fieldNameEditor.setEnabled(false, p); + super.updateApplyButton(); + } + + private void updateDateFieldStringEditorState() { + final boolean val = enableDateFieldActionEditor.getBooleanValue(); + final Composite p = getFieldEditorParent(); + dateFormatEditor.setEnabled(val, p); + fieldNameEditor.setEnabled(val, p); + } + + @Override + public void propertyChange(PropertyChangeEvent event) { + super.propertyChange(event); + if (enableDateFieldActionEditor.equals(event.getSource())) { + updateDateFieldStringEditorState(); + } + setValid((dateFormatEditor.isValid() && fieldNameEditor.isValid())); + updatePageButtons(); + } + + private void updatePageButtons() { + final boolean valid = isValid(); + final Button defaultButton = getShell().getDefaultButton(); + if (!valid) { + getApplyButton().setEnabled(false); + if (defaultButton != null) { + defaultButton.setEnabled(false); + } + } else { + getApplyButton().setEnabled(true); + if (defaultButton != null) { + defaultButton.setEnabled(true); + } + } + } +}