/* *------------------------------------------------------------------------------ * Copyright (C) 2015-2016 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.metadata.editor; import java.awt.Point; import java.awt.event.MouseAdapter; import java.awt.event.MouseEvent; import java.io.File; import java.util.ArrayList; import java.util.Collection; import java.util.HashMap; import java.util.HashSet; import java.util.Iterator; import java.util.List; import java.util.Map; import java.util.Map.Entry; import java.util.Set; import javax.swing.JButton; import javax.swing.JMenuItem; import javax.swing.JPopupMenu; import omero.gateway.model.AnnotationData; import omero.gateway.model.DataObject; import omero.gateway.model.FileAnnotationData; import org.openmicroscopy.shoola.agents.metadata.IconManager; import org.openmicroscopy.shoola.util.ui.UIUtilities; import org.openmicroscopy.shoola.util.ui.WrapLayout; /** * A {@link AnnotationTaskPaneUI} for displaying {@link FileAnnotationData} * * @author Dominik Lindner      <a * href="mailto:d.lindner@dundee.ac.uk">d.lindner@dundee.ac.uk</a> */ public class AttachmentsTaskPaneUI extends AnnotationTaskPaneUI { /** Hold the {@link DocComponent}s representing the file annotations */ private List<DocComponent> filesDocList; /** * The selection menu to attach either local documents or already upload * files. */ private JPopupMenu docSelectionMenu; /** Flag to indicate if the FileAnnotations should be selectable */ private boolean selectable; /** The collection of annotations to replace. */ private List<FileAnnotationData> toReplace; /** Remove attachments button */ private JButton removeDocsButton; /** Add attachments button */ private JButton addDocsButton; /** * Creates a new instance * * @param model * Reference to the {@link EditorModel} * @param view * Reference to the {@link EditorUI} * @param controller * Reference to the {@link EditorControl} */ AttachmentsTaskPaneUI(EditorModel model, EditorUI view, EditorControl controller) { super(model, view, controller); filesDocList = new ArrayList<DocComponent>(); toReplace = new ArrayList<FileAnnotationData>(); setLayout(new WrapLayout(WrapLayout.LEFT)); setBackground(UIUtilities.BACKGROUND_COLOR); } /** * Attaches the passed file. Returns <code>true</code> if the file * does not already exist, <code>false</code> otherwise. * * @param files The files to attach. * @return See above */ boolean attachFiles(File[] files) { List<FileAnnotationData> list = getCurrentAttachmentsSelection(); DocComponent doc; List<File> toAdd = new ArrayList<File>(); Object data = null; if (filesDocList.size() > 0) { Iterator<DocComponent> i = filesDocList.iterator(); FileAnnotationData fa; while (i.hasNext()) { doc = i.next(); data = doc.getData(); if (data instanceof FileAnnotationData) { fa = (FileAnnotationData) data; for (int j = 0; j < files.length; j++) { if (fa.getId() >= 0 && fa.getFileName().equals(files[j].getName())) { toReplace.add(fa); } } } } } for (int i = 0; i < files.length; i++) { toAdd.add(files[i]); } if (toAdd.size() > 0) { data = null; try { Iterator<File> j = toAdd.iterator(); while (j.hasNext()) { list.add(new FileAnnotationData(j.next())); } } catch (Exception e) {} firePropertyChange(EditorControl.SAVE_PROPERTY, Boolean.valueOf(false), Boolean.valueOf(true)); } layoutAttachments(list); return toAdd.size() > 0; } /** * Removes the passed file from the display. * * @param file The file to remove. */ void removeAttachedFile(Object file) { if (file == null) return; FileAnnotationData fData = (FileAnnotationData) file; List<FileAnnotationData> attachments = getCurrentAttachmentsSelection(); Iterator<FileAnnotationData> i = attachments.iterator(); FileAnnotationData data; List<FileAnnotationData> toKeep = new ArrayList<FileAnnotationData>(); while (i.hasNext()) { data = i.next(); if (data.getId() != fData.getId()) toKeep.add(data); } if (filesDocList.size() > 0) { Iterator<DocComponent> j = filesDocList.iterator(); DocComponent doc; Object fa; while (j.hasNext()) { doc = j.next(); fa = doc.getData(); if (fa instanceof FileAnnotationData) { data = (FileAnnotationData) fa; if (data.getId() <= 0 && !data.equals(file)) { toKeep.add(data); } } } } handleObjectsSelection(FileAnnotationData.class, toKeep, true); } /** * Returns the collection of attachments. * * @return See above. */ List<FileAnnotationData> removeAttachedFiles() { List<FileAnnotationData> list = new ArrayList<FileAnnotationData>(); if (filesDocList.size() == 0) { return list; } List<FileAnnotationData> toKeep = new ArrayList<FileAnnotationData>(); FileAnnotationData data; DocComponent doc; Object object; Iterator<DocComponent> i = filesDocList.iterator(); while (i.hasNext()) { doc = i.next(); object = doc.getData(); if (doc.canUnlink()) { if (object instanceof FileAnnotationData) { data = (FileAnnotationData) object; if (data.getId() > 0) list.add(data); } } else { toKeep.add((FileAnnotationData) object); } } handleObjectsSelection(FileAnnotationData.class, toKeep, false); return list; } /** * Handles the selection of objects via the selection wizard. * * @param type The type of objects to handle. * @param objects The objects to handle. * @param fire Pass <code>true</code> to notify, <code>false</code> * otherwise. */ void handleObjectsSelection(Class<?> type, Collection objects, boolean fire) { layoutAttachments(objects); } /** * Returns the list of attachments currently selected by the user. * * @return See above. */ private List<FileAnnotationData> getCurrentAttachmentsSelection() { List<FileAnnotationData> list = new ArrayList<FileAnnotationData>(); if (filesDocList.size() == 0) return list; DocComponent doc; Object object; FileAnnotationData data; Iterator<DocComponent> i = filesDocList.iterator(); while (i.hasNext()) { doc = i.next(); object = doc.getData(); if (object instanceof FileAnnotationData) { data = (FileAnnotationData) object; if (data.getId() > 0) list.add(data); } } return list; } @Override void refreshUI() { clearDisplay(); Collection list; if (model.isMultiSelection()) list = model.getAllAttachments(); else list = model.getAttachments(); layoutAttachments(list); addDocsButton.setEnabled(model.canAddAnnotationLink()); removeDocsButton.setEnabled(model.canAddAnnotationLink()); } void layoutAttachments(Collection list) { removeAll(); filesDocList.clear(); DocComponent doc; int h = 0; int v; if (list != null && list.size() > 0) { Iterator i = list.iterator(); DataObject data; switch (filter) { case SHOW_ALL: while (i.hasNext()) { data = (DataObject) i.next(); if (!toReplace.contains(data)) { doc = new DocComponent(data, model, true, selectable); doc.addPropertyChangeListener(controller); filesDocList.add(doc); add(doc); v = doc.getPreferredSize().height; if (h < v) h = v; } } break; case ADDED_BY_OTHERS: while (i.hasNext()) { data = (DataObject) i.next(); if (!toReplace.contains(data)) { doc = new DocComponent(data, model, true, selectable); doc.addPropertyChangeListener(controller); filesDocList.add(doc); if (model.isAnnotatedByOther(data)) { add(doc); v = doc.getPreferredSize().height; if (h < v) h = v; } } } break; case ADDED_BY_ME: while (i.hasNext()) { data = (DataObject) i.next(); if (!toReplace.contains(data)) { doc = new DocComponent(data, model, true, selectable); doc.addPropertyChangeListener(controller); filesDocList.add(doc); if (model.isLinkOwner(data)) { add(doc); v = doc.getPreferredSize().height; if (h < v) h = v; } } } } } if (filesDocList.size() == 0 ) { doc = new DocComponent(null, model, true, false); filesDocList.add(doc); add(doc); } revalidate(); repaint(); } @Override void clearDisplay() { removeAll(); filesDocList.clear(); } @Override List<JButton> getToolbarButtons() { List<JButton> buttons = new ArrayList<JButton>(); IconManager icons = IconManager.getInstance(); addDocsButton = new JButton( icons.getIcon(IconManager.PLUS_12)); addDocsButton.setBackground(UIUtilities.BACKGROUND_COLOR); addDocsButton.setToolTipText("Attach a document."); addDocsButton.addMouseListener(new MouseAdapter() { public void mouseReleased(MouseEvent e) { if (addDocsButton.isEnabled()) { Point p = e.getPoint(); createDocSelectionMenu().show(addDocsButton, p.x, p.y); } } }); UIUtilities.unifiedButtonLookAndFeel(addDocsButton); buttons.add(addDocsButton); removeDocsButton = new JButton( icons.getIcon(IconManager.MINUS_12)); UIUtilities.unifiedButtonLookAndFeel(removeDocsButton); removeDocsButton.setBackground(UIUtilities.BACKGROUND_COLOR); removeDocsButton.setToolTipText("Remove Attachments."); removeDocsButton.addMouseListener(controller); removeDocsButton.setActionCommand("" + EditorControl.REMOVE_DOCS); buttons.add(removeDocsButton); final JButton selectButton = new JButton(icons.getIcon(IconManager.ANALYSIS)); selectButton.setBackground(UIUtilities.BACKGROUND_COLOR); selectButton.setToolTipText("Select Files for Scripts"); selectButton.addMouseListener(new MouseAdapter() { public void mouseReleased(MouseEvent e) { if (selectButton.isEnabled()) { selectable = !selectable; refreshUI(); } } }); UIUtilities.unifiedButtonLookAndFeel(selectButton); buttons.add(selectButton); return buttons; } /** * Creates the selection menu. * * @return See above. */ private JPopupMenu createDocSelectionMenu() { if (docSelectionMenu != null) return docSelectionMenu; docSelectionMenu = new JPopupMenu(); JMenuItem item = new JMenuItem("Local document..."); item.setToolTipText("Import a local document to the server " + "and attach it."); item.addActionListener(controller); item.setActionCommand("" + EditorControl.ADD_LOCAL_DOCS); docSelectionMenu.add(item); item = new JMenuItem("Uploaded document..."); item.setToolTipText("Attach a document already uploaded " + "to the server."); item.addActionListener(controller); item.setActionCommand("" + EditorControl.ADD_UPLOADED_DOCS); docSelectionMenu.add(item); return docSelectionMenu; } @Override List<AnnotationData> getAnnotationsToSave() { List<AnnotationData> l = new ArrayList<AnnotationData>(); Collection<FileAnnotationData> original = model.getAllAttachments(); Iterator<FileAnnotationData> j = original.iterator(); List<Long> ids = new ArrayList<Long>(); while (j.hasNext()) { ids.add(((AnnotationData) j.next()).getId()); } Iterator<DocComponent> i = filesDocList.iterator(); Map<Long, Integer> map = new HashMap<Long, Integer>(); Map<Long, AnnotationData> annotations = new HashMap<Long, AnnotationData>(); Integer count; while (i.hasNext()) { DocComponent doc = i.next(); Object object = doc.getData(); if (object instanceof FileAnnotationData) { AnnotationData annotation = (AnnotationData) object; long id = annotation.getId(); if (!ids.contains(id)) { l.add(annotation); } else { count = map.get(id); if (count != null) { count++; map.put(id, count); } else { count = 1; annotations.put(id, annotation); map.put(id, count); } } } } //check the count Entry<Long, Integer> entry; Iterator<Entry<Long, Integer>> k = map.entrySet().iterator(); int n = filesDocList.size(); Map<DataObject, Boolean> m; while (k.hasNext()) { entry = k.next(); count = entry.getValue(); if (count != null && count == n) { //Check if the annotation needs to be added AnnotationData annotation = annotations.get(entry.getKey()); m = model.getObjectsWith(annotation); if (m.size() < count) { l.add(annotation); } } } return l; } @Override List<Object> getAnnotationsToRemove() { List<Object> l = new ArrayList<Object>(); Set<Long> idsToKeep = new HashSet<Long>(); Iterator<DocComponent> i = filesDocList.iterator(); while (i.hasNext()) { DocComponent doc = i.next(); Object object = doc.getData(); if (object instanceof FileAnnotationData) { AnnotationData annotation = (AnnotationData) object; long id = annotation.getId(); if (id > 0) idsToKeep.add(id); } } Collection<FileAnnotationData> original = model.getAllAttachments(); Iterator<FileAnnotationData> j = original.iterator(); while (j.hasNext()) { AnnotationData annotation = (AnnotationData) j.next(); long id = annotation.getId(); if (!idsToKeep.contains(id)) l.add(annotation); } return l; } Collection<FileAnnotationData> getSelectedFileAnnotations() { Collection<FileAnnotationData> result = new ArrayList<FileAnnotationData>(); for(DocComponent c : filesDocList) if(c.isSelected()) result.add((FileAnnotationData)c.getData()); return result; } /** * Returns <code>true</code> some tags can be unlinked, * <code>false</code> otherwise. * * @return See above. */ boolean hasAttachmentsToUnlink() { if (filesDocList.size() == 0) return false; DocComponent doc; Object object; Iterator<DocComponent> i = filesDocList.iterator(); while (i.hasNext()) { doc = i.next(); object = doc.getData(); if (doc.canUnlink()) { if (object instanceof FileAnnotationData) { return true; } } } return false; } @Override void onRelatedNodesSet() { } }