/*
This file is part of leafdigital leafChat.
leafChat 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.
leafChat 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 leafChat. If not, see <http://www.gnu.org/licenses/>.
Copyright 2011 Samuel Marshall.
*/
package com.leafdigital.scripting;
import java.io.File;
import java.util.*;
import util.*;
import com.leafdigital.scripting.Script.SaveContinuation;
import com.leafdigital.ui.api.*;
import leafchat.core.api.*;
/** Plugin that handles scripts. */
public class ScriptingPlugin implements Plugin,Script.StateListener
{
private LinkedList<Script> scripts = new LinkedList<Script>();
private ScriptingTool st;
private PluginContext context;
final static File scriptsFolder=new File(PlatformUtils.getUserFolder(),"scripts");
@Override
public void init(PluginContext context, PluginLoadReporter reporter) throws GeneralException
{
this.context=context;
//ItemEvent.debugMessages(context.getMessageInfo(Msg.class),0); System.exit(0);
// Register tool
st=new ScriptingTool(context);
context.getSingle(UI.class).registerTool(st);
// Request message just for when people try to quit with unsaved changes
context.requestMessages(SystemStateMsg.class,this);
}
@Override
public void close() throws GeneralException
{
}
@Override
public String toString()
{
return "Scripting plugin";
}
Script[] getScripts()
{
return scripts.toArray(new Script[scripts.size()]);
}
/**
* @param name Proposed name for new script
* @return True if that name is ok to use
*/
static boolean isNewNameOkay(String name)
{
// Required name pattern
String fullName=name+".leafChatScript";
if(!fullName.matches(Script.ALLOWED_NAMES)) return false;
// Names already in use
if((new File(scriptsFolder,fullName)).exists()) return false;
// OK!
return true;
}
@Override
public void scriptStateChanged(Script s)
{
st.informChanged(s);
}
/** Dialog used to prevent quit while unsaved script editor window is up. */
@UIHandler("quitconfirm")
public class QuitConfirm
{
QuitConfirm(SystemStateMsg m) throws GeneralException
{
objectToQuit=false;
UI ui=context.getSingle(UI.class);
quitConfirm = ui.createDialog("quitconfirm",this);
quitConfirm.show(null);
if(objectToQuit) m.markStopped();
}
private Dialog quitConfirm;
private boolean objectToQuit;
/** Callback: Quit button. */
@UIAction
public void actionQuit()
{
quitConfirm.close();
}
/** Callback: Cancel button. */
@UIAction
public void actionCancel()
{
quitConfirm.close();
objectToQuit=true;
}
}
/**
* Message: system state (used to object to quit, and to init).
* @param m Message
* @throws GeneralException
*/
public void msg(SystemStateMsg m) throws GeneralException
{
if(m.getType() == SystemStateMsg.REQUESTSHUTDOWN)
{
boolean changes = false;
for(Script s : scripts)
{
if(s.isChanged())
{
changes = true;
break;
}
}
if(!changes)
{
return; // No script changes so quit is ok
}
new QuitConfirm(m);
}
else if(m.getType() == SystemStateMsg.PLUGINSLOADED)
{
// Load user scripts
scriptsFolder.mkdirs();
File[] scriptFiles = IOUtils.listFiles(scriptsFolder);
for(int i=0; i<scriptFiles.length; i++)
{
if(scriptFiles[i].getName().matches(Script.ALLOWED_NAMES) && scriptFiles[i].isFile())
{
try
{
Script s = new Script(context, scriptFiles[i]);
s.addStateListener(this);
scripts.add(s);
}
catch(GeneralException e)
{
ErrorMsg.report("Error loading user script",e);
}
}
}
}
}
/**
* Adds a new named script.
* @param name Name for script
* @param afterOK Runnable gets run if the script save is successful as in
* it doesn't throw an exception (even if compile fails)
* @throws GeneralException
*/
public void newScript(String name,Runnable afterOK) throws GeneralException
{
final Script s=new Script(context,new File(scriptsFolder,name+".leafChatScript"));
newScript(s,afterOK);
}
/**
* Adds a new script.
* @param s Script to add
* @param afterOK Runnable gets run if the script save is successful as in
* it doesn't throw an exception (even if compile fails)
* @throws GeneralException
*/
public void newScript(final Script s,
final Runnable afterOK) throws GeneralException
{
scripts.add(s);
s.save(new SaveContinuation()
{
@Override
public void afterSave(boolean success)
{
if(!success)
{
try
{
s.saveAndDisable();
}
catch(GeneralException e)
{
try
{
s.delete();
}
catch(Throwable t)
{
}
scripts.remove(s);
ErrorMsg.report("Unexpected error saving new script",e);
return;
}
}
afterOK.run();
}
@Override
public void afterSave(Throwable t)
{
try
{
s.delete();
}
catch(Throwable t2)
{
}
scripts.remove(s);
ErrorMsg.report("Unexpected error saving new script",t);
}
});
s.addStateListener(this);
}
/**
* Deletes a script.
* @param s Script to delete
* @throws GeneralException
*/
public void deleteScript(Script s) throws GeneralException
{
s.delete();
scripts.remove(s);
}
}