/*******************************************************************************
* 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.explorer;
import java.io.File;
import java.net.URL;
import java.time.LocalDateTime;
import java.util.ArrayList;
import java.util.Collections;
import java.util.List;
import java.util.Objects;
import java.util.Optional;
import javax.swing.tree.DefaultMutableTreeNode;
import javax.swing.tree.DefaultTreeModel;
import javax.swing.tree.TreePath;
import org.dcm4che3.data.Tag;
import org.dcm4che3.util.UIDUtils;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.weasis.core.api.gui.util.JMVUtils;
import org.weasis.core.api.media.data.MediaElement;
import org.weasis.core.api.media.data.MediaSeries;
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.TagReadable;
import org.weasis.core.api.media.data.TagUtil;
import org.weasis.core.api.media.data.TagW;
import org.weasis.core.api.media.data.TagW.TagType;
import org.weasis.core.api.media.data.Thumbnail;
import org.weasis.core.ui.model.GraphicModel;
import org.weasis.dicom.codec.DicomSeries;
import org.weasis.dicom.codec.DicomSpecialElement;
import org.weasis.dicom.codec.TagD;
import it.cnr.imaa.essi.lablib.gui.checkboxtree.DefaultTreeCheckingModel;
import it.cnr.imaa.essi.lablib.gui.checkboxtree.TreeCheckingModel;
public class CheckTreeModel {
private static final Logger LOGGER = LoggerFactory.getLogger(CheckTreeModel.class);
public static final TagW SourceSeriesForPR = new TagW("SourceSeriesForPR", TagType.OBJECT); //$NON-NLS-1$
private final DefaultMutableTreeNode rootNode;
private final DefaultTreeModel model;
private final TreeCheckingModel checkingModel;
private final List<TreePath> defaultSelectedPaths;
public CheckTreeModel(DicomModel dicomModel) {
this.model = buildModel(dicomModel);
this.rootNode = (DefaultMutableTreeNode) model.getRoot();
this.checkingModel = new DefaultTreeCheckingModel(model);
this.defaultSelectedPaths = Collections.synchronizedList(new ArrayList<TreePath>());
}
public DefaultMutableTreeNode getRootNode() {
return rootNode;
}
public DefaultTreeModel getModel() {
return model;
}
public TreeCheckingModel getCheckingModel() {
return checkingModel;
}
public TreePath[] getCheckingPaths() {
return checkingModel.getCheckingPaths();
}
public void setDefaultSelectionPaths(List<TreePath> selectedPaths) {
defaultSelectedPaths.clear();
defaultSelectedPaths.addAll(selectedPaths);
}
public List<TreePath> getDefaultSelectedPaths() {
return defaultSelectedPaths;
}
private static void buildSeries(DefaultMutableTreeNode studyNode, Series<?> series) {
DefaultMutableTreeNode seriesNode = new ToolTipTreeNode(series, true);
List<DicomSpecialElement> specialElements =
(List<DicomSpecialElement>) series.getTagValue(TagW.DicomSpecialElementList);
if (specialElements != null) {
for (DicomSpecialElement specialElement : specialElements) {
seriesNode.add(new DefaultMutableTreeNode(specialElement, false) {
@Override
public String toString() {
DicomSpecialElement d = (DicomSpecialElement) getUserObject();
StringBuilder buf = new StringBuilder();
boolean newElement = JMVUtils.getNULLtoFalse(d.getTagValue(TagW.ObjectToSave));
if (newElement) {
buf.append("<html>"); //$NON-NLS-1$
buf.append("<font color='orange'><b>NEW </b></font>"); //$NON-NLS-1$
}
buf.append(d.getShortLabel());
if (newElement) {
buf.append("</html>"); //$NON-NLS-1$
}
return buf.toString();
}
});
}
}
boolean hasGraphics = false;
for (MediaElement dicom : series.getMedias(null, null)) {
seriesNode.add(new DefaultMutableTreeNode(dicom, false) {
@Override
public String toString() {
MediaElement m = (MediaElement) getUserObject();
Integer val = TagD.getTagValue(m, Tag.InstanceNumber, Integer.class);
StringBuilder buf = new StringBuilder();
if (val != null) {
buf.append("["); //$NON-NLS-1$
buf.append(val);
buf.append("] "); //$NON-NLS-1$
}
String sopUID = TagD.getTagValue(m, Tag.SOPInstanceUID, String.class);
if (sopUID != null) {
buf.append(sopUID);
}
return buf.toString();
}
});
if (!hasGraphics) {
GraphicModel grModel = (GraphicModel) dicom.getTagValue(TagW.PresentationModel);
hasGraphics = grModel != null && grModel.hasSerializableGraphics();
}
}
List<?> children = Collections.list(studyNode.children());
int index = Collections.binarySearch(children, seriesNode, DicomSorter.SERIES_COMPARATOR);
index = index < 0 ? -(index + 1) : index;
studyNode.insert(seriesNode, index);
if (hasGraphics) {
String seriesInstanceUID = UIDUtils.createUID();
Series<?> prSeries = new DicomSeries(seriesInstanceUID);
prSeries.setTag(TagD.get(Tag.SeriesNumber), TagD.getTagValue(series, Tag.SeriesNumber, Integer.class));
prSeries.setTag(TagD.get(Tag.Modality), "PR"); //$NON-NLS-1$
prSeries.setTag(TagD.get(Tag.SeriesInstanceUID), seriesInstanceUID);
prSeries.setTag(TagW.ObjectToSave, Boolean.TRUE);
prSeries.setTag(SourceSeriesForPR, series);
prSeries.setTag(TagD.get(Tag.SeriesDescription),
Optional.ofNullable(TagD.getTagValue(series, Tag.SeriesDescription, String.class)).orElse("") //$NON-NLS-1$
+ " [GRAPHICS]"); //$NON-NLS-1$
DefaultMutableTreeNode prVirtualNode = new ToolTipTreeNode(prSeries, false);
studyNode.insert(prVirtualNode, index + 1);
}
return;
}
public static DefaultTreeModel buildModel(DicomModel dicomModel) {
DefaultMutableTreeNode rootNode = new DefaultMutableTreeNode(DicomExplorer.ALL_PATIENTS);
synchronized (dicomModel) {
for (MediaSeriesGroup pt : dicomModel.getChildren(MediaSeriesGroupNode.rootNode)) {
DefaultMutableTreeNode patientNode = new DefaultMutableTreeNode(pt, true);
for (MediaSeriesGroup study : dicomModel.getChildren(pt)) {
DefaultMutableTreeNode studyNode = new DefaultMutableTreeNode(study, true);
for (MediaSeriesGroup item : dicomModel.getChildren(study)) {
if (item instanceof Series) {
buildSeries(studyNode, (Series<?>) item);
}
}
List<?> children = Collections.list(patientNode.children());
int index = Collections.binarySearch(children, studyNode, DicomSorter.STUDY_COMPARATOR);
if (index < 0) {
patientNode.insert(studyNode, -(index + 1));
} else {
patientNode.insert(studyNode, index);
}
}
List<?> children = Collections.list(rootNode.children());
int index = Collections.binarySearch(children, patientNode, DicomSorter.PATIENT_COMPARATOR);
if (index < 0) {
rootNode.insert(patientNode, -(index + 1));
} else {
rootNode.insert(patientNode, index);
}
}
}
return new DefaultTreeModel(rootNode, false);
}
static class ToolTipTreeNode extends DefaultMutableTreeNode {
private static final long serialVersionUID = 6815757092280682077L;
public ToolTipTreeNode(TagReadable userObject, boolean allowsChildren) {
super(Objects.requireNonNull(userObject), allowsChildren);
}
public String getToolTipText() {
TagReadable s = (TagReadable) getUserObject();
Thumbnail thumb = (Thumbnail) s.getTagValue(TagW.Thumbnail);
if (thumb != null) {
try {
File path = thumb.getThumbnailPath();
if (path != null) {
URL url = path.toURI().toURL();
if (url != null) {
StringBuilder buf = new StringBuilder();
buf.append("<html>"); //$NON-NLS-1$
buf.append("<img src=\""); //$NON-NLS-1$
buf.append(url.toString());
buf.append("\"><br>"); //$NON-NLS-1$
LocalDateTime date = TagD.dateTime(Tag.SeriesDate, Tag.SeriesTime, s);
if (date != null) {
buf.append(TagUtil.formatDateTime(date));
}
buf.append("</html>"); //$NON-NLS-1$
return buf.toString();
}
}
} catch (Exception e) {
LOGGER.error("Display tooltip", e); //$NON-NLS-1$
}
}
return null;
}
@Override
public String toString() {
MediaSeries<?> s = (MediaSeries<?>) getUserObject();
StringBuilder buf = new StringBuilder();
boolean newElement = JMVUtils.getNULLtoFalse(s.getTagValue(TagW.ObjectToSave));
if (newElement) {
buf.append("<html>"); //$NON-NLS-1$
buf.append("<font color='orange'><b>NEW </b></font>"); //$NON-NLS-1$
}
Integer val = TagD.getTagValue(s, Tag.SeriesNumber, Integer.class);
if (val != null) {
buf.append("["); //$NON-NLS-1$
buf.append(val);
buf.append("] "); //$NON-NLS-1$
}
String modality = TagD.getTagValue(s, Tag.Modality, String.class);
if (modality != null) {
buf.append(modality);
buf.append(" "); //$NON-NLS-1$
}
String desc = TagD.getTagValue(s, Tag.SeriesDescription, String.class);
if (desc != null) {
buf.append(desc);
}
if (newElement) {
buf.append("</html>"); //$NON-NLS-1$
}
return buf.toString();
}
}
}