/**************************************************************************
OmegaT - Computer Assisted Translation (CAT) tool
with fuzzy matching, translation memory, keyword search,
glossaries, and translation leveraging into updated projects.
Copyright (C) 2011 Briac Pilpre (briacp@gmail.com)
2013 Alex Buloichik
2014 Briac Pilpre (briacp@gmail.com), Yu Tang
2015 Yu Tang, Aaron Madlon-Kay
Home page: http://www.omegat.org/
Support center: http://groups.yahoo.com/group/OmegaT/
This file is part of OmegaT.
OmegaT is free software: you can redistribute it and/or modify
it under the terms of the GNU General Public License as published by
the Free Software Foundation, either version 3 of the License, or
(at your option) any later version.
OmegaT is distributed in the hope that it will be useful,
but WITHOUT ANY WARRANTY; without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
GNU General Public License for more details.
You should have received a copy of the GNU General Public License
along with this program. If not, see <http://www.gnu.org/licenses/>.
**************************************************************************/
package org.omegat.gui.scripting;
import java.awt.BorderLayout;
import java.awt.Component;
import java.awt.Desktop;
import java.awt.Dimension;
import java.awt.FlowLayout;
import java.awt.Toolkit;
import java.awt.event.ActionEvent;
import java.awt.event.ActionListener;
import java.awt.event.InputEvent;
import java.awt.event.KeyEvent;
import java.awt.event.MouseEvent;
import java.awt.event.MouseMotionAdapter;
import java.awt.event.WindowAdapter;
import java.awt.event.WindowEvent;
import java.io.File;
import java.io.FileFilter;
import java.io.IOException;
import java.util.Collection;
import java.util.Collections;
import java.util.HashMap;
import java.util.Map;
import java.util.concurrent.CancellationException;
import java.util.concurrent.ExecutionException;
import java.util.logging.Level;
import java.util.logging.Logger;
import javax.script.ScriptEngineFactory;
import javax.swing.AbstractAction;
import javax.swing.JButton;
import javax.swing.JComponent;
import javax.swing.JEditorPane;
import javax.swing.JFileChooser;
import javax.swing.JFrame;
import javax.swing.JList;
import javax.swing.JMenu;
import javax.swing.JMenuBar;
import javax.swing.JMenuItem;
import javax.swing.JOptionPane;
import javax.swing.JPanel;
import javax.swing.JPopupMenu;
import javax.swing.JRootPane;
import javax.swing.JScrollPane;
import javax.swing.JSeparator;
import javax.swing.JSplitPane;
import javax.swing.JTextField;
import javax.swing.KeyStroke;
import javax.swing.ListModel;
import javax.swing.SwingConstants;
import javax.swing.SwingWorker;
import javax.swing.WindowConstants;
import javax.swing.event.ListSelectionEvent;
import javax.swing.event.ListSelectionListener;
import javax.swing.event.PopupMenuEvent;
import javax.swing.event.PopupMenuListener;
import javax.swing.text.BadLocationException;
import javax.swing.text.Document;
import org.apache.commons.io.FilenameUtils;
import org.omegat.core.Core;
import org.omegat.core.CoreEvents;
import org.omegat.core.events.IApplicationEventListener;
import org.omegat.gui.shortcuts.PropertiesShortcuts;
import org.omegat.help.Help;
import org.omegat.util.Log;
import org.omegat.util.OStrings;
import org.omegat.util.Preferences;
import org.omegat.util.StringUtil;
import org.omegat.util.gui.OSXIntegration;
import org.omegat.util.gui.StaticUIUtils;
import org.openide.awt.Mnemonics;
/**
* Scripting window
*
* @author Briac Pilpre
* @author Alex Buloichik
* @author Yu Tang
* @author Aaron Madlon-Kay
*/
public class ScriptingWindow {
private static final Logger LOGGER = Logger.getLogger(ScriptingWindow.class.getName());
static ScriptingWindow window;
public static void loadPlugins() {
CoreEvents.registerApplicationEventListener(new IApplicationEventListener() {
@Override
public void onApplicationStartup() {
window = new ScriptingWindow();
}
@Override
public void onApplicationShutdown() {
}
});
}
public static void unloadPlugins() {
if (window != null) {
window.frame.dispose();
}
}
final JFrame frame;
public ScriptingWindow() {
frame = new JFrame(OStrings.getString("SCW_TITLE"));
StaticUIUtils.setWindowIcon(frame);
StaticUIUtils.setEscapeClosable(frame);
frame.addWindowListener(new WindowAdapter() {
@Override
public void windowClosing(WindowEvent e) {
monitor.stop();
}
});
setScriptsDirectory(Preferences.getPreferenceDefault(Preferences.SCRIPTS_DIRECTORY, DEFAULT_SCRIPTS_DIR));
initWindowLayout();
addScriptCommandToOmegaT();
addRunShortcutToOmegaT();
updateQuickScripts();
monitor = new ScriptsMonitor(this);
if (m_scriptsDirectory != null) {
monitor.start(m_scriptsDirectory);
}
logResult(listScriptEngines());
}
private String listScriptEngines() {
StringBuilder sb = new StringBuilder(OStrings.getString("SCW_LIST_ENGINES") + "\n");
for (ScriptEngineFactory engine : ScriptRunner.MANAGER.getEngineFactories()) {
sb.append(" - ");
sb.append(engine.getEngineName());
sb.append(" ");
sb.append(engine.getLanguageName());
sb.append(" v.");
sb.append(engine.getLanguageVersion());
sb.append(" (").append(OStrings.getString("SCW_EXTENSIONS")).append(" ");
boolean hasMore = false;
for (String ext : engine.getExtensions()) {
if (hasMore) {
sb.append(", ");
}
sb.append(ext);
hasMore = true;
}
sb.append(")");
sb.append("\n");
}
return sb.toString();
}
private void addScriptCommandToOmegaT() {
JMenu toolsMenu = Core.getMainWindow().getMainMenu().getToolsMenu();
toolsMenu.add(new JSeparator());
JMenuItem scriptMenu = new JMenuItem();
Mnemonics.setLocalizedText(scriptMenu, OStrings.getString("TF_MENU_TOOLS_SCRIPTING"));
scriptMenu.addActionListener(e -> frame.setVisible(true));
toolsMenu.add(scriptMenu);
for (int i = 0; i < NUMBERS_OF_QUICK_SCRIPTS; i++) {
JMenuItem menuItem = new JMenuItem();
m_quickMenus[i] = menuItem;
unsetQuickScriptMenu(i);
// Since the script is run while editing a segment, the shortcut should not interfere
// with the segment content, so we set it to a Function key.
m_quickMenus[i].setAccelerator(KeyStroke.getKeyStroke("shift ctrl F" + (i + 1)));
toolsMenu.add(menuItem);
}
}
private int scriptKey(int i) {
return i + 1;
}
private void unsetQuickScriptMenu(int index) {
m_quickScripts[index] = null;
removeAllQuickScriptActionListenersFrom(m_quickMenus[index]);
if (m_quickMenus.length < index || m_quickMenus[index] == null) {
return;
}
m_quickMenus[index].setEnabled(false);
Mnemonics.setLocalizedText(m_quickMenus[index],
"&" + scriptKey(index) + " - " + OStrings.getString("SCW_SCRIPTS_NONE"));
}
private void setQuickScriptMenu(ScriptItem scriptItem, int index) {
m_quickScripts[index] = scriptItem.getFile().getName();
removeAllQuickScriptActionListenersFrom(m_quickMenus[index]);
m_quickMenus[index].addActionListener(new QuickScriptActionListener(index));
// Since the script is run while editing a segment, the shortcut should not interfere
// with the segment content, so we set it to a Function key.
m_quickMenus[index].setAccelerator(KeyStroke.getKeyStroke("shift ctrl F" + (index + 1)));
m_quickMenus[index].setEnabled(true);
if ("".equals(scriptItem.getDescription())) {
m_quickMenus[index].setToolTipText(scriptItem.getDescription());
}
Mnemonics.setLocalizedText(m_quickMenus[index], "&" + scriptKey(index) + " - " + scriptItem.getScriptName());
}
private void removeAllQuickScriptActionListenersFrom(JMenuItem menu) {
if (menu == null) {
return;
}
for (ActionListener l: menu.getActionListeners()) {
if (l instanceof QuickScriptActionListener) {
menu.removeActionListener(l);
}
}
}
private class QuickScriptActionListener implements ActionListener {
private final int index;
QuickScriptActionListener(int index) {
this.index = index;
}
@Override
public void actionPerformed(ActionEvent e) {
runQuickScript(index);
}
}
private void runQuickScript(int index) {
if (m_quickScripts[index] == null) {
logResult(OStrings.getString("SCW_NO_SCRIPT_SELECTED"));
return;
}
logResult(StringUtil.format(OStrings.getString("SCW_QUICK_RUN"), (index + 1)));
ScriptItem scriptFile = new ScriptItem(new File(m_scriptsDirectory, m_quickScripts[index]));
executeScriptFile(scriptFile);
}
private void addRunShortcutToOmegaT() {
JRootPane appliRootPane = Core.getMainWindow().getApplicationFrame().getRootPane();
appliRootPane.getInputMap(JComponent.WHEN_ANCESTOR_OF_FOCUSED_COMPONENT).put(
KeyStroke.getKeyStroke(KeyEvent.VK_R, InputEvent.CTRL_DOWN_MASK | InputEvent.ALT_DOWN_MASK, false),
"RUN_CURRENT_SCRIPT");
appliRootPane.getActionMap().put("RUN_CURRENT_SCRIPT", new AbstractAction() {
private static final long serialVersionUID = 1L;
@Override
public void actionPerformed(ActionEvent e) {
runScript();
}
});
}
private void initWindowLayout() {
// set default size and position
frame.setBounds(50, 80, 1150, 650);
StaticUIUtils.persistGeometry(frame, Preferences.SCRIPTWINDOW_GEOMETRY_PREFIX);
frame.getContentPane().setLayout(new BorderLayout(0, 0));
m_scriptList = new JList<>();
JScrollPane scrollPaneList = new JScrollPane(m_scriptList);
m_scriptList.addListSelectionListener(new ListSelectionListener() {
@Override
public void valueChanged(ListSelectionEvent evt) {
if (!evt.getValueIsAdjusting()) {
onListSelectionChanged();
}
}
});
m_scriptList.addMouseMotionListener(new MouseMotionAdapter() {
@Override
public void mouseMoved(MouseEvent e) {
ListModel<ScriptItem> lm = m_scriptList.getModel();
int index = m_scriptList.locationToIndex(e.getPoint());
if (index > -1) {
m_scriptList.setToolTipText(lm.getElementAt(index).getFile().getName());
}
}
});
m_txtResult = new JEditorPane();
JScrollPane scrollPaneResults = new JScrollPane(m_txtResult);
//m_txtScriptEditor = new StandardScriptEditor();
m_txtScriptEditor = getScriptEditor();
m_txtScriptEditor.initLayout(this);
JSplitPane splitPane1 = new JSplitPane(JSplitPane.VERTICAL_SPLIT, m_txtScriptEditor.getPanel(),
scrollPaneResults);
splitPane1.setOneTouchExpandable(true);
splitPane1.setDividerLocation(430);
Dimension minimumSize1 = new Dimension(100, 50);
//scrollPaneEditor.setMinimumSize(minimumSize1);
scrollPaneResults.setMinimumSize(minimumSize1);
JSplitPane splitPane = new JSplitPane(JSplitPane.HORIZONTAL_SPLIT, scrollPaneList, splitPane1);
splitPane.setOneTouchExpandable(true);
splitPane.setDividerLocation(250);
Dimension minimumSize = new Dimension(100, 50);
scrollPaneList.setMinimumSize(minimumSize);
scrollPaneResults.setMinimumSize(minimumSize);
frame.getContentPane().add(splitPane, BorderLayout.CENTER);
JPanel panelSouth = new JPanel();
FlowLayout flPanelSouth = (FlowLayout) panelSouth.getLayout();
flPanelSouth.setAlignment(FlowLayout.LEFT);
frame.getContentPane().add(panelSouth, BorderLayout.SOUTH);
setupRunButtons(panelSouth);
frame.setDefaultCloseOperation(WindowConstants.DISPOSE_ON_CLOSE);
frame.setJMenuBar(createMenuBar());
}
private AbstractScriptEditor getScriptEditor() {
try {
Class<?> richScriptEditorClass = Class.forName("org.omegat.gui.scripting.RichScriptEditor");
return (AbstractScriptEditor) richScriptEditorClass.newInstance();
} catch (ClassNotFoundException e) {
// RichScriptEditor not present, fallback to the standard editor
logResult("RichScriptEditor not present, fallback to the standard editor");
} catch (InstantiationException | IllegalAccessException e) {
logResult("Error loading RichScriptEditor: ", e);
}
return new StandardScriptEditor();
}
private class QuickScriptUpdater implements ActionListener {
int index;
int scriptKey;
QuickScriptUpdater(int index) {
this.scriptKey = scriptKey(index);
this.index = index;
}
public void updateQuickScript(ScriptItem scriptItem) {
Preferences.setPreference(Preferences.SCRIPTS_QUICK_PREFIX + scriptKey,
scriptItem.getFile().getName());
m_quickScriptButtons[index].setToolTipText(scriptItem.getToolTip());
m_quickScriptButtons[index].setText("<" + scriptKey + ">");
setQuickScriptMenu(scriptItem, index);
logResult(StringUtil.format(OStrings.getString("SCW_SAVE_QUICK_SCRIPT"), scriptItem, scriptKey));
}
public void updateQuickScript() {
ScriptItem scriptItem = m_scriptList.getSelectedValue();
updateQuickScript(scriptItem);
}
@Override
public void actionPerformed(ActionEvent evt) {
updateQuickScript();
}
}
private void setupRunButtons(JPanel panel) {
m_btnRunScript = new JButton();
Mnemonics.setLocalizedText(m_btnRunScript, OStrings.getString("SCW_RUN_SCRIPT"));
m_btnRunScript.setAlignmentX(Component.LEFT_ALIGNMENT);
m_btnRunScript.setHorizontalAlignment(SwingConstants.LEFT);
m_btnRunScript.addActionListener(new ActionListener() {
@Override
public void actionPerformed(ActionEvent a) {
runScript();
}
});
panel.add(m_btnRunScript);
m_btnCancelScript = new JButton();
Mnemonics.setLocalizedText(m_btnCancelScript, OStrings.getString("SCW_CANCEL_SCRIPT"));
m_btnCancelScript.setToolTipText(OStrings.getString("SCW_CANCEL_BUTTON_TOOLTIP"));
m_btnCancelScript.setAlignmentX(Component.LEFT_ALIGNMENT);
m_btnCancelScript.setHorizontalAlignment(SwingConstants.LEFT);
m_btnCancelScript.addActionListener(e -> cancelCurrentScript());
panel.add(m_btnCancelScript);
for (int i = 0; i < NUMBERS_OF_QUICK_SCRIPTS; i++) {
final int index = i;
final int scriptKey = scriptKey(index);
m_quickScriptButtons[i] = new JButton(String.valueOf(scriptKey));
// Run a script from the quick button bar
m_quickScriptButtons[i].addActionListener(new ActionListener() {
@Override
public void actionPerformed(ActionEvent a) {
if (Preferences.existsPreference(Preferences.SCRIPTS_QUICK_PREFIX + scriptKey)) {
runQuickScript(index);
} else {
logResult(StringUtil.format(OStrings.getString("SCW_NO_SCRIPT_BOUND"), scriptKey));
}
}
});
JPopupMenu quickScriptPopup = new JPopupMenu();
// Add a script to the quick script button bar
final JMenuItem addQuickScriptMenuItem = new JMenuItem(OStrings.getString("SCW_ADD_SCRIPT"));
addQuickScriptMenuItem.addActionListener(new QuickScriptUpdater(index));
quickScriptPopup.add(addQuickScriptMenuItem);
// Remove a script from the button bar
final JMenuItem removeQuickScriptMenuItem = new JMenuItem(OStrings.getString("SCW_REMOVE_SCRIPT"));
removeQuickScriptMenuItem.addActionListener(new ActionListener() {
@Override
public void actionPerformed(ActionEvent evt) {
String scriptName = Preferences.getPreferenceDefault(Preferences.SCRIPTS_QUICK_PREFIX + scriptKey,
"(unknown)");
logResult(StringUtil.format(OStrings.getString("SCW_REMOVED_QUICK_SCRIPT"), scriptName, scriptKey));
Preferences.setPreference(Preferences.SCRIPTS_QUICK_PREFIX + scriptKey, "");
m_quickScriptButtons[index].setToolTipText(OStrings.getString("SCW_NO_SCRIPT_SET"));
m_quickScriptButtons[index].setText(" " + scriptKey + " ");
unsetQuickScriptMenu(index);
}
});
quickScriptPopup.add(removeQuickScriptMenuItem);
quickScriptPopup.addPopupMenuListener(new PopupMenuListener() {
@Override
public void popupMenuWillBecomeVisible(PopupMenuEvent e) {
// Disable add a script command if script selection empty
addQuickScriptMenuItem.setEnabled(!m_scriptList.isSelectionEmpty());
// Disable remove a script command if the quick run button is not bounded
String scriptName = Preferences.getPreferenceDefault(Preferences.SCRIPTS_QUICK_PREFIX + scriptKey,
null);
removeQuickScriptMenuItem.setEnabled(!StringUtil.isEmpty(scriptName));
}
@Override
public void popupMenuWillBecomeInvisible(PopupMenuEvent e) {
// do nothing
}
@Override
public void popupMenuCanceled(PopupMenuEvent e) {
// do nothing
}
});
m_quickScriptButtons[i].setComponentPopupMenu(quickScriptPopup);
panel.add(m_quickScriptButtons[i]);
}
}
private void runScript() {
m_txtResult.setText("");
if (m_currentScriptItem == null) {
logResult(OStrings.getString("SCW_NO_SCRIPT_SELECTED"));
return;
}
String scriptSource = "<EDITOR>";
if (m_currentScriptItem.getFile() != null) {
if (!m_currentScriptItem.getFile().canRead()) {
logResult(OStrings.getString("SCW_CANNOT_READ_SCRIPT"));
return;
}
scriptSource = m_currentScriptItem.getFile().getAbsolutePath();
}
String scriptString = m_txtScriptEditor.getTextArea().getText();
if (scriptString.trim().isEmpty()) {
try {
scriptString = m_currentScriptItem.getText();
m_txtScriptEditor.getTextArea().setText(scriptString);
} catch (IOException e) {
e.printStackTrace();
}
}
logResult(StringUtil.format(OStrings.getString("SCW_RUNNING_SCRIPT"), scriptSource));
executeScript(scriptString, m_currentScriptItem);
}
private class ScriptWorker extends SwingWorker<String, Void> {
private final String scriptString;
private final ScriptItem scriptItem;
private final Map<String, Object> bindings;
private long start;
ScriptWorker(String scriptString, ScriptItem scriptItem, Map<String, Object> bindings) {
this.scriptString = scriptString;
this.scriptItem = scriptItem;
this.bindings = bindings;
}
@Override
protected String doInBackground() throws Exception {
start = System.currentTimeMillis();
return ScriptRunner.executeScript(scriptString, scriptItem, bindings);
}
@Override
protected void done() {
try {
String result = get();
logResult(result);
logResult(StringUtil.format(OStrings.getString("SCW_SCRIPT_DONE"), System.currentTimeMillis() - start));
} catch (CancellationException e) {
logResult(StringUtil.format(OStrings.getString("SCW_SCRIPT_CANCELED"),
System.currentTimeMillis() - start));
} catch (InterruptedException e) {
e.printStackTrace();
} catch (ExecutionException e) {
logResult(OStrings.getString("SCW_SCRIPT_ERROR"), e);
}
}
}
public void executeScript(String scriptString, ScriptItem scriptItem) {
executeScript(scriptString, scriptItem, Collections.emptyMap());
}
public void executeScriptFile(ScriptItem scriptItem) {
executeScriptFile(scriptItem, Collections.emptyMap());
}
public void executeScriptFile(ScriptItem scriptItem, Map<String, Object> additionalBindings) {
try {
String scriptString = scriptItem.getText();
executeScript(scriptString, scriptItem, additionalBindings);
} catch (IOException e) {
// TODO: Do we really want to handle the exception here, like this?
// This method can be called in instances when the Scripting Window
// is not visible, so it might make more sense to let the caller
// handle the exception.
logResult(StringUtil.format(OStrings.getString("SCW_SCRIPT_LOAD_ERROR"), scriptItem.getFile()), e);
}
}
public void executeScript(String scriptString, ScriptItem scriptItem, Map<String, Object> additionalBindings) {
if (!scriptString.endsWith("\n")) {
scriptString += "\n";
}
Map<String, Object> bindings = new HashMap<String, Object>(additionalBindings);
bindings.put(ScriptRunner.VAR_CONSOLE, new IScriptLogger() {
@Override
public void print(Object o) {
logResult(o.toString(), false);
}
@Override
public void println(Object o) {
logResult(o.toString(), true);
}
@Override
public void clear() {
m_txtResult.setText("");
}
});
cancelCurrentScript();
scriptWorker = new ScriptWorker(scriptString, scriptItem, bindings);
scriptWorker.execute();
}
/**
* Cancel the currently running script, if any.
* <p>
* <b>Note!</b> Canceling the worker does not do anything in and of itself.
* The running script must poll for interruption with e.g.
* {@link java.lang.Thread#interrupted()}.
*
* @see <a href="http://stackoverflow.com/a/24875881/448068">StackOverflow
* answer about interrupting scripts</a>
*/
private void cancelCurrentScript() {
if (scriptWorker != null) {
scriptWorker.cancel(true);
}
}
private void logResult(String s, Throwable t) {
logResultToWindow(s + "\n" + t.getMessage(), true);
LOGGER.log(Level.SEVERE, s, t);
}
private void logResult(String s) {
logResult(s, true);
}
private void logResult(String s, boolean newLine) {
logResultToWindow(s, newLine);
LOGGER.log(Level.INFO, s);
}
/**
* Print log text to the Scripting Window's console area. A trailing line break will be added
* if the parameter newLine is true.
*/
private void logResultToWindow(String s, boolean newLine) {
Document doc = m_txtResult.getDocument();
try {
doc.insertString(doc.getLength(), s + (newLine ? "\n" : ""), null);
} catch (BadLocationException e1) {
/* empty */
}
}
private void setScriptsDirectory(String scriptsDir) {
File dir;
try {
dir = new File(scriptsDir).getCanonicalFile();
} catch (IOException ex) {
dir = new File(scriptsDir).getAbsoluteFile();
}
setScriptsDirectory(dir);
}
private void setScriptsDirectory(File scriptsDir) {
if (!scriptsDir.isDirectory()) {
updateQuickScripts();
return;
}
m_scriptsDirectory = scriptsDir;
Preferences.setPreference(Preferences.SCRIPTS_DIRECTORY, scriptsDir.getPath());
OSXIntegration.setProxyIcon(frame.getRootPane(), m_scriptsDirectory);
if (m_txtScriptsDir != null) {
m_txtScriptsDir.setText(scriptsDir.getPath());
}
if (monitor != null) {
monitor.stop();
monitor.start(m_scriptsDirectory);
}
}
private void updateQuickScripts() {
for (int i = 0; i < NUMBERS_OF_QUICK_SCRIPTS; i++) {
int key = scriptKey(i);
String scriptName = Preferences.getPreferenceDefault(
Preferences.SCRIPTS_QUICK_PREFIX + key, null);
if (m_scriptsDirectory != null && !StringUtil.isEmpty(scriptName)) {
setQuickScriptMenu(new ScriptItem(new File(m_scriptsDirectory, scriptName)), i);
m_quickScriptButtons[i].setToolTipText(scriptName);
m_quickScriptButtons[i].setText("<" + key + ">");
} else {
unsetQuickScriptMenu(i);
if (m_quickScriptButtons.length < i || m_quickScriptButtons[i] == null) {
return;
}
m_quickScriptButtons[i].setToolTipText(OStrings.getString("SCW_NO_SCRIPT_SET"));
m_quickScriptButtons[i].setText(String.valueOf(key));
}
}
}
void setScriptItems(Collection<ScriptItem> items) {
m_scriptList.setListData(items.toArray(new ScriptItem[items.size()]));
}
private void onListSelectionChanged() {
if (m_scriptList.isSelectionEmpty()) {
return;
}
m_currentScriptItem = m_scriptList.getSelectedValue();
displayScriptItem();
}
/** Display the content of a script item in the Script Editor area. */
private void displayScriptItem() {
try {
m_txtScriptEditor
.setHighlighting(FilenameUtils.getExtension(m_currentScriptItem.getFile().getName().toLowerCase()));
m_txtScriptEditor.getTextArea().setText(m_currentScriptItem.getText());
m_txtScriptEditor.getTextArea().setCaretPosition(0);
} catch (IOException ex) {
logResult(OStrings.getString("SCW_CANNOT_READ_SCRIPT"));
}
}
public String getSelectedText() {
return m_txtScriptEditor.getTextArea().getSelectedText();
}
// Menu Actions
private class OpenScriptAction implements ActionListener {
public void actionPerformed(ActionEvent e) {
// If a project is opened, set the file chooser to the project root instead of the default script path
File openFileDir = Core.getProject().isProjectLoaded()
? Core.getProject().getProjectProperties().getProjectRootDir() : m_scriptsDirectory;
JFileChooser chooser = new JFileChooser(openFileDir);
chooser.setDialogTitle(OStrings.getString("SCW_SCRIPTS_OPEN_SCRIPT_TITLE"));
chooser.setDialogTitle("Select a Script File");
chooser.setFileSelectionMode(JFileChooser.FILES_ONLY);
int result = chooser.showOpenDialog(frame);
if (result == JFileChooser.APPROVE_OPTION) {
// we should write the result into the directory text field
//File file = chooser.getSelectedFile();
//setScriptsDirectory(file);
m_currentScriptItem = new ScriptItem(chooser.getSelectedFile());
displayScriptItem();
}
}
}
private class NewScriptAction implements ActionListener {
public void actionPerformed(ActionEvent e) {
m_currentScriptItem = null;
// TODO Check if the current script needs saving before clearing the
// editor.
m_txtScriptEditor.getTextArea().setText("");
m_txtScriptEditor.getTextArea().setCaretPosition(0);
// Avoid selecting scripts in the list after hitting Ctrl+N
m_txtScriptEditor.getTextArea().grabFocus();
}
}
private class RunScriptAction implements ActionListener {
public void actionPerformed(ActionEvent e) {
if (m_currentScriptItem == null) {
m_currentScriptItem = new ScriptItem(null);
}
runScript();
}
}
private class SaveScriptAction implements ActionListener {
public void actionPerformed(ActionEvent e) {
if (m_currentScriptItem == null || m_currentScriptItem.getFile() == null) {
JFileChooser chooser = new JFileChooser(m_scriptsDirectory);
chooser.setDialogTitle(OStrings.getString("SCW_SAVE_SCRIPT"));
int result = chooser.showSaveDialog(frame);
if (result == JFileChooser.APPROVE_OPTION) {
m_currentScriptItem = new ScriptItem(chooser.getSelectedFile());
} else {
return;
}
}
if (m_currentScriptItem == null) {
return;
}
try {
m_currentScriptItem.setText(m_txtScriptEditor.getTextArea().getText());
logResult(StringUtil.format(OStrings.getString("SCW_SAVE_OK"),
m_currentScriptItem.getFile().getAbsolutePath()));
} catch (IOException ex) {
logResult(OStrings.getString("SCW_SAVE_ERROR"), ex);
}
}
}
private class SelectScriptFolderAction implements ActionListener {
public void actionPerformed(ActionEvent e) {
JFileChooser chooser = new JFileChooser(m_scriptsDirectory);
chooser.setDialogTitle(OStrings.getString("SCW_SCRIPTS_FOLDER_CHOOSE_TITLE"));
chooser.setFileSelectionMode(JFileChooser.DIRECTORIES_ONLY);
int result = chooser.showOpenDialog(frame);
if (result == JFileChooser.APPROVE_OPTION) {
// we should write the result into the directory text field
File file = chooser.getSelectedFile();
setScriptsDirectory(file);
}
}
}
private class ExploreScriptFolderAction implements ActionListener {
public void actionPerformed(ActionEvent e) {
try {
// Normalize file name in case it is displayed
m_scriptsDirectory = m_scriptsDirectory.getCanonicalFile();
} catch (Exception ex) {
// Ignore
}
if (!m_scriptsDirectory.exists()) {
Core.getMainWindow().showStatusMessageRB("LFC_ERROR_FILE_DOESNT_EXIST", m_scriptsDirectory);
return;
}
try {
Desktop.getDesktop().open(m_scriptsDirectory);
} catch (Exception ex) {
Log.logErrorRB(ex, "RPF_ERROR");
Core.getMainWindow().displayErrorRB(ex, "RPF_ERROR");
}
}
}
private JMenuBar createMenuBar() {
mb = new JMenuBar();
JMenu menu = new JMenu();
Mnemonics.setLocalizedText(menu, OStrings.getString("SCW_MENU_TITLE"));
JMenuItem item;
// https://sourceforge.net/p/omegat/feature-requests/1314/
item = new JMenuItem();
Mnemonics.setLocalizedText(item, OStrings.getString("SCW_LOAD_FILE"));
item.addActionListener(new OpenScriptAction());
item.setAccelerator(
KeyStroke.getKeyStroke(KeyEvent.VK_O, Toolkit.getDefaultToolkit().getMenuShortcutKeyMask()));
menu.add(item);
item = new JMenuItem();
Mnemonics.setLocalizedText(item, OStrings.getString("SCW_NEW_SCRIPT"));
item.addActionListener(new NewScriptAction());
item.setAccelerator(
KeyStroke.getKeyStroke(KeyEvent.VK_N, Toolkit.getDefaultToolkit().getMenuShortcutKeyMask()));
menu.add(item);
item = new JMenuItem();
Mnemonics.setLocalizedText(item, OStrings.getString("SCW_SAVE_SCRIPT"));
item.addActionListener(new SaveScriptAction());
item.setAccelerator(
KeyStroke.getKeyStroke(KeyEvent.VK_S, Toolkit.getDefaultToolkit().getMenuShortcutKeyMask()));
menu.add(item);
item = new JMenuItem();
Mnemonics.setLocalizedText(item, OStrings.getString("SCW_RUN_SCRIPT"));
item.addActionListener(new RunScriptAction());
item.setAccelerator(
KeyStroke.getKeyStroke(KeyEvent.VK_R, Toolkit.getDefaultToolkit().getMenuShortcutKeyMask()));
menu.add(item);
menu.addSeparator();
item = new JMenuItem();
Mnemonics.setLocalizedText(item, OStrings.getString("SCW_MENU_SET_SCRIPTS_FOLDER"));
item.addActionListener(new SelectScriptFolderAction());
menu.add(item);
item = new JMenuItem();
Mnemonics.setLocalizedText(item, OStrings.getString("SCW_MENU_ACCESS_FOLDER"));
item.addActionListener(new ExploreScriptFolderAction());
menu.add(item);
menu.addSeparator();
item = new JMenuItem();
Mnemonics.setLocalizedText(item, OStrings.getString("SCW_MENU_CLOSE"));
item.setAccelerator(
KeyStroke.getKeyStroke(KeyEvent.VK_W, Toolkit.getDefaultToolkit().getMenuShortcutKeyMask()));
item.addActionListener(e -> {
frame.setVisible(false);
frame.dispose();
});
menu.add(item);
PropertiesShortcuts.getMainMenuShortcuts().bindKeyStrokes(menu);
mb.add(menu);
// Edit Menu
m_txtScriptEditor.enhanceMenu(mb);
buildSetsMenu(mb);
menu = new JMenu();
Mnemonics.setLocalizedText(menu, OStrings.getString("SCW_MENU_HELP"));
item = new JMenuItem();
Mnemonics.setLocalizedText(item, OStrings.getString("SCW_MENU_JAVADOC"));
item.addActionListener(e -> {
try {
Help.showJavadoc();
} catch (IOException ex) {
Log.log(ex);
}
});
menu.add(item);
mb.add(menu);
return mb;
}
private class SaveSetAction implements ActionListener {
public void actionPerformed(ActionEvent e) {
String setName = JOptionPane.showInputDialog(frame,
OStrings.getString("SCW_SAVE_SET_MSG"), OStrings.getString("SCW_MENU_SAVE_SET"),
JOptionPane.QUESTION_MESSAGE);
if (setName == null) {
return;
}
try {
ScriptSet.saveSet(new File(m_scriptsDirectory, setName + ".set"), setName, m_quickScripts);
buildSetsMenu(mb);
} catch (IOException e1) {
e1.printStackTrace();
}
}
}
private class LoadSetAction implements ActionListener {
public void actionPerformed(ActionEvent e) {
JMenuItem source = (JMenuItem) e.getSource();
ScriptSet set = (ScriptSet) source.getClientProperty("set");
// Unset all previous scripts
for (int i = 0; i < NUMBERS_OF_QUICK_SCRIPTS; i++) {
Preferences.setPreference(Preferences.SCRIPTS_QUICK_PREFIX + scriptKey(i), "");
unsetQuickScriptMenu(i);
}
for (int i = 0; i < NUMBERS_OF_QUICK_SCRIPTS; i++) {
ScriptItem si = set.getScriptItem(scriptKey(i));
if (si != null) {
Preferences.setPreference(Preferences.SCRIPTS_QUICK_PREFIX + scriptKey(i),
si.getFile().getName());
new QuickScriptUpdater(i).updateQuickScript(si);
updateQuickScripts();
}
}
}
}
protected void buildSetsMenu(JMenuBar mb) {
m_setsMenu.removeAll();
Mnemonics.setLocalizedText(m_setsMenu, OStrings.getString("SCW_MENU_SETS"));
JMenuItem item = new JMenuItem();
Mnemonics.setLocalizedText(item, OStrings.getString("SCW_MENU_SAVE_SET"));
item.addActionListener(new SaveSetAction());
m_setsMenu.add(item);
m_setsMenu.addSeparator();
if (m_scriptsDirectory == null) {
return;
}
for (File script : m_scriptsDirectory.listFiles(new FileFilter(){
@Override
public boolean accept(File script) {
return script.getName().endsWith(".set");
}
})) {
ScriptSet set = new ScriptSet(script);
JMenuItem setMenuItem = new JMenuItem();
setMenuItem.setText(set.getTitle());
setMenuItem.putClientProperty("set", set);
setMenuItem.addActionListener(new LoadSetAction());
m_setsMenu.add(setMenuItem);
}
mb.add(m_setsMenu);
//m_scriptList.setListData(items.toArray(new ScriptItem[items.size()]));
}
public static final String DEFAULT_SCRIPTS_DIR = "scripts";
protected static final int NUMBERS_OF_QUICK_SCRIPTS = 12;
private JList<ScriptItem> m_scriptList;
private JEditorPane m_txtResult;
private AbstractScriptEditor m_txtScriptEditor;
private JButton m_btnRunScript;
private JButton m_btnCancelScript;
private JMenuBar mb;
private ScriptWorker scriptWorker;
protected ScriptsMonitor monitor;
private File m_scriptsDirectory;
private ScriptItem m_currentScriptItem;
private JTextField m_txtScriptsDir;
private JMenu m_setsMenu = new JMenu();
private final String[] m_quickScripts = new String[NUMBERS_OF_QUICK_SCRIPTS];
private final JMenuItem[] m_quickMenus = new JMenuItem[NUMBERS_OF_QUICK_SCRIPTS];
private final JButton[] m_quickScriptButtons = new JButton[NUMBERS_OF_QUICK_SCRIPTS];
}