/**************************************************************************
OmegaT - Computer Assisted Translation (CAT) tool
with fuzzy matching, translation memory, keyword search,
glossaries, and translation leveraging into updated projects.
Copyright (C) 2014 Briac Pilpre
2015 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.io.File;
import java.io.FilenameFilter;
import java.util.ArrayList;
import java.util.Collections;
import java.util.HashMap;
import java.util.List;
import org.apache.commons.io.FilenameUtils;
import org.omegat.core.CoreEvents;
import org.omegat.core.data.SourceTextEntry;
import org.omegat.core.events.IApplicationEventListener;
import org.omegat.core.events.IEditorEventListener;
import org.omegat.core.events.IEntryEventListener;
import org.omegat.core.events.IProjectEventListener;
import org.omegat.util.DirectoryMonitor;
/**
* Monitor to check changes in the script directory.
*
* @author Briac Pilpre
*/
public class ScriptsMonitor implements DirectoryMonitor.DirectoryCallback, DirectoryMonitor.Callback {
private static final boolean SCRIPTING_EVENTS = true;
private static boolean applicationStartupEventScriptsExecuted = false;
private static final FilenameFilter FILTER;
static {
List<String> extensions = ScriptRunner.getAvailableScriptExtensions();
FILTER = (dir, name) -> extensions.contains(FilenameUtils.getExtension(name).toLowerCase());
}
public ScriptsMonitor(final ScriptingWindow scriptingWindow) {
this.m_scriptingWindow = scriptingWindow;
if (SCRIPTING_EVENTS) {
// Initialize the events script list for all the events
for (EventType t : EventType.values()) {
m_eventsScript.put(t, new ArrayList<ScriptItem>());
}
}
}
public void start(final File scriptDir) {
this.m_scriptDir = scriptDir;
m_monitor = new DirectoryMonitor(scriptDir, this, this);
m_monitor.start();
// Immediately execute APPLICATION_STARTUP event scripts
if (!applicationStartupEventScriptsExecuted) { // first-time only
applicationStartupEventScriptsExecuted = true;
addEventScripts(EventType.APPLICATION_STARTUP);
ArrayList<ScriptItem> scripts = m_eventsScript.get(EventType.APPLICATION_STARTUP);
for (ScriptItem si : scripts) {
m_scriptingWindow.executeScriptFile(si);
}
scripts.clear();
}
}
public void stop() {
if (m_monitor != null) {
m_monitor.fin();
}
}
/**
* Executed on file changed.
*/
@Override
public void fileChanged(File file) {
}
@Override
public void directoryChanged(File file) {
if (!m_scriptDir.isDirectory()) {
// No script directory.
return;
}
// Plain Scripts
// Only display files with an extension supported by the engines
// currently installed.
ArrayList<ScriptItem> scriptsList = new ArrayList<ScriptItem>();
// Replace the script filename by its description, if available
for (File script : m_scriptDir.listFiles(FILTER)) {
scriptsList.add(new ScriptItem(script));
}
Collections.sort(scriptsList);
m_scriptingWindow.setScriptItems(scriptsList);
if (SCRIPTING_EVENTS) {
hookApplicationEvent();
hookEntryEvent();
hookProjectEvent();
hookEditorEvent();
}
}
private void hookEntryEvent() {
if (m_entryEventListener != null) {
CoreEvents.unregisterEntryEventListener(m_entryEventListener);
}
addEventScripts(EventType.ENTRY_ACTIVATED);
addEventScripts(EventType.NEW_FILE);
m_entryEventListener = new IEntryEventListener() {
@Override
public void onNewFile(String activeFileName) {
HashMap<String, Object> binding = new HashMap<String, Object>();
binding.put("activeFileName", activeFileName);
for (ScriptItem si : m_eventsScript.get(EventType.NEW_FILE)) {
m_scriptingWindow.executeScriptFile(si, binding);
}
}
@Override
public void onEntryActivated(SourceTextEntry newEntry) {
HashMap<String, Object> binding = new HashMap<String, Object>();
binding.put("newEntry", newEntry);
for (ScriptItem si : m_eventsScript.get(EventType.ENTRY_ACTIVATED)) {
m_scriptingWindow.executeScriptFile(si, binding);
}
}
};
CoreEvents.registerEntryEventListener(m_entryEventListener);
}
private void hookProjectEvent() {
if (m_projectEventListener != null) {
CoreEvents.unregisterProjectChangeListener(m_projectEventListener);
}
addEventScripts(EventType.PROJECT_CHANGED);
m_projectEventListener = new IProjectEventListener() {
@Override
public void onProjectChanged(PROJECT_CHANGE_TYPE eventType) {
HashMap<String, Object> binding = new HashMap<String, Object>();
binding.put("eventType", eventType);
for (ScriptItem si : m_eventsScript.get(EventType.PROJECT_CHANGED)) {
m_scriptingWindow.executeScriptFile(si, binding);
}
}
};
CoreEvents.registerProjectChangeListener(m_projectEventListener);
}
private void hookApplicationEvent() {
if (m_applicationEventListener != null) {
CoreEvents.unregisterApplicationEventListener(m_applicationEventListener);
}
// APPLICATION_STARTUP is not working because it is registered too late.
// addEventScripts(EventType.APPLICATION_STARTUP);
addEventScripts(EventType.APPLICATION_SHUTDOWN);
m_applicationEventListener = new IApplicationEventListener() {
@Override
public void onApplicationStartup() {
// for (ScriptItem si : m_eventsScript.get(EventType.APPLICATION_STARTUP)) {
// m_scriptingWindow.executeScriptFile(si, true);
// }
}
@Override
public void onApplicationShutdown() {
for (ScriptItem si : m_eventsScript.get(EventType.APPLICATION_SHUTDOWN)) {
m_scriptingWindow.executeScriptFile(si);
}
}
};
CoreEvents.registerApplicationEventListener(m_applicationEventListener);
}
private void hookEditorEvent() {
if (m_editorEventListener != null) {
CoreEvents.unregisterEditorEventListener(m_editorEventListener);
}
addEventScripts(EventType.NEW_WORD);
m_editorEventListener = new IEditorEventListener() {
@Override
public void onNewWord(String newWord) {
HashMap<String, Object> binding = new HashMap<String, Object>();
binding.put("newWord", newWord);
for (ScriptItem si : m_eventsScript.get(EventType.NEW_WORD)) {
m_scriptingWindow.executeScriptFile(si, binding);
}
}
};
CoreEvents.registerEditorEventListener(m_editorEventListener);
}
private void addEventScripts(EventType eventType) {
String entryDirName = eventType.name().toLowerCase();
File entryActivatedDir = new File(m_scriptDir, entryDirName);
if (!entryActivatedDir.isDirectory()) {
return;
}
ArrayList<ScriptItem> eventScripts = m_eventsScript.get(eventType);
// Avoid executing scripts that may be deleted during the directory change.
eventScripts.clear();
for (File script : entryActivatedDir.listFiles(FILTER)) {
ScriptItem scriptItem = new ScriptItem(script);
if (!eventScripts.contains(scriptItem)) {
eventScripts.add(scriptItem);
}
}
}
private enum EventType {
// ApplicationEvent
APPLICATION_STARTUP,
APPLICATION_SHUTDOWN,
// EditorEvent
NEW_WORD,
// FontEvent
//FONT_CHANGED,
// ProjectEvent
PROJECT_CHANGED,
// EntryEvent
ENTRY_ACTIVATED,
NEW_FILE
}
private File m_scriptDir;
protected DirectoryMonitor m_monitor;
private ScriptingWindow m_scriptingWindow;
// Event listeners.
private IEntryEventListener m_entryEventListener;
private IProjectEventListener m_projectEventListener;
private IApplicationEventListener m_applicationEventListener;
private IEditorEventListener m_editorEventListener;
// Map holding the script fired for the different event listeners.
private HashMap<EventType, ArrayList<ScriptItem>> m_eventsScript = new HashMap<EventType, ArrayList<ScriptItem>>();
}