diff --git a/app/src/processing/app/Base.java b/app/src/processing/app/Base.java index 4c76dc7b1..0e78015ca 100644 --- a/app/src/processing/app/Base.java +++ b/app/src/processing/app/Base.java @@ -101,10 +101,6 @@ public class Base { ContributionManagerDialog exampleManagerFrame; ContributionManagerDialog updateManagerFrame; - // set to true after the first time the menu is built. - // so that the errors while building don't show up again. - boolean builtOnce; - // Location for untitled items static File untitledFolder; @@ -1234,25 +1230,6 @@ public class Base { File entry = checkSketchFolder(subfolder, name); if (entry != null) { -// File entry = new File(subfolder, list[i] + getExtension()); -// // if a .pde file of the same prefix as the folder exists.. -// if (entry.exists()) { -// //String sanityCheck = sanitizedName(list[i]); -// //if (!sanityCheck.equals(list[i])) { -// if (!Sketch.isSanitaryName(list[i])) { -// if (!builtOnce) { -// String complaining = -// "The sketch \"" + list[i] + "\" cannot be used.\n" + -// "Sketch names must contain only basic letters and numbers\n" + -// "(ASCII-only with no spaces, " + -// "and it cannot start with a number).\n" + -// "To get rid of this message, remove the sketch from\n" + -// entry.getAbsolutePath(); -// Base.showMessage("Ignoring sketch with bad name", complaining); -// } -// continue; -// } - JMenuItem item = new JMenuItem(name); item.addActionListener(listener); item.setActionCommand(entry.getAbsolutePath()); @@ -1365,22 +1342,6 @@ public class Base { if (entry.exists()) { return entry; } - // for the new releases, don't bother lecturing.. just ignore the sketch - /* - if (!Sketch.isSanitaryName(list[i])) { - if (!builtOnce) { - String complaining = - "The sketch \"" + list[i] + "\" cannot be used.\n" + - "Sketch names must contain only basic letters and numbers\n" + - "(ASCII-only with no spaces, " + - "and it cannot start with a number).\n" + - "To get rid of this message, remove the sketch from\n" + - entry.getAbsolutePath(); - Base.showMessage("Ignoring sketch with bad name", complaining); - } - continue; - } - */ } return null; } diff --git a/app/src/processing/app/Editor.java b/app/src/processing/app/Editor.java index 87311016e..3a7afd4d1 100644 --- a/app/src/processing/app/Editor.java +++ b/app/src/processing/app/Editor.java @@ -89,10 +89,12 @@ public abstract class Editor extends JFrame implements RunnerListener { private Point sketchWindowLocation; // undo fellers - private JMenuItem undoItem, redoItem; + private JMenuItem undoItem, redoItem, copyItems, cutItems; protected UndoAction undoAction; protected RedoAction redoAction; /** the currently selected tab's undo manager */ + protected CopyAction copyAction; + protected CutAction cutAction; private UndoManager undo; // used internally for every edit. Groups hotkey-event text manipulations and // groups multi-character inputs into a single undos. @@ -439,6 +441,11 @@ public abstract class Editor extends JFrame implements RunnerListener { } + public EditorConsole getConsole() { + return console; + } + + // public Settings getTheme() { // return mode.getTheme(); @@ -722,23 +729,13 @@ public abstract class Editor extends JFrame implements RunnerListener { menu.addSeparator(); - // TODO "cut" and "copy" should really only be enabled - // if some text is currently selected - item = Toolkit.newJMenuItem(Language.text("menu.edit.cut"), 'X'); - item.addActionListener(new ActionListener() { - public void actionPerformed(ActionEvent e) { - handleCut(); - } - }); - menu.add(item); + cutItems = Toolkit.newJMenuItem("Cut", 'X'); + cutItems.addActionListener(cutAction = new CutAction()); + menu.add(cutItems); - item = Toolkit.newJMenuItem(Language.text("menu.edit.copy"), 'C'); - item.addActionListener(new ActionListener() { - public void actionPerformed(ActionEvent e) { - textarea.copy(); - } - }); - menu.add(item); + copyItems = Toolkit.newJMenuItem("Copy", 'C'); + copyItems.addActionListener(copyAction = new CopyAction()); + menu.add(copyItems); item = Toolkit.newJMenuItemShift(Language.text("menu.edit.copy_as_html"), 'C'); item.addActionListener(new ActionListener() { @@ -876,7 +873,25 @@ public abstract class Editor extends JFrame implements RunnerListener { } }); menu.add(item); - + // Listener to the Edit menu item + menu.addMenuListener(new MenuListener() { + + @Override + public void menuCanceled(MenuEvent e) { + } + + @Override + public void menuDeselected(MenuEvent e) { + } + /* Updating the copy and cut JMenuItems + * as soon as the Edit menu is selected + */ + @Override + public void menuSelected(MenuEvent e) { + copyAction.updateCopyState(); + cutAction.updateCutState(); + } + }); return menu; } @@ -1263,6 +1278,52 @@ public abstract class Editor extends JFrame implements RunnerListener { // . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . + class CutAction extends AbstractAction { + public CutAction() { + super("Cut"); + this.setEnabled(false); + } + + public void actionPerformed(ActionEvent e) { + System.out.println(e.getActionCommand()); + handleCut(); + } + + public void updateCutState() { + if (canCut()) { + cutItems.setEnabled(true); + } else { + cutItems.setEnabled(false); + } + } + + public boolean canCut() { + return textarea.isSelectionActive(); + } + } + + class CopyAction extends AbstractAction { + public CopyAction() { + super("Copy"); + this.setEnabled(false); + } + + public void actionPerformed(ActionEvent e) { + textarea.copy(); + } + + public void updateCopyState() { + if (canCopy()) { + copyItems.setEnabled(true); + } else { + copyItems.setEnabled(false); + } + } + + public boolean canCopy() { + return textarea.isSelectionActive(); + } + } class UndoAction extends AbstractAction { public UndoAction() { @@ -1889,6 +1950,7 @@ public abstract class Editor extends JFrame implements RunnerListener { protected void handleCommentUncomment() { + // log("Entering handleCommentUncomment()"); startCompoundEdit(); String prefix = getCommentPrefix(); @@ -1911,32 +1973,41 @@ public abstract class Editor extends JFrame implements RunnerListener { // If the text is empty, ignore the user. // Also ensure that all lines are commented (not just the first) // when determining whether to comment or uncomment. - int length = textarea.getDocumentLength(); boolean commented = true; for (int i = startLine; commented && (i <= stopLine); i++) { - int pos = textarea.getLineStartOffset(i); - if (pos + prefixLen > length) { - commented = false; - } else { - // Check the first characters to see if it's already a comment. - String begin = textarea.getText(pos, prefixLen); - //System.out.println("begin is '" + begin + "'"); - commented = begin.equals(prefix); - } + String lineText = textarea.getLineText(i).trim(); + if (lineText.length() == 0) + continue; //ignore blank lines + commented = lineText.startsWith(prefix); } + // log("Commented: " + commented); + + // This is the line start offset of the first line, which is added to + // all other lines while adding a comment. Required when commenting + // lines which have uneven whitespaces in the beginning. Makes the + // commented lines look more uniform. + int lso = Math.abs(textarea.getLineStartNonWhiteSpaceOffset(startLine) + - textarea.getLineStartOffset(startLine)); + for (int line = startLine; line <= stopLine; line++) { - int location = textarea.getLineStartOffset(line); + int location = textarea.getLineStartNonWhiteSpaceOffset(line); + String lineText = textarea.getLineText(line); + if (lineText.trim().length() == 0) + continue; //ignore blank lines if (commented) { // remove a comment - textarea.select(location, location + prefixLen); - if (textarea.getSelectedText().equals(prefix)) { - textarea.setSelectedText(""); + if (lineText.trim().startsWith(prefix + " ")) { + textarea.select(location, location + prefixLen + 1); + } else { + textarea.select(location, location + prefixLen); } + textarea.setSelectedText(""); } else { // add a comment + location = textarea.getLineStartOffset(line) + lso; textarea.select(location, location); - textarea.setSelectedText(prefix); + textarea.setSelectedText(prefix + " "); //Add a '// ' } } // Subtract one from the end, otherwise selects past the current line. diff --git a/app/src/processing/app/EditorConsole.java b/app/src/processing/app/EditorConsole.java index 935539841..eee75c099 100644 --- a/app/src/processing/app/EditorConsole.java +++ b/app/src/processing/app/EditorConsole.java @@ -59,6 +59,9 @@ public class EditorConsole extends JScrollPane { int maxLineCount; + PrintStream sketchOut; + PrintStream sketchErr; + // Single static instance shared because there's only one real System.out. // Within the input handlers, the currentConsole variable will be used to // echo things to the correct location. @@ -99,8 +102,8 @@ public class EditorConsole extends JScrollPane { File errFile = new File(consoleDir, stamp + ".err"); stderrFile = new FileOutputStream(errFile); - consoleOut = new PrintStream(new EditorConsoleStream(false)); - consoleErr = new PrintStream(new EditorConsoleStream(true)); + consoleOut = new PrintStream(new EditorConsoleStream(false, null)); + consoleErr = new PrintStream(new EditorConsoleStream(true, null)); System.setOut(consoleOut); System.setErr(consoleErr); @@ -148,6 +151,9 @@ public class EditorConsole extends JScrollPane { setBorder(null); } + sketchOut = new PrintStream(new EditorConsoleStream(false, this)); + sketchErr = new PrintStream(new EditorConsoleStream(true, this)); + // periodically post buffered messages to the console // should the interval come from the preferences file? new javax.swing.Timer(250, new ActionListener() { @@ -163,6 +169,14 @@ public class EditorConsole extends JScrollPane { }).start(); } + public PrintStream getOut() { + return sketchOut; + } + + public PrintStream getErr() { + return sketchErr; + } + /** * Update the font family and sizes based on the Preferences window. @@ -244,7 +258,7 @@ public class EditorConsole extends JScrollPane { * folder itself is deleted, which can't be guaranteed when using * the deleteOnExit() method. */ - public void handleQuit() { + public static void handleQuit() { // replace original streams to remove references to console's streams System.setOut(systemOut); System.setErr(systemErr); @@ -312,12 +326,13 @@ public class EditorConsole extends JScrollPane { private static class EditorConsoleStream extends OutputStream { - //static EditorConsole current; final boolean err; // whether stderr or stdout final byte single[] = new byte[1]; + EditorConsole console; - public EditorConsoleStream(boolean err) { + public EditorConsoleStream(boolean err, EditorConsole console) { this.err = err; + this.console = console; } public void close() { } @@ -329,19 +344,10 @@ public class EditorConsole extends JScrollPane { } public void write(byte b[], int offset, int length) { - if (currentConsole != null) { - //currentConsole.write(b, offset, length, err); -// currentConsole.message(new String(b, offset, length), err, false); + if (console != null) + console.message(new String(b, offset, length), err); + else if (currentConsole != null) currentConsole.message(new String(b, offset, length), err); - } else { - try { - if (err) { - systemErr.write(b); - } else { - systemOut.write(b); - } - } catch (IOException e) { } // just ignore, where would we write? - } final OutputStream echo = err ? stderrFile : stdoutFile; if (echo != null) { diff --git a/app/src/processing/app/EditorHeader.java b/app/src/processing/app/EditorHeader.java index b49be2cd5..89044983e 100644 --- a/app/src/processing/app/EditorHeader.java +++ b/app/src/processing/app/EditorHeader.java @@ -119,7 +119,6 @@ public class EditorHeader extends JComponent { if ((x > menuLeft) && (x < menuRight)) { popup.show(EditorHeader.this, x, y); - } else { Sketch sketch = editor.getSketch(); // for (int i = 0; i < sketch.getCodeCount(); i++) { @@ -469,13 +468,17 @@ public class EditorHeader extends JComponent { // may be redundant. repaint(); } - public void popupMenuWillBecomeInvisible(PopupMenuEvent e) { } public void popupMenuWillBecomeVisible(PopupMenuEvent e) { } }); */ } JMenuItem item; + InputMap mInputMap = editor.getRootPane().getInputMap(JComponent.WHEN_ANCESTOR_OF_FOCUSED_COMPONENT); + ActionMap mActionMap = editor.getRootPane().getActionMap(); + Action action; + String mapKey; + KeyStroke keyStroke; // maybe this shouldn't have a command key anyways.. // since we're not trying to make this a full ide.. @@ -508,75 +511,93 @@ public class EditorHeader extends JComponent { */ //item = new JMenuItem("New Tab"); - item = Toolkit.newJMenuItemShift(Language.text("editor.header.new_tab"), 'N'); - item.addActionListener(new ActionListener() { - public void actionPerformed(ActionEvent e) { - editor.getSketch().handleNewCode(); - editor.setWatcherSave(); - } - }); + item = Toolkit.newJMenuItemShift(Language.text("editor.header.new_tab"), KeyEvent.VK_N); + action = new AbstractAction() { + @Override + public void actionPerformed(ActionEvent e) { + editor.getSketch().handleNewCode(); + editor.setWatcherSave(); + } + }; + mapKey = "editor.header.new_tab"; + keyStroke = KeyStroke.getKeyStroke(KeyEvent.VK_N, Toolkit.SHORTCUT_ALT_KEY_MASK); + mInputMap.put(keyStroke, mapKey); + mActionMap.put(mapKey, action); + item.addActionListener(action); menu.add(item); item = new JMenuItem(Language.text("editor.header.rename")); - item.addActionListener(new ActionListener() { - public void actionPerformed(ActionEvent e) { - editor.getSketch().handleRenameCode(); - /* - // this is already being called by nameCode(), the second stage of rename - if (editor.sketch.current == editor.sketch.code[0]) { - editor.sketchbook.rebuildMenus(); - } - */ + action = new AbstractAction() { + @Override + public void actionPerformed(ActionEvent e) { + editor.getSketch().handleRenameCode(); + /* + // this is already being called by nameCode(), the second stage of rename + if (editor.sketch.current == editor.sketch.code[0]) { + editor.sketchbook.rebuildMenus(); } - }); + */ + } + }; + item.addActionListener(action); menu.add(item); - item = new JMenuItem(Language.text("editor.header.delete")); - item.addActionListener(new ActionListener() { - public void actionPerformed(ActionEvent e) { - Sketch sketch = editor.getSketch(); - if (!Base.isMacOS() && // ok on OS X - editor.base.editors.size() == 1 && // mmm! accessor - sketch.getCurrentCodeIndex() == 0) { - Base.showWarning(Language.text("editor.header.delete.warning.title"), - Language.text("editor.header.delete.warning.text"), null); - } else { - editor.getSketch().handleDeleteCode(); - editor.setWatcherSave(); - } + item = Toolkit.newJMenuItemShift(Language.text("editor.header.delete"), KeyEvent.VK_D); + action = new AbstractAction() { + @Override + public void actionPerformed(ActionEvent e) { + Sketch sketch = editor.getSketch(); + if (!Base.isMacOS() && // ok on OS X + editor.base.editors.size() == 1 && // mmm! accessor + sketch.getCurrentCodeIndex() == 0) { + Base.showWarning(Language.text("editor.header.delete.warning.title"), + Language.text("editor.header.delete.warning.text"), null); + } else { + editor.getSketch().handleDeleteCode(); + editor.setWatcherSave(); } - }); + } + }; + mapKey = "editor.header.delete"; + keyStroke = KeyStroke.getKeyStroke(KeyEvent.VK_D, Toolkit.SHORTCUT_ALT_KEY_MASK); + mInputMap.put(keyStroke, mapKey); + mActionMap.put(mapKey, action); + item.addActionListener(action); menu.add(item); menu.addSeparator(); // KeyEvent.VK_LEFT and VK_RIGHT will make Windows beep - - item = new JMenuItem(Language.text("editor.header.previous_tab")); - KeyStroke ctrlAltLeft = - KeyStroke.getKeyStroke(KeyEvent.VK_LEFT, Toolkit.SHORTCUT_ALT_KEY_MASK); - item.setAccelerator(ctrlAltLeft); - // this didn't want to work consistently - /* - item.addActionListener(new ActionListener() { - public void actionPerformed(ActionEvent e) { - editor.sketch.prevCode(); - } - }); - */ + item = Toolkit.newJMenuItemAlt(Language.text("editor.header.previous_tab"), KeyEvent.VK_LEFT); + action = new AbstractAction() { + @Override + public void actionPerformed(ActionEvent e) { +// Sketch sketch = editor.getSketch(); +// sketch.setCurrentCode(sketch.getCurrentCodeIndex() - 1); + editor.getSketch().handlePrevCode(); + } + }; + mapKey = "editor.header.previous_tab"; + keyStroke = KeyStroke.getKeyStroke(KeyEvent.VK_LEFT, Toolkit.SHORTCUT_ALT_KEY_MASK); + mInputMap.put(keyStroke, mapKey); + mActionMap.put(mapKey, action); + item.addActionListener(action); menu.add(item); - item = new JMenuItem(Language.text("editor.header.next_tab")); - KeyStroke ctrlAltRight = - KeyStroke.getKeyStroke(KeyEvent.VK_RIGHT, Toolkit.SHORTCUT_ALT_KEY_MASK); - item.setAccelerator(ctrlAltRight); - /* - item.addActionListener(new ActionListener() { - public void actionPerformed(ActionEvent e) { - editor.sketch.nextCode(); - } - }); - */ + item = Toolkit.newJMenuItemAlt(Language.text("editor.header.next_tab"), KeyEvent.VK_RIGHT); + action = new AbstractAction() { + @Override + public void actionPerformed(ActionEvent e) { +// Sketch sketch = editor.getSketch(); +// sketch.setCurrentCode(sketch.getCurrentCodeIndex() + 1); + editor.getSketch().handleNextCode(); + } + }; + mapKey = "editor.header.next_tab"; + keyStroke = KeyStroke.getKeyStroke(KeyEvent.VK_RIGHT, Toolkit.SHORTCUT_ALT_KEY_MASK); + mInputMap.put(keyStroke, mapKey); + mActionMap.put(mapKey, action); + item.addActionListener(action); menu.add(item); Sketch sketch = editor.getSketch(); @@ -584,10 +605,10 @@ public class EditorHeader extends JComponent { menu.addSeparator(); ActionListener jumpListener = new ActionListener() { - public void actionPerformed(ActionEvent e) { - editor.getSketch().setCurrentCode(e.getActionCommand()); - } - }; + public void actionPerformed(ActionEvent e) { + editor.getSketch().setCurrentCode(e.getActionCommand()); + } + }; for (SketchCode code : sketch.getCode()) { item = new JMenuItem(code.getPrettyName()); item.addActionListener(jumpListener); diff --git a/app/src/processing/app/Language.java b/app/src/processing/app/Language.java index e18fb3aa2..7d2a561ec 100644 --- a/app/src/processing/app/Language.java +++ b/app/src/processing/app/Language.java @@ -22,47 +22,53 @@ package processing.app; import java.io.*; +import java.net.MalformedURLException; import java.net.URL; +import java.net.URLClassLoader; import java.net.URLConnection; import java.util.*; -import processing.core.PApplet; - /** * Internationalization (i18n) - * @author Darius Morawiec */ -public class Language { - static private final String FILE = "processing.app.languages.PDE"; - //static private final String LISTING = "processing/app/languages/languages.txt"; +public class Language { + /** + * Store the language information in a file separate from the preferences, + * because preferences need the language on load time. + */ + static private final String LANG_FILE = "language.properties"; + + /** Directory of available languages */ + static private final String LANG_FILES = "languages"; - // Store the language information in a file separate from the preferences, - // because preferences need the language on load time. - static protected final String PREF_FILE = "language.txt"; - static protected final File prefFile = Base.getSettingsFile(PREF_FILE); + /** Definition of package for fallback */ + //static private final String LANG_PACKAGE = "processing.app.languages"; + static private final String LANG_BASE_NAME = "PDE"; + + static private Properties props; + static private File propsFile; + + /** Language */ + private String language; + + /** Available languages */ + private HashMap languages; + + /** Define the location of language files */ + static private File langFiles = Base.getSettingsFile(LANG_FILES); + + /** Set version of current PDE */ + static private final String version = Base.getVersionName(); + static private ResourceBundle bundle; /** Single instance of this Language class */ static private volatile Language instance; - - /** The system language */ - private String language; - - /** Available languages */ - private HashMap languages; - - private ResourceBundle bundle; - + private Language() { - String systemLanguage = Locale.getDefault().getLanguage(); - language = loadLanguage(); - boolean writePrefs = false; - - if (language == null) { - language = systemLanguage; - writePrefs = true; - } + // Set default language + language = "en"; // Set available languages languages = new HashMap(); @@ -70,18 +76,85 @@ public class Language { languages.put(code, Locale.forLanguageTag(code).getDisplayLanguage(Locale.forLanguageTag(code))); } - // Set default language - if (!languages.containsKey(language)) { - language = "en"; - writePrefs = true; - } + if(loadProps()){ - if (writePrefs) { - saveLanguage(language); + boolean updateProps = false; + boolean updateLangFiles = false; + + // Define and check version + if(props.containsKey("version") && langFiles.exists()){ + if(!props.getProperty("version").equals(version)){ + updateLangFiles = true; + } + } else { + updateLangFiles = true; + } + + // Copy new language properties + if(updateLangFiles){ + if(updateLangFiles()){ + props.setProperty("version", version); + updateProps = true; + } + } + + // Define language + if(props.containsKey("language")){ + language = props.getProperty("language"); + } else { + if (!languages.containsKey(Locale.getDefault().getLanguage())) { + language = Locale.getDefault().getLanguage(); + } + props.setProperty("language", language); + updateProps = true; + } + + // Save changes + if(updateProps){ + updateProps(); + } + } + + try { + URL[] paths = { langFiles.toURI().toURL() }; + bundle = ResourceBundle.getBundle( + Language.LANG_BASE_NAME, + new Locale(language), + new URLClassLoader(paths), + new UTF8Control() + ); + } catch (MalformedURLException e) { + // Fallback: Does we need a fallback? +// bundle = ResourceBundle.getBundle( +// Language.LANG_PACKAGE+"."+Language.LANG_BASE_NAME, +// new Locale(this.language), +// new UTF8Control() +// ); + } + } + + + private static boolean updateLangFiles() { + // Delete old languages + if(langFiles.exists()){ + File[] lang = langFiles.listFiles(); + for (int i = 0; i < lang.length; i++) { + lang[i].delete(); + } + langFiles.delete(); + } + // Copy new languages + String javaPath = new File(Base.class.getProtectionDomain().getCodeSource().getLocation().getFile()).getParentFile().getAbsolutePath(); + try { + Base.copyDir( + new File(javaPath+"/lib/languages"), // from shared library folder + langFiles // to editable settings folder + ); + return true; + } catch (IOException e) { + e.printStackTrace(); + return false; } - - // Get bundle with translations (processing.app.language.PDE) - bundle = ResourceBundle.getBundle(Language.FILE, new Locale(this.language), new UTF8Control()); } @@ -101,6 +174,8 @@ public class Language { "tr", // Turkish "zh" // chinese }; + + Arrays.sort(SUPPORTED); return SUPPORTED; /* @@ -120,21 +195,58 @@ public class Language { */ } - - /** Read the saved language */ - static private String loadLanguage() { - try { - if (prefFile.exists()) { - String language = PApplet.loadStrings(prefFile)[0]; - language = language.trim().toLowerCase(); - if (!language.equals("")) { - return language; - } - } - } catch (Exception e) { - e.printStackTrace(); + + /** Load properties of language.properties */ + static private boolean loadProps(){ + if (props == null) { + props = new Properties(); } - return null; + propsFile = Base.getSettingsFile(LANG_FILE); + if(!propsFile.exists()){ + try { + Base.saveFile("", propsFile); + } catch (IOException e) { + e.printStackTrace(); + return false; + } + } + InputStream is = null; + try { + is = new FileInputStream(propsFile); + } catch (Exception e) { + return false; + } + try { + props.load(is); + } catch (IOException e) { + e.printStackTrace(); + return false; + } + try { + is.close(); + } catch (IOException e) { + e.printStackTrace(); + return false; + } + return true; + } + + + /** Save changes in language.properties */ + static private boolean updateProps(){ + if (props != null) { + try { + OutputStream out = new FileOutputStream(propsFile); + props.store(out, "language preferences"); + } catch (FileNotFoundException e) { + e.printStackTrace(); + return false; + } catch (IOException e) { + e.printStackTrace(); + return false; + } + } + return true; } @@ -143,12 +255,12 @@ public class Language { * 'set' because a language change requires a restart of Processing. */ static public void saveLanguage(String language) { - try { - Base.saveFile(language, prefFile); - } catch (Exception e) { - e.printStackTrace(); + if (loadProps()) { + props.setProperty("language", language); + if (updateProps()) { + Base.getPlatform().saveLanguage(language); + } } - Base.getPlatform().saveLanguage(language); } @@ -164,66 +276,51 @@ public class Language { return instance; } - + /** Get translation from bundles. */ static public String text(String text) { - ResourceBundle bundle = init().bundle; - + init(); try { return bundle.getString(text); } catch (MissingResourceException e) { return text; } } - + static public String interpolate(String text, Object... arguments) { - return String.format(init().bundle.getString(text), arguments); + init(); + return String.format(bundle.getString(text), arguments); } static public String pluralize(String text, int count) { - ResourceBundle bundle = init().bundle; - + init(); String fmt = text + ".%s"; - if (bundle.containsKey(String.format(fmt, count))) { return interpolate(String.format(fmt, count), count); } return interpolate(String.format(fmt, "n"), count); } - + /** Get all available languages */ static public Map getLanguages() { return init().languages; } - + /** Get current language */ static public String getLanguage() { return init().language; } -// /** Set new language (called by Preferences) */ -// static public void setLanguage(String language) { -// this.language = language; -// -// try { -// File file = Base.getContentFile("lib/language.txt"); -// Base.saveFile(language, file); -// } catch (Exception e) { -// e.printStackTrace(); -// } -// } - - /** * Custom 'Control' class for consistent encoding. * http://stackoverflow.com/questions/4659929/how-to-use-utf-8-in-resource-properties-with-resourcebundle */ - static class UTF8Control extends ResourceBundle.Control { + static private class UTF8Control extends ResourceBundle.Control { public ResourceBundle newBundle(String baseName, Locale locale, String format, ClassLoader loader, boolean reload) throws IllegalAccessException, InstantiationException,IOException { // The below is a copy of the default implementation. String bundleName = toBundleName(baseName, locale); diff --git a/app/src/processing/app/Preferences.java b/app/src/processing/app/Preferences.java index 90d631aa7..9b141004a 100644 --- a/app/src/processing/app/Preferences.java +++ b/app/src/processing/app/Preferences.java @@ -63,8 +63,8 @@ public class Preferences { * Standardized width for buttons. Mac OS X 10.3 wants 70 as its default, * Windows XP needs 66, and my Ubuntu machine needs 80+, so 80 seems proper. */ - static public int BUTTON_WIDTH = - Integer.valueOf(Language.text("preferences.button.width")); + static public int BUTTON_WIDTH = + Integer.parseInt(Language.text("preferences.button.width")); /** height of the EditorHeader, EditorToolbar, and EditorStatus */ static final int GRID_SIZE = 32; diff --git a/app/src/processing/app/PreferencesFrame.java b/app/src/processing/app/PreferencesFrame.java index 25d41aa95..7064e3e6e 100644 --- a/app/src/processing/app/PreferencesFrame.java +++ b/app/src/processing/app/PreferencesFrame.java @@ -60,8 +60,8 @@ public class PreferencesFrame { JCheckBox memoryOverrideBox; JTextField memoryField; JCheckBox checkUpdatesBox; - JComboBox fontSizeField; - JComboBox consoleSizeField; + JComboBox fontSizeField; + JComboBox consoleSizeField; JCheckBox inputMethodBox; JCheckBox autoAssociateBox; @@ -73,13 +73,13 @@ public class PreferencesFrame { JCheckBox importSuggestionsBox; JCheckBox codeCompletionTriggerBox; - JComboBox displaySelectionBox; - JComboBox languageSelectionBox; + JComboBox displaySelectionBox; + JComboBox languageSelectionBox; int displayCount; String[] monoFontFamilies; - JComboBox fontSelectionBox; + JComboBox fontSelectionBox; /** Base object so that updates can be applied to the list of editors. */ Base base; @@ -152,7 +152,7 @@ public class PreferencesFrame { Container languageBox = Box.createHorizontalBox(); JLabel languageLabel = new JLabel(Language.text("preferences.language")+": "); languageBox.add(languageLabel); - languageSelectionBox = new JComboBox(); + languageSelectionBox = new JComboBox(); Map languages = Language.getLanguages(); String[] languageSelection = new String[languages.size()]; @@ -163,7 +163,7 @@ public class PreferencesFrame { languageSelection[i++] = lang.getValue(); } } - languageSelectionBox.setModel(new DefaultComboBoxModel(languageSelection)); + languageSelectionBox.setModel(new DefaultComboBoxModel(languageSelection)); languageBox.add(languageSelectionBox); label = new JLabel(" ("+Language.text("preferences.requires_restart")+")"); languageBox.add(label); @@ -189,7 +189,7 @@ public class PreferencesFrame { fontLabel.setToolTipText(fontTip); fontBox.add(fontLabel); // get a wide name in there before getPreferredSize() is called - fontSelectionBox = new JComboBox(new Object[] { Toolkit.getMonoFontName() }); + fontSelectionBox = new JComboBox(new String[] { Toolkit.getMonoFontName() }); fontSelectionBox.setToolTipText(fontTip); // fontSelectionBox.addItem(Toolkit.getMonoFont(size, style)); //updateDisplayList(); @@ -492,7 +492,7 @@ public class PreferencesFrame { final String tip = "" + Language.text("preferences.run_sketches_on_display.tip"); displayLabel.setToolTipText(tip); displayBox.add(displayLabel); - displaySelectionBox = new JComboBox(); + displaySelectionBox = new JComboBox(); updateDisplayList(); // needs to happen here for getPreferredSize() displayBox.add(displaySelectionBox); pain.add(displayBox); @@ -845,7 +845,7 @@ public class PreferencesFrame { void initFontList() { if (monoFontFamilies == null) { monoFontFamilies = Toolkit.getMonoFontFamilies(); - fontSelectionBox.setModel(new DefaultComboBoxModel(monoFontFamilies)); + fontSelectionBox.setModel(new DefaultComboBoxModel(monoFontFamilies)); String family = Preferences.get("editor.font.family"); // Set a reasonable default, in case selecting the family fails @@ -866,7 +866,7 @@ public class PreferencesFrame { // displaySelectionBox.add(String.valueOf(i + 1)); } // PApplet.println(items); - displaySelectionBox.setModel(new DefaultComboBoxModel(items)); + displaySelectionBox.setModel(new DefaultComboBoxModel(items)); // displaySelectionBox = new JComboBox(items); } } diff --git a/app/src/processing/app/Sketch.java b/app/src/processing/app/Sketch.java index 9f908902d..7006b329a 100644 --- a/app/src/processing/app/Sketch.java +++ b/app/src/processing/app/Sketch.java @@ -493,9 +493,10 @@ public class Sketch { // A regression introduced by Florian's bug report (below) years earlier. if (!(renamingCode && sanitaryName.equals(current.getPrettyName()))) { // Make sure no .pde *and* no .java files with the same name already exist + // (other than the one we are currently attempting to rename) // http://processing.org/bugs/bugzilla/543.html for (SketchCode c : code) { - if (sanitaryName.equalsIgnoreCase(c.getPrettyName())) { + if (c != current && sanitaryName.equalsIgnoreCase(c.getPrettyName())) { Base.showMessage("Nope", "A file named \"" + c.getFileName() + "\" already exists at\n" + "\"" + folder.getAbsolutePath() + "\""); @@ -1199,7 +1200,8 @@ public class Sketch { // System.out.println(current.visited); // } // if current is null, then this is the first setCurrent(0) - if ((currentIndex == which) && (current != null)) { + if (((currentIndex == which) && (current != null)) + || which >= codeCount || which < 0) { return; } diff --git a/app/src/processing/app/UpdateCheck.java b/app/src/processing/app/UpdateCheck.java index 23e5b96be..098eda1c2 100644 --- a/app/src/processing/app/UpdateCheck.java +++ b/app/src/processing/app/UpdateCheck.java @@ -25,6 +25,7 @@ package processing.app; import java.io.BufferedReader; import java.io.InputStream; import java.io.InputStreamReader; +import java.io.IOException; import java.net.URL; import java.util.Random; @@ -47,10 +48,12 @@ import processing.core.PApplet; * proposals and that kind of thing so that we can keep Processing free. */ public class UpdateCheck { - Base base; - String downloadURL = "http://processing.org/download/latest.txt"; + private final Base base; - static final long ONE_DAY = 24 * 60 * 60 * 1000; + static private final String DOWNLOAD_URL = "http://processing.org/download/"; + static private final String LATEST_URL = "http://processing.org/download/latest.txt"; + + static private final long ONE_DAY = 24 * 60 * 60 * 1000; public UpdateCheck(Base base) { @@ -60,22 +63,18 @@ public class UpdateCheck { try { Thread.sleep(20 * 1000); // give the PDE time to get rolling updateCheck(); + } catch (Exception e) { - // this can safely be ignored, too many instances where no net - // connection is available, so we'll leave it well alone. -// String msg = e.getMessage(); -// if (msg.contains("UnknownHostException")) { -// // nah, do nothing.. this happens when not connected to the net -// } else { -// e.printStackTrace(); -// } - } + // This can safely be ignored, too many situations where no net + // connection is available that behave in strange ways. + // Covers likely IOException, InterruptedException, and any others. + } } }, "Update Checker").start(); } - public void updateCheck() throws Exception { + public void updateCheck() throws IOException, InterruptedException { // generate a random id in case none exists yet Random r = new Random(); long id = r.nextLong(); @@ -95,7 +94,7 @@ public class UpdateCheck { System.getProperty("os.version") + "\t" + System.getProperty("os.arch")); - int latest = readInt(downloadURL + "?" + info); + int latest = readInt(LATEST_URL + "?" + info); String lastString = Preferences.get("update.last"); long now = System.currentTimeMillis(); @@ -123,12 +122,14 @@ public class UpdateCheck { // Wait for xml file to be downloaded and updates to come in. // (this should really be handled better). Thread.sleep(5 * 1000); - if ((!base.libraryManagerFrame.hasAlreadyBeenOpened() && - base.libraryManagerFrame.hasUpdates(base)) || - (!base.toolManagerFrame.hasAlreadyBeenOpened() && - base.toolManagerFrame.hasUpdates(base)) || - (!base.modeManagerFrame.hasAlreadyBeenOpened() && - base.modeManagerFrame.hasUpdates(base))) { + if ((!base.libraryManagerFrame.hasAlreadyBeenOpened() + && !base.toolManagerFrame.hasAlreadyBeenOpened() + && !base.modeManagerFrame.hasAlreadyBeenOpened() + && !base.exampleManagerFrame.hasAlreadyBeenOpened()) + && (base.libraryManagerFrame.hasUpdates(base) + || base.toolManagerFrame.hasUpdates(base) + || base.modeManagerFrame.hasUpdates(base) + || base.exampleManagerFrame.hasUpdates(base))) { promptToOpenContributionManager(); } } @@ -149,7 +150,7 @@ public class UpdateCheck { options, options[0]); if (result == JOptionPane.YES_OPTION) { - Base.openURL("http://processing.org/download/"); + Base.openURL(DOWNLOAD_URL); return true; } @@ -178,7 +179,7 @@ public class UpdateCheck { } - protected int readInt(String filename) throws Exception { + protected int readInt(String filename) throws IOException { URL url = new URL(filename); InputStream stream = url.openStream(); InputStreamReader isr = new InputStreamReader(stream); diff --git a/app/src/processing/app/contrib/ContributionListPanel.java b/app/src/processing/app/contrib/ContributionListPanel.java index 0a4c0ed8a..b5fa561ea 100644 --- a/app/src/processing/app/contrib/ContributionListPanel.java +++ b/app/src/processing/app/contrib/ContributionListPanel.java @@ -179,7 +179,7 @@ public class ContributionListPanel extends JPanel implements Scrollable, Contrib public void filterLibraries(List filteredContributions) { synchronized (panelByContribution) { - Set hiddenPanels = new TreeSet(contribListing.getComparator()); + Set hiddenPanels = new TreeSet(contribListing.getComparator()); hiddenPanels.addAll(panelByContribution.keySet()); for (Contribution info : filteredContributions) { diff --git a/app/src/processing/app/contrib/ContributionManagerDialog.java b/app/src/processing/app/contrib/ContributionManagerDialog.java index cab598c51..ce28a939f 100644 --- a/app/src/processing/app/contrib/ContributionManagerDialog.java +++ b/app/src/processing/app/contrib/ContributionManagerDialog.java @@ -46,7 +46,7 @@ public class ContributionManagerDialog { JFrame dialog; String title; ContributionFilter filter; - JComboBox categoryChooser; + JComboBox categoryChooser; JScrollPane scrollPane; ContributionListPanel contributionListPanel; StatusPanel status; @@ -219,7 +219,7 @@ public class ContributionManagerDialog { filterPanel.add(Box.createHorizontalStrut(5)); - categoryChooser = new JComboBox(); + categoryChooser = new JComboBox(); categoryChooser.setMaximumRowCount(20); updateCategoryChooser(); // filterPanel.add(categoryChooser, c); diff --git a/app/src/processing/app/tools/ColorSelector.java b/app/src/processing/app/tools/ColorSelector.java index f3bf693f7..b36a6ae12 100644 --- a/app/src/processing/app/tools/ColorSelector.java +++ b/app/src/processing/app/tools/ColorSelector.java @@ -43,7 +43,7 @@ public class ColorSelector implements Tool { * Only create one instance, otherwise we'll have dozens of animation * threads going if you open/close a lot of editor windows. */ - static ColorChooser selector; + private static volatile ColorChooser selector; private Editor editor; diff --git a/app/src/processing/app/tools/CreateFont.java b/app/src/processing/app/tools/CreateFont.java index 7d8f0427d..9ecee84be 100644 --- a/app/src/processing/app/tools/CreateFont.java +++ b/app/src/processing/app/tools/CreateFont.java @@ -54,7 +54,7 @@ public class CreateFont extends JFrame implements Tool { // Dimension windowSize; - JList fontSelector; + JList fontSelector; JTextField sizeSelector; JButton charsetButton; JCheckBox smoothBox; @@ -175,7 +175,7 @@ public class CreateFont extends JFrame implements Tool { list = new String[index]; System.arraycopy(flist, 0, list, 0, index); - fontSelector = new JList(list); + fontSelector = new JList(list); fontSelector.addListSelectionListener(new ListSelectionListener() { public void valueChanged(ListSelectionEvent e) { if (e.getValueIsAdjusting() == false) { @@ -499,14 +499,14 @@ class CharacterSelector extends JFrame { JRadioButton allCharsButton; JRadioButton unicodeCharsButton; JScrollPane unicodeBlockScroller; - JList charsetList; + JList charsetList; public CharacterSelector() { super("Character Selector"); charsetList = new CheckBoxList(); - DefaultListModel model = new DefaultListModel(); + DefaultListModel model = new DefaultListModel(); charsetList.setModel(model); for (String item : blockNames) { model.addElement(new JCheckBox(item)); @@ -824,7 +824,7 @@ class CharacterSelector extends JFrame { // collection, but it seems to have been picked up so many places with others // placing their copyright on it, that I haven't been able to determine the // original author. [fry 20100216] -class CheckBoxList extends JList { +class CheckBoxList extends JList { protected static Border noFocusBorder = new EmptyBorder(1, 1, 1, 1); public CheckBoxList() { @@ -836,8 +836,7 @@ class CheckBoxList extends JList { int index = locationToIndex(e.getPoint()); if (index != -1) { - JCheckBox checkbox = (JCheckBox) - getModel().getElementAt(index); + JCheckBox checkbox = getModel().getElementAt(index); checkbox.setSelected(!checkbox.isSelected()); repaint(); } @@ -864,4 +863,4 @@ class CheckBoxList extends JList { return checkbox; } } -} \ No newline at end of file +} diff --git a/app/src/processing/mode/java/Compiler.java b/app/src/processing/mode/java/Compiler.java index 30d1b0e1a..d82d7864f 100644 --- a/app/src/processing/mode/java/Compiler.java +++ b/app/src/processing/mode/java/Compiler.java @@ -131,12 +131,12 @@ public class Compiler { // so that it can grab the compiler JAR files from it. ClassLoader loader = build.mode.getClassLoader(); try { - Class batchClass = + Class batchClass = Class.forName("org.eclipse.jdt.core.compiler.batch.BatchCompiler", false, loader); - Class progressClass = + Class progressClass = Class.forName("org.eclipse.jdt.core.compiler.CompilationProgress", false, loader); - Class[] compileArgs = - new Class[] { String[].class, PrintWriter.class, PrintWriter.class, progressClass }; + Class[] compileArgs = + new Class[] { String[].class, PrintWriter.class, PrintWriter.class, progressClass }; Method compileMethod = batchClass.getMethod("compile", compileArgs); success = (Boolean) compileMethod.invoke(null, new Object[] { command, outWriter, writer, null }); diff --git a/app/src/processing/mode/java/PdeKeyListener.java b/app/src/processing/mode/java/PdeKeyListener.java index ec4655507..a286fd8ca 100644 --- a/app/src/processing/mode/java/PdeKeyListener.java +++ b/app/src/processing/mode/java/PdeKeyListener.java @@ -80,6 +80,7 @@ public class PdeKeyListener { Sketch sketch = editor.getSketch(); + /* if ((event.getModifiers() & CTRL_ALT) == CTRL_ALT) { if (code == KeyEvent.VK_LEFT) { sketch.handlePrevCode(); @@ -89,6 +90,7 @@ public class PdeKeyListener { return true; } } + */ if ((event.getModifiers() & InputEvent.META_MASK) != 0) { //event.consume(); // does nothing diff --git a/app/src/processing/mode/java/PresentMode.java b/app/src/processing/mode/java/PresentMode.java index 05ada7d9d..dc0f1dd11 100644 --- a/app/src/processing/mode/java/PresentMode.java +++ b/app/src/processing/mode/java/PresentMode.java @@ -49,11 +49,6 @@ public class PresentMode { //JMenu preferencesMenu; static JComboBox selector; - /** - * Index of the currently selected display to be used for present mode. - */ - static GraphicsDevice device; - static { GraphicsEnvironment environment = @@ -75,7 +70,6 @@ public class PresentMode { selector.addActionListener(new ActionListener() { public void actionPerformed(ActionEvent e) { int index = selector.getSelectedIndex(); - //device = devices[index]; Preferences.setInteger("run.present.display", index + 1); } }); diff --git a/app/src/processing/mode/java/runner/Runner.java b/app/src/processing/mode/java/runner/Runner.java index 4fbf5f8f1..35336047f 100644 --- a/app/src/processing/mode/java/runner/Runner.java +++ b/app/src/processing/mode/java/runner/Runner.java @@ -67,6 +67,9 @@ public class Runner implements MessageConsumer { protected Editor editor; protected JavaBuild build; protected Process process; + + protected PrintStream sketchErr; + protected PrintStream sketchOut; public Runner(JavaBuild build, RunnerListener listener) throws SketchException { @@ -76,15 +79,18 @@ public class Runner implements MessageConsumer { if (listener instanceof Editor) { this.editor = (Editor) listener; -// } else { -// System.out.println("actually it's a " + listener.getClass().getName()); + sketchErr = editor.getConsole().getErr(); + sketchOut = editor.getConsole().getOut(); + } else { + sketchErr = System.err; + sketchOut = System.out; } // Make sure all the imported libraries will actually run with this setup. int bits = Base.getNativeBits(); for (Library library : build.getImportedLibraries()) { if (!library.supportsArch(PApplet.platform, bits)) { - System.err.println(library.getName() + " does not run in " + bits + "-bit mode."); + sketchErr.println(library.getName() + " does not run in " + bits + "-bit mode."); int opposite = (bits == 32) ? 64 : 32; if (Base.isMacOS()) { //if (library.supportsArch(PConstants.MACOSX, opposite)) { // should always be true @@ -173,7 +179,7 @@ public class Runner implements MessageConsumer { try { Thread.sleep(100); } catch (InterruptedException e1) { - e1.printStackTrace(); + e1.printStackTrace(sketchErr); } } } @@ -388,18 +394,18 @@ public class Runner implements MessageConsumer { "Preferences window. For more information, read Help \u2192 Troubleshooting.", null); } else { for (String err : errorStrings) { - System.err.println(err); + sketchErr.println(err); } - System.err.println("Using startup command: " + PApplet.join(args, " ")); + sketchErr.println("Using startup command: " + PApplet.join(args, " ")); } } else { //exc.printStackTrace(); - System.err.println("Could not run the sketch (Target VM failed to initialize)."); + sketchErr.println("Could not run the sketch (Target VM failed to initialize)."); if (Preferences.getBoolean("run.options.memory")) { // Only mention this if they've even altered the memory setup - System.err.println("Make sure that you haven't set the maximum available memory too high."); + sketchErr.println("Make sure that you haven't set the maximum available memory too high."); } - System.err.println("For more information, read revisions.txt and Help \u2192 Troubleshooting."); + sketchErr.println("For more information, read revisions.txt and Help \u2192 Troubleshooting."); } // changing this to separate editor and listener [091124] //if (editor != null) { @@ -491,7 +497,7 @@ public class Runner implements MessageConsumer { outThread = new StreamRedirectThread("JVM stdout Reader", process.getInputStream(), - System.out); + sketchOut); errThread.start(); outThread.start(); @@ -578,7 +584,7 @@ public class Runner implements MessageConsumer { // First just report the exception and its placement reportException(message, or, event.thread()); // Then try to pretty it up with a better message - handleCommonErrors(exceptionName, message, listener); + handleCommonErrors(exceptionName, message, listener, sketchErr); if (editor != null) { editor.deactivateRun(); @@ -598,41 +604,42 @@ public class Runner implements MessageConsumer { */ public static boolean handleCommonErrors(final String exceptionClass, final String message, - final RunnerListener listener) { + final RunnerListener listener, + final PrintStream err) { if (exceptionClass.equals("java.lang.OutOfMemoryError")) { if (message.contains("exceeds VM budget")) { // TODO this is a kludge for Android, since there's no memory preference listener.statusError("OutOfMemoryError: This code attempts to use more memory than available."); - System.err.println("An OutOfMemoryError means that your code is either using up too much memory"); - System.err.println("because of a bug (e.g. creating an array that's too large, or unintentionally"); - System.err.println("loading thousands of images), or simply that it's trying to use more memory"); - System.err.println("than what is supported by the current device."); + err.println("An OutOfMemoryError means that your code is either using up too much memory"); + err.println("because of a bug (e.g. creating an array that's too large, or unintentionally"); + err.println("loading thousands of images), or simply that it's trying to use more memory"); + err.println("than what is supported by the current device."); } else { listener.statusError("OutOfMemoryError: You may need to increase the memory setting in Preferences."); - System.err.println("An OutOfMemoryError means that your code is either using up too much memory"); - System.err.println("because of a bug (e.g. creating an array that's too large, or unintentionally"); - System.err.println("loading thousands of images), or that your sketch may need more memory to run."); - System.err.println("If your sketch uses a lot of memory (for instance if it loads a lot of data files)"); - System.err.println("you can increase the memory available to your sketch using the Preferences window."); + err.println("An OutOfMemoryError means that your code is either using up too much memory"); + err.println("because of a bug (e.g. creating an array that's too large, or unintentionally"); + err.println("loading thousands of images), or that your sketch may need more memory to run."); + err.println("If your sketch uses a lot of memory (for instance if it loads a lot of data files)"); + err.println("you can increase the memory available to your sketch using the Preferences window."); } } else if (exceptionClass.equals("java.lang.UnsatisfiedLinkError")) { listener.statusError("A library used by this sketch is not installed properly."); - System.err.println("A library relies on native code that's not available."); - System.err.println("Or only works properly when the sketch is run as a " + + err.println("A library relies on native code that's not available."); + err.println("Or only works properly when the sketch is run as a " + ((Base.getNativeBits() == 32) ? "64-bit " : "32-bit ") + " application."); } else if (exceptionClass.equals("java.lang.StackOverflowError")) { listener.statusError("StackOverflowError: This sketch is attempting too much recursion."); - System.err.println("A StackOverflowError means that you have a bug that's causing a function"); - System.err.println("to be called recursively (it's calling itself and going in circles),"); - System.err.println("or you're intentionally calling a recursive function too much,"); - System.err.println("and your code should be rewritten in a more efficient manner."); + err.println("A StackOverflowError means that you have a bug that's causing a function"); + err.println("to be called recursively (it's calling itself and going in circles),"); + err.println("or you're intentionally calling a recursive function too much,"); + err.println("and your code should be rewritten in a more efficient manner."); } else if (exceptionClass.equals("java.lang.UnsupportedClassVersionError")) { listener.statusError("UnsupportedClassVersionError: A library is using code compiled with an unsupported version of Java."); - System.err.println("This version of Processing only supports libraries and JAR files compiled for Java 1.6 or earlier."); - System.err.println("A library used by this sketch was compiled for Java 1.7 or later, "); - System.err.println("and needs to be recompiled to be compatible with Java 1.6."); + err.println("This version of Processing only supports libraries and JAR files compiled for Java 1.6 or earlier."); + err.println("A library used by this sketch was compiled for Java 1.7 or later, "); + err.println("and needs to be recompiled to be compatible with Java 1.6."); } else if (exceptionClass.equals("java.lang.NoSuchMethodError") || exceptionClass.equals("java.lang.NoSuchFieldError")) { @@ -692,7 +699,7 @@ public class Runner implements MessageConsumer { } catch (IncompatibleThreadStateException e) { // This shouldn't happen, but if it does, print the exception in case // it's something that needs to be debugged separately. - e.printStackTrace(); + e.printStackTrace(sketchErr); } // before giving up, try to extract from the throwable object itself // since sometimes exceptions are re-thrown from a different context @@ -724,7 +731,7 @@ public class Runner implements MessageConsumer { or.invokeMethod(thread, method, new ArrayList(), ObjectReference.INVOKE_SINGLE_THREADED); } catch (Exception e) { - e.printStackTrace(); + e.printStackTrace(sketchErr); } // Give up, nothing found inside the pile of stack frames SketchException rex = new SketchException(message); @@ -795,8 +802,8 @@ public class Runner implements MessageConsumer { // always shove out the message, since it might not fall under // the same setup as we're expecting - System.err.print(s); + sketchErr.print(s); //System.err.println("[" + s.length() + "] " + s); - System.err.flush(); + sketchErr.flush(); } } diff --git a/build/build.xml b/build/build.xml index f52d1f639..8c776d0a1 100755 --- a/build/build.xml +++ b/build/build.xml @@ -154,7 +154,7 @@ - + diff --git a/build/macosx/language_gen.py b/build/macosx/language_gen.py index 6a55283f2..463d28fd6 100755 --- a/build/macosx/language_gen.py +++ b/build/macosx/language_gen.py @@ -5,7 +5,7 @@ import os, re BASEDIR = os.path.dirname(os.path.realpath(__file__)) def supported_languages(): - path = "../../app/src/processing/app/languages/languages.txt" + path = "../../build/shared/lib/languages/languages.txt" with open(os.path.join(BASEDIR, path)) as f: lines = f.read().splitlines() diff --git a/build/shared/lib/language.txt b/build/shared/lib/language.txt deleted file mode 100644 index 8b1378917..000000000 --- a/build/shared/lib/language.txt +++ /dev/null @@ -1 +0,0 @@ - diff --git a/app/src/processing/app/languages/PDE.properties b/build/shared/lib/languages/PDE.properties similarity index 100% rename from app/src/processing/app/languages/PDE.properties rename to build/shared/lib/languages/PDE.properties diff --git a/app/src/processing/app/languages/PDE_de.properties b/build/shared/lib/languages/PDE_de.properties similarity index 100% rename from app/src/processing/app/languages/PDE_de.properties rename to build/shared/lib/languages/PDE_de.properties diff --git a/app/src/processing/app/languages/PDE_el.properties b/build/shared/lib/languages/PDE_el.properties similarity index 100% rename from app/src/processing/app/languages/PDE_el.properties rename to build/shared/lib/languages/PDE_el.properties diff --git a/app/src/processing/app/languages/PDE_en.properties b/build/shared/lib/languages/PDE_en.properties similarity index 100% rename from app/src/processing/app/languages/PDE_en.properties rename to build/shared/lib/languages/PDE_en.properties diff --git a/app/src/processing/app/languages/PDE_es.properties b/build/shared/lib/languages/PDE_es.properties similarity index 100% rename from app/src/processing/app/languages/PDE_es.properties rename to build/shared/lib/languages/PDE_es.properties diff --git a/app/src/processing/app/languages/PDE_fr.properties b/build/shared/lib/languages/PDE_fr.properties similarity index 100% rename from app/src/processing/app/languages/PDE_fr.properties rename to build/shared/lib/languages/PDE_fr.properties diff --git a/app/src/processing/app/languages/PDE_ja.properties b/build/shared/lib/languages/PDE_ja.properties similarity index 100% rename from app/src/processing/app/languages/PDE_ja.properties rename to build/shared/lib/languages/PDE_ja.properties diff --git a/app/src/processing/app/languages/PDE_ko.properties b/build/shared/lib/languages/PDE_ko.properties similarity index 100% rename from app/src/processing/app/languages/PDE_ko.properties rename to build/shared/lib/languages/PDE_ko.properties diff --git a/app/src/processing/app/languages/PDE_nl.properties b/build/shared/lib/languages/PDE_nl.properties similarity index 100% rename from app/src/processing/app/languages/PDE_nl.properties rename to build/shared/lib/languages/PDE_nl.properties diff --git a/app/src/processing/app/languages/PDE_pt.properties b/build/shared/lib/languages/PDE_pt.properties similarity index 100% rename from app/src/processing/app/languages/PDE_pt.properties rename to build/shared/lib/languages/PDE_pt.properties diff --git a/app/src/processing/app/languages/PDE_tr.properties b/build/shared/lib/languages/PDE_tr.properties similarity index 100% rename from app/src/processing/app/languages/PDE_tr.properties rename to build/shared/lib/languages/PDE_tr.properties diff --git a/app/src/processing/app/languages/PDE_zh.properties b/build/shared/lib/languages/PDE_zh.properties similarity index 100% rename from app/src/processing/app/languages/PDE_zh.properties rename to build/shared/lib/languages/PDE_zh.properties diff --git a/app/src/processing/app/languages/languages.txt b/build/shared/lib/languages/languages.txt similarity index 100% rename from app/src/processing/app/languages/languages.txt rename to build/shared/lib/languages/languages.txt diff --git a/core/src/processing/core/PApplet.java b/core/src/processing/core/PApplet.java index 34d3473b8..c39e076b2 100644 --- a/core/src/processing/core/PApplet.java +++ b/core/src/processing/core/PApplet.java @@ -35,6 +35,7 @@ import java.awt.Font; import java.awt.Frame; import java.awt.Image; import java.awt.Toolkit; +import java.awt.color.ColorSpace; import java.awt.image.BufferedImage; import java.io.*; import java.lang.reflect.*; @@ -1937,7 +1938,7 @@ public class PApplet implements PConstants { InternalEventQueue eventQueue = new InternalEventQueue(); - class InternalEventQueue { + static class InternalEventQueue { protected Event queue[] = new Event[10]; protected int offset; protected int count; @@ -4653,7 +4654,6 @@ public class PApplet implements PConstants { return null; } else { //Image awtImage = Toolkit.getDefaultToolkit().createImage(bytes); - //PImage image = loadImageMT(awtImage); Image awtImage = new ImageIcon(bytes).getImage(); if (awtImage instanceof BufferedImage) { @@ -4678,12 +4678,11 @@ public class PApplet implements PConstants { } PImage image = new PImage(awtImage); - image.parent = this; - if (image.width == -1) { System.err.println("The file " + filename + " contains bad image data, or may not be an image."); } + // if it's a .gif image, test to see if it has transparency if (extension.equals("gif") || extension.equals("png")) { image.checkAlpha(); @@ -7864,7 +7863,7 @@ public class PApplet implements PConstants { //} if (splitCount == 0) { String splits[] = new String[1]; - splits[0] = new String(value); + splits[0] = value; return splits; } //int pieceCount = splitCount + 1; diff --git a/core/src/processing/core/PGraphics.java b/core/src/processing/core/PGraphics.java index 6d1d05a5d..c3ba398ba 100644 --- a/core/src/processing/core/PGraphics.java +++ b/core/src/processing/core/PGraphics.java @@ -7678,10 +7678,10 @@ public class PGraphics extends PImage implements PConstants { float g2 = (c2 >> 8) & 0xff; float b2 = c2 & 0xff; - return (((int) (a1 + (a2-a1)*amt) << 24) | - ((int) (r1 + (r2-r1)*amt) << 16) | - ((int) (g1 + (g2-g1)*amt) << 8) | - ((int) (b1 + (b2-b1)*amt))); + return ((PApplet.round(a1 + (a2-a1)*amt) << 24) | + (PApplet.round(r1 + (r2-r1)*amt) << 16) | + (PApplet.round(g1 + (g2-g1)*amt) << 8) | + (PApplet.round(b1 + (b2-b1)*amt))); } else if (mode == HSB) { if (lerpColorHSB1 == null) { @@ -7691,7 +7691,7 @@ public class PGraphics extends PImage implements PConstants { float a1 = (c1 >> 24) & 0xff; float a2 = (c2 >> 24) & 0xff; - int alfa = ((int) (a1 + (a2-a1)*amt)) << 24; + int alfa = (PApplet.round(a1 + (a2-a1)*amt)) << 24; Color.RGBtoHSB((c1 >> 16) & 0xff, (c1 >> 8) & 0xff, c1 & 0xff, lerpColorHSB1); diff --git a/core/src/processing/core/PGraphicsJava2D.java b/core/src/processing/core/PGraphicsJava2D.java index a9931ad09..422aaadcd 100644 --- a/core/src/processing/core/PGraphicsJava2D.java +++ b/core/src/processing/core/PGraphicsJava2D.java @@ -67,6 +67,11 @@ public class PGraphicsJava2D extends PGraphics { GeneralPath gpath; + // path for contours so gpath can be closed + GeneralPath auxPath; + + boolean openContour; + /// break the shape at the next vertex (next vertex() call is a moveto()) boolean breakShape; @@ -612,6 +617,7 @@ public class PGraphicsJava2D extends PGraphics { // this way, just check to see if gpath is null, and if it isn't // then just use it to continue the shape. gpath = null; + auxPath = null; } @@ -767,31 +773,63 @@ public class PGraphicsJava2D extends PGraphics { @Override public void beginContour() { - breakShape = true; + if (openContour) { + PGraphics.showWarning("Already called beginContour()"); + return; + } + + // draw contours to auxiliary path so main path can be closed later + GeneralPath contourPath = auxPath; + auxPath = gpath; + gpath = contourPath; + + if (contourPath != null) { // first contour does not break + breakShape = true; + } + + openContour = true; } @Override public void endContour() { - // does nothing, just need the break in beginContour() + if (!openContour) { + PGraphics.showWarning("Need to call beginContour() first"); + return; + } + + // close this contour + if (gpath != null) gpath.closePath(); + + // switch back to main path + GeneralPath contourPath = gpath; + gpath = auxPath; + auxPath = contourPath; + + openContour = false; } @Override public void endShape(int mode) { + if (openContour) { // correct automagically, notify user + endContour(); + PGraphics.showWarning("Missing endContour() before endShape()"); + } if (gpath != null) { // make sure something has been drawn if (shape == POLYGON) { if (mode == CLOSE) { gpath.closePath(); } + if (auxPath != null) { + gpath.append(auxPath, false); + } drawShape(gpath); } } shape = 0; } - - ////////////////////////////////////////////////////////////// // CLIPPING @@ -2727,15 +2765,30 @@ public class PGraphicsJava2D extends PGraphics { // MASK + static final String MASK_WARNING = + "mask() cannot be used on the main drawing surface"; + + @Override - public void mask(int alpha[]) { - showMethodWarning("mask"); + @SuppressWarnings("deprecation") + public void mask(int[] alpha) { + if (primarySurface) { + showWarning(MASK_WARNING); + + } else { + super.mask(alpha); + } } @Override public void mask(PImage alpha) { - showMethodWarning("mask"); + if (primarySurface) { + showWarning(MASK_WARNING); + + } else { + super.mask(alpha); + } } diff --git a/core/src/processing/core/PShape.java b/core/src/processing/core/PShape.java index bb8189708..9aae40799 100644 --- a/core/src/processing/core/PShape.java +++ b/core/src/processing/core/PShape.java @@ -618,7 +618,9 @@ public class PShape implements PConstants { protected void beginContourImpl() { - if (vertexCodes.length == vertexCodeCount) { + if (vertexCodes == null) { + vertexCodes = new int[10]; + } else if (vertexCodes.length == vertexCodeCount) { vertexCodes = PApplet.expand(vertexCodes); } vertexCodes[vertexCodeCount++] = BREAK; diff --git a/core/src/processing/core/PShapeSVG.java b/core/src/processing/core/PShapeSVG.java index 02e81e0c9..d91e1b3f2 100644 --- a/core/src/processing/core/PShapeSVG.java +++ b/core/src/processing/core/PShapeSVG.java @@ -1814,7 +1814,7 @@ public class PShapeSVG extends PShape { namedGlyphs.put(fg.name, fg); } if (fg.unicode != 0) { - unicodeGlyphs.put(new Character(fg.unicode), fg); + unicodeGlyphs.put(Character.valueOf(fg.unicode), fg); } } glyphs[glyphCount++] = fg; @@ -1848,7 +1848,7 @@ public class PShapeSVG extends PShape { char[] c = str.toCharArray(); for (int i = 0; i < c.length; i++) { // call draw on each char (pulling it w/ the unicode table) - FontGlyph fg = unicodeGlyphs.get(new Character(c[i])); + FontGlyph fg = unicodeGlyphs.get(Character.valueOf(c[i])); if (fg != null) { fg.draw(g); // add horizAdvX/unitsPerEm to the x coordinate along the way @@ -1866,7 +1866,7 @@ public class PShapeSVG extends PShape { float s = size / face.unitsPerEm; g.translate(x, y); g.scale(s, -s); - FontGlyph fg = unicodeGlyphs.get(new Character(c)); + FontGlyph fg = unicodeGlyphs.get(Character.valueOf(c)); if (fg != null) g.shape(fg); g.popMatrix(); } @@ -1877,7 +1877,7 @@ public class PShapeSVG extends PShape { char[] c = str.toCharArray(); for (int i = 0; i < c.length; i++) { // call draw on each char (pulling it w/ the unicode table) - FontGlyph fg = unicodeGlyphs.get(new Character(c[i])); + FontGlyph fg = unicodeGlyphs.get(Character.valueOf(c[i])); if (fg != null) { w += (float) fg.horizAdvX / face.unitsPerEm; } diff --git a/core/src/processing/data/JSONObject.java b/core/src/processing/data/JSONObject.java index 705ee3ff8..f5f02541e 100644 --- a/core/src/processing/data/JSONObject.java +++ b/core/src/processing/data/JSONObject.java @@ -1492,7 +1492,7 @@ public class JSONObject { return d; } } else { - Long myLong = new Long(string); + Long myLong = Long.valueOf(string); if (myLong.longValue() == myLong.intValue()) { return Integer.valueOf(myLong.intValue()); } else { diff --git a/core/src/processing/data/Table.java b/core/src/processing/data/Table.java index efe5a9e75..0b8107b67 100644 --- a/core/src/processing/data/Table.java +++ b/core/src/processing/data/Table.java @@ -3862,7 +3862,7 @@ public class Table { // . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . - class HashMapBlows { + static class HashMapBlows { HashMap dataToIndex = new HashMap(); ArrayList indexToData = new ArrayList(); diff --git a/core/src/processing/opengl/PGraphicsOpenGL.java b/core/src/processing/opengl/PGraphicsOpenGL.java index de4efe556..5977ec53d 100644 --- a/core/src/processing/opengl/PGraphicsOpenGL.java +++ b/core/src/processing/opengl/PGraphicsOpenGL.java @@ -2364,7 +2364,7 @@ public class PGraphicsOpenGL extends PGraphics { if (normalMode == NORMAL_MODE_AUTO) inGeo.calcQuadStripNormals(); tessellator.tessellateQuadStrip(); } else if (shape == POLYGON) { - tessellator.tessellatePolygon(false, mode == CLOSE, + tessellator.tessellatePolygon(true, mode == CLOSE, normalMode == NORMAL_MODE_AUTO); } } diff --git a/core/src/processing/opengl/PJOGL.java b/core/src/processing/opengl/PJOGL.java index cb2b72019..4845d5fdd 100644 --- a/core/src/processing/opengl/PJOGL.java +++ b/core/src/processing/opengl/PJOGL.java @@ -1206,7 +1206,7 @@ public class PJOGL extends PGL { } - protected class Tessellator implements PGL.Tessellator { + protected static class Tessellator implements PGL.Tessellator { protected GLUtessellator tess; protected TessellatorCallback callback; protected GLUCallback gluCallback; diff --git a/core/src/processing/opengl/PShader.java b/core/src/processing/opengl/PShader.java index b34351c87..aad807194 100644 --- a/core/src/processing/opengl/PShader.java +++ b/core/src/processing/opengl/PShader.java @@ -1438,7 +1438,7 @@ public class PShader implements PConstants { // // Class to store a user-specified value for a uniform parameter // in the shader - protected class UniformValue { + protected static class UniformValue { static final int INT1 = 0; static final int INT2 = 1; static final int INT3 = 2; diff --git a/core/src/processing/opengl/PShapeOpenGL.java b/core/src/processing/opengl/PShapeOpenGL.java index a771ff053..d41f3132a 100644 --- a/core/src/processing/opengl/PShapeOpenGL.java +++ b/core/src/processing/opengl/PShapeOpenGL.java @@ -173,7 +173,7 @@ public class PShapeOpenGL extends PShape { protected boolean needBufferInit = false; // Flag to indicate if the shape can have holes or not. - protected boolean solid; + protected boolean solid = true; protected boolean breakShape = false; protected boolean shapeCreated = false; @@ -2995,7 +2995,7 @@ public class PShapeOpenGL extends PShape { if (rounded) { saveBezierVertexSettings(); inGeo.addRect(a, b, c, d, tl, tr, br, bl, stroke); - tessellator.tessellatePolygon(false, true, true); + tessellator.tessellatePolygon(true, true, true); restoreBezierVertexSettings(); } else { inGeo.addRect(a, b, c, d, stroke); @@ -3289,7 +3289,7 @@ public class PShapeOpenGL extends PShape { saveCurveVertexSettings(); tessellator.resetCurveVertexCount(); } - tessellator.tessellatePolygon(false, close, true); + tessellator.tessellatePolygon(true, close, true); if (bez || quad) restoreBezierVertexSettings(); if (curv) restoreCurveVertexSettings(); } diff --git a/core/todo.txt b/core/todo.txt index dfeea4e40..12efc1276 100644 --- a/core/todo.txt +++ b/core/todo.txt @@ -1,4 +1,10 @@ 0232 core (3.0a5) +X detect CMYK JPEG images and return null +X https://community.oracle.com/thread/1272045?start=0&tstart=0 + +python has to use launch() instead of open() +map() is bad for Python (and JavaScript?) + _ args[] should be null if none passed (otherwise args == null checks are weird) _ size(640,360 , P3D) doesn't work properly _ https://github.com/processing/processing/issues/2924 @@ -53,9 +59,17 @@ o Sort out blending differences with P2D/P3D o might be that compatible images not setting alpha mode correctly o image = gc.createCompatibleVolatileImage(source.width, source.height, Transparency.TRANSLUCENT); o https://github.com/processing/processing/issues/1844 -_ check into contour winding fixes -_ https://github.com/processing/processing/issues/2665 -_ https://github.com/processing/processing/pull/2927 +X Prevent lerpColor from always rounding down +X https://github.com/processing/processing/issues/2812 +X https://github.com/processing/processing/pull/2813 +X Allow mask() with PGraphicsJava2D +X https://github.com/processing/processing/pull/2910 +X OpenGL renderers ignore vertex winding in contours +X https://github.com/processing/processing/issues/2665 +X https://github.com/processing/processing/pull/2927 +X NPE when calling Client.ip() after the connection has been closed +X https://github.com/processing/processing/issues/2576 +X https://github.com/processing/processing/pull/2922 andres A Confusing message: The shader doesn't have a uniform called "foo" diff --git a/java/libraries/net/src/processing/net/Client.java b/java/libraries/net/src/processing/net/Client.java index de39b6e9f..fb8fa95ee 100644 --- a/java/libraries/net/src/processing/net/Client.java +++ b/java/libraries/net/src/processing/net/Client.java @@ -51,7 +51,6 @@ public class Client implements Runnable { Thread thread; Socket socket; - String ip; int port; String host; @@ -274,7 +273,10 @@ public class Client implements Runnable { * @brief Returns the IP address of the machine as a String */ public String ip() { - return socket.getInetAddress().getHostAddress(); + if (socket != null){ + return socket.getInetAddress().getHostAddress(); + } + return null; } diff --git a/java/libraries/net/src/processing/net/Server.java b/java/libraries/net/src/processing/net/Server.java index 05addd256..3d55b6442 100644 --- a/java/libraries/net/src/processing/net/Server.java +++ b/java/libraries/net/src/processing/net/Server.java @@ -178,6 +178,15 @@ public class Server implements Runnable { } + /** + * Return true if this server is still active and hasn't run + * into any trouble. + */ + public boolean active() { + return thread != null; + } + + static public String ip() { try { return InetAddress.getLocalHost().getHostAddress(); @@ -310,8 +319,8 @@ public class Server implements Runnable { public void write(int data) { // will also cover char int index = 0; while (index < clientCount) { - clients[index].write(data); if (clients[index].active()) { + clients[index].write(data); index++; } else { removeIndex(index); @@ -323,8 +332,8 @@ public class Server implements Runnable { public void write(byte data[]) { int index = 0; while (index < clientCount) { - clients[index].write(data); if (clients[index].active()) { + clients[index].write(data); index++; } else { removeIndex(index); @@ -336,8 +345,8 @@ public class Server implements Runnable { public void write(String data) { int index = 0; while (index < clientCount) { - clients[index].write(data); if (clients[index].active()) { + clients[index].write(data); index++; } else { removeIndex(index); diff --git a/java/libraries/serial/src/processing/serial/Serial.java b/java/libraries/serial/src/processing/serial/Serial.java index f473f863d..e816c62f4 100644 --- a/java/libraries/serial/src/processing/serial/Serial.java +++ b/java/libraries/serial/src/processing/serial/Serial.java @@ -135,6 +135,15 @@ public class Serial implements SerialPortEventListener { } + /** + * Return true if this port is still active and hasn't run + * into any trouble. + */ + public boolean active() { + return port.isOpened(); + } + + public void pre() { if (serialAvailableMethod != null && invokeSerialAvailable) { invokeSerialAvailable = false; diff --git a/pdex/src/processing/mode/experimental/DebugEditor.java b/pdex/src/processing/mode/experimental/DebugEditor.java index 0cb28d79b..a4385d499 100755 --- a/pdex/src/processing/mode/experimental/DebugEditor.java +++ b/pdex/src/processing/mode/experimental/DebugEditor.java @@ -1725,79 +1725,6 @@ public class DebugEditor extends JavaEditor implements ActionListener { errorCheckerService.runManualErrorCheck(); } } - - /** - * Handles toggle comment. Slightly improved from the default implementation - * in {@link processing.app.Editor} - */ - protected void handleCommentUncomment() { - // log("Entering handleCommentUncomment()"); - startCompoundEdit(); - - String prefix = getCommentPrefix(); - int prefixLen = prefix.length(); - - int startLine = textarea.getSelectionStartLine(); - int stopLine = textarea.getSelectionStopLine(); - - int lastLineStart = textarea.getLineStartOffset(stopLine); - int selectionStop = textarea.getSelectionStop(); - // If the selection ends at the beginning of the last line, - // then don't (un)comment that line. - if (selectionStop == lastLineStart) { - // Though if there's no selection, don't do that - if (textarea.isSelectionActive()) { - stopLine--; - } - } - - // If the text is empty, ignore the user. - // Also ensure that all lines are commented (not just the first) - // when determining whether to comment or uncomment. - boolean commented = true; - for (int i = startLine; commented && (i <= stopLine); i++) { - String lineText = textarea.getLineText(i).trim(); - if (lineText.length() == 0) - continue; //ignore blank lines - commented = lineText.startsWith(prefix); - } - - // log("Commented: " + commented); - - // This is the line start offset of the first line, which is added to - // all other lines while adding a comment. Required when commenting - // lines which have uneven whitespaces in the beginning. Makes the - // commented lines look more uniform. - int lso = Math.abs(textarea.getLineStartNonWhiteSpaceOffset(startLine) - - textarea.getLineStartOffset(startLine)); - - for (int line = startLine; line <= stopLine; line++) { - int location = textarea.getLineStartNonWhiteSpaceOffset(line); - String lineText = textarea.getLineText(line); - if (lineText.trim().length() == 0) - continue; //ignore blank lines - if (commented) { - // remove a comment - if (lineText.trim().startsWith(prefix + " ")) { - textarea.select(location, location + prefixLen + 1); - } else { - textarea.select(location, location + prefixLen); - } - textarea.setSelectedText(""); - } else { - // add a comment - location = textarea.getLineStartOffset(line) + lso; - textarea.select(location, location); - textarea.setSelectedText(prefix + " "); //Add a '// ' - } - } - // Subtract one from the end, otherwise selects past the current line. - // (Which causes subsequent calls to keep expanding the selection) - textarea.select(textarea.getLineStartOffset(startLine), - textarea.getLineStopOffset(stopLine) - 1); - stopCompoundEdit(); - sketch.setModified(true); - } // TweakMode code /** diff --git a/pdex/src/processing/mode/experimental/TextAreaPainter.java b/pdex/src/processing/mode/experimental/TextAreaPainter.java index 657f75c4d..b6f0b6d43 100644 --- a/pdex/src/processing/mode/experimental/TextAreaPainter.java +++ b/pdex/src/processing/mode/experimental/TextAreaPainter.java @@ -457,29 +457,43 @@ public class TextAreaPainter extends processing.app.syntax.TextAreaPainter } public String getToolTipText(java.awt.event.MouseEvent evt) { - if(ta.editor.hasJavaTabs) return ""; // disabled for java tabs + if (ta.editor.hasJavaTabs) { // disabled for java tabs + setToolTipText(null); + return super.getToolTipText(evt); + } int off = ta.xyToOffset(evt.getX(), evt.getY()); - if (off < 0) - return ""; + if (off < 0) { + setToolTipText(null); + return super.getToolTipText(evt); + } int line = ta.getLineOfOffset(off); - if (line < 0) - return ""; + if (line < 0) { + setToolTipText(null); + return super.getToolTipText(evt); + } String s = ta.getLineText(line); if (s == "") return evt.toString(); - else if (s.length() == 0) - return ""; - else { + else if (s.length() == 0) { + setToolTipText(null); + return super.getToolTipText(evt); + } else { int x = ta.xToOffset(line, evt.getX()), x2 = x + 1, x1 = x - 1; int xLS = off - ta.getLineStartNonWhiteSpaceOffset(line); - if (x < 0 || x >= s.length()) - return ""; + if (x < 0 || x >= s.length()) { + setToolTipText(null); + return super.getToolTipText(evt); + } String word = s.charAt(x) + ""; - if (s.charAt(x) == ' ') - return ""; + if (s.charAt(x) == ' ') { + setToolTipText(null); + return super.getToolTipText(evt); + } if (!(Character.isLetterOrDigit(s.charAt(x)) || s.charAt(x) == '_' || s - .charAt(x) == '$')) - return ""; + .charAt(x) == '$')) { + setToolTipText(null); + return super.getToolTipText(evt); + } int i = 0; while (true) { i++; @@ -509,8 +523,10 @@ public class TextAreaPainter extends processing.app.syntax.TextAreaPainter break; } } - if (Character.isDigit(word.charAt(0))) - return ""; + if (Character.isDigit(word.charAt(0))) { + setToolTipText(null); + return super.getToolTipText(evt); + } String tooltipText = errorCheckerService.getASTGenerator() .getLabelForASTNode(line, word, xLS); @@ -518,9 +534,9 @@ public class TextAreaPainter extends processing.app.syntax.TextAreaPainter // + "|" + line + "| offset " + xLS + word + " <= offf: "+off+ "\n"); if (tooltipText != null) return tooltipText; - return ""; } - + setToolTipText(null); + return super.getToolTipText(evt); } // TweakMode code diff --git a/todo.txt b/todo.txt index cc750c80b..a3923fdbc 100644 --- a/todo.txt +++ b/todo.txt @@ -4,6 +4,10 @@ X size(640,360 , P3D) doesn't work properly X https://github.com/processing/processing/issues/2924 X https://github.com/processing/processing/pull/2925 X remove sound library, have it installed separately like video +X Fix the shortcut keybindings in editor tab popup menu +X https://github.com/processing/processing/issues/179 +X https://github.com/processing/processing/pull/2821 + _ any problems with new code signing crap? _ issues raised around the symlink (just replace with a copy of the binary?) _ https://developer.apple.com/library/prerelease/mac/technotes/tn2206/_index.html#//apple_ref/doc/uid/DTS40007919-CH1-TNTAG205 @@ -12,9 +16,11 @@ deb questions: https://github.com/processing/processing/issues/114 better Linux packaging... http://askubuntu.com/questions/396857/how-can-i-add-processing-to-the-unity-launcher -python has to use launch() instead of open() -map() is bad for Python (and JavaScript?) +_ add script to download JRE and JDK from Oracle +manindra +X ToolTipManager error +X https://github.com/processing/processing/issues/2926 pulls X Cmd + H runs sketch instead of hiding the PDE (OS X) @@ -29,6 +35,35 @@ X Update ECJ, use 1.7 as source and target Java version X https://github.com/processing/processing/pull/2907 X Fix infinite recursion in sound library X https://github.com/processing/processing/pull/2897 +X Add missing generic type parameters +X https://github.com/processing/processing/pull/2899 +X Remove unused Base.builtOnce instance variable +X https://github.com/processing/processing/pull/2864 +X miscellaneous fixes +X https://github.com/processing/processing/pull/2865 +X moved the language stuff to the settings folder +X https://github.com/processing/processing/pull/2941 +X Some minor UpdateChecker refactorings +X https://github.com/processing/processing/pull/2830 +X Minor improvements to the Contribution Manager's updates check +X https://github.com/processing/processing/pull/2861 +X make Cut and Copy in the edit menu active only if some text is selected +X https://github.com/processing/processing/pull/2834 +X Fix renaming from RGB to Rgb.java and others +X https://github.com/processing/processing/pull/2825 +X sketches should only write to the console of their editor window +X https://github.com/processing/processing/issues/153 +X https://github.com/processing/processing/issues/2858 +X https://github.com/processing/processing/pull/2827 + +pulls (net) +X NullPointerException message when Server writes to a disconnected client +X https://github.com/processing/processing/issues/2577 +X https://github.com/processing/processing/pull/2578 +X Implement the active() method for Serial and Server +X https://github.com/processing/processing/issues/2364 +X https://github.com/processing/processing/pull/2588 + _ Add support for localizing contributions _ https://github.com/processing/processing/pull/2833 _ Fix renaming from RGB to Rgb.java and others @@ -88,6 +123,8 @@ _ http://stackoverflow.com/questions/4933677/detecting-windows-ie-proxy-settin _ http://www.java2s.com/Code/Java/Network-Protocol/DetectProxySettingsforInternetConnection.htm _ problems with non-US keyboards and some shortcuts _ https://github.com/processing/processing/issues/2199 +_ improve start time by populating sketchbook/libraries on threads +_ https://github.com/processing/processing/issues/2945 medium