/* *------------------------------------------------------------------------------ * Copyright (C) 2006 University of Dundee. All rights reserved. * * * This program 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 2 of the License, or * (at your option) any later version. * This program 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, write to the Free Software Foundation, Inc., * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA. * *------------------------------------------------------------------------------ */ package org.openmicroscopy.shoola.agents.treeviewer.view; import java.awt.Rectangle; import java.io.BufferedReader; import java.io.BufferedWriter; import java.io.File; import java.io.FileReader; import java.io.FileWriter; import java.util.ArrayList; import java.util.Collection; import java.util.Collections; import java.util.HashMap; import java.util.HashSet; import java.util.Iterator; import java.util.List; import java.util.Map; import java.util.Set; import java.util.Map.Entry; import javax.swing.JMenu; import javax.swing.event.ChangeEvent; import javax.swing.event.ChangeListener; import org.apache.commons.io.FilenameUtils; import org.openmicroscopy.shoola.agents.events.SaveData; import org.openmicroscopy.shoola.agents.treeviewer.TreeViewerAgent; import org.openmicroscopy.shoola.env.Agent; import org.openmicroscopy.shoola.env.Environment; import org.openmicroscopy.shoola.env.LookupNames; import org.openmicroscopy.shoola.env.data.events.SaveEventRequest; import org.openmicroscopy.shoola.env.data.events.SaveEventResponse; import org.openmicroscopy.shoola.env.data.model.ApplicationData; import org.openmicroscopy.shoola.env.event.EventBus; import omero.log.LogMessage; import org.openmicroscopy.shoola.env.rnd.RndProxyDef; import org.openmicroscopy.shoola.env.ui.TaskBar; import org.openmicroscopy.shoola.util.StringComparator; import omero.gateway.model.DataObject; import omero.gateway.model.ExperimenterData; import omero.gateway.model.ImageData; /** * Factory to create {@link TreeViewer} component. * This class keeps track of the {@link TreeViewer} instance that has been * created and is not yet in the {@link TreeViewer#DISCARDED} state. * * @author Jean-Marie Burel      * <a href="mailto:j.burel@dundee.ac.uk">j.burel@dundee.ac.uk</a> * @version 2.2 * @since OME2.2 */ public class TreeViewerFactory implements ChangeListener { /** Keeps track of viewers used to view archived images. */ static final String IMAGE_ARCHIVED = "imageNotArchived";//"imageArchived"; /** Keeps track of viewers used to view images. */ static final String IMAGE_NOT_ARCHIVED = "imageNotArchived"; /** The name of the file. */ private static final String FILE_NAME = "externalApplication.txt"; /** The name of the windows menu. */ private static final String MENU_NAME = "Data Manager"; /** The terms used to separate the file ID from the external application. */ private static final String SEPARATOR = "="; /** The sole instance. */ private static final TreeViewerFactory singleton = new TreeViewerFactory(); /** * Registers the application. * * @param data The application to register. * @param mimeType The mimeType of the file. */ static void register(ApplicationData data, String mimeType) { if (mimeType == null) return; List<ApplicationData> list = singleton.applications.get(mimeType); if (list == null) { list = new ArrayList<ApplicationData>(); list.add(data); singleton.applications.put(mimeType, list); } else { //Add the applications if needed. String path = data.getApplicationPath(); Iterator<ApplicationData> i = list.iterator(); ApplicationData app; boolean registered = false; while (i.hasNext()) { app = i.next(); if (app.getApplicationPath().equals(path)) { registered = true; break; } } if (!registered) { list.add(data); Collections.sort(list, singleton.comparator); } } } /** * Returns the collection of external applications used to * open the document. * * @param type The MIME type of the document. * @return See above. */ static List<ApplicationData> getApplications(String type) { return singleton.applications.get(type); } //static /** * Returns the <code>window</code> menu. * * @return See above. */ static JMenu getWindowMenu() { return singleton.windowMenu; } /** * Returns <code>true</code> is the {@link #windowMenu} is attached * to the <code>TaskBar</code>, <code>false</code> otherwise. * * @return See above. */ static boolean isWindowMenuAttachedToTaskBar() { return singleton.isAttached; } /** Attaches the {@link #windowMenu} to the <code>TaskBar</code>. */ static void attachWindowMenuToTaskBar() { if (isWindowMenuAttachedToTaskBar()) return; TaskBar tb = TreeViewerAgent.getRegistry().getTaskBar(); tb.addToMenu(TaskBar.WINDOW_MENU, getWindowMenu()); singleton.isAttached = true; } /** * Returns the collection of active viewers. * * @return See above. */ static Set getViewers() { return singleton.viewers; } /** * Returns <code>true</code> if there is only one {@link TreeViewer} * available, <code>false</code> otherwise. * * @return See above. */ static boolean isLastViewer() { return (singleton.viewers.size() <= 1); } /** * Returns the {@link TreeViewer}. * * @param exp The experiment the TreeViewer is for. * @return See above. */ public static TreeViewer getTreeViewer(ExperimenterData exp) { TreeViewerModel model = new TreeViewerModel(exp); return singleton.getTreeViewer(model, null); } /** * Stores the image to copy the rendering settings from. * * @param image The image to copy the rendering settings from. * @param settings Copied 'pending' rendering settings */ public static void copyRndSettings(ImageData image, RndProxyDef settings) { Iterator v = singleton.viewers.iterator(); TreeViewerComponent comp; while (v.hasNext()) { comp = (TreeViewerComponent) v.next(); comp.setRndSettings(image, settings); } } /** * Notifies that the rendering settings have been copied. * * @param imageIds The collection of updated images */ public static void onRndSettingsCopied(Collection<Long> imageIds) { Iterator<TreeViewer> v = singleton.viewers.iterator(); TreeViewerComponent comp; while (v.hasNext()) { comp = (TreeViewerComponent) v.next(); comp.onRndSettingsCopied(imageIds); } } /** * Saves the data before closing the application. * * @param evt * @param agent */ public static void saveOnClose(SaveEventRequest evt, Object agent) { //if (!(evt instanceof SaveData)) return; Iterator v = singleton.viewers.iterator(); TreeViewerComponent comp; //tmp EventBus bus = TreeViewerAgent.getRegistry().getEventBus(); while (v.hasNext()) { comp = (TreeViewerComponent) v.next(); comp.saveOnClose((SaveData) evt.getAnswer()); bus.post(new SaveEventResponse(evt, (Agent) agent)); } } /** * Notifies the model that the user's group has successfully be modified * if the passed value is <code>true</code>, unsuccessfully * if <code>false</code>. * * @param success Pass <code>true</code> if successful, <code>false</code> * otherwise. */ public static void onGroupSwitched(boolean success) { if (!success) return; Iterator<TreeViewer> v = singleton.viewers.iterator(); TreeViewerComponent comp; while (v.hasNext()) { comp = (TreeViewerComponent) v.next(); comp.onGroupSwitched(success); } } /** * Notifies the model that the user is reconnected. * * @return Returns <code>true</code> if some viewers are already stored, * <code>false</code> otherwise. */ public static boolean onReconnected() { Iterator<TreeViewer> v = singleton.viewers.iterator(); TreeViewerComponent comp; while (v.hasNext()) { comp = (TreeViewerComponent) v.next(); comp.onReconnected(); } return singleton.viewers.size() > 0; } /** * Notifies the model that the user has annotated data. * * @param containers The objects to handle. * @param count A positive value if annotations are added, a negative value * if annotations are removed. */ public static void onAnnotated(List<DataObject> containers, int count) { Iterator v = singleton.viewers.iterator(); TreeViewerComponent comp; while (v.hasNext()) { comp = (TreeViewerComponent) v.next(); comp.onAnnotated(containers, count); } } /** * Returns the {@link TreeViewer}. * * @param exp The experiment the TreeViewer is for. * @param bounds The bounds of the component invoking a new * {@link TreeViewer}. * @return See above. */ public static TreeViewer getTreeViewer(ExperimenterData exp, Rectangle bounds) { TreeViewerModel model = new TreeViewerModel(exp); return singleton.getTreeViewer(model, bounds); } /** Close all the instances.*/ public static void terminate() { singleton.shutDown(); } /** Writes the external applications used to open document. */ public static void writeExternalApplications() { if (singleton.applications == null || singleton.applications.size() == 0) return; try { Environment env = (Environment) TreeViewerAgent.getRegistry().lookup(LookupNames.ENV); String name = env.getOmeroHome()+File.separator+FILE_NAME; File f = new File(name); if (f.exists()) f.delete(); BufferedWriter output = new BufferedWriter(new FileWriter(name)); Entry entry; Iterator i = singleton.applications.entrySet().iterator(); String format; List list; Iterator j; ApplicationData data; while (i.hasNext()) { entry = (Entry) i.next(); format = (String) entry.getKey(); list = (List) entry.getValue(); if (list != null) { j = list.iterator(); while (j.hasNext()) { data = (ApplicationData) j.next(); output.write(format+SEPARATOR+data.getApplicationPath()); output.newLine(); } } } if (output != null) output.close(); } catch (Exception e) { LogMessage msg = new LogMessage(); msg.print("An error occurred while writing the external " + "applications back to the file."); msg.print(e); TreeViewerAgent.getRegistry().getLogger().error( TreeViewerFactory.class, msg); } } /** The tracked component. */ //private TreeViewer viewer; /** The tracked components. */ private Set<TreeViewer> viewers; /** The windows menu. */ private JMenu windowMenu; /** * Indicates if the {@link #windowMenu} is attached to the * <code>TaskBar</code>. */ private boolean isAttached; /** The external applications used to open file or images. */ private Map<String, List<ApplicationData>> applications; /** The comparator used to sort the applications. */ private StringComparator comparator; /** Creates a new instance. */ private TreeViewerFactory() { //viewer = null; applications = null; viewers = new HashSet<TreeViewer>(); isAttached = false; windowMenu = new JMenu(MENU_NAME); comparator = new StringComparator(); } /** Shuts donw the components.*/ private void shutDown() { Set<TreeViewer> viewers = singleton.viewers; Iterator<TreeViewer> i = viewers.iterator(); TreeViewer viewer; while (i.hasNext()) { viewer = i.next(); ((TreeViewerComponent) viewer).shutDown(); } viewers.clear(); } /** * Creates or recycles a viewer component for the specified * <code>model</code>. * * @param model The Model. * @param bounds The bounds of the component invoking a new * {@link TreeViewer}. * @return A {@link TreeViewer}. */ private TreeViewer getTreeViewer(TreeViewerModel model, Rectangle bounds) { Iterator v = viewers.iterator(); TreeViewerComponent comp; while (v.hasNext()) { comp = (TreeViewerComponent) v.next(); comp.setRecycled(true); return comp; } //if (viewer != null) return viewer; readExternalApplications(); comp = new TreeViewerComponent(model); model.initialize(comp); comp.initialize(bounds); //viewer = component; comp.addChangeListener(this); viewers.add(comp); return comp; } /** Reads the file hosting the external applications. */ private void readExternalApplications() { if (applications != null) return; applications = new HashMap<String, List<ApplicationData>>(); Environment env = (Environment) TreeViewerAgent.getRegistry().lookup(LookupNames.ENV); String name = FilenameUtils.concat(env.getOmeroHome(),FILE_NAME); File f = new File(name); if (!f.exists()) return; try { BufferedReader input = new BufferedReader(new FileReader(f)); try { String line = null; String mimeType; String[] values; int index; StringBuffer buffer; List<ApplicationData> list; while ((line = input.readLine()) != null) { if (line.contains(SEPARATOR)) { values = line.split(SEPARATOR); if (values.length >= 2) { mimeType = values[0]; index = 1; buffer = new StringBuffer(); for (int i = 1; i < values.length; i++) { buffer.append(values[i]); if (index != values.length-1) buffer.append(SEPARATOR); index++; } list = applications.get(mimeType); if (list == null) { list = new ArrayList<ApplicationData>(); applications.put(mimeType, list); } File application = new File(buffer.toString()); list.add(new ApplicationData(application)); } } } //sort out the list. Iterator<String> k = applications.keySet().iterator(); while (k.hasNext()) { list = applications.get(k.next()); Collections.sort(list, singleton.comparator); } } finally { input.close(); } } catch (Exception e) { LogMessage msg = new LogMessage(); msg.print("An error occurred while reading the external " + "applications file."); msg.print(e); TreeViewerAgent.getRegistry().getLogger().error( TreeViewerFactory.class, msg); } } /** * Removes all the references to viewer when the state is * {@link TreeViewer#DISCARDED discarded}. * @see ChangeListener#stateChanged(ChangeEvent) */ public void stateChanged(ChangeEvent ce) { TreeViewerComponent comp = (TreeViewerComponent) ce.getSource(); if (comp.getState() == TreeViewer.DISCARDED) viewers.remove(comp); } }