/*******************************************************************************
* 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.dicom.viewer2d.mip;
import java.io.File;
import java.util.ArrayList;
import java.util.List;
import javax.swing.ImageIcon;
import javax.swing.JDialog;
import org.dcm4che3.data.Tag;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.weasis.core.api.explorer.ObservableEvent;
import org.weasis.core.api.explorer.model.DataExplorerModel;
import org.weasis.core.api.gui.task.TaskInterruptionException;
import org.weasis.core.api.gui.task.TaskMonitor;
import org.weasis.core.api.gui.util.ActionState;
import org.weasis.core.api.gui.util.ActionW;
import org.weasis.core.api.gui.util.GuiExecutor;
import org.weasis.core.api.gui.util.SliderCineListener;
import org.weasis.core.api.image.OpManager;
import org.weasis.core.api.image.WindowOp;
import org.weasis.core.api.media.data.MediaSeries;
import org.weasis.core.api.media.data.MediaSeriesGroup;
import org.weasis.core.api.media.data.Series;
import org.weasis.core.api.media.data.TagW;
import org.weasis.core.api.service.AuditLog;
import org.weasis.core.ui.editor.ViewerPluginBuilder;
import org.weasis.core.ui.editor.image.ImageViewerEventManager;
import org.weasis.core.ui.editor.image.ImageViewerPlugin;
import org.weasis.core.ui.editor.image.ViewCanvas;
import org.weasis.dicom.codec.DcmMediaReader;
import org.weasis.dicom.codec.DicomImageElement;
import org.weasis.dicom.codec.DicomSeries;
import org.weasis.dicom.codec.TagD;
import org.weasis.dicom.explorer.DicomModel;
import org.weasis.dicom.viewer2d.Messages;
import org.weasis.dicom.viewer2d.View2d;
import org.weasis.dicom.viewer2d.View2dFactory;
public class MipView extends View2d {
private static final Logger LOGGER = LoggerFactory.getLogger(MipView.class);
public static final ImageIcon MIP_ICON_SETTING =
new ImageIcon(MipView.class.getResource("/icon/22x22/mip-setting.png")); //$NON-NLS-1$
public static final ActionW MIP = new ActionW(Messages.getString("MipView.mip"), "mip", 0, 0, null); //$NON-NLS-1$ //$NON-NLS-2$
public static final ActionW MIP_THICKNESS =
new ActionW(Messages.getString("MipView.img_extend"), "mip_thick", 0, 0, null); //$NON-NLS-1$//$NON-NLS-2$
public enum Type {
MIN, MEAN, MAX;
};
private volatile MipProcess process;
public MipView(ImageViewerEventManager<DicomImageElement> eventManager) {
super(eventManager);
}
@Override
protected void initActionWState() {
super.initActionWState();
actionsInView.put(ViewCanvas.ZOOM_TYPE_CMD, ZoomType.BEST_FIT);
actionsInView.put(MIP_THICKNESS.cmd(), 2);
actionsInView.put(MipView.MIP.cmd(), MipView.Type.MAX);
actionsInView.put("no.ko", true); //$NON-NLS-1$
// Propagate the preset
OpManager disOp = getDisplayOpManager();
disOp.setParamValue(WindowOp.OP_NAME, ActionW.DEFAULT_PRESET.cmd(), false);
}
public void initMIPSeries(ViewCanvas<?> selView) {
if (selView != null) {
actionsInView.put(ActionW.SORTSTACK.cmd(), selView.getActionValue(ActionW.SORTSTACK.cmd()));
actionsInView.put(ActionW.INVERSESTACK.cmd(), selView.getActionValue(ActionW.INVERSESTACK.cmd()));
actionsInView.put(ActionW.FILTERED_SERIES.cmd(), selView.getActionValue(ActionW.FILTERED_SERIES.cmd()));
MediaSeries s = selView.getSeries();
setSeries(s, null);
}
}
@Override
protected void setImage(DicomImageElement img) {
// Avoid to listen synch events
}
public boolean IsProcessRunning() {
return process != null;
}
protected void stopCurrentProcess() {
final MipProcess t = process;
if (t != null) {
process = null;
// Close won't stop the process immediately
t.taskMonitor.close();
t.interrupt();
}
}
public void exitMipMode(MediaSeries<DicomImageElement> series, DicomImageElement selectedDicom) {
// reset current process
this.setActionsInView(MipView.MIP.cmd(), null);
this.setActionsInView(MipView.MIP_THICKNESS.cmd(), null);
setMip(null);
ImageViewerPlugin<DicomImageElement> container = this.getEventManager().getSelectedView2dContainer();
container.setSelectedAndGetFocus();
View2d newView2d = new View2d(this.getEventManager());
newView2d.registerDefaultListeners();
newView2d.setSeries(series, selectedDicom);
container.replaceView(this, newView2d);
}
public static void buildMip(JDialog dialog, final MipView view, final boolean fullSeries) {
if (view == null) {
return;
}
view.stopCurrentProcess();
final Type mipType = (Type) view.getActionValue(MipView.MIP.cmd());
final Integer extend = (Integer) view.getActionValue(MIP_THICKNESS.cmd());
final MediaSeries<DicomImageElement> ser = view.series;
if (ser == null || extend == null || mipType == null) {
return;
}
view.process =
new MipProcess(Messages.getString("MipView.build"), new TaskMonitor(dialog == null ? view : dialog, //$NON-NLS-1$
Messages.getString("MipView.monitoring_proc"), Messages.getString("MipView.init"), 0, 2 * extend + 1)) { //$NON-NLS-1$ //$NON-NLS-2$
@Override
public void run() {
final List<DicomImageElement> dicoms = new ArrayList<DicomImageElement>();
try {
taskMonitor.setMillisToPopup(1250);
SeriesBuilder.applyMipParameters(taskMonitor, view, ser, dicoms, mipType, extend, fullSeries);
} catch (TaskInterruptionException e) {
dicoms.clear();
LOGGER.info(e.getMessage());
} catch (Throwable t) {
dicoms.clear();
AuditLog.logError(LOGGER, t, "Mip renderding error"); //$NON-NLS-1$
} finally {
// Following actions need to be executed in EDT thread
GuiExecutor.instance().execute(new Runnable() {
@Override
public void run() {
try {
if (dicoms.size() == 1) {
view.setMip(dicoms.get(0));
} else if (dicoms.size() > 1) {
DicomImageElement dcm = dicoms.get(0);
Series s =
new DicomSeries(TagD.getTagValue(dcm, Tag.SeriesInstanceUID, String.class));
s.addAll(dicoms);
((DcmMediaReader) dcm.getMediaReader()).writeMetaData(s);
DataExplorerModel model =
(DataExplorerModel) ser.getTagValue(TagW.ExplorerModel);
if (model instanceof DicomModel) {
DicomModel dicomModel = (DicomModel) model;
MediaSeriesGroup study = dicomModel.getParent(ser, DicomModel.study);
if (study != null) {
s.setTag(TagW.ExplorerModel, dicomModel);
dicomModel.addHierarchyNode(study, s);
dicomModel.firePropertyChange(new ObservableEvent(
ObservableEvent.BasicAction.ADD, dicomModel, null, s));
}
View2dFactory factory = new View2dFactory();
ViewerPluginBuilder.openSequenceInPlugin(factory, s, model, false, false);
}
}
} finally {
taskMonitor.close();
}
}
});
}
}
};
view.process.start();
}
protected void setMip(DicomImageElement dicom) {
DicomImageElement oldImage = getImage();
if (dicom != null) {
// Trick: call super to change the image as "this" method is empty
super.setImage(dicom);
}
if (oldImage == null) {
eventManager.updateComponentsListener(MipView.this);
} else {
// Force to draw crosslines without changing the slice position
ActionState sequence = eventManager.getAction(ActionW.SCROLL_SERIES);
if (sequence instanceof SliderCineListener) {
SliderCineListener cineAction = (SliderCineListener) sequence;
cineAction.stateChanged(cineAction.getSliderModel());
}
// Close stream
oldImage.dispose();
// Delete file in cache
File file = oldImage.getFile();
if (file != null) {
file.delete();
}
}
}
static class MipProcess extends Thread {
final TaskMonitor taskMonitor;
public MipProcess(String name, TaskMonitor taskMonitor) {
super(name);
this.taskMonitor = taskMonitor;
}
}
}