processing.mode.java.JavaEditor Maven / Gradle / Ivy
Go to download
Show more of this group Show more artifacts with this name
Show all versions of java-mode Show documentation
Show all versions of java-mode Show documentation
Processing is a programming language, development environment, and online community.
This Java Mode package contains the Java mode for Processing IDE.
The newest version!
package processing.mode.java;
import java.awt.*;
import java.awt.event.*;
import java.beans.*;
import java.io.*;
import java.util.ArrayList;
import java.util.Collections;
import java.util.Iterator;
import java.util.List;
import java.util.Map;
import javax.swing.*;
import javax.swing.border.*;
import javax.swing.event.*;
import javax.swing.text.BadLocationException;
import javax.swing.text.Document;
import processing.core.PApplet;
import processing.data.StringList;
import processing.app.*;
import processing.app.contrib.*;
import processing.app.syntax.JEditTextArea;
import processing.app.syntax.PdeTextAreaDefaults;
import processing.app.ui.*;
import processing.app.ui.Toolkit;
import processing.mode.java.debug.LineBreakpoint;
import processing.mode.java.debug.LineHighlight;
import processing.mode.java.debug.LineID;
import processing.mode.java.pdex.PreprocessingService;
import processing.mode.java.pdex.ImportStatement;
import processing.mode.java.pdex.JavaTextArea;
import processing.mode.java.pdex.PDEX;
import processing.mode.java.pdex.JavaProblem;
import processing.mode.java.pdex.SourceUtils;
import processing.mode.java.preproc.PdePreprocessor;
import processing.mode.java.runner.Runner;
import processing.mode.java.tweak.ColorControlBox;
import processing.mode.java.tweak.Handle;
import processing.mode.java.tweak.SketchParser;
import processing.mode.java.tweak.TweakClient;
public class JavaEditor extends Editor {
JavaMode jmode;
// Runner associated with this editor window
private Runner runtime;
private boolean runtimeLaunchRequested;
private final Object runtimeLock = new Object[0];
// Need to sort through the rest of these additions [fry]
protected final List breakpointedLines = new ArrayList<>();
protected LineHighlight currentLine; // where the debugger is suspended
protected final String breakpointMarkerComment = " //<>//";
protected JMenu debugMenu;
protected JMenuItem debugItem;
protected Debugger debugger;
protected boolean debugEnabled;
protected VariableInspector inspector;
protected JMenuItem inspectorItem;
static final int ERROR_TAB_INDEX = 0;
private boolean hasJavaTabs;
private boolean javaTabWarned;
protected PreprocessingService preprocessingService;
protected PDEX pdex;
protected JavaEditor(Base base, String path, EditorState state,
Mode mode) throws EditorException {
super(base, path, state, mode);
jmode = (JavaMode) mode;
debugger = new Debugger(this);
inspector = new VariableInspector(this);
// set breakpoints from marker comments
for (LineID lineID : stripBreakpointComments()) {
//System.out.println("setting: " + lineID);
debugger.setBreakpoint(lineID);
}
// setting breakpoints will flag sketch as modified, so override this here
getSketch().setModified(false);
hasJavaTabs = checkForJavaTabs();
/*
// hack to add a JPanel to the right-hand side of the text area
JPanel textAndError = new JPanel();
// parent is a vertical box with the toolbar, the header, and the text area
Box box = (Box) textarea.getParent();
// remove the text area temporarily
box.remove(2);
textAndError.setLayout(new BorderLayout());
errorColumn = new MarkerColumn(this, textarea.getMinimumSize().height);
textAndError.add(errorColumn, BorderLayout.EAST);
textarea.setBounds(0, 0, errorColumn.getX() - 1, textarea.getHeight());
textAndError.add(textarea);
// add our hacked version back to the editor
box.add(textAndError);
*/
preprocessingService = new PreprocessingService(this);
pdex = new PDEX(this, preprocessingService);
Toolkit.setMenuMnemonics(textarea.getRightClickPopup());
// ensure completion is hidden when editor loses focus
addWindowFocusListener(new WindowFocusListener() {
public void windowLostFocus(WindowEvent e) {
getJavaTextArea().hideSuggestion();
}
public void windowGainedFocus(WindowEvent e) { }
});
}
public PdePreprocessor createPreprocessor(final String sketchName) {
return new PdePreprocessor(sketchName);
}
protected JEditTextArea createTextArea() {
return new JavaTextArea(new PdeTextAreaDefaults(mode), this);
}
public EditorToolbar createToolbar() {
return new JavaToolbar(this);
}
private int previousTabCount = 1;
// TODO: this is a clumsy way to get notified when tabs get added/deleted
// Override the parent call to add hook to the rebuild() method
public EditorHeader createHeader() {
return new EditorHeader(this) {
public void rebuild() {
super.rebuild();
// after Rename and New Tab, we may have new .java tabs
boolean newHasJavaTabs = checkForJavaTabs();
boolean hasJavaTabsChanged = hasJavaTabs != newHasJavaTabs;
hasJavaTabs = newHasJavaTabs;
if (preprocessingService != null) {
if (hasJavaTabsChanged) {
preprocessingService.handleHasJavaTabsChange(hasJavaTabs);
pdex.hasJavaTabsChanged(hasJavaTabs);
if (hasJavaTabs) {
setProblemList(Collections.emptyList());
}
}
int currentTabCount = sketch.getCodeCount();
if (currentTabCount != previousTabCount) {
previousTabCount = currentTabCount;
pdex.sketchChanged();
}
}
}
};
}
@Override
public EditorFooter createFooter() {
EditorFooter footer = super.createFooter();
addErrorTable(footer);
return footer;
}
public Formatter createFormatter() {
return new AutoFormat();
}
// . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . .
public JMenu buildFileMenu() {
//String appTitle = JavaToolbar.getTitle(JavaToolbar.EXPORT, false);
String appTitle = Language.text("menu.file.export_application");
JMenuItem exportApplication = Toolkit.newJMenuItemShift(appTitle, 'E');
exportApplication.addActionListener(new ActionListener() {
public void actionPerformed(ActionEvent e) {
handleExportApplication();
}
});
return buildFileMenu(new JMenuItem[] { exportApplication });
}
public JMenu buildSketchMenu() {
JMenuItem runItem = Toolkit.newJMenuItem(Language.text("menu.sketch.run"), 'R');
runItem.addActionListener(new ActionListener() {
public void actionPerformed(ActionEvent e) {
handleRun();
}
});
JMenuItem presentItem = Toolkit.newJMenuItemShift(Language.text("menu.sketch.present"), 'R');
presentItem.addActionListener(new ActionListener() {
public void actionPerformed(ActionEvent e) {
handlePresent();
}
});
JMenuItem stopItem = new JMenuItem(Language.text("menu.sketch.stop"));
stopItem.addActionListener(new ActionListener() {
public void actionPerformed(ActionEvent e) {
if (isDebuggerEnabled()) {
Messages.log("Invoked 'Stop' menu item");
debugger.stopDebug();
} else {
handleStop();
}
}
});
JMenuItem tweakItem = Toolkit.newJMenuItemShift(Language.text("menu.sketch.tweak"), 'T');
// tweakItem.setSelected(JavaMode.enableTweak);
tweakItem.addActionListener(new ActionListener() {
public void actionPerformed(ActionEvent e) {
// JavaMode.enableTweak = true;
// handleRun();
handleTweak();
}
});
return buildSketchMenu(new JMenuItem[] {
runItem, presentItem, tweakItem, stopItem
});
}
public JMenu buildHelpMenu() {
JMenu menu = new JMenu(Language.text("menu.help"));
JMenuItem item;
// macosx already has its own about menu
if (!Platform.isMacOS()) {
item = new JMenuItem(Language.text("menu.help.about"));
item.addActionListener(new ActionListener() {
public void actionPerformed(ActionEvent e) {
new About(JavaEditor.this);
}
});
menu.add(item);
}
item = new JMenuItem(Language.text("menu.help.welcome"));
item.addActionListener(new ActionListener() {
public void actionPerformed(ActionEvent e) {
try {
new Welcome(base, Preferences.getSketchbookPath().equals(Preferences.getOldSketchbookPath()));
} catch (IOException ioe) {
Messages.showWarning("Unwelcome Error",
"Please report this error to\n" +
"https://github.com/processing/processing/issues", ioe);
}
}
});
menu.add(item);
item = new JMenuItem(Language.text("menu.help.environment"));
item.addActionListener(new ActionListener() {
public void actionPerformed(ActionEvent e) {
showReference("environment" + File.separator + "index.html");
}
});
menu.add(item);
item = new JMenuItem(Language.text("menu.help.reference"));
item.addActionListener(new ActionListener() {
public void actionPerformed(ActionEvent e) {
showReference("index.html");
}
});
menu.add(item);
item = Toolkit.newJMenuItemShift(Language.text("menu.help.find_in_reference"), 'F');
item.addActionListener(new ActionListener() {
public void actionPerformed(ActionEvent e) {
if (textarea.isSelectionActive()) {
handleFindReference();
} else {
statusNotice(Language.text("editor.status.find_reference.select_word_first"));
}
}
});
menu.add(item);
menu.addSeparator();
final JMenu libRefSubmenu = new JMenu(Language.text("menu.help.libraries_reference"));
// Populate only when sub-menu is opened, to avoid having spurious menu
// options if a library is deleted, or a missing menu option if a library is added
libRefSubmenu.addMenuListener(new MenuListener() {
@Override
public void menuSelected(MenuEvent e) {
// Adding this in case references are included in a core library,
// or other core libraries are included in the future
boolean isCoreLibMenuItemAdded =
addLibReferencesToSubMenu(mode.coreLibraries, libRefSubmenu);
if (isCoreLibMenuItemAdded && !mode.contribLibraries.isEmpty()) {
libRefSubmenu.addSeparator();
}
boolean isContribLibMenuItemAdded =
addLibReferencesToSubMenu(mode.contribLibraries, libRefSubmenu);
if (!isContribLibMenuItemAdded && !isCoreLibMenuItemAdded) {
JMenuItem emptyMenuItem = new JMenuItem(Language.text("menu.help.empty"));
emptyMenuItem.setEnabled(false);
emptyMenuItem.setFocusable(false);
emptyMenuItem.setFocusPainted(false);
libRefSubmenu.add(emptyMenuItem);
} else if (!isContribLibMenuItemAdded && !mode.coreLibraries.isEmpty()) {
//re-populate the menu to get rid of terminal separator
libRefSubmenu.removeAll();
addLibReferencesToSubMenu(mode.coreLibraries, libRefSubmenu);
}
}
@Override
public void menuDeselected(MenuEvent e) {
libRefSubmenu.removeAll();
}
@Override
public void menuCanceled(MenuEvent e) {
menuDeselected(e);
}
});
menu.add(libRefSubmenu);
final JMenu toolRefSubmenu = new JMenu(Language.text("menu.help.tools_reference"));
// Populate only when sub-menu is opened, to avoid having spurious menu
// options if a tool is deleted, or a missing menu option if a library is added
toolRefSubmenu.addMenuListener(new MenuListener() {
@Override
public void menuSelected(MenuEvent e) {
boolean isCoreToolMenuItemAdded = false;
boolean isContribToolMenuItemAdded = false;
List contribTools = base.getToolContribs();
// Adding this in in case a reference folder is added for MovieMaker, or in case
// other core tools are introduced later
isCoreToolMenuItemAdded = addToolReferencesToSubMenu(base.getCoreTools(), toolRefSubmenu);
if (isCoreToolMenuItemAdded && !contribTools.isEmpty())
toolRefSubmenu.addSeparator();
isContribToolMenuItemAdded = addToolReferencesToSubMenu(contribTools, toolRefSubmenu);
if (!isContribToolMenuItemAdded && !isCoreToolMenuItemAdded) {
toolRefSubmenu.removeAll(); // in case a separator was added
final JMenuItem emptyMenuItem = new JMenuItem(Language.text("menu.help.empty"));
emptyMenuItem.setEnabled(false);
emptyMenuItem.setBorderPainted(false);
emptyMenuItem.setFocusable(false);
emptyMenuItem.setFocusPainted(false);
toolRefSubmenu.add(emptyMenuItem);
}
else if (!isContribToolMenuItemAdded && !contribTools.isEmpty()) {
// re-populate the menu to get rid of terminal separator
toolRefSubmenu.removeAll();
addToolReferencesToSubMenu(base.getCoreTools(), toolRefSubmenu);
}
}
@Override
public void menuDeselected(MenuEvent e) {
toolRefSubmenu.removeAll();
}
@Override
public void menuCanceled(MenuEvent e) {
menuDeselected(e);
}
});
menu.add(toolRefSubmenu);
menu.addSeparator();
item = new JMenuItem(Language.text("menu.help.online"));
item.setEnabled(false);
menu.add(item);
item = new JMenuItem(Language.text("menu.help.getting_started"));
item.addActionListener(new ActionListener() {
public void actionPerformed(ActionEvent e) {
Platform.openURL(Language.text("menu.help.getting_started.url"));
}
});
menu.add(item);
item = new JMenuItem(Language.text("menu.help.troubleshooting"));
item.addActionListener(new ActionListener() {
public void actionPerformed(ActionEvent e) {
Platform.openURL(Language.text("menu.help.troubleshooting.url"));
}
});
menu.add(item);
item = new JMenuItem(Language.text("menu.help.faq"));
item.addActionListener(new ActionListener() {
public void actionPerformed(ActionEvent e) {
Platform.openURL(Language.text("menu.help.faq.url"));
}
});
menu.add(item);
item = new JMenuItem(Language.text("menu.help.foundation"));
item.addActionListener(new ActionListener() {
public void actionPerformed(ActionEvent e) {
Platform.openURL(Language.text("menu.help.foundation.url"));
}
});
menu.add(item);
item = new JMenuItem(Language.text("menu.help.visit"));
item.addActionListener(new ActionListener() {
public void actionPerformed(ActionEvent e) {
Platform.openURL(Language.text("menu.help.visit.url"));
}
});
menu.add(item);
return menu;
}
//. . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . .
/**
* Populates the JMenu with JMenuItems, one for each Library that has a
* reference accompanying it. The JMenuItems open the index.htm/index.html
* file of the reference in the user's default browser, or the readme.txt in
* the user's default text editor.
*
* @param libsList
* A list of the Libraries to be added
* @param subMenu
* The JMenu to which the JMenuItems corresponding to the Libraries
* are to be added
* @return true if and only if any JMenuItems were added; false otherwise
*/
private boolean addLibReferencesToSubMenu(List libsList, JMenu subMenu) {
boolean isItemAdded = false;
Iterator iter = libsList.iterator();
while (iter.hasNext()) {
final Library libContrib = iter.next();
if (libContrib.hasReference()) {
JMenuItem libRefItem = new JMenuItem(libContrib.getName());
libRefItem.addActionListener(new ActionListener() {
@Override
public void actionPerformed(ActionEvent arg0) {
showReferenceFile(libContrib.getReferenceIndexFile());
}
});
subMenu.add(libRefItem);
isItemAdded = true;
}
}
return isItemAdded;
}
/**
* Populates the JMenu with JMenuItems, one for each Tool that has a reference
* accompanying it. The JMenuItems open the index.htm/index.html file of the
* reference in the user's default browser, or the readme.txt in the user's
* default text editor.
*
* @param toolsList
* A list of Tools to be added
* @param subMenu
* The JMenu to which the JMenuItems corresponding to the Tools are
* to be added
* @return true if and only if any JMenuItems were added; false otherwise
*/
private boolean addToolReferencesToSubMenu(List toolsList, JMenu subMenu) {
boolean isItemAdded = false;
Iterator iter = toolsList.iterator();
while (iter.hasNext()) {
final ToolContribution toolContrib = iter.next();
final File toolRef = new File(toolContrib.getFolder(), "reference/index.html");
if (toolRef.exists()) {
JMenuItem libRefItem = new JMenuItem(toolContrib.getName());
libRefItem.addActionListener(new ActionListener() {
@Override
public void actionPerformed(ActionEvent arg0) {
showReferenceFile(toolRef);
}
});
subMenu.add(libRefItem);
isItemAdded = true;
}
}
return isItemAdded;
}
// . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . .
public String getCommentPrefix() {
return "//";
}
// . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . .
/**
* Called by Sketch → Export.
* Handles calling the export() function on sketch, and
* queues all the gui status stuff that comes along with it.
*
* Made synchronized to (hopefully) avoid problems of people
* hitting export twice, quickly, and horking things up.
*/
/*
public void handleExportApplet() {
if (handleExportCheckModified()) {
toolbar.activate(JavaToolbar.EXPORT);
try {
boolean success = jmode.handleExportApplet(sketch);
if (success) {
File appletFolder = new File(sketch.getFolder(), "applet");
Base.openFolder(appletFolder);
statusNotice("Done exporting.");
} else {
// error message will already be visible
}
} catch (Exception e) {
statusError(e);
}
toolbar.deactivate(JavaToolbar.EXPORT);
}
}
*/
/**
* Handler for Sketch → Export Application
*/
public void handleExportApplication() {
// toolbar.activate(JavaToolbar.EXPORT);
if (handleExportCheckModified()) {
statusNotice(Language.text("export.notice.exporting"));
try {
if (exportApplicationPrompt()) {
Platform.openFolder(sketch.getFolder());
statusNotice(Language.text("export.notice.exporting.done"));
} else {
// error message will already be visible
// or there was no error, in which case it was canceled.
}
} catch (Exception e) {
statusNotice(Language.text("export.notice.exporting.error"));
e.printStackTrace();
}
}
// toolbar.deactivate(JavaToolbar.EXPORT);
}
// Can't be .windows because that'll be stripped off as a per-platform pref
static final String EXPORT_PREFIX = "export.application.platform_";
static final String EXPORT_MACOSX = EXPORT_PREFIX + "macosx";
static final String EXPORT_WINDOWS = EXPORT_PREFIX + "windows";
static final String EXPORT_LINUX = EXPORT_PREFIX + "linux";
final JButton exportButton = new JButton(Language.text("prompt.export"));
final JButton cancelButton = new JButton(Language.text("prompt.cancel"));
final JCheckBox windowsButton = new JCheckBox("Windows");
final JCheckBox macosxButton = new JCheckBox("Mac OS X");
final JCheckBox linuxButton = new JCheckBox("Linux");
protected void updateExportButton() {
exportButton.setEnabled(windowsButton.isSelected() ||
macosxButton.isSelected() ||
linuxButton.isSelected());
}
protected boolean exportApplicationPrompt() throws IOException, SketchException {
JPanel panel = new JPanel();
panel.setLayout(new BoxLayout(panel, BoxLayout.Y_AXIS));
panel.add(Box.createVerticalStrut(6));
// Box panel = Box.createVerticalBox();
// Box labelBox = Box.createHorizontalBox();
// String msg = "Click Export to Application to create a standalone, " +
// "double-clickable application for the selected plaforms.";
// String msg = "Export to Application creates a standalone, \n" +
// "double-clickable application for the selected plaforms.";
String line1 = Language.text("export.description.line1");
String line2 = Language.text("export.description.line2");
//String line2 = "standalone application for the current plaform.";
JLabel label1 = new JLabel(line1, SwingConstants.CENTER);
JLabel label2 = new JLabel(line2, SwingConstants.CENTER);
label1.setAlignmentX(Component.LEFT_ALIGNMENT);
label2.setAlignmentX(Component.LEFT_ALIGNMENT);
panel.add(label1);
panel.add(label2);
// The longer line is different between Windows and OS X.
// int wide = Math.max(label1.getPreferredSize().width,
// label2.getPreferredSize().width);
panel.add(Box.createVerticalStrut(12));
// final JCheckBox windowsButton = new JCheckBox("Windows");
// final JCheckBox macosxButton = new JCheckBox("Mac OS X");
// final JCheckBox linuxButton = new JCheckBox("Linux");
windowsButton.setSelected(Preferences.getBoolean(EXPORT_WINDOWS));
windowsButton.addItemListener(new ItemListener() {
public void itemStateChanged(ItemEvent e) {
Preferences.setBoolean(EXPORT_WINDOWS, windowsButton.isSelected());
updateExportButton();
}
});
// Only possible to export OS X applications on OS X
if (!Platform.isMacOS()) {
// Make sure they don't have a previous 'true' setting for this
Preferences.setBoolean(EXPORT_MACOSX, false);
}
macosxButton.setSelected(Preferences.getBoolean(EXPORT_MACOSX));
macosxButton.addItemListener(new ItemListener() {
public void itemStateChanged(ItemEvent e) {
Preferences.setBoolean(EXPORT_MACOSX, macosxButton.isSelected());
updateExportButton();
}
});
if (!Platform.isMacOS()) {
macosxButton.setEnabled(false);
macosxButton.setToolTipText(Language.text("export.tooltip.macosx"));
}
linuxButton.setSelected(Preferences.getBoolean(EXPORT_LINUX));
linuxButton.addItemListener(new ItemListener() {
public void itemStateChanged(ItemEvent e) {
Preferences.setBoolean(EXPORT_LINUX, linuxButton.isSelected());
updateExportButton();
}
});
updateExportButton(); // do the initial enable/disable based on prefs.txt
JPanel platformPanel = new JPanel();
//platformPanel.setLayout(new BoxLayout(platformPanel, BoxLayout.X_AXIS));
platformPanel.add(windowsButton);
platformPanel.add(Box.createHorizontalStrut(6));
platformPanel.add(macosxButton);
platformPanel.add(Box.createHorizontalStrut(6));
platformPanel.add(linuxButton);
platformPanel.setBorder(new TitledBorder(Language.text("export.platforms")));
//Dimension goodIdea = new Dimension(wide, platformPanel.getPreferredSize().height);
//platformPanel.setMaximumSize(goodIdea);
// wide = Math.max(wide, platformPanel.getPreferredSize().width);
platformPanel.setAlignmentX(Component.LEFT_ALIGNMENT);
panel.add(platformPanel);
int divWidth = platformPanel.getPreferredSize().width;
//int indent = new JCheckBox().getPreferredSize().width;
int indent = 0;
final JCheckBox showStopButton = new JCheckBox(Language.text("export.options.show_stop_button"));
showStopButton.setSelected(Preferences.getBoolean("export.application.stop"));
showStopButton.addItemListener(new ItemListener() {
public void itemStateChanged(ItemEvent e) {
Preferences.setBoolean("export.application.stop", showStopButton.isSelected());
}
});
showStopButton.setEnabled(Preferences.getBoolean("export.application.present"));
showStopButton.setBorder(new EmptyBorder(3, 13 + indent, 6, 13));
final JCheckBox presentButton = new JCheckBox(Language.text("export.options.present"));
presentButton.setSelected(Preferences.getBoolean("export.application.present"));
presentButton.addItemListener(new ItemListener() {
public void itemStateChanged(ItemEvent e) {
boolean sal = presentButton.isSelected();
Preferences.setBoolean("export.application.present", sal);
showStopButton.setEnabled(sal);
}
});
presentButton.setBorder(new EmptyBorder(3, 13, 3, 13));
JPanel presentPanel = new JPanel();
presentPanel.setLayout(new BoxLayout(presentPanel, BoxLayout.Y_AXIS));
Box fullScreenBox = Box.createHorizontalBox();
fullScreenBox.add(presentButton);
/*
//run.present.stop.color
// presentColorPanel = new JTextField();
// presentColorPanel.setFocusable(false);
// presentColorPanel.setEnabled(false);
presentColorPanel = new JPanel() {
public void paintComponent(Graphics g) {
g.setColor(Preferences.getColor("run.present.bgcolor"));
Dimension size = getSize();
g.fillRect(0, 0, size.width, size.height);
}
};
presentColorPanel.setBorder(BorderFactory.createBevelBorder(BevelBorder.LOWERED));
// presentColorPanel.setBorder(BorderFactory.createBevelBorder(BevelBorder.RAISED));
presentColorPanel.setMaximumSize(new Dimension(30, 20));
fullScreenBox.add(presentColorPanel);
*/
fullScreenBox.add(new ColorPreference("run.present.bgcolor"));
//presentPanel.add(fullScreenButton);
fullScreenBox.add(Box.createHorizontalStrut(10));
fullScreenBox.add(Box.createHorizontalGlue());
presentPanel.add(fullScreenBox);
// presentColorPanel.addMouseListener(new MouseAdapter() {
// public void mousePressed(MouseEvent e) {
// new ColorListener("run.present.bgcolor");
// }
// });
Box showStopBox = Box.createHorizontalBox();
showStopBox.add(showStopButton);
showStopBox.add(new ColorPreference("run.present.stop.color"));
showStopBox.add(Box.createHorizontalStrut(10));
showStopBox.add(Box.createHorizontalGlue());
presentPanel.add(showStopBox);
//presentPanel.add(showStopButton);
// presentPanel.add(Box.createHorizontalStrut(10));
// presentPanel.add(Box.createHorizontalGlue());
presentPanel.setBorder(new TitledBorder(Language.text("export.full_screen")));
// wide = Math.max(wide, platformPanel.getPreferredSize().width);
presentPanel.setAlignmentX(Component.LEFT_ALIGNMENT);
panel.add(presentPanel);
// Dimension good;
// good = new Dimension(wide, label1.getPreferredSize().height);
// label1.setMaximumSize(good);
// good = new Dimension(wide, label2.getPreferredSize().height);
// label2.setMaximumSize(good);
// good = new Dimension(wide, presentPanel.getPreferredSize().height);
//
JPanel embedPanel = new JPanel();
embedPanel.setLayout(new BoxLayout(embedPanel, BoxLayout.Y_AXIS));
String platformName = null;
if (Platform.isMacOS()) {
platformName = "Mac OS X";
} else if (Platform.isWindows()) {
platformName = "Windows (" + Platform.getNativeBits() + "-bit)";
} else if (Platform.isLinux()) {
platformName = "Linux (" + Platform.getNativeBits() + "-bit)";
}
boolean embed = Preferences.getBoolean("export.application.embed_java");
final String embedWarning =
"" +
// "" +
"Embedding Java will make the " + platformName + " application " +
"larger, but it will be far more likely to work. " +
"Users on other platforms will need to " +
"install Java " + PApplet.javaPlatform + ".";
final String nopeWarning =
"" +
// "" +
"Users on all platforms will have to install the latest " +
"version of Java " + PApplet.javaPlatform +
" from http://java.com/download. " +
"
";
//"from java.com/download.";
final JLabel warningLabel = new JLabel(embed ? embedWarning : nopeWarning);
warningLabel.addMouseListener(new MouseAdapter() {
public void mousePressed(MouseEvent event) {
Platform.openURL("http://java.com/download");
}
});
warningLabel.setBorder(new EmptyBorder(3, 13 + indent, 3, 13));
final JCheckBox embedJavaButton =
new JCheckBox(Language.text("export.embed_java.for") + " " + platformName);
embedJavaButton.setSelected(embed);
embedJavaButton.addItemListener(new ItemListener() {
public void itemStateChanged(ItemEvent e) {
boolean selected = embedJavaButton.isSelected();
Preferences.setBoolean("export.application.embed_java", selected);
if (selected) {
warningLabel.setText(embedWarning);
} else {
warningLabel.setText(nopeWarning);
}
}
});
embedJavaButton.setBorder(new EmptyBorder(3, 13, 3, 13));
embedPanel.add(embedJavaButton);
embedPanel.add(warningLabel);
embedPanel.setBorder(new TitledBorder(Language.text("export.embed_java")));
panel.add(embedPanel);
//
if (Platform.isMacOS()) {
JPanel signPanel = new JPanel();
signPanel.setLayout(new BoxLayout(signPanel, BoxLayout.Y_AXIS));
signPanel.setBorder(new TitledBorder(Language.text("export.code_signing")));
// gatekeeper: http://support.apple.com/kb/ht5290
// for developers: https://developer.apple.com/developer-id/
String thePain =
//"" +
"In recent versions of OS X, Apple has introduced the \u201CGatekeeper\u201D system, " +
"which makes it more difficult to run applications like those exported from Processing. ";
if (new File("/usr/bin/codesign_allocate").exists()) {
thePain +=
"This application will be \u201Cself-signed\u201D which means that Finder may report that the " +
"application is from an \u201Cunidentified developer\u201D. If the application will not " +
"run, try right-clicking the app and selecting Open from the pop-up menu. Or you can visit " +
"System Preferences \u2192 Security & Privacy and select Allow apps downloaded from: anywhere. ";
} else {
thePain +=
"Gatekeeper requires applications to be \u201Csigned\u201D, or they will be reported as damaged. " +
"To prevent this message, install Xcode (and the Command Line Tools) from the App Store, or visit " +
"System Preferences \u2192 Security & Privacy and select Allow apps downloaded from: anywhere. ";
}
thePain +=
"To avoid the messages entirely, manually code sign your app. " +
"For more information: https://developer.apple.com/developer-id/";
// xattr -d com.apple.quarantine thesketch.app
//signPanel.add(new JLabel(thePain));
//JEditorPane area = new JEditorPane("text/html", thePain);
//JTextPane area = new JEditorPane("text/html", thePain);
// JTextArea area = new JTextArea(thePain);
// area.setBackground(null);
// area.setFont(new Font("Dialog", Font.PLAIN, 10));
// area.setLineWrap(true);
// area.setWrapStyleWord(true);
// Are you f-king serious, Java API developers?
JLabel area = new JLabel("" + thePain + "");
area.setBorder(new EmptyBorder(3, 13, 3, 13));
// area.setPreferredSize(new Dimension(embedPanel.getPreferredSize().width, 100));
// area.setPreferredSize(new Dimension(300, 200));
signPanel.add(area);
// signPanel.add(Box.createHorizontalGlue());
signPanel.setAlignmentX(Component.LEFT_ALIGNMENT);
area.addMouseListener(new MouseAdapter() {
public void mousePressed(MouseEvent event) {
Platform.openURL("https://developer.apple.com/developer-id/");
}
});
panel.add(signPanel);
}
//
//String[] options = { Language.text("prompt.export"), Language.text("prompt.cancel") };
final JButton[] options = { exportButton, cancelButton };
final JOptionPane optionPane = new JOptionPane(panel,
JOptionPane.PLAIN_MESSAGE,
JOptionPane.YES_NO_OPTION,
null,
options,
exportButton); //options[0]);
final JDialog dialog = new JDialog(this, Language.text("export"), true);
dialog.setContentPane(optionPane);
exportButton.addActionListener(new ActionListener() {
public void actionPerformed(ActionEvent e) {
optionPane.setValue(exportButton);
}
});
cancelButton.addActionListener(new ActionListener() {
public void actionPerformed(ActionEvent e) {
optionPane.setValue(cancelButton);
}
});
optionPane.addPropertyChangeListener(new PropertyChangeListener() {
public void propertyChange(PropertyChangeEvent e) {
String prop = e.getPropertyName();
if (dialog.isVisible() &&
(e.getSource() == optionPane) &&
(prop.equals(JOptionPane.VALUE_PROPERTY))) {
// If you were going to check something before
// closing the window, you'd do it here.
dialog.setVisible(false);
}
}
});
dialog.pack();
// System.out.println("after pack: " + panel.getPreferredSize());
// dialog.setSize(optionPane.getPreferredSize());
dialog.setResizable(false);
// Center the window in the middle of the editor
Rectangle bounds = getBounds();
dialog.setLocation(bounds.x + (bounds.width - dialog.getSize().width) / 2,
bounds.y + (bounds.height - dialog.getSize().height) / 2);
dialog.setVisible(true);
Object value = optionPane.getValue();
if (value.equals(exportButton)) {
return jmode.handleExportApplication(sketch);
} else if (value.equals(cancelButton) || value.equals(-1)) {
// closed window by hitting Cancel or ESC
statusNotice(Language.text("export.notice.exporting.cancel"));
}
return false;
}
class ColorPreference extends JPanel implements ActionListener {
ColorChooser chooser;
String prefName;
public ColorPreference(String pref) {
prefName = pref;
setBorder(BorderFactory.createBevelBorder(BevelBorder.LOWERED));
setPreferredSize(new Dimension(30, 20));
setMaximumSize(new Dimension(30, 20));
addMouseListener(new MouseAdapter() {
public void mouseReleased(MouseEvent e) {
Color color = Preferences.getColor(prefName);
chooser = new ColorChooser(JavaEditor.this, true, color, Language.text("color_chooser.select"), ColorPreference.this);
chooser.show();
}
});
}
public void paintComponent(Graphics g) {
g.setColor(Preferences.getColor(prefName));
Dimension size = getSize();
g.fillRect(0, 0, size.width, size.height);
}
public void actionPerformed(ActionEvent e) {
Color color = chooser.getColor();
Preferences.setColor(prefName, color);
//presentColorPanel.repaint();
repaint();
chooser.hide();
}
}
// protected void selectColor(String prefName) {
// Color color = Preferences.getColor(prefName);
// final ColorChooser chooser = new ColorChooser(JavaEditor.this, true, color,
// "Select", new ActionListener() {
//
// @Override
// public void actionPerformed(ActionEvent e) {
// Preferences.setColor(prefName, c.getColor());
// }
// });
// }
/**
* Checks to see if the sketch has been modified, and if so,
* asks the user to save the sketch or cancel the export.
* This prevents issues where an incomplete version of the sketch
* would be exported, and is a fix for
* Bug 157
*/
protected boolean handleExportCheckModified() {
if (sketch.isReadOnly()) {
// if the files are read-only, need to first do a "save as".
Messages.showMessage(Language.text("export.messages.is_read_only"),
Language.text("export.messages.is_read_only.description"));
return false;
}
// don't allow if untitled
if (sketch.isUntitled()) {
Messages.showMessage(Language.text("export.messages.cannot_export"),
Language.text("export.messages.cannot_export.description"));
return false;
}
if (sketch.isModified()) {
Object[] options = { Language.text("prompt.ok"), Language.text("prompt.cancel") };
int result = JOptionPane.showOptionDialog(this,
Language.text("export.unsaved_changes"),
Language.text("menu.file.save"),
JOptionPane.OK_CANCEL_OPTION,
JOptionPane.QUESTION_MESSAGE,
null,
options,
options[0]);
if (result == JOptionPane.OK_OPTION) {
handleSave(true);
} else {
// why it's not CANCEL_OPTION is beyond me (at least on the mac)
// but f-- it.. let's get this shite done..
//} else if (result == JOptionPane.CANCEL_OPTION) {
statusNotice(Language.text("export.notice.cancel.unsaved_changes"));
//toolbar.clear();
return false;
}
}
return true;
}
public void handleRun() {
if (isDebuggerEnabled()) {
// Hitting Run while a sketch is running should restart the sketch
// https://github.com/processing/processing/issues/3623
if (debugger.isStarted()) {
debugger.stopDebug();
}
// Don't start the sketch paused, continue until a breakpoint or error
// https://github.com/processing/processing/issues/3096
debugger.continueDebug();
} else {
handleLaunch(false, false);
}
}
public void handlePresent() {
handleLaunch(true, false);
}
public void handleTweak() {
autoSave();
if (sketch.isModified()) {
Messages.showMessage(Language.text("menu.file.save"),
Language.text("tweak_mode.save_before_tweak"));
return;
}
handleLaunch(false, true);
}
protected void handleLaunch(boolean present, boolean tweak) {
prepareRun();
toolbar.activateRun();
synchronized (runtimeLock) {
runtimeLaunchRequested = true;
}
new Thread(() -> {
try {
synchronized (runtimeLock) {
if (runtimeLaunchRequested) {
runtimeLaunchRequested = false;
if (!tweak) {
runtime = jmode.handleLaunch(sketch, JavaEditor.this, present);
} else {
runtime = jmode.handleTweak(sketch, JavaEditor.this);
}
}
}
} catch (Exception e) {
EventQueue.invokeLater(() -> statusError(e));
}
}).start();
}
/**
* Event handler called when hitting the stop button. Stops a running debug
* session or performs standard stop action if not currently debugging.
*/
public void handleStop() {
if (debugger.isStarted()) {
debugger.stopDebug();
} else {
toolbar.activateStop();
try {
synchronized (runtimeLock) {
if (runtimeLaunchRequested) {
// Cancel the launch before the runtime was created
runtimeLaunchRequested = false;
}
if (runtime != null) {
// Cancel the launch after the runtime was created
runtime.close(); // kills the window
runtime = null;
}
}
} catch (Exception e) {
statusError(e);
}
toolbar.deactivateStop();
toolbar.deactivateRun();
// focus the PDE again after quitting presentation mode [toxi 030903]
toFront();
}
}
public void handleStep(int modifiers) {
if (modifiers == 0) {
Messages.log("Invoked 'Step Over' menu item");
debugger.stepOver();
} else if ((modifiers & ActionEvent.SHIFT_MASK) != 0) {
Messages.log("Invoked 'Step Into' menu item");
debugger.stepInto();
} else if ((modifiers & ActionEvent.ALT_MASK) != 0) {
Messages.log("Invoked 'Step Out' menu item");
debugger.stepOut();
}
}
public void handleContinue() {
Messages.log("Invoked 'Continue' menu item");
debugger.continueDebug();
}
public void onRunnerExiting(Runner runner) {
synchronized (runtimeLock) {
if (this.runtime == runner) {
deactivateRun();
}
}
}
// /** Toggle a breakpoint on the current line. */
// public void toggleBreakpoint() {
// toggleBreakpoint(getCurrentLineID().lineIdx());
// }
@Override
public void toggleBreakpoint(int lineIndex) {
debugger.toggleBreakpoint(lineIndex);
}
public boolean handleSaveAs() {
//System.out.println("handleSaveAs");
String oldName = getSketch().getCode(0).getFileName();
//System.out.println("old name: " + oldName);
boolean saved = super.handleSaveAs();
if (saved) {
// re-set breakpoints in first tab (name has changed)
List bps = debugger.getBreakpoints(oldName);
debugger.clearBreakpoints(oldName);
String newName = getSketch().getCode(0).getFileName();
//System.out.println("new name: " + newName);
for (LineBreakpoint bp : bps) {
LineID line = new LineID(newName, bp.lineID().lineIdx());
//System.out.println("setting: " + line);
debugger.setBreakpoint(line);
}
// add breakpoint marker comments to source file
for (SketchCode code : getSketch().getCode()) {
addBreakpointComments(code.getFileName());
}
// set new name of variable inspector
//inspector.setTitle(getSketch().getName());
}
return saved;
}
/**
* Add import statements to the current tab for all of packages inside
* the specified jar file.
*/
public void handleImportLibrary(String libraryName) {
// make sure the user didn't hide the sketch folder
sketch.ensureExistence();
// import statements into the main sketch file (code[0])
// if the current code is a .java file, insert into current
//if (current.flavor == PDE) {
if (mode.isDefaultExtension(sketch.getCurrentCode())) {
sketch.setCurrentCode(0);
}
Library lib = mode.findLibraryByName(libraryName);
if (lib == null) {
statusError("Unable to locate library: "+libraryName);
return;
}
// could also scan the text in the file to see if each import
// statement is already in there, but if the user has the import
// commented out, then this will be a problem.
StringList list = lib.getImports(); // ask the library for its imports
if (list == null) {
// Default to old behavior and load each package in the primary jar
list = Util.packageListFromClassPath(lib.getJarPath());
}
StringBuilder sb = new StringBuilder();
// for (int i = 0; i < list.length; i++) {
for (String item : list) {
sb.append("import ");
// sb.append(list[i]);
sb.append(item);
sb.append(".*;\n");
}
sb.append('\n');
sb.append(getText());
setText(sb.toString());
setSelection(0, 0); // scroll to start
sketch.setModified(true);
}
@Override
public void librariesChanged() {
preprocessingService.notifyLibrariesChanged();
}
@Override
public void codeFolderChanged() {
preprocessingService.notifyCodeFolderChanged();
}
@Override
public void sketchChanged() {
preprocessingService.notifySketchChanged();
}
public void statusError(String what) {
super.statusError(what);
// new Exception("deactivating RUN").printStackTrace();
// toolbar.deactivate(JavaToolbar.RUN);
toolbar.deactivateRun();
}
public void internalCloseRunner() {
// Added temporarily to dump error log. TODO: Remove this later [mk29]
//if (JavaMode.errorLogsEnabled) {
// writeErrorsToFile();
//}
handleStop();
}
// . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . .
// Additions from PDE X, Debug Mode, Twerk Mode...
/**
* Used instead of the windowClosing event handler, since it's not called on
* mode switch. Called when closing the editor window. Stops running debug
* sessions and kills the variable inspector window.
*/
@Override
public void dispose() {
//System.out.println("window dispose");
// quit running debug session
if (debugEnabled) {
debugger.stopDebug();
}
if (inspector != null) {
inspector.dispose();
}
preprocessingService.dispose();
pdex.dispose();
super.dispose();
}
/**
* Creates the debug menu. Includes ActionListeners for the menu items.
* Intended for adding to the menu bar.
*
* @return The debug menu
*/
protected JMenu buildDebugMenu() {
debugMenu = new JMenu(Language.text("menu.debug"));
JMenuItem item;
// "use the debugger" sounds too colloquial, and "enable" sounds too technical
// enableDebug =
// Toolkit.newJCheckBoxMenuItem(Language.text("menu.debug.enable"),
// KeyEvent.VK_D);
// enableDebug =
// Toolkit.newJCheckBoxMenuItem(Language.text("menu.debug.enable"),
// KeyEvent.VK_D);
debugItem = Toolkit.newJMenuItem(Language.text("menu.debug.enable"), 'D');
// enableDebug.setSelected(false);
debugItem.addActionListener(new ActionListener() {
public void actionPerformed(ActionEvent e) {
// updateDebugToggle();
toggleDebug();
}
});
// toggleDebugger.addChangeListener(new ChangeListener() {
// public void stateChanged(ChangeEvent e) {
// }
// });
debugMenu.add(debugItem);
debugMenu.addSeparator();
// item = Toolkit.newJMenuItemAlt(Language.text("menu.debug.debug"), KeyEvent.VK_R);
// item.addActionListener(new ActionListener() {
// public void actionPerformed(ActionEvent e) {
// Logger.getLogger(JavaEditor.class.getName()).log(Level.INFO, "Invoked 'Debug' menu item");
// debugger.startDebug();
// }
// });
// debugMenu.add(item);
item = Toolkit.newJMenuItem(Language.text("menu.debug.continue"), KeyEvent.VK_U);
item.addActionListener(new ActionListener() {
public void actionPerformed(ActionEvent e) {
handleContinue();
}
});
debugMenu.add(item);
item.setEnabled(false);
// item = new JMenuItem(Language.text("menu.debug.stop"));
// item.addActionListener(new ActionListener() {
// public void actionPerformed(ActionEvent e) {
// Logger.getLogger(JavaEditor.class.getName()).log(Level.INFO, "Invoked 'Stop' menu item");
// debugger.stopDebug();
// }
// });
// debugMenu.add(item);
item = Toolkit.newJMenuItem(Language.text("menu.debug.step"), KeyEvent.VK_J);
item.addActionListener(new ActionListener() {
public void actionPerformed(ActionEvent e) {
handleStep(0);
}
});
debugMenu.add(item);
item.setEnabled(false);
item = Toolkit.newJMenuItemShift(Language.text("menu.debug.step_into"), KeyEvent.VK_J);
item.addActionListener(new ActionListener() {
public void actionPerformed(ActionEvent e) {
handleStep(ActionEvent.SHIFT_MASK);
}
});
debugMenu.add(item);
item.setEnabled(false);
item = Toolkit.newJMenuItemAlt(Language.text("menu.debug.step_out"), KeyEvent.VK_J);
item.addActionListener(new ActionListener() {
public void actionPerformed(ActionEvent e) {
handleStep(ActionEvent.ALT_MASK);
}
});
debugMenu.add(item);
item.setEnabled(false);
debugMenu.addSeparator();
item =
Toolkit.newJMenuItem(Language.text("menu.debug.toggle_breakpoint"), 'B');
item.addActionListener(new ActionListener() {
public void actionPerformed(ActionEvent e) {
Messages.log("Invoked 'Toggle Breakpoint' menu item");
// TODO wouldn't getCaretLine() do the same thing with less effort?
toggleBreakpoint(getCurrentLineID().lineIdx());
}
});
debugMenu.add(item);
item.setEnabled(false);
/*
inspectorItem = Toolkit.newJMenuItem(Language.text("menu.debug.show_variables"), 'Y');
inspectorItem.addActionListener(new ActionListener() {
public void actionPerformed(ActionEvent e) {
toggleVariableInspector();
}
});
debugMenu.add(inspectorItem);
inspectorItem.setEnabled(false);
*/
/*
item = new JMenuItem(Language.text("menu.debug.list_breakpoints"));
item.addActionListener(new ActionListener() {
public void actionPerformed(ActionEvent e) {
Logger.getLogger(JavaEditor.class.getName()).log(Level.INFO, "Invoked 'List Breakpoints' menu item");
debugger.listBreakpoints();
}
});
debugMenu.add(item);
debugMenu.addSeparator();
*/
/*
item = new JMenuItem(Language.text("menu.debug.print_stack_trace"));
item.addActionListener(new ActionListener() {
public void actionPerformed(ActionEvent e) {
Logger.getLogger(JavaEditor.class.getName()).log(Level.INFO, "Invoked 'Print Stack Trace' menu item");
debugger.printStackTrace();
}
});
debugMenu.add(item);
item = new JMenuItem(Language.text("menu.debug.print_locals"));
item.addActionListener(new ActionListener() {
public void actionPerformed(ActionEvent e) {
Logger.getLogger(JavaEditor.class.getName()).log(Level.INFO, "Invoked 'Print Locals' menu item");
debugger.printLocals();
}
});
debugMenu.add(item);
item = new JMenuItem(Language.text("menu.debug.print_fields"));
item.addActionListener(new ActionListener() {
public void actionPerformed(ActionEvent e) {
Logger.getLogger(JavaEditor.class.getName()).log(Level.INFO, "Invoked 'Print This' menu item");
debugger.printThis();
}
});
debugMenu.add(item);
item = new JMenuItem(Language.text("menu.debug.print_source_location"));
item.addActionListener(new ActionListener() {
public void actionPerformed(ActionEvent e) {
Logger.getLogger(JavaEditor.class.getName()).log(Level.INFO, "Invoked 'Print Source' menu item");
debugger.printSource();
}
});
debugMenu.add(item);
item = new JMenuItem(Language.text("menu.debug.print_threads"));
item.addActionListener(new ActionListener() {
public void actionPerformed(ActionEvent e) {
Logger.getLogger(JavaEditor.class.getName()).log(Level.INFO, "Invoked 'Print Threads' menu item");
debugger.printThreads();
}
});
debugMenu.add(item);
debugMenu.addSeparator();
*/
// item = Toolkit.newJMenuItem(Language.text("menu.debug.toggle_variable_inspector"), KeyEvent.VK_I);
// item.addActionListener(new ActionListener() {
// public void actionPerformed(ActionEvent e) {
// Logger.getLogger(JavaEditor.class.getName()).log(Level.INFO, "Invoked 'Toggle Variable Inspector' menu item");
// toggleVariableInspector();
// }
// });
// debugMenu.add(item);
return debugMenu;
}
@Override
public boolean isDebuggerEnabled() {
return debugEnabled;
}
@Override
public JMenu buildModeMenu() {
return buildDebugMenu();
}
// handleOpenInternal() only called by the Editor constructor, meaning that
// this code is all useless. All these things will be in their default state.
// /**
// * Event handler called when loading another sketch in this editor.
// * Clears breakpoints of previous sketch.
// * @return true if a sketch was opened, false if aborted
// */
// @Override
// protected void handleOpenInternal(String path) throws EditorException {
// super.handleOpenInternal(path);
//
// // should already been stopped (open calls handleStop)
// if (debugger != null) {
// debugger.clearBreakpoints();
// }
// clearBreakpointedLines();
// variableInspector().reset();
// }
/**
* Extract breakpointed lines from source code marker comments. This removes
* marker comments from the editor text. Intended to be called on loading a
* sketch, since re-setting the sketches contents after removing the markers
* will clear all breakpoints.
*
* @return the list of {@link LineID}s where breakpoint marker comments were
* removed from.
*/
protected List stripBreakpointComments() {
List bps = new ArrayList<>();
// iterate over all tabs
Sketch sketch = getSketch();
for (int i = 0; i < sketch.getCodeCount(); i++) {
SketchCode tab = sketch.getCode(i);
String code = tab.getProgram();
String lines[] = code.split("\\r?\\n"); // newlines not included
//System.out.println(code);
// scan code for breakpoint comments
int lineIdx = 0;
for (String line : lines) {
//System.out.println(line);
if (line.endsWith(breakpointMarkerComment)) {
LineID lineID = new LineID(tab.getFileName(), lineIdx);
bps.add(lineID);
//System.out.println("found breakpoint: " + lineID);
// got a breakpoint
//dbg.setBreakpoint(lineID);
int index = line.lastIndexOf(breakpointMarkerComment);
lines[lineIdx] = line.substring(0, index);
}
lineIdx++;
}
//tab.setProgram(code);
code = PApplet.join(lines, "\n");
setTabContents(tab.getFileName(), code);
}
return bps;
}
/**
* Add breakpoint marker comments to the source file of a specific tab. This
* acts on the source file on disk, not the editor text. Intended to be
* called just after saving the sketch.
*
* @param tabFilename the tab file name
*/
protected void addBreakpointComments(String tabFilename) {
SketchCode tab = getTab(tabFilename);
if (tab == null) {
// this method gets called twice when saving sketch for the first time
// once with new name and another with old(causing NPE). Keep an eye out
// for potential issues. See #2675. TODO:
Messages.loge("Illegal tab name to addBreakpointComments() " + tabFilename);
return;
}
List bps = debugger.getBreakpoints(tab.getFileName());
// load the source file
////switched to using methods provided by the SketchCode class
// File sourceFile = new File(sketch.getFolder(), tab.getFileName());
//System.out.println("file: " + sourceFile);
try {
tab.load();
String code = tab.getProgram();
//System.out.println("code: " + code);
String lines[] = code.split("\\r?\\n"); // newlines not included
for (LineBreakpoint bp : bps) {
//System.out.println("adding bp: " + bp.lineID());
lines[bp.lineID().lineIdx()] += breakpointMarkerComment;
}
code = PApplet.join(lines, "\n");
//System.out.println("new code: " + code);
tab.setProgram(code);
tab.save();
} catch (IOException ex) {
Messages.loge(null, ex);
}
}
@Override
public boolean handleSave(boolean immediately) {
// note modified tabs
final List modified = new ArrayList<>();
for (int i = 0; i < getSketch().getCodeCount(); i++) {
SketchCode tab = getSketch().getCode(i);
if (tab.isModified()) {
modified.add(tab.getFileName());
}
}
boolean saved = super.handleSave(immediately);
if (saved) {
if (immediately) {
for (String tabFilename : modified) {
addBreakpointComments(tabFilename);
}
} else {
EventQueue.invokeLater(new Runnable() {
@Override
public void run() {
for (String tabFilename : modified) {
addBreakpointComments(tabFilename);
}
}
});
}
}
// if file location has changed, update autosaver
// autosaver.reloadAutosaveDir();
return saved;
}
/**
* Set text contents of a specific tab. Updates underlying document and text
* area. Clears Breakpoints.
*
* @param tabFilename the tab file name
* @param code the text to set
*/
protected void setTabContents(String tabFilename, String code) {
// remove all breakpoints of this tab
debugger.clearBreakpoints(tabFilename);
SketchCode currentTab = getCurrentTab();
// set code of tab
SketchCode tab = getTab(tabFilename);
if (tab != null) {
tab.setProgram(code);
// this updates document and text area
// TODO: does this have any negative effects? (setting the doc to null)
tab.setDocument(null);
setCode(tab);
// switch back to original tab
setCode(currentTab);
}
}
public void clearConsole() {
console.clear();
}
public void clearSelection() {
setSelection(getCaretOffset(), getCaretOffset());
}
/**
* Select a line in the current tab.
* @param lineIdx 0-based line number
*/
public void selectLine(int lineIdx) {
setSelection(getLineStartOffset(lineIdx), getLineStopOffset(lineIdx));
}
/**
* Set the cursor to the start of a line.
* @param lineIdx 0-based line number
*/
public void cursorToLineStart(int lineIdx) {
setSelection(getLineStartOffset(lineIdx), getLineStartOffset(lineIdx));
}
/**
* Set the cursor to the end of a line.
* @param lineIdx 0-based line number
*/
public void cursorToLineEnd(int lineIdx) {
setSelection(getLineStopOffset(lineIdx), getLineStopOffset(lineIdx));
}
/**
* Switch to a tab.
* @param tabFileName the file name identifying the tab. (as in
* {@link SketchCode#getFileName()})
*/
public void switchToTab(String tabFileName) {
Sketch s = getSketch();
for (int i = 0; i < s.getCodeCount(); i++) {
if (tabFileName.equals(s.getCode(i).getFileName())) {
s.setCurrentCode(i);
break;
}
}
}
public Debugger getDebugger() {
return debugger;
}
/**
* Access the custom text area object.
* @return the text area object
*/
public JavaTextArea getJavaTextArea() {
return (JavaTextArea) textarea;
}
public PreprocessingService getPreprocessingService() {
return preprocessingService;
}
/**
* Grab current contents of the sketch window, advance the console, stop any
* other running sketches, auto-save the user's code... not in that order.
*/
@Override
public void prepareRun() {
autoSave();
super.prepareRun();
downloadImports();
preprocessingService.cancel();
}
/**
* Downloads libraries that have been imported, that aren't available as a
* LocalContribution, but that have an AvailableContribution associated with
* them.
*/
protected void downloadImports() {
for (SketchCode sc : sketch.getCode()) {
if (sc.isExtension("pde")) {
String tabCode = sc.getProgram();
List imports = SourceUtils.parseProgramImports(tabCode);
if (!imports.isEmpty()) {
ArrayList importHeaders = new ArrayList<>();
for (ImportStatement importStatement : imports) {
importHeaders.add(importStatement.getFullClassName());
}
List installLibsHeaders =
getNotInstalledAvailableLibs(importHeaders);
if (!installLibsHeaders.isEmpty()) {
StringBuilder libList = new StringBuilder("Would you like to install them now?");
for (AvailableContribution ac : installLibsHeaders) {
libList.append("\n • ").append(ac.getName());
}
int option = Messages.showYesNoQuestion(this,
Language.text("contrib.import.dialog.title"),
Language.text("contrib.import.dialog.primary_text"),
libList.toString());
if (option == JOptionPane.YES_OPTION) {
ContributionManager.downloadAndInstallOnImport(base, installLibsHeaders);
}
}
}
}
}
}
/**
* Returns a list of AvailableContributions of those libraries that the user
* wants imported, but that are not installed.
*
* @param importHeaders
*/
private List getNotInstalledAvailableLibs(ArrayList importHeadersList) {
Map importMap =
ContributionListing.getInstance().getLibrariesByImportHeader();
List libList = new ArrayList<>();
for (String importHeaders : importHeadersList) {
int dot = importHeaders.lastIndexOf('.');
String entry = (dot == -1) ? importHeaders : importHeaders.substring(0,
dot);
if (entry.startsWith("java.") ||
entry.startsWith("javax.") ||
entry.startsWith("processing.")) {
continue;
}
Library library = null;
try {
library = this.getMode().getLibrary(entry);
if (library == null) {
Contribution c = importMap.get(importHeaders);
if (c != null && c instanceof AvailableContribution) {
libList.add((AvailableContribution) c);// System.out.println(importHeaders
// + "not found");
}
}
} catch (Exception e) {
// Not gonna happen (hopefully)
Contribution c = importMap.get(importHeaders);
if (c != null && c instanceof AvailableContribution) {
libList.add((AvailableContribution) c);// System.out.println(importHeaders
// + "not found");
}
}
}
return libList;
}
/**
* Displays a JDialog prompting the user to save when the user hits
* run/present/etc.
*/
protected void autoSave() {
if (!JavaMode.autoSaveEnabled) {
return;
}
try {
if (sketch.isModified() && !sketch.isUntitled()) {
if (JavaMode.autoSavePromptEnabled) {
final JDialog autoSaveDialog =
new JDialog(base.getActiveEditor(), getSketch().getName(), true);
Container container = autoSaveDialog.getContentPane();
JPanel panelMain = new JPanel();
panelMain.setBorder(BorderFactory.createEmptyBorder(4, 0, 2, 2));
panelMain.setLayout(new BoxLayout(panelMain, BoxLayout.PAGE_AXIS));
JPanel panelLabel = new JPanel(new FlowLayout(FlowLayout.LEFT));
JLabel label = new JLabel(" There are unsaved"
+ " changes in your sketch.
"
+ " Do you want to save it before"
+ " running? ");
label.setFont(new Font(label.getFont().getName(),
Font.PLAIN, label.getFont().getSize() + 1));
panelLabel.add(label);
panelMain.add(panelLabel);
final JCheckBox dontRedisplay = new JCheckBox("Remember this decision");
JPanel panelButtons = new JPanel(new FlowLayout(FlowLayout.CENTER, 8, 2));
JButton btnRunSave = new JButton("Save and Run");
btnRunSave.addActionListener(new ActionListener() {
@Override
public void actionPerformed(ActionEvent e) {
handleSave(true);
if (dontRedisplay.isSelected()) {
JavaMode.autoSavePromptEnabled = !dontRedisplay.isSelected();
JavaMode.defaultAutoSaveEnabled = true;
jmode.savePreferences();
}
autoSaveDialog.dispose();
}
});
panelButtons.add(btnRunSave);
JButton btnRunNoSave = new JButton("Run, Don't Save");
btnRunNoSave.addActionListener(new ActionListener() {
@Override
public void actionPerformed(ActionEvent e) {
if (dontRedisplay.isSelected()) {
JavaMode.autoSavePromptEnabled = !dontRedisplay.isSelected();
JavaMode.defaultAutoSaveEnabled = false;
jmode.savePreferences();
}
autoSaveDialog.dispose();
}
});
panelButtons.add(btnRunNoSave);
panelMain.add(panelButtons);
JPanel panelCheck = new JPanel();
panelCheck.setLayout(new FlowLayout(FlowLayout.CENTER, 0, 0));
panelCheck.add(dontRedisplay);
panelMain.add(panelCheck);
container.add(panelMain);
autoSaveDialog.setResizable(false);
autoSaveDialog.pack();
autoSaveDialog.setLocationRelativeTo(base.getActiveEditor());
autoSaveDialog.setVisible(true);
} else if (JavaMode.defaultAutoSaveEnabled) {
handleSave(true);
}
}
} catch (Exception e) {
statusError(e);
}
}
/**
* Access variable inspector window.
* @return the variable inspector object
*/
public VariableInspector variableInspector() {
return inspector;
}
protected void activateRun() {
debugItem.setEnabled(false);
// toolbar.activate(JavaToolbar.RUN);
toolbar.activateRun();
}
/**
* Deactivate the Run button. This is called by Runner to notify that the
* sketch has stopped running, usually in response to an error (or maybe
* the sketch completing and exiting?) Tools should not call this function.
* To initiate a "stop" action, call handleStop() instead.
*/
public void deactivateRun() {
toolbar.deactivateRun();
debugItem.setEnabled(true);
}
protected void activateDebug() {
//debugToolbar.activate(DebugToolbar.DEBUG);
activateRun();
}
protected void deactivateDebug() {
deactivateRun();
}
protected void activateContinue() {
((JavaToolbar) toolbar).activateContinue();
}
protected void deactivateContinue() {
((JavaToolbar) toolbar).deactivateContinue();
}
protected void activateStep() {
((JavaToolbar) toolbar).activateStep();
}
protected void deactivateStep() {
((JavaToolbar) toolbar).deactivateStep();
}
public void toggleDebug() {
debugEnabled = !debugEnabled;
rebuildToolbar();
repaint(); // show/hide breakpoints in the gutter
if (debugEnabled) {
debugItem.setText(Language.text("menu.debug.disable"));
} else {
debugItem.setText(Language.text("menu.debug.enable"));
}
inspector.setVisible(debugEnabled);
for (Component item : debugMenu.getMenuComponents()) {
if (item instanceof JMenuItem && item != debugItem) {
item.setEnabled(debugEnabled);
}
}
}
/*
public void toggleVariableInspector() {
if (inspector.isVisible()) {
inspectorItem.setText(Language.text("menu.debug.show_variables"));
inspector.setVisible(false);
} else {
// inspector.setFocusableWindowState(false); // to not get focus when set visible
inspectorItem.setText(Language.text("menu.debug.show_variables"));
inspector.setVisible(true);
// inspector.setFocusableWindowState(true); // allow to get focus again
}
}
*/
// public void showVariableInspector() {
// tray.setVisible(true);
// }
// /**
// * Set visibility of the variable inspector window.
// * @param visible true to set the variable inspector visible,
// * false for invisible.
// */
// public void showVariableInspector(boolean visible) {
// tray.setVisible(visible);
// }
//
//
// public void hideVariableInspector() {
// tray.setVisible(true);
// }
//
//
// /** Toggle visibility of the variable inspector window. */
// public void toggleVariableInspector() {
// tray.setFocusableWindowState(false); // to not get focus when set visible
// tray.setVisible(!tray.isVisible());
// tray.setFocusableWindowState(true); // allow to get focus again
// }
/**
* Set the line to highlight as currently suspended at. Will override the
* breakpoint color, if set. Switches to the appropriate tab and scroll to
* the line by placing the cursor there.
* @param line the line to highlight as current suspended line
*/
public void setCurrentLine(LineID line) {
clearCurrentLine();
if (line == null) {
// safety, e.g. when no line mapping is found and the null line is used.
return;
}
switchToTab(line.fileName());
// scroll to line, by setting the cursor
cursorToLineStart(line.lineIdx());
// highlight line
currentLine = new LineHighlight(line.lineIdx(), this);
currentLine.setMarker(JavaTextArea.STEP_MARKER);
currentLine.setPriority(10); // fixes current line being hidden by the breakpoint when moved down
}
/** Clear the highlight for the debuggers current line. */
public void clearCurrentLine() {
if (currentLine != null) {
currentLine.clear();
currentLine.dispose();
// revert to breakpoint color if any is set on this line
for (LineHighlight hl : breakpointedLines) {
if (hl.getLineID().equals(currentLine.getLineID())) {
hl.paint();
break;
}
}
currentLine = null;
}
}
/**
* Add highlight for a breakpointed line.
* @param lineID the line id to highlight as breakpointed
*/
public void addBreakpointedLine(LineID lineID) {
LineHighlight hl = new LineHighlight(lineID, this);
hl.setMarker(JavaTextArea.BREAK_MARKER);
breakpointedLines.add(hl);
// repaint current line if it's on this line
if (currentLine != null && currentLine.getLineID().equals(lineID)) {
currentLine.paint();
}
}
/**
* Remove a highlight for a breakpointed line. Needs to be on the current tab.
* @param lineIdx the line index on the current tab to remove a breakpoint
* highlight from
*/
public void removeBreakpointedLine(int lineIdx) {
LineID line = getLineIDInCurrentTab(lineIdx);
//System.out.println("line id: " + line.fileName() + " " + line.lineIdx());
LineHighlight foundLine = null;
for (LineHighlight hl : breakpointedLines) {
if (hl.getLineID().equals(line)) {
foundLine = hl;
break;
}
}
if (foundLine != null) {
foundLine.clear();
breakpointedLines.remove(foundLine);
foundLine.dispose();
// repaint current line if it's on this line
if (currentLine != null && currentLine.getLineID().equals(line)) {
currentLine.paint();
}
}
}
/** Remove all highlights for breakpointed lines. */
public void clearBreakpointedLines() {
for (LineHighlight hl : breakpointedLines) {
hl.clear();
hl.dispose();
}
breakpointedLines.clear(); // remove all breakpoints
// fix highlights not being removed when tab names have
// changed due to opening a new sketch in same editor
getJavaTextArea().clearGutterText();
// repaint current line
if (currentLine != null) {
currentLine.paint();
}
}
/**
* Retrieve a {@link LineID} object for a line on the current tab.
* @param lineIdx the line index on the current tab
* @return the {@link LineID} object representing a line index on the
* current tab
*/
public LineID getLineIDInCurrentTab(int lineIdx) {
return new LineID(getSketch().getCurrentCode().getFileName(), lineIdx);
}
/**
* Retrieve line of sketch where the cursor currently resides.
* @return the current {@link LineID}
*/
protected LineID getCurrentLineID() {
String tab = getSketch().getCurrentCode().getFileName();
int lineNo = getTextArea().getCaretLine();
return new LineID(tab, lineNo);
}
/**
* Check whether a {@link LineID} is on the current tab.
* @param line the {@link LineID}
* @return true, if the {@link LineID} is on the current tab.
*/
public boolean isInCurrentTab(LineID line) {
return line.fileName().equals(getSketch().getCurrentCode().getFileName());
}
/**
* Event handler called when switching between tabs. Loads all line
* background colors set for the tab.
* @param code tab to switch to
*/
@Override
public void setCode(SketchCode code) {
Document oldDoc = code.getDocument();
//System.out.println("tab switch: " + code.getFileName());
// set the new document in the textarea, etc. need to do this first
super.setCode(code);
Document newDoc = code.getDocument();
if (oldDoc != newDoc && pdex != null) {
pdex.documentChanged(newDoc);
}
// set line background colors for tab
final JavaTextArea ta = getJavaTextArea();
// can be null when setCode is called the first time (in constructor)
if (ta != null) {
// clear all gutter text
ta.clearGutterText();
// first paint breakpoints
if (breakpointedLines != null) {
for (LineHighlight hl : breakpointedLines) {
if (isInCurrentTab(hl.getLineID())) {
hl.paint();
}
}
}
// now paint current line (if any)
if (currentLine != null) {
if (isInCurrentTab(currentLine.getLineID())) {
currentLine.paint();
}
}
}
if (getDebugger() != null && getDebugger().isStarted()) {
getDebugger().startTrackingLineChanges();
}
if (errorColumn != null) {
errorColumn.repaint();
}
}
/**
* Get a tab by its file name.
* @param filename the filename to search for.
* @return the {@link SketchCode} object for the tab, or null if not found
*/
public SketchCode getTab(String filename) {
Sketch s = getSketch();
for (SketchCode c : s.getCode()) {
if (c.getFileName().equals(filename)) {
return c;
}
}
return null;
}
/**
* Retrieve the current tab.
* @return the {@link SketchCode} representing the current tab
*/
public SketchCode getCurrentTab() {
return getSketch().getCurrentCode();
}
/**
* Access the currently edited document.
* @return the document object
*/
public Document currentDocument() {
return getCurrentTab().getDocument();
}
public void statusBusy() {
statusNotice(Language.text("editor.status.debug.busy"));
}
public void statusHalted() {
statusNotice(Language.text("editor.status.debug.halt"));
}
/**
* Updates the error table in the Error Window.
* Overridden to handle the fugly import suggestions text.
*/
@Override
public void updateErrorTable(List problems) {
errorTable.clearRows();
for (Problem p : problems) {
JavaProblem jp = (JavaProblem) p;
String message = p.getMessage();
if (JavaMode.importSuggestEnabled &&
jp.getImportSuggestions() != null &&
jp.getImportSuggestions().length > 0) {
message += " (double-click for suggestions)";
}
errorTable.addRow(p, message,
sketch.getCode(jp.getTabIndex()).getPrettyName(),
Integer.toString(p.getLineNumber() + 1));
// Added +1 because lineNumbers internally are 0-indexed
}
}
@Override
public void errorTableDoubleClick(Object item) {
JavaProblem p = (JavaProblem) item;
// MouseEvent evt = null;
String[] suggs = p.getImportSuggestions();
if (suggs != null && suggs.length > 0) {
// String t = p.getMessage() + "(Import Suggestions available)";
// FontMetrics fm = getFontMetrics(getFont());
// int x1 = fm.stringWidth(p.getMessage());
// int x2 = fm.stringWidth(t);
// if (evt.getX() > x1 && evt.getX() < x2) {
String[] list = p.getImportSuggestions();
String className = list[0].substring(list[0].lastIndexOf('.') + 1);
String[] temp = new String[list.length];
for (int i = 0; i < list.length; i++) {
temp[i] = "Import '" + className + "' (" + list[i] + ")";
}
// showImportSuggestion(temp, evt.getXOnScreen(), evt.getYOnScreen() - 3 * getFont().getSize());
Point mouse = MouseInfo.getPointerInfo().getLocation();
showImportSuggestion(temp, mouse.x, mouse.y);
} else {
errorTableClick(item);
}
}
JFrame frmImportSuggest;
private void showImportSuggestion(String[] list, int x, int y) {
if (frmImportSuggest != null) {
// frmImportSuggest.setVisible(false);
// frmImportSuggest = null;
return;
}
final JList classList = new JList<>(list);
classList.setSelectionMode(ListSelectionModel.SINGLE_SELECTION);
frmImportSuggest = new JFrame();
frmImportSuggest.setUndecorated(true);
frmImportSuggest.setDefaultCloseOperation(JFrame.DISPOSE_ON_CLOSE);
JPanel panel = new JPanel();
panel.setLayout(new BoxLayout(panel, BoxLayout.Y_AXIS));
panel.setBackground(Color.WHITE);
frmImportSuggest.setBackground(Color.WHITE);
panel.add(classList);
JLabel label = new JLabel("
(Click to insert)");
label.setBackground(Color.WHITE);
label.setHorizontalTextPosition(SwingConstants.LEFT);
panel.add(label);
panel.validate();
frmImportSuggest.getContentPane().add(panel);
frmImportSuggest.pack();
classList.addListSelectionListener(new ListSelectionListener() {
public void valueChanged(ListSelectionEvent e) {
if (classList.getSelectedValue() != null) {
try {
String t = classList.getSelectedValue().trim();
Messages.log(t);
int x = t.indexOf('(');
String impString = "import " + t.substring(x + 1, t.indexOf(')')) + ";\n";
int ct = getSketch().getCurrentCodeIndex();
getSketch().setCurrentCode(0);
getTextArea().getDocument().insertString(0, impString, null);
getSketch().setCurrentCode(ct);
} catch (BadLocationException ble) {
Messages.log("Failed to insert import");
ble.printStackTrace();
}
}
frmImportSuggest.setVisible(false);
frmImportSuggest.dispose();
frmImportSuggest = null;
}
});
frmImportSuggest.addWindowFocusListener(new WindowFocusListener() {
@Override
public void windowLostFocus(WindowEvent e) {
if (frmImportSuggest != null) {
frmImportSuggest.dispose();
frmImportSuggest = null;
}
}
@Override
public void windowGainedFocus(WindowEvent e) {
}
});
frmImportSuggest.setLocation(x, y);
frmImportSuggest.setBounds(x, y, 250, 100);
frmImportSuggest.pack();
frmImportSuggest.setVisible(true);
}
public boolean hasJavaTabs() {
return hasJavaTabs;
}
/**
* Checks if the sketch contains java tabs. If it does, the editor ain't
* built for it, yet. Also, user should really start looking at a full IDE
* like Eclipse. Disable compilation check and some more features.
*/
private boolean checkForJavaTabs() {
for (SketchCode code : getSketch().getCode()) {
if (code.getExtension().equals("java")) {
if (!javaTabWarned) {
System.out.println(getSketch().getName() + " contains .java tabs. ");
System.out.println("Some editor features (like completion " +
"and error checking) will be disabled.");
//Base.showWarning("Cannot debug advanced sketches", msg);
javaTabWarned = true;
}
return true;
}
}
return false;
}
@Override
protected void applyPreferences() {
super.applyPreferences();
if (jmode != null) {
jmode.loadPreferences();
Messages.log("Applying prefs");
// trigger it once to refresh UI
pdex.preferencesChanged();
}
}
// . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . .
// TWEAK MODE
static final String PREF_TWEAK_PORT = "tweak.port";
static final String PREF_TWEAK_SHOW_CODE = "tweak.showcode";
public String[] baseCode;
TweakClient tweakClient;
protected void startTweakMode() {
getJavaTextArea().startTweakMode();
}
protected void stopTweakMode(List> handles) {
tweakClient.shutdown();
getJavaTextArea().stopTweakMode();
// remove space from the code (before and after)
//removeSpacesFromCode();
// check which tabs were modified
boolean[] tweakedTabs = getTweakedTabs(handles);
boolean modified = anythingTrue(tweakedTabs);
if (modified) {
// ask to keep the values
if (Messages.showYesNoQuestion(this, Language.text("tweak_mode"),
Language.text("tweak_mode.keep_changes.line1"),
Language.text("tweak_mode.keep_changes.line2")) == JOptionPane.YES_OPTION) {
for (int i = 0; i < sketch.getCodeCount(); i++) {
if (tweakedTabs[i]) {
sketch.getCode(i).setModified(true);
} else {
// load the saved code of tabs that didn't change
// (there might be formatting changes that should not be saved)
sketch.getCode(i).setProgram(sketch.getCode(i).getSavedProgram());
/* Wild Hack: set document to null so the text editor will refresh
the program contents when the document tab is being clicked */
sketch.getCode(i).setDocument(null);
if (i == sketch.getCurrentCodeIndex()) {
// this will update the current code
setCode(sketch.getCurrentCode());
}
}
}
// save the sketch
try {
sketch.save();
} catch (IOException e) {
Messages.showWarning("Error", "Could not save the modified sketch.", e);
}
// repaint the editor header (show the modified tabs)
header.repaint();
textarea.invalidate();
} else { // no or canceled = don't keep changes
loadSavedCode();
// update the painter to draw the saved (old) code
textarea.invalidate();
}
} else {
// number values were not modified but we need to load the saved code
// because of some formatting changes
loadSavedCode();
textarea.invalidate();
}
}
static private boolean anythingTrue(boolean[] list) {
for (boolean b : list) {
if (b) return true;
}
return false;
}
protected void updateInterface(List> handles,
List> colorBoxes) {
getJavaTextArea().updateInterface(handles, colorBoxes);
}
static private boolean[] getTweakedTabs(List> handles) {
boolean[] outgoing = new boolean[handles.size()];
for (int i = 0; i < handles.size(); i++) {
for (Handle h : handles.get(i)) {
if (h.valueChanged()) {
outgoing[i] = true;
}
}
}
return outgoing;
}
protected void initBaseCode() {
SketchCode[] code = sketch.getCode();
baseCode = new String[code.length];
for (int i = 0; i < code.length; i++) {
baseCode[i] = code[i].getSavedProgram();
}
}
protected void initEditorCode(List> handles, boolean withSpaces) {
SketchCode[] sketchCode = sketch.getCode();
for (int tab=0; tab> handles = parser.allHandles;
if (code.length < 1) {
return false;
}
if (handles.size() == 0) {
return false;
}
int afterSizePos = SketchParser.getAfterSizePos(baseCode[0]);
if (afterSizePos < 0) {
return false;
}
// get port number from preferences.txt
int port;
String portStr = Preferences.get(PREF_TWEAK_PORT);
if (portStr == null) {
Preferences.set(PREF_TWEAK_PORT, "auto");
portStr = "auto";
}
if (portStr.equals("auto")) {
// random port for udp (0xc000 - 0xffff)
port = (int)(Math.random()*0x3fff) + 0xc000;
} else {
port = Preferences.getInteger(PREF_TWEAK_PORT);
}
// create the client that will send the new values to the sketch
tweakClient = new TweakClient(port);
// update handles with a reference to the client object
for (int tab=0; tab 0) {
header += "int[] tweakmode_int = new int["+numOfInts+"];\n";
}
if (numOfFloats > 0) {
header += "float[] tweakmode_float = new float["+numOfFloats+"];\n\n";
}
// add the server code that will receive the value change messages
// header += TweakClient.getServerCode(port, numOfInts>0, numOfFloats>0);
header += "TweakModeServer tweakmode_Server;\n";
header += "void tweakmode_initAllVars() {\n";
//for (int i=0; i list : handles) {
//for (Handle n : handles[i]) {
for (Handle n : list) {
header += " " + n.name + " = " + n.strValue + ";\n";
}
}
header += "}\n\n";
header += "void tweakmode_initCommunication() {\n";
header += " tweakmode_Server = new TweakModeServer();\n";
header += " tweakmode_Server.setup();\n";
header += " tweakmode_Server.start();\n";
header += "}\n";
header += "\n\n\n\n\n";
// add call to our initAllVars and initOSC functions
// from the setup() function.
String addToSetup = "\n\n\n"+
" /* TWEAKMODE */\n"+
" tweakmode_initAllVars();\n"+
" tweakmode_initCommunication();\n"+
" /* TWEAKMODE */\n\n";
afterSizePos = SketchParser.getAfterSizePos(c);
c = replaceString(c, afterSizePos, afterSizePos, addToSetup);
// Server code defines a class, so it should go later in the sketch
String serverCode =
TweakClient.getServerCode(port, numOfInts>0, numOfFloats>0);
code[0].setProgram(header + c + serverCode);
// print out modified code
String showModCode = Preferences.get(PREF_TWEAK_SHOW_CODE);
if (showModCode == null) {
Preferences.setBoolean(PREF_TWEAK_SHOW_CODE, false);
}
if (Preferences.getBoolean(PREF_TWEAK_SHOW_CODE)) {
System.out.println("\nTweakMode modified code:\n");
for (int i=0; i handles[])
static private int howManyInts(List> handles) {
int count = 0;
for (List list : handles) {
for (Handle n : list) {
if ("int".equals(n.type) || "hex".equals(n.type) || "webcolor".equals(n.type)) {
count++;
}
}
}
return count;
}
//private int howManyFloats(ArrayList handles[])
static private int howManyFloats(List> handles) {
int count = 0;
for (List list : handles) {
for (Handle n : list) {
if ("float".equals(n.type)) {
count++;
}
}
}
return count;
}
}
© 2015 - 2024 Weber Informatics LLC | Privacy Policy