/*******************************************************************************
* Copyright (c) 2016 Weasis Team and others.
* All rights reserved. This program and the accompanying materials
* are made available under the terms of the Eclipse Public License v1.0
* which accompanies this distribution, and is available at
* http://www.eclipse.org/legal/epl-v10.html
*
* Contributors:
* Nicolas Roduit - initial API and implementation
*******************************************************************************/
package org.weasis.core.api.explorer.model;
import java.beans.PropertyChangeListener;
import java.beans.PropertyChangeSupport;
import java.io.IOException;
import java.util.Arrays;
import java.util.Collection;
import java.util.Iterator;
import java.util.List;
import javax.swing.SwingUtilities;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.weasis.core.api.command.Option;
import org.weasis.core.api.command.Options;
import org.weasis.core.api.explorer.ObservableEvent;
import org.weasis.core.api.gui.util.GuiExecutor;
import org.weasis.core.api.media.data.Codec;
import org.weasis.core.api.media.data.MediaElement;
import org.weasis.core.api.media.data.MediaSeriesGroup;
import org.weasis.core.api.media.data.MediaSeriesGroupNode;
import org.weasis.core.api.media.data.Series;
import org.weasis.core.api.media.data.TagView;
import org.weasis.core.api.media.data.TagW;
import org.weasis.core.api.service.BundleTools;
public abstract class AbstractFileModel implements TreeModel, DataExplorerModel {
private static final Logger LOGGER = LoggerFactory.getLogger(AbstractFileModel.class);
public static final String[] functions = { "get", "close" }; //$NON-NLS-1$ //$NON-NLS-2$
public static final String NAME = "All Files"; //$NON-NLS-1$
public static final TreeModelNode group =
new TreeModelNode(1, 0, TagW.Group, new TagView(TagW.Group, TagW.FileName));
public static final TreeModelNode series =
new TreeModelNode(2, 0, TagW.SubseriesInstanceUID, new TagView(TagW.FileName));
private static final List<TreeModelNode> modelStrucure = Arrays.asList(TreeModelNode.ROOT, group, series);
private final Tree<MediaSeriesGroup> model;
private PropertyChangeSupport propertyChange = null;
public AbstractFileModel() {
model = new Tree<>(MediaSeriesGroupNode.rootNode);
}
@Override
public synchronized List<Codec> getCodecPlugins() {
return BundleTools.CODEC_PLUGINS;
}
@Override
public Collection<MediaSeriesGroup> getChildren(MediaSeriesGroup node) {
return model.getSuccessors(node);
}
@Override
public MediaSeriesGroup getHierarchyNode(MediaSeriesGroup parent, Object value) {
if (parent != null || value != null) {
synchronized (model) {
for (MediaSeriesGroup node : model.getSuccessors(parent)) {
if (node.matchIdValue(value)) {
return node;
}
}
}
}
return null;
}
@Override
public void addHierarchyNode(MediaSeriesGroup root, MediaSeriesGroup leaf) {
synchronized (model) {
model.addLeaf(root, leaf);
}
}
@Override
public void removeHierarchyNode(MediaSeriesGroup root, MediaSeriesGroup leaf) {
synchronized (model) {
Tree<MediaSeriesGroup> tree = model.getTree(root);
if (tree != null) {
tree.removeLeaf(leaf);
}
}
}
@Override
public MediaSeriesGroup getParent(MediaSeriesGroup node, TreeModelNode modelNode) {
if (null != node && modelNode != null) {
if (node.getTagID().equals(modelNode.getTagElement())) {
return node;
}
synchronized (model) {
Tree<MediaSeriesGroup> tree = model.getTree(node);
if (tree != null) {
Tree<MediaSeriesGroup> parent;
while ((parent = tree.getParent()) != null) {
if (parent.getHead().getTagID().equals(modelNode.getTagElement())) {
return parent.getHead();
}
tree = parent;
}
}
}
}
return null;
}
public void dispose() {
synchronized (model) {
for (Iterator<MediaSeriesGroup> iterator =
this.getChildren(MediaSeriesGroupNode.rootNode).iterator(); iterator.hasNext();) {
iterator.next().dispose();
}
}
model.clear();
}
@Override
public String toString() {
return NAME;
}
@Override
public List<TreeModelNode> getModelStructure() {
return modelStrucure;
}
@Override
public void addPropertyChangeListener(PropertyChangeListener propertychangelistener) {
if (propertyChange == null) {
propertyChange = new PropertyChangeSupport(this);
}
propertyChange.addPropertyChangeListener(propertychangelistener);
}
@Override
public void removePropertyChangeListener(PropertyChangeListener propertychangelistener) {
if (propertyChange != null) {
propertyChange.removePropertyChangeListener(propertychangelistener);
}
}
@Override
public void firePropertyChange(final ObservableEvent event) {
if (propertyChange != null) {
if (event == null) {
throw new NullPointerException();
}
if (SwingUtilities.isEventDispatchThread()) {
propertyChange.firePropertyChange(event);
} else {
SwingUtilities.invokeLater(() -> propertyChange.firePropertyChange(event));
}
}
}
public void removeTopGroup(MediaSeriesGroup topGroup) {
if (topGroup != null) {
firePropertyChange(
new ObservableEvent(ObservableEvent.BasicAction.REMOVE, AbstractFileModel.this, null, topGroup));
Collection<MediaSeriesGroup> seriesList = getChildren(topGroup);
for (Iterator<MediaSeriesGroup> it = seriesList.iterator(); it.hasNext();) {
it.next().dispose();
}
removeHierarchyNode(MediaSeriesGroupNode.rootNode, topGroup);
LOGGER.info("Remove Group: {}", topGroup); //$NON-NLS-1$
}
}
public void removeSeries(MediaSeriesGroup seriesGroup) {
if (seriesGroup != null) {
// remove first series in UI (Viewer using this series)
firePropertyChange(
new ObservableEvent(ObservableEvent.BasicAction.REMOVE, AbstractFileModel.this, null, seriesGroup));
// remove in the data model
MediaSeriesGroup topGroup = getParent(seriesGroup, AbstractFileModel.group);
removeHierarchyNode(topGroup, seriesGroup);
seriesGroup.dispose();
LOGGER.info("Remove Series/Image: {}", seriesGroup); //$NON-NLS-1$
}
}
@Override
public boolean applySplittingRules(Series original, MediaElement media) {
return false;
}
public abstract void get(String[] argv) throws IOException;
public void close(String[] argv) throws IOException {
final String[] usage = { "Close images", //$NON-NLS-1$
"Usage: dicom:close (-a | ([-g UID]... [-s UID]...)) ", //$NON-NLS-1$
" -a --all close all series", //$NON-NLS-1$
" -g --group=UID close a group from its UID", " -s --series=UID close an series/image from its UID", //$NON-NLS-1$ //$NON-NLS-2$
" -? --help show help" }; //$NON-NLS-1$
final Option opt = Options.compile(usage).parse(argv);
final List<String> gargs = opt.getList("group"); //$NON-NLS-1$
final List<String> iargs = opt.getList("series"); //$NON-NLS-1$
if (opt.isSet("help") || (gargs.isEmpty() && iargs.isEmpty() && !opt.isSet("all"))) { //$NON-NLS-1$ //$NON-NLS-2$
opt.usage();
return;
}
GuiExecutor.instance().execute(() -> {
AbstractFileModel dataModel = AbstractFileModel.this;
firePropertyChange(new ObservableEvent(ObservableEvent.BasicAction.SELECT, dataModel, null, dataModel));
if (opt.isSet("all")) { //$NON-NLS-1$
for (MediaSeriesGroup g : model.getSuccessors(MediaSeriesGroupNode.rootNode)) {
dataModel.removeTopGroup(g);
}
} else {
if (opt.isSet("group")) { //$NON-NLS-1$
for (String gUID : gargs) {
dataModel.removeTopGroup(getHierarchyNode(MediaSeriesGroupNode.rootNode, gUID));
}
}
if (opt.isSet("series")) { //$NON-NLS-1$
for (String uid : iargs) {
for (MediaSeriesGroup topGroup : model.getSuccessors(MediaSeriesGroupNode.rootNode)) {
MediaSeriesGroup s = getHierarchyNode(topGroup, uid);
if (s != null) {
removeSeries(s);
break;
}
}
}
}
}
});
}
@Override
public TreeModelNode getTreeModelNodeForNewPlugin() {
return group;
}
}