/* * 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()); } }