/******************************************************************************* * 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.pref.node; import java.io.File; import java.io.FileInputStream; import java.io.FileOutputStream; import java.util.ArrayList; import java.util.List; import javax.swing.JComboBox; import javax.swing.JComponent; import javax.swing.JDialog; import javax.swing.JOptionPane; import javax.swing.ListSelectionModel; import javax.swing.SwingUtilities; import javax.swing.plaf.basic.BasicComboPopup; import javax.xml.stream.XMLInputFactory; import javax.xml.stream.XMLOutputFactory; import javax.xml.stream.XMLStreamConstants; import javax.xml.stream.XMLStreamException; import javax.xml.stream.XMLStreamReader; import javax.xml.stream.XMLStreamWriter; import org.osgi.framework.BundleContext; import org.osgi.framework.FrameworkUtil; import org.slf4j.Logger; import org.slf4j.LoggerFactory; import org.weasis.core.api.gui.util.JMVUtils; import org.weasis.core.api.service.BundlePreferences; import org.weasis.core.api.util.FileUtil; import org.weasis.core.api.util.ResourceUtil; import org.weasis.core.api.util.StringUtil; import org.weasis.dicom.codec.TransferSyntax; import org.weasis.dicom.explorer.Messages; public abstract class AbstractDicomNode { private static final Logger LOGGER = LoggerFactory.getLogger(AbstractDicomNode.class); protected static final String T_NODES = "nodes"; //$NON-NLS-1$ protected static final String T_NODE = "node"; //$NON-NLS-1$ protected static final String T_DESCRIPTION = "description"; //$NON-NLS-1$ protected static final String T_TYPE = "type"; //$NON-NLS-1$ protected static final String T_USAGE_TYPE = "usageType"; //$NON-NLS-1$ protected static final String T_TSUID = "tsuid"; //$NON-NLS-1$ public enum Type { DICOM(Messages.getString("AbstractDicomNode.dcm_node"), "dicomNodes.xml"), DICOM_CALLING(Messages.getString("AbstractDicomNode.dcm_calling_node"), "dicomCallingNodes.xml"), //$NON-NLS-1$ //$NON-NLS-2$ //$NON-NLS-3$ //$NON-NLS-4$ PRINTER(Messages.getString("AbstractDicomNode.dcm_printer"), "dicomPrinterNodes.xml"), WEB(Messages.getString("AbstractDicomNode.dcm_web_node"), "dicomWebNodes.xml"), //$NON-NLS-1$ //$NON-NLS-2$ //$NON-NLS-3$ //$NON-NLS-4$ WEB_QIDO(Messages.getString("AbstractDicomNode.dcm_rs_node"), "dicomWebQidoNodes.xml"); //$NON-NLS-1$ //$NON-NLS-2$ final String title; final String filename; Type(String title, String filename) { this.title = title; this.filename = filename; } @Override public String toString() { return title; } public String getFilename() { return filename; } } public enum UsageType { STORAGE(Messages.getString("AbstractDicomNode.storage")), //$NON-NLS-1$ RETRIEVE(Messages.getString("AbstractDicomNode.retrieve")), BOTH(Messages.getString("AbstractDicomNode.both")); //$NON-NLS-1$ //$NON-NLS-2$ final String title; UsageType(String title) { this.title = title; } @Override public String toString() { return title; } } public enum RetrieveType { CMOVE("C-MOVE"), CGET("C-GET"), WADO("WADO"); //$NON-NLS-1$ //$NON-NLS-2$ //$NON-NLS-3$ String title; RetrieveType(String title) { this.title = title; } @Override public String toString() { return title; } } private String description; private TransferSyntax tsuid; private Type type; private UsageType usageType; private boolean local; public AbstractDicomNode(String description, Type type, UsageType usageType) { if (type == null) { throw new IllegalArgumentException("Type cannot be null"); //$NON-NLS-1$ } this.description = description; this.tsuid = TransferSyntax.NONE; this.type = type; this.usageType = usageType; this.local = true; } public String getDescription() { return description; } public void setDescription(String description) { this.description = description; } @Override public String toString() { return description; } public TransferSyntax getTsuid() { return tsuid; } public void setTsuid(TransferSyntax tsuid) { this.tsuid = tsuid; } public String getToolTips() { return description; } public Type getType() { return type; } public void setType(Type type) { this.type = type == null ? Type.DICOM : type; } public UsageType getUsageType() { return usageType; } public void setUsageType(UsageType usageType) { this.usageType = usageType; } public boolean isLocal() { return local; } public void setLocal(boolean local) { this.local = local; } public void saveDicomNode(XMLStreamWriter writer) throws XMLStreamException { writer.writeAttribute(T_DESCRIPTION, description); writer.writeAttribute(T_TYPE, StringUtil.getEmpty2NullEnum(type)); writer.writeAttribute(T_USAGE_TYPE, StringUtil.getEmpty2NullEnum(usageType)); writer.writeAttribute(T_TSUID, StringUtil.getEmpty2NullEnum(tsuid)); } public static void loadDicomNodes(JComboBox<AbstractDicomNode> comboBox, Type type) { loadDicomNodes(comboBox, type, UsageType.BOTH); } public static void loadDicomNodes(JComboBox<AbstractDicomNode> comboBox, Type type, UsageType usage) { List<AbstractDicomNode> list = loadDicomNodes(type, usage); for (AbstractDicomNode node : list) { comboBox.addItem(node); } } public static List<AbstractDicomNode> loadDicomNodes(Type type, UsageType usage) { List<AbstractDicomNode> list = new ArrayList<>(); // Load nodes from resources loadDicomNodes(list, ResourceUtil.getResource(type.getFilename()), type, false, usage); // Load nodes from local data final BundleContext context = FrameworkUtil.getBundle(AbstractDicomNode.class).getBundleContext(); loadDicomNodes(list, new File(BundlePreferences.getDataFolder(context), type.getFilename()), type, true, usage); return list; } public static void saveDicomNodes(JComboBox<? extends AbstractDicomNode> comboBox, Type type) { XMLStreamWriter writer = null; XMLOutputFactory factory = XMLOutputFactory.newInstance(); final BundleContext context = FrameworkUtil.getBundle(AbstractDicomNode.class).getBundleContext(); try { writer = factory.createXMLStreamWriter( new FileOutputStream(new File(BundlePreferences.getDataFolder(context), type.getFilename())), "UTF-8"); //$NON-NLS-1$ writer.writeStartDocument("UTF-8", "1.0"); //$NON-NLS-1$ //$NON-NLS-2$ writer.writeStartElement(T_NODES); for (int i = 0; i < comboBox.getItemCount(); i++) { AbstractDicomNode node = comboBox.getItemAt(i); if (node.isLocal() && type == node.getType()) { writer.writeStartElement(T_NODE); node.saveDicomNode(writer); writer.writeEndElement(); } } writer.writeEndElement(); writer.writeEndDocument(); writer.flush(); } catch (Exception e) { LOGGER.error("Error on writing DICOM node file", e); //$NON-NLS-1$ } finally { FileUtil.safeClose(writer); } } private static void loadDicomNodes(List<AbstractDicomNode> list, File prefs, Type type, boolean local, UsageType usage) { if (prefs.canRead()) { XMLStreamReader xmler = null; XMLInputFactory factory = XMLInputFactory.newInstance(); try { xmler = factory.createXMLStreamReader(new FileInputStream(prefs)); int eventType; while (xmler.hasNext()) { eventType = xmler.next(); switch (eventType) { case XMLStreamConstants.START_ELEMENT: readDicomNodes(xmler, list, type, local, usage); break; default: break; } } } catch (Exception e) { LOGGER.error("Error on reading DICOM node file", e); //$NON-NLS-1$ } finally { FileUtil.safeClose(xmler); } } } private static void readDicomNodes(XMLStreamReader xmler, List<AbstractDicomNode> list, Type type, boolean local, UsageType usage) throws XMLStreamException { String key = xmler.getName().getLocalPart(); if (T_NODES.equals(key)) { while (xmler.hasNext()) { int eventType = xmler.next(); switch (eventType) { case XMLStreamConstants.START_ELEMENT: readDicomNode(xmler, list, type, local, usage); break; default: break; } } } } private static void readDicomNode(XMLStreamReader xmler, List<AbstractDicomNode> list, Type type, boolean local, UsageType usage) throws XMLStreamException { String key = xmler.getName().getLocalPart(); if (T_NODE.equals(key)) { try { Type t = Type.valueOf(xmler.getAttributeValue(null, T_TYPE)); if (type != t) { return; } if (usage != UsageType.BOTH) { UsageType u = UsageType.valueOf(xmler.getAttributeValue(null, T_USAGE_TYPE)); if (u != UsageType.BOTH && u != usage) { return; } } AbstractDicomNode node; if (AbstractDicomNode.Type.WEB == type) { node = DicomWebNode.buildDicomWebNode(xmler); } else if (AbstractDicomNode.Type.PRINTER == type) { node = DicomPrintNode.buildDicomPrintNode(xmler); } else { node = DefaultDicomNode.buildDicomNodeEx(xmler); } node.setLocal(local); node.setType(t); list.add(node); } catch (Exception e) { LOGGER.error("Cannot read DicomNode: {}", e); //$NON-NLS-1$ } } } public static void addNodeActionPerformed(JComboBox<? extends AbstractDicomNode> comboBox, Type type) { JDialog dialog; if (Type.WEB == type) { dialog = new DicomWebNodeDialog(SwingUtilities.getWindowAncestor(comboBox), Type.WEB.toString(), null, (JComboBox<DicomWebNode>) comboBox); } else { dialog = new DicomNodeDialog(SwingUtilities.getWindowAncestor(comboBox), Type.DICOM.toString(), null, (JComboBox<DefaultDicomNode>) comboBox, type); } JMVUtils.showCenterScreen(dialog, comboBox); } public static void editNodeActionPerformed(JComboBox<? extends AbstractDicomNode> comboBox) { AbstractDicomNode node = (AbstractDicomNode) comboBox.getSelectedItem(); if (node != null) { if (node.isLocal()) { Type type = node.getType(); JDialog dialog; if (Type.WEB == type) { dialog = new DicomWebNodeDialog(SwingUtilities.getWindowAncestor(comboBox), Type.WEB.toString(), (DicomWebNode) node, (JComboBox<DicomWebNode>) comboBox); } else { dialog = new DicomNodeDialog(SwingUtilities.getWindowAncestor(comboBox), Type.DICOM.toString(), (DefaultDicomNode) node, (JComboBox<DefaultDicomNode>) comboBox, type); } JMVUtils.showCenterScreen(dialog, comboBox); } else { JOptionPane.showMessageDialog(comboBox, Messages.getString("AbstractDicomNode.only_usr_cr_msg"), //$NON-NLS-1$ Messages.getString("DicomPrintDialog.error"), JOptionPane.ERROR_MESSAGE); //$NON-NLS-1$ } } } public static void deleteNodeActionPerformed(JComboBox<? extends AbstractDicomNode> comboBox) { int index = comboBox.getSelectedIndex(); if (index >= 0) { AbstractDicomNode node = comboBox.getItemAt(index); if (node.isLocal()) { int response = JOptionPane.showConfirmDialog(comboBox, String.format(Messages.getString("AbstractDicomNode.delete_msg"), node), Type.DICOM.toString(), //$NON-NLS-1$ JOptionPane.YES_NO_OPTION, JOptionPane.WARNING_MESSAGE); if (response == 0) { comboBox.removeItemAt(index); AbstractDicomNode.saveDicomNodes(comboBox, node.getType()); } } else { JOptionPane.showMessageDialog(comboBox, Messages.getString("AbstractDicomNode.only_usr_cr_msg"), //$NON-NLS-1$ Messages.getString("DicomPrintDialog.error"), JOptionPane.ERROR_MESSAGE); //$NON-NLS-1$ } } } public static void addTooltipToComboList(final JComboBox<? extends AbstractDicomNode> combo) { Object comp = combo.getUI().getAccessibleChild(combo, 0); if (comp instanceof BasicComboPopup) { final BasicComboPopup popup = (BasicComboPopup) comp; popup.getList().getSelectionModel().addListSelectionListener(e -> { if (!e.getValueIsAdjusting()) { ListSelectionModel model = (ListSelectionModel) e.getSource(); int first = model.getMinSelectionIndex(); if (first >= 0) { AbstractDicomNode item = combo.getItemAt(first); ((JComponent) combo.getRenderer()).setToolTipText(item.getToolTips()); } } }); } } }