/*
* Copyright 2010-2015 Institut Pasteur.
*
* This file is part of Icy.
*
* Icy 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.
*
* Icy 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 Icy. If not, see <http://www.gnu.org/licenses/>.
*/
package icy.workspace;
import icy.file.FileUtil;
import icy.file.xml.XMLPersistent;
import icy.file.xml.XMLPersistentHelper;
import icy.gui.frame.progress.ProgressFrame;
import icy.gui.util.RibbonUtil;
import icy.plugin.PluginDescriptor;
import icy.plugin.PluginInstaller;
import icy.plugin.PluginLoader;
import icy.plugin.PluginRepositoryLoader;
import icy.preferences.RepositoryPreferences.RepositoryInfo;
import icy.util.StringUtil;
import icy.util.XMLUtil;
import icy.workspace.Workspace.TaskDefinition.BandDefinition;
import icy.workspace.Workspace.TaskDefinition.BandDefinition.ItemDefinition;
import java.io.File;
import java.net.URL;
import java.util.ArrayList;
import java.util.List;
import org.pushingpixels.flamingo.api.common.AbstractCommandButton;
import org.pushingpixels.flamingo.api.ribbon.AbstractRibbonBand;
import org.pushingpixels.flamingo.api.ribbon.JRibbonBand;
import org.pushingpixels.flamingo.api.ribbon.RibbonElementPriority;
import org.pushingpixels.flamingo.api.ribbon.RibbonTask;
import org.pushingpixels.flamingo.internal.ui.ribbon.JBandControlPanel.ControlPanelGroup;
import org.w3c.dom.Element;
import org.w3c.dom.Node;
/**
* @author Stephane
*/
public class Workspace implements XMLPersistent, Comparable<Workspace>
{
public static boolean contains(List<TaskDefinition> tasks, TaskDefinition task)
{
for (TaskDefinition t : tasks)
if (task.getName().equals(t.getName()))
return true;
return false;
}
public static boolean contains(List<BandDefinition> bands, BandDefinition band)
{
for (BandDefinition b : bands)
if (band.getName().equals(b.getName()))
return true;
return false;
}
public static Workspace getWorkspace(List<Workspace> list, String name)
{
for (Workspace workspace : list)
if (workspace.getName().equals(name))
return workspace;
return null;
}
public static boolean addWorkspace(List<Workspace> list, Workspace workspace)
{
if (!list.contains(workspace))
{
list.add(workspace);
return true;
}
return false;
}
public static boolean removeWorkspace(List<Workspace> list, String name)
{
return list.remove(getWorkspace(list, name));
}
public class TaskDefinition implements XMLPersistent
{
private static final String ID_NAME = "name";
public class BandDefinition implements XMLPersistent
{
public class ItemDefinition implements XMLPersistent
{
private static final String ID_CLASSNAME = "classname";
private static final String ID_PRIORITY = "priority";
String className;
RibbonElementPriority priority;
ItemDefinition()
{
super();
className = "";
priority = RibbonElementPriority.MEDIUM;
}
ItemDefinition(Node node)
{
this();
loadFromXML(node);
}
ItemDefinition(JRibbonBand band, AbstractCommandButton button)
{
// class name is saved in button.name
this(button.getName(), RibbonUtil.getButtonPriority(band, button));
}
ItemDefinition(String className, RibbonElementPriority prio)
{
this();
this.className = className;
priority = prio;
}
ItemDefinition(String className)
{
this(className, RibbonElementPriority.LOW);
}
private RibbonElementPriority stringToPrio(String value)
{
if (StringUtil.isEmpty(value))
return RibbonElementPriority.MEDIUM;
final String prio = value.toLowerCase();
if (prio.equals("low"))
return RibbonElementPriority.LOW;
if (prio.equals("top"))
return RibbonElementPriority.TOP;
return RibbonElementPriority.MEDIUM;
}
private String prioToString(RibbonElementPriority value)
{
switch (value)
{
case LOW:
return "low";
case MEDIUM:
default:
return "med";
case TOP:
return "top";
}
}
@Override
public boolean loadFromXML(Node node)
{
if (node == null)
return false;
final String nodeName = node.getNodeName();
if (nodeName.equals(ID_SEPARATOR))
className = ID_SEPARATOR;
else if (nodeName.equals(ID_ITEM))
{
final Element element = (Element) node;
className = XMLUtil.getAttributeValue(element, ID_CLASSNAME, "");
priority = stringToPrio(XMLUtil.getAttributeValue(element, ID_PRIORITY, ""));
}
else
return false;
return true;
}
@Override
public boolean saveToXML(Node node)
{
if (node == null)
return false;
final String nodeName = node.getNodeName();
if (nodeName.equals(ID_ITEM))
{
final Element element = (Element) node;
XMLUtil.setAttributeValue(element, ID_CLASSNAME, className);
XMLUtil.setAttributeValue(element, ID_PRIORITY, prioToString(priority));
}
else if (!nodeName.equals(ID_SEPARATOR))
return false;
return true;
}
/**
* @return the className
*/
public String getClassName()
{
if (isSeparator())
return "";
return className;
}
/**
* @param className
* the className to set
*/
public void setClassName(String className)
{
this.className = className;
}
/**
* return true if this item is a separator
*/
public boolean isSeparator()
{
return StringUtil.equals(className, ID_SEPARATOR);
}
/**
* return true if this item is empty
*/
public boolean isEmpty()
{
return StringUtil.isEmpty(className);
}
/**
* @return the priority
*/
public RibbonElementPriority getPriority()
{
return priority;
}
/**
* set the priority
*/
public void setPriority(RibbonElementPriority value)
{
priority = value;
}
public BandDefinition getBandDefinition()
{
return BandDefinition.this;
}
public String getBandName()
{
return BandDefinition.this.getName();
}
public TaskDefinition getTaskDefinition()
{
return TaskDefinition.this;
}
public String getTaskName()
{
return TaskDefinition.this.getName();
}
public Workspace getWorkspace()
{
return Workspace.this;
}
public String getWorkspaceName()
{
return Workspace.this.getName();
}
public boolean remove()
{
return BandDefinition.this.removeItem(this);
}
}
private static final String ID_ITEM = "item";
private static final String ID_SEPARATOR = "separator";
String name;
final ArrayList<ItemDefinition> items;
BandDefinition()
{
super();
name = "";
items = new ArrayList<ItemDefinition>();
}
BandDefinition(Node node)
{
this();
loadFromXML(node);
}
BandDefinition(JRibbonBand ribbonBand)
{
this();
loadFrom(ribbonBand);
}
/**
* add ItemDefinition from AbstractCommandButton component
*
* @param band
* @param button
*/
public ItemDefinition addItem(JRibbonBand band, AbstractCommandButton button)
{
return addItem(button.getName(), RibbonUtil.getButtonPriority(band, button));
}
public ItemDefinition addItem(String className, RibbonElementPriority prio)
{
// don't want to have same item in a band
ItemDefinition result = findItem(className);
if (result == null)
{
result = new ItemDefinition(className, prio);
items.add(result);
}
else
result.priority = prio;
return result;
}
public ItemDefinition addItem(String className)
{
return addItem(className, RibbonElementPriority.LOW);
}
public void addSeparator()
{
addItem(ID_SEPARATOR);
}
/**
* Add all items contained in the specified JRibbonBand.
*/
public boolean addItems(JRibbonBand ribbonBand)
{
if (ribbonBand == null)
return false;
for (ControlPanelGroup panelGroup : ribbonBand.getControlPanel().getControlPanelGroups())
{
addSeparator();
for (AbstractCommandButton button : panelGroup.getRibbonButtons(RibbonElementPriority.LOW))
addItem(ribbonBand, button);
for (AbstractCommandButton button : panelGroup.getRibbonButtons(RibbonElementPriority.MEDIUM))
addItem(ribbonBand, button);
for (AbstractCommandButton button : panelGroup.getRibbonButtons(RibbonElementPriority.TOP))
addItem(ribbonBand, button);
}
return true;
}
/**
* Add all items from the specified Node.
*/
public boolean addItems(Node node)
{
if (node == null)
return false;
final ArrayList<Node> nodesItem = XMLUtil.getChildren(node);
for (Node n : nodesItem)
{
final ItemDefinition item = new ItemDefinition(n);
// only add if not empty
if (!item.isEmpty())
items.add(item);
}
return true;
}
/**
* remove an item from the band
*
* @param item
*/
public boolean removeItem(ItemDefinition item)
{
if (item != null)
return items.remove(item);
return false;
}
/**
* remove an item from the band
*
* @param className
*/
public boolean removeItem(String className)
{
return removeItem(findItem(className));
}
/**
* remove all items from the band
*/
public void clear()
{
items.clear();
}
public TaskDefinition getTaskDefinition()
{
return TaskDefinition.this;
}
public String getTaskName()
{
return TaskDefinition.this.getName();
}
public Workspace getWorkspace()
{
return Workspace.this;
}
public String getWorkspaceName()
{
return Workspace.this.getName();
}
public boolean loadFrom(JRibbonBand ribbonBand)
{
if (ribbonBand == null)
return false;
name = ribbonBand.getTitle();
// clear before loading items
items.clear();
return addItems(ribbonBand);
}
@Override
public boolean loadFromXML(Node node)
{
if (node == null)
return false;
name = XMLUtil.getAttributeValue((Element) node, ID_NAME, "");
// clear before loading items
items.clear();
return addItems(node);
}
@Override
public boolean saveToXML(Node node)
{
if (node == null)
return false;
XMLUtil.setAttributeValue((Element) node, ID_NAME, name);
XMLUtil.removeAllChildren(node);
for (ItemDefinition item : items)
{
if (item.isSeparator())
item.saveToXML(XMLUtil.addElement(node, ID_SEPARATOR));
else
item.saveToXML(XMLUtil.addElement(node, ID_ITEM));
}
return true;
}
public ItemDefinition findItem(String className)
{
for (ItemDefinition item : items)
if (StringUtil.equals(item.getClassName(), className))
return item;
return null;
}
/**
* @return the name
*/
public String getName()
{
return name;
}
/**
* @return the items
*/
public ArrayList<ItemDefinition> getItems()
{
return new ArrayList<ItemDefinition>(items);
}
}
private static final String ID_BAND = "band";
String name;
final ArrayList<BandDefinition> bands;
TaskDefinition()
{
super();
name = "";
bands = new ArrayList<BandDefinition>();
}
TaskDefinition(Node node)
{
this();
loadFromXML(node);
}
TaskDefinition(RibbonTask ribbonTask)
{
this();
loadFrom(ribbonTask);
}
public Workspace getWorkspace()
{
return Workspace.this;
}
public String getWorkspaceName()
{
return Workspace.this.getName();
}
/**
* Add a BandDefinition from JRibbonBand component
*/
public BandDefinition addBand(JRibbonBand ribbonBand)
{
if (ribbonBand == null)
return null;
final BandDefinition result = addBand(ribbonBand.getTitle());
// add items from ribbonBand
result.clear();
result.addItems(ribbonBand);
return result;
}
/**
* Add a BandDefinition
*/
public BandDefinition addBand(String bandName)
{
BandDefinition band = findBand(bandName);
if (band == null)
{
band = new BandDefinition();
band.name = bandName;
bands.add(band);
}
return band;
}
/**
* Add bands from specified RibbonTask.
*/
public boolean addBands(RibbonTask ribbonTask)
{
if (ribbonTask == null)
return false;
for (AbstractRibbonBand<?> ribbonBand : ribbonTask.getBands())
if (ribbonBand instanceof JRibbonBand)
addBand((JRibbonBand) ribbonBand);
return true;
}
/**
* Remove a BandDefinition by name
*
* @param bandName
* : name of the band to remove
*/
public boolean removeBand(String bandName)
{
BandDefinition band = findBand(bandName);
if (band == null)
return false;
return removeBand(band);
}
/**
* Remove a band definition
*/
public boolean removeBand(BandDefinition band)
{
for (ItemDefinition itd : band.getItems())
band.removeItem(itd);
bands.remove(band);
return true;
}
public ItemDefinition addItem(String bandName, String className)
{
return addBand(bandName).addItem(className);
}
/**
* remove all bands from the task
*/
public void clear()
{
bands.clear();
}
/**
* Load from the specified RibbonTask.
*/
public boolean loadFrom(RibbonTask ribbonTask)
{
if (ribbonTask == null)
return false;
name = ribbonTask.getTitle();
// clear before loading bands
bands.clear();
return addBands(ribbonTask);
}
@Override
public boolean loadFromXML(Node node)
{
if (node == null)
return false;
name = XMLUtil.getAttributeValue((Element) node, ID_NAME, "");
// clear before loading
bands.clear();
final ArrayList<Node> nodesBand = XMLUtil.getChildren(node, ID_BAND);
for (Node n : nodesBand)
bands.add(new BandDefinition(n));
return true;
}
@Override
public boolean saveToXML(Node node)
{
if (node == null)
return false;
XMLUtil.setAttributeValue((Element) node, ID_NAME, name);
XMLUtil.removeAllChildren(node);
for (BandDefinition band : bands)
band.saveToXML(XMLUtil.addElement(node, ID_BAND));
return true;
}
public BandDefinition findBand(String name)
{
for (BandDefinition band : bands)
if (band.name.equals(name))
return band;
return null;
}
public ItemDefinition findItem(String className)
{
for (BandDefinition band : bands)
{
final ItemDefinition item = band.findItem(className);
if (item != null)
return item;
}
return null;
}
/**
* @return the name
*/
public String getName()
{
return name;
}
/**
* @return the items
*/
public ArrayList<BandDefinition> getBands()
{
return new ArrayList<BandDefinition>(bands);
}
}
public static final String[] DEFAULT_ACTIVE_WORKSPACES = {"Initial Beta ToolSet", "Tutorial Basics"};
// public static final String WORKSPACE_DEFAULT_NAME = "default";
public static final String WORKSPACE_SYSTEM_NAME = "sys";
private static final String ID_NAME = "name";
private static final String ID_DESCRIPTION = "description";
private static final String ID_TASK = "task";
private String name;
private String description;
private final ArrayList<TaskDefinition> tasks;
// only for online fetched workspace
private RepositoryInfo repository;
private boolean installing;
/**
* empty workspace
*/
public Workspace()
{
super();
name = "";
description = "";
tasks = new ArrayList<TaskDefinition>();
repository = null;
installing = false;
}
/**
* workspace loaded from file
*/
public Workspace(File file) throws IllegalArgumentException
{
this();
load(file);
}
/**
* workspace loaded from url (online)
*/
public Workspace(URL url, RepositoryInfo repos) throws IllegalArgumentException
{
this();
load(url);
repository = repos;
}
/**
* workspace loaded from his name
*/
public Workspace(String name) throws IllegalArgumentException
{
this();
this.name = name;
load();
}
public String getLocalFilename()
{
return WorkspaceLoader.WORKSPACE_PATH + FileUtil.separator + name + WorkspaceLoader.EXT;
}
/**
* @return the name
*/
public String getName()
{
return name;
}
/**
* @return the description
*/
public String getDescription()
{
return description;
}
public boolean isEmpty()
{
return tasks.isEmpty();
}
/**
* @param name
* the name to set
*/
public void setName(String name)
{
this.name = name;
}
/**
* @param description
* the description to set
*/
public void setDescription(String description)
{
this.description = description;
}
/**
* @return the installing
*/
public boolean isInstalling()
{
return installing;
}
public RepositoryInfo getRepository()
{
return repository;
}
/**
* Clear all tasks.
*/
public void clear()
{
tasks.clear();
}
public TaskDefinition findTask(String taskName)
{
for (TaskDefinition task : tasks)
if (task.name.equals(taskName))
return task;
return null;
}
public BandDefinition findBand(String taskName, String bandName)
{
final TaskDefinition task = findTask(taskName);
if (task != null)
return task.findBand(bandName);
return null;
}
public ItemDefinition findItem(String className)
{
for (TaskDefinition task : tasks)
{
final ItemDefinition item = task.findItem(className);
if (item != null)
return item;
}
return null;
}
/**
* @return the definitions
*/
public ArrayList<TaskDefinition> getTasks()
{
return new ArrayList<TaskDefinition>(tasks);
}
/**
* @return all items contained in this workspace
*/
public ArrayList<ItemDefinition> getAllItems()
{
final ArrayList<ItemDefinition> result = new ArrayList<ItemDefinition>();
for (TaskDefinition task : tasks)
for (BandDefinition band : task.bands)
result.addAll(band.items);
return result;
}
/**
* add a TaskDefinition from RibbonTask component
*/
public TaskDefinition addTask(RibbonTask ribbonTask)
{
if (ribbonTask == null)
return null;
final TaskDefinition result = addTask(ribbonTask.getTitle());
// add bands from ribbonTask
result.clear();
result.addBands(ribbonTask);
return result;
}
/**
* add a TaskDefinition
*/
public TaskDefinition addTask(String taskName)
{
TaskDefinition task = findTask(taskName);
if (task == null)
{
task = new TaskDefinition();
task.name = taskName;
tasks.add(task);
}
return task;
}
/**
* add a BandDefinition
*/
public BandDefinition addBand(String taskName, String bandName)
{
return addTask(taskName).addBand(bandName);
}
/**
* add a ItemDefinition
*/
public ItemDefinition addItem(String taskName, String bandName, String className)
{
return addTask(taskName).addItem(bandName, className);
}
public boolean removeTask(String taskName)
{
return tasks.remove(findTask(taskName));
}
/**
* load from local
*/
public boolean load()
{
return XMLPersistentHelper.loadFromXML(this, getLocalFilename());
}
/**
* load from file
*/
public boolean load(File file)
{
return XMLPersistentHelper.loadFromXML(this, file);
}
/**
* load from file
*/
public boolean load(URL url)
{
return XMLPersistentHelper.loadFromXML(this, url);
}
@Override
public boolean loadFromXML(Node node)
{
if (node == null)
return false;
name = XMLUtil.getAttributeValue((Element) node, ID_NAME, "");
description = XMLUtil.getAttributeValue((Element) node, ID_DESCRIPTION, "");
// don't load the "enabled" property here
// clear before loading
tasks.clear();
final ArrayList<Node> nodesTask = XMLUtil.getChildren(node, ID_TASK);
for (Node n : nodesTask)
tasks.add(new TaskDefinition(n));
return true;
}
/**
* save
*/
public boolean save()
{
return XMLPersistentHelper.saveToXML(this, getLocalFilename());
}
@Override
public boolean saveToXML(Node node)
{
if (node == null)
return false;
XMLUtil.setAttributeValue((Element) node, ID_NAME, name);
XMLUtil.setAttributeValue((Element) node, ID_DESCRIPTION, description);
// don't save the "enabled" property here
XMLUtil.removeAllChildren(node);
for (TaskDefinition task : tasks)
task.saveToXML(XMLUtil.addElement(node, ID_TASK));
return true;
}
/**
* Install the workspace.<br>
* Return 0 if workspace cannot be installed<br>
* Return 1 if workspace correctly installed<br>
* Return 2 if workspace partially installed<br>
*/
public int install(final ProgressFrame progressFrame)
{
if (installing)
return 0;
installing = true;
try
{
// get all items
final ArrayList<ItemDefinition> items = getAllItems();
final ArrayList<PluginDescriptor> pluginsToInstall = new ArrayList<PluginDescriptor>();
if (progressFrame != null)
progressFrame.setMessage("Waiting for plugin loader to find plugins...");
// wait while online loader is ready
PluginRepositoryLoader.waitLoaded();
if (progressFrame != null)
progressFrame.setMessage("Installing workspace '" + name + "' : searching for installed plugins...");
for (ItemDefinition item : items)
{
// avoid separator item
if (!item.isSeparator())
{
final String className = item.getClassName();
// try first from loaded plugins
PluginDescriptor plugin = PluginLoader.getPlugin(className);
// not found ?
if (plugin == null)
{
// then try from repository plugins
plugin = PluginRepositoryLoader.getPlugin(className);
if (plugin == null)
{
System.err.println("Can't install plugin '" + className + "' : not found in repositery");
return 0;
}
// add to installation list
PluginDescriptor.addToList(pluginsToInstall, plugin);
}
}
}
if (progressFrame != null)
progressFrame.setMessage("Installing workspace '" + name + "' : downloading plugins...");
// install missing plugins (no confirmation needed)
for (PluginDescriptor plugin : pluginsToInstall)
PluginInstaller.install(plugin, progressFrame != null);
// wait installation completion
PluginInstaller.waitInstall();
final List<PluginDescriptor> installedPlugins = PluginLoader.getPlugins(false);
// get number of correctly installed plugins
int numberOfInstalledPlugin = 0;
for (PluginDescriptor plugin : pluginsToInstall)
if (PluginDescriptor.existInList(installedPlugins, plugin))
numberOfInstalledPlugin++;
// return 1 if complete installation
if (numberOfInstalledPlugin == pluginsToInstall.size())
return 1;
// return 2 if partial installation
else if (numberOfInstalledPlugin > 0)
return 2;
// return 0 if no installation
return 0;
}
finally
{
installing = false;
}
}
@Override
public int compareTo(Workspace o)
{
return name.compareTo(o.getName());
}
}