Files
processing4/app/src/processing/mode/javascript/JavaScriptEditor.java
T

565 lines
14 KiB
Java

package processing.mode.javascript;
import processing.mode.javascript.ServingEditor;
import java.awt.event.ActionEvent;
import java.awt.event.ActionListener;
import java.io.File;
import java.io.IOException;
import javax.swing.JMenu;
import javax.swing.JMenuItem;
import processing.app.Base;
import processing.app.EditorState;
import processing.app.Settings;
import processing.app.Editor;
import processing.app.EditorToolbar;
import processing.app.Sketch;
import processing.app.Formatter;
import processing.app.Mode;
import processing.mode.java.AutoFormat;
import javax.swing.*;
public class JavaScriptEditor extends ServingEditor
{
final static String PROP_KEY_MODE = "mode";
final static String PROP_VAL_MODE = "JavaScript";
private JavaScriptMode jsMode;
private DirectivesEditor directivesEditor;
// tapping into Java mode might not be wanted?
processing.mode.java.PdeKeyListener listener;
protected JavaScriptEditor ( Base base, String path, EditorState state, Mode mode )
{
super(base, path, state, mode);
listener = new processing.mode.java.PdeKeyListener(this,textarea);
jsMode = (JavaScriptMode) mode;
}
public EditorToolbar createToolbar ()
{
return new JavaScriptToolbar(this, base);
}
public Formatter createFormatter ()
{
return new AutoFormat();
}
// - - - - - - - - - - - - - - - - - -
// Menu methods
public JMenu buildFileMenu ()
{
JMenuItem exportItem = Base.newJMenuItem("Export", 'E');
exportItem.addActionListener(new ActionListener() {
public void actionPerformed(ActionEvent e) {
handleExport( true );
}
});
return buildFileMenu(new JMenuItem[] { exportItem });
}
public JMenu buildSketchMenu ()
{
JMenuItem startServerItem = Base.newJMenuItem("Start Server", 'R');
startServerItem.addActionListener(new ActionListener() {
public void actionPerformed(ActionEvent e) {
handleStartServer();
}
});
JMenuItem openInBrowserItem = Base.newJMenuItem("Reopen in Browser", 'B');
openInBrowserItem.addActionListener(new ActionListener() {
public void actionPerformed(ActionEvent e) {
handleOpenInBrowser();
}
});
JMenuItem stopServerItem = new JMenuItem("Stop Server");
stopServerItem.addActionListener(new ActionListener() {
public void actionPerformed(ActionEvent e) {
handleStopServer();
}
});
JMenuItem copyServerAddressItem = new JMenuItem("Copy Server Address");
copyServerAddressItem.addActionListener(new ActionListener(){
public void actionPerformed(ActionEvent e) {
handleCopyServerAddress();
}
});
// copyServerAddressItem.getInputMap().put(
// javax.swing.KeyStroke.getKeyStroke('C', java.awt.event.InputEvent.ALT_MASK | java.awt.event.InputEvent.META_MASK ),
// new AbstractAction () {
// public void actionPerformed ( ActionEvent e ) {
// handleCopyServerAddress();
// }
// }
// );
JMenuItem setServerPortItem = new JMenuItem("Set Server Port");
setServerPortItem.addActionListener(new ActionListener(){
public void actionPerformed (ActionEvent e) {
handleSetServerPort();
}
});
return buildSketchMenu(new JMenuItem[] {
startServerItem, openInBrowserItem, stopServerItem,
copyServerAddressItem, setServerPortItem
});
}
public JMenu buildModeMenu() {
JMenu menu = new JMenu("JavaScript");
JMenuItem item;
item = new JMenuItem("Playback Settings (Directives)");
item.addActionListener(new ActionListener() {
public void actionPerformed(ActionEvent e) {
handleShowDirectivesEditor();
}
});
menu.add(item);
menu.addSeparator();
item = new JMenuItem("Start Custom Template");
item.addActionListener(new ActionListener() {
public void actionPerformed(ActionEvent e) {
handleCreateCustomTemplate();
}
});
menu.add(item);
item = new JMenuItem("Show Custom Template");
item.addActionListener(new ActionListener() {
public void actionPerformed(ActionEvent e) {
handleOpenCustomTemplateFolder();
}
});
menu.add(item);
return menu;
}
public JMenu buildHelpMenu ()
{
JMenu menu = new JMenu("Help ");
JMenuItem item;
// TODO switch to "http://js.processing.org/"?
item = new JMenuItem("QuickStart for JS Devs");
item.addActionListener(new ActionListener() {
public void actionPerformed(ActionEvent e) {
Base.openURL("http://processingjs.org/reference/articles/jsQuickStart");
}
});
menu.add(item);
item = new JMenuItem("QuickStart for Processing Devs");
item.addActionListener(new ActionListener() {
public void actionPerformed(ActionEvent e) {
Base.openURL("http://processingjs.org/reference/articles/p5QuickStart");
}
});
menu.add(item);
/* TODO Implement an environment page
item = new JMenuItem("Environment");
item.addActionListener(new ActionListener() {
public void actionPerformed(ActionEvent e) {
showReference("environment" + File.separator + "index.html");
}
});
menu.add(item);
*/
/* TODO Implement a troubleshooting page
item = new JMenuItem("Troubleshooting");
item.addActionListener(new ActionListener() {
public void actionPerformed(ActionEvent e) {
Base.openURL("http://wiki.processing.org/w/Troubleshooting");
}
});
menu.add(item);
*/
item = new JMenuItem("Reference");
item.addActionListener(new ActionListener() {
public void actionPerformed(ActionEvent e) {
//TODO get offline reference archive corresponding to the release
// packaged with this mode see: P.js ticket 1146 "Offline Reference"
Base.openURL("http://processingjs.org/reference");
}
});
menu.add(item);
item = Base.newJMenuItemShift("Find in Reference", 'F');
item.addActionListener(new ActionListener() {
public void actionPerformed(ActionEvent e) {
handleFindReferenceHACK();
}
});
menu.add(item);
/* TODO FAQ
item = new JMenuItem("Frequently Asked Questions");
item.addActionListener(new ActionListener() {
public void actionPerformed(ActionEvent e) {
Base.openURL("http://wiki.processing.org/w/FAQ");
}
});
menu.add(item);
*/
item = new JMenuItem("Visit Processingjs.org");
item.addActionListener(new ActionListener() {
public void actionPerformed(ActionEvent e) {
Base.openURL("http://processingjs.org/");
}
});
menu.add(item);
// OSX has its own about menu
if (!Base.isMacOS()) {
menu.addSeparator();
item = new JMenuItem("About Processing");
item.addActionListener( new ActionListener() {
public void actionPerformed(ActionEvent e) {
base.handleAbout();
}
});
menu.add(item);
}
return menu;
}
public String getCommentPrefix ()
{
return "//";
}
/**
* Called when the window is going to be reused for another sketch.
*/
public void internalCloseRunner ()
{
handleStopServer();
if ( directivesEditor != null )
{
directivesEditor.hide();
directivesEditor = null;
}
}
public void deactivateRun ()
{
// not sure what to do here ..
}
// - - - - - - - - - - - - - - - - - -
private void handleSetServerPort ()
{
statusEmpty();
boolean wasRunning = serverRunning();
if ( wasRunning ) {
statusNotice("Server was running, changing the port requires a restart.");
stopServer();
}
setServerPort();
saveSketchSettings();
if ( wasRunning ) {
startServer( getExportFolder() );
}
}
private void handleCreateCustomTemplate ()
{
Sketch sketch = getSketch();
File ajs = sketch.getMode().
getContentFile(JavaScriptBuild.EXPORTED_FOLDER_NAME);
File tjs = getCustomTemplateFolder();
if ( !tjs.exists() )
{
try {
Base.copyDir( ajs, tjs );
statusNotice( "Default template copied." );
Base.openFolder( tjs );
} catch ( java.io.IOException ioe ) {
Base.showWarning("Copy default template folder",
"Something went wrong when copying the template folder.", ioe);
}
}
else
statusError( "You need to remove the current "+
"\""+JavaScriptBuild.TEMPLATE_FOLDER_NAME+"\" "+
"folder from the sketch." );
}
private void handleOpenCustomTemplateFolder ()
{
File tjs = getCustomTemplateFolder();
if ( tjs.exists() )
{
Base.openFolder( tjs );
}
else
{
// TODO: promt to create one?
statusNotice( "You have no custom template with this sketch. Create one from the menu!" );
}
}
private void handleCopyServerAddress ()
{
String address = getServerAddress();
if ( address != null )
{
java.awt.datatransfer.StringSelection stringSelection =
new java.awt.datatransfer.StringSelection( address );
java.awt.datatransfer.Clipboard clipboard =
java.awt.Toolkit.getDefaultToolkit().getSystemClipboard();
clipboard.setContents( stringSelection, null );
}
}
private void handleShowDirectivesEditor ()
{
if ( directivesEditor == null )
{
directivesEditor = new DirectivesEditor(this);
}
directivesEditor.show();
}
// this catches the textarea right-click events
public void showReference( String filename )
{
// TODO: catch handleFindReference directly
handleFindReferenceHACK();
}
private void handleFindReferenceHACK ()
{
if (textarea.isSelectionActive()) {
Base.openURL(
"http://www.google.com/search?q=" +
textarea.getSelectedText().trim() +
"+site%3Ahttp%3A%2F%2Fprocessingjs.org%2Freference"
);
}
}
private void handleStartStopServer ()
{
startStopServer( getExportFolder() );
}
/**
* Replacement for RUN:
* export to folder, start server, open in default browser.
*/
public void handleStartServer ()
{
statusEmpty();
if ( !handleExport( false ) ) return;
startServer( getExportFolder() );
toolbar.activate(JavaScriptToolbar.RUN);
}
private void handleOpenInBrowser ()
{
openBrowserForServer();
}
/**
* Replacement for STOP: stop server.
*/
public void handleStopServer ()
{
stopServer();
toolbar.deactivate(JavaScriptToolbar.RUN);
}
/**
* Call the export method of the sketch and handle the gui stuff
*/
public boolean handleExport ( boolean openFolder )
{
if ( !handleExportCheckModified() )
{
return false;
}
else
{
toolbar.activate(JavaScriptToolbar.EXPORT);
try
{
boolean success = jsMode.handleExport(sketch);
if ( success && openFolder )
{
File exportFolder = new File( sketch.getFolder(),
JavaScriptBuild.EXPORTED_FOLDER_NAME );
Base.openFolder( exportFolder );
statusNotice("Finished exporting.");
} else if ( !success ) {
// error message already displayed by handleExport
return false;
}
} catch (Exception e) {
statusError(e);
toolbar.deactivate(JavaScriptToolbar.EXPORT);
return false;
}
toolbar.deactivate(JavaScriptToolbar.EXPORT);
}
return true;
}
/**
* Changed from Editor.java to automaticaly export and
* handle the server when it's running. Normal save ops otherwise.
*/
public boolean handleSaveRequest(boolean immediately)
{
if (untitled) {
return handleSaveAs();
// need to get the name, user might also cancel here
} else if (immediately) {
handleSave();
statusEmpty();
handleStartServer();
} else {
SwingUtilities.invokeLater(new Runnable() {
public void run() {
handleSave();
statusEmpty();
handleStartServer();
}
});
}
return true;
}
private boolean handleExportCheckModified ()
{
if (sketch.isModified()) {
Object[] options = { "OK", "Cancel" };
int result = JOptionPane.showOptionDialog(this,
"Save changes before export?",
"Save",
JOptionPane.OK_CANCEL_OPTION,
JOptionPane.QUESTION_MESSAGE,
null,
options,
options[0]);
if (result == JOptionPane.OK_OPTION) {
handleSaveRequest(true);
} else {
statusNotice("Export canceled, changes must first be saved.");
return false;
}
}
return true;
}
public void handleSave ()
{
toolbar.activate(JavaScriptToolbar.SAVE);
super.handleSave();
toolbar.deactivate(JavaScriptToolbar.SAVE);
}
public boolean handleSaveAs ()
{
toolbar.activate(JavaScriptToolbar.SAVE);
boolean result = super.handleSaveAs();
toolbar.deactivate(JavaScriptToolbar.SAVE);
return result;
}
public void handleImportLibrary (String item)
{
Base.showWarning("Processing.js doesn't support libraries",
"Libraries are not supported. Import statements are " +
"ignored, and code relying on them will break.",
null);
}
// ------- utilities ---------
private File getExportFolder ()
{
return new File( getSketch().getFolder(),
JavaScriptBuild.EXPORTED_FOLDER_NAME );
}
private File getCustomTemplateFolder ()
{
return new File( getSketch().getFolder(),
JavaScriptBuild.TEMPLATE_FOLDER_NAME );
}
private void saveSketchSettings ()
{
statusEmpty();
File sketchProps = getSketchPropertiesFile();
Settings settings;
try {
settings = new Settings(sketchProps);
} catch ( IOException ioe ) {
ioe.printStackTrace();
return;
}
if ( settings == null )
{
statusError( "Unable to create sketch properties file!" );
return;
}
settings.set( PROP_KEY_MODE, PROP_VAL_MODE );
int port = getServerPort();
if ( port > 0 ) settings.set( PROP_KEY_SERVER_PORT, (port+"") );
settings.save();
}
}