package org.weasis.dicom.qr; /******************************************************************************* * 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 *******************************************************************************/ import java.awt.BorderLayout; import java.awt.Color; import java.awt.Component; import java.awt.FlowLayout; import java.awt.event.ActionListener; import java.io.File; import java.io.IOException; import java.time.LocalDate; import java.time.LocalDateTime; import java.time.temporal.TemporalAdjusters; import java.time.temporal.WeekFields; import java.util.ArrayList; import java.util.List; import java.util.concurrent.ExecutorService; import java.util.stream.Collectors; import java.util.stream.Stream; import javax.swing.BorderFactory; import javax.swing.Box; import javax.swing.BoxLayout; import javax.swing.ComboBoxModel; import javax.swing.DefaultComboBoxModel; import javax.swing.JButton; import javax.swing.JComboBox; import javax.swing.JLabel; import javax.swing.JOptionPane; import javax.swing.JPanel; import javax.swing.JPopupMenu; import javax.swing.JProgressBar; import javax.swing.JTextField; import javax.swing.SwingUtilities; import javax.swing.border.Border; import javax.swing.border.TitledBorder; import javax.swing.event.ListDataEvent; import javax.swing.tree.DefaultMutableTreeNode; import javax.swing.tree.TreePath; import org.dcm4che3.data.Attributes; import org.dcm4che3.data.Tag; import org.dcm4che3.net.Status; import org.slf4j.Logger; import org.slf4j.LoggerFactory; import org.weasis.core.api.gui.util.AbstractItemDialogPage; import org.weasis.core.api.gui.util.AppProperties; import org.weasis.core.api.gui.util.DropDownButton; import org.weasis.core.api.gui.util.DropDownLabel; import org.weasis.core.api.gui.util.GroupCheckBoxMenu; import org.weasis.core.api.gui.util.GroupRadioMenu; import org.weasis.core.api.gui.util.GuiExecutor; import org.weasis.core.api.gui.util.JMVUtils; import org.weasis.core.api.gui.util.WinUtil; import org.weasis.core.api.media.data.MediaSeriesGroup; import org.weasis.core.api.media.data.MediaSeriesGroupNode; import org.weasis.core.api.media.data.TagUtil; import org.weasis.core.api.media.data.TagW; import org.weasis.core.api.util.FileUtil; import org.weasis.core.api.util.FontTools; import org.weasis.core.api.util.LocalUtil; import org.weasis.core.api.util.StringUtil; import org.weasis.core.api.util.ThreadUtil; import org.weasis.core.ui.pref.PreferenceDialog; import org.weasis.dicom.codec.TagD; import org.weasis.dicom.codec.TagD.Level; import org.weasis.dicom.codec.display.Modality; import org.weasis.dicom.codec.utils.DicomMediaUtils; import org.weasis.dicom.explorer.DicomModel; import org.weasis.dicom.explorer.ImportDicom; import org.weasis.dicom.explorer.pref.node.AbstractDicomNode; import org.weasis.dicom.explorer.pref.node.AbstractDicomNode.RetrieveType; import org.weasis.dicom.explorer.pref.node.AbstractDicomNode.UsageType; import org.weasis.dicom.explorer.pref.node.DefaultDicomNode; import org.weasis.dicom.explorer.pref.node.DicomWebNode; import org.weasis.dicom.op.CFind; import org.weasis.dicom.param.AdvancedParams; import org.weasis.dicom.param.ConnectOptions; import org.weasis.dicom.param.DicomParam; import org.weasis.dicom.param.DicomState; import org.weasis.dicom.tool.DicomListener; import com.github.lgooddatepicker.components.DatePicker; import com.github.lgooddatepicker.components.DatePickerSettings.DateArea; import com.github.lgooddatepicker.optionalusertools.DateChangeListener; public class DicomQrView extends AbstractItemDialogPage implements ImportDicom { private static final Logger LOGGER = LoggerFactory.getLogger(DicomQrView.class); public enum Period { ALL(Messages.getString("DicomQrView.all_dates"), null), //$NON-NLS-1$ TODAY(Messages.getString("DicomQrView.today"), LocalDate.now()), //$NON-NLS-1$ YESTERDAY(Messages.getString("DicomQrView.yesterday"), LocalDate.now().minusDays(1)), //$NON-NLS-1$ BEFORE_YESTERDAY(Messages.getString("DicomQrView.day_before_yest"), LocalDate.now().minusDays(2)), //$NON-NLS-1$ CUR_WEEK(Messages.getString("DicomQrView.this_week"), LocalDate.now().with(WeekFields.of(LocalUtil.getLocaleFormat()).dayOfWeek(), 1), //$NON-NLS-1$ LocalDate.now()), CUR_MONTH(Messages.getString("DicomQrView.this_month"), LocalDate.now().with(TemporalAdjusters.firstDayOfMonth()), LocalDate.now()), //$NON-NLS-1$ CUR_YEAR(Messages.getString("DicomQrView.this_year"), LocalDate.now().with(TemporalAdjusters.firstDayOfYear()), LocalDate.now()), //$NON-NLS-1$ LAST_DAY(Messages.getString("DicomQrView.last_24h"), LocalDate.now().minusDays(1), LocalDate.now()), //$NON-NLS-1$ LAST_2_DAYS(Messages.getString("DicomQrView.last_2_d"), LocalDate.now().minusDays(2), LocalDate.now()), //$NON-NLS-1$ LAST_3_DAYS(Messages.getString("DicomQrView.last_3_d"), LocalDate.now().minusDays(3), LocalDate.now()), //$NON-NLS-1$ LAST_WEEK(Messages.getString("DicomQrView.last_w"), LocalDate.now().minusWeeks(1), LocalDate.now()), //$NON-NLS-1$ LAST_2_WEEKS(Messages.getString("DicomQrView.last_2_w"), LocalDate.now().minusWeeks(2), LocalDate.now()), //$NON-NLS-1$ LAST_MONTH(Messages.getString("DicomQrView.last_m"), LocalDate.now().minusMonths(1), LocalDate.now()), //$NON-NLS-1$ LAST_3_MONTHS(Messages.getString("DicomQrView.last_3_m"), LocalDate.now().minusMonths(3), LocalDate.now()), //$NON-NLS-1$ LAST_6_MONTHS(Messages.getString("DicomQrView.last_6_m"), LocalDate.now().minusMonths(6), LocalDate.now()), //$NON-NLS-1$ LAST_YEAR(Messages.getString("DicomQrView.last_year"), LocalDate.now().minusYears(1), LocalDate.now()); //$NON-NLS-1$ private final String displayName; private final LocalDate start; private final LocalDate end; private Period(String name, LocalDate date) { this.displayName = name; this.start = date; this.end = date; } private Period(String name, LocalDate start, LocalDate end) { this.displayName = name; this.start = start; this.end = end; } public String getDisplayName() { return displayName; } public LocalDate getStart() { return start; } public LocalDate getEnd() { return end; } @Override public String toString() { return displayName; } } private static final String LAST_SEL_NODE = "lastSelNode"; //$NON-NLS-1$ private static final String LAST_CALLING_NODE = "lastCallingNode"; //$NON-NLS-1$ private static final String LAST_RETRIEVE_TYPE = "lastRetrieveType"; //$NON-NLS-1$ static final File tempDir = FileUtil.createTempDir(AppProperties.buildAccessibleTempDirectory("tmp", "qr")); //$NON-NLS-1$ //$NON-NLS-2$ private final Border spaceY = BorderFactory.createEmptyBorder(10, 3, 0, 3); private final JPanel basePanel = new JPanel(); private final JPanel panelGroup = new JPanel(); private final JComboBox<AbstractDicomNode> comboDestinationNode = new JComboBox<>(); private final JTextField tfSearch = new JTextField(); private final DicomModel dicomModel = new DicomModel(); private final RetrieveTree tree = new RetrieveTree(dicomModel); private final DefaultMutableTreeNode rootNode = new DefaultMutableTreeNode("rootNode", true); //$NON-NLS-1$ private final JComboBox<TagW> comboTags = new JComboBox<>(TagD.getTagFromIDs(Tag.PatientName, Tag.PatientID, Tag.AccessionNumber, Tag.StudyID, Tag.StudyDescription, Tag.InstitutionName, Tag.ReferringPhysicianName, Tag.PerformingPhysicianName, Tag.NameOfPhysiciansReadingStudy)); private final GroupCheckBoxMenu groupMod = new GroupCheckBoxMenu(); private final DropDownButton modButton = new DropDownButton("search_mod", new DropDownLabel(Messages.getString("DicomQrView.modalities"), panelGroup), groupMod) { //$NON-NLS-1$ //$NON-NLS-2$ @Override protected JPopupMenu getPopupMenu() { JPopupMenu menu = (getMenuModel() == null) ? new JPopupMenu() : getMenuModel().createJPopupMenu(); menu.setInvoker(this); return menu; } }; private final GroupRadioMenu<Period> groupDate = new GroupRadioMenu<Period>() { @Override public void contentsChanged(ListDataEvent e) { super.contentsChanged(e); Period p = getSelectedItem(); if (p != null) { startDatePicker.removeDateChangeListener(dateChangeListener); endDatePicker.removeDateChangeListener(dateChangeListener); startDatePicker.setDate(p.getStart()); endDatePicker.setDate(p.getEnd()); startDatePicker.addDateChangeListener(dateChangeListener); endDatePicker.addDateChangeListener(dateChangeListener); } } }; private final DropDownButton dateButton = new DropDownButton("search_date", new DropDownLabel(Messages.getString("DicomQrView.dates"), panelGroup), groupDate) { //$NON-NLS-1$ //$NON-NLS-2$ @Override protected JPopupMenu getPopupMenu() { JPopupMenu menu = (getMenuModel() == null) ? new JPopupMenu() : getMenuModel().createJPopupMenu(); menu.setInvoker(this); return menu; } }; private final DateChangeListener dateChangeListener = a -> groupDate.setSelected(null); private final ActionListener destNodeListener = evt -> applySelectedArchive(); private final DatePicker startDatePicker = buildDatePicker(); private final DatePicker endDatePicker = buildDatePicker(); private final JComboBox<RetrieveType> comboDicomRetrieveType = new JComboBox<>(RetrieveType.values()); private final JComboBox<AbstractDicomNode> comboCallingNode = new JComboBox<>(); private final DicomListener dicomListener; private final ExecutorService executor = ThreadUtil.buildNewFixedThreadExecutor(3, "Dicom Q/R task"); //$NON-NLS-1$ public DicomQrView() { super(Messages.getString("DicomQrView.title")); //$NON-NLS-1$ initGUI(); tree.setBorder(BorderFactory.createCompoundBorder(spaceY, new TitledBorder(null, Messages.getString("DicomQrView.result"), //$NON-NLS-1$ TitledBorder.DEFAULT_JUSTIFICATION, TitledBorder.DEFAULT_POSITION, FontTools.getFont12Bold(), Color.GRAY))); add(tree, BorderLayout.CENTER); initialize(true); DicomListener dcmListener = null; try { dcmListener = new DicomListener(tempDir); } catch (IOException e) { LOGGER.error("Cannot creast DICOM listener", e); //$NON-NLS-1$ } dicomListener = dcmListener; } public void initGUI() { setLayout(new BorderLayout()); basePanel.setLayout(new BoxLayout(basePanel, BoxLayout.Y_AXIS)); basePanel.add(getArchivePanel()); basePanel.add(getCallingNodePanel()); basePanel.add(getSearchPanel()); basePanel.add(getCtrlSearchPanel()); add(basePanel, BorderLayout.NORTH); } public JPanel getArchivePanel() { final JPanel sPanel = new JPanel(); sPanel.setAlignmentY(Component.TOP_ALIGNMENT); sPanel.setAlignmentX(Component.LEFT_ALIGNMENT); sPanel.setLayout(new FlowLayout(FlowLayout.LEFT, 3, 3)); JLabel lblDest = new JLabel(Messages.getString("DicomQrView.arc") + StringUtil.COLON); //$NON-NLS-1$ sPanel.add(lblDest); JMVUtils.setPreferredWidth(comboDestinationNode, 185, 185); AbstractDicomNode.addTooltipToComboList(comboDestinationNode); sPanel.add(comboDestinationNode); sPanel.add(Box.createHorizontalStrut(10)); JLabel lblTetrieve = new JLabel(Messages.getString("DicomQrView.retrieve") + StringUtil.COLON); //$NON-NLS-1$ sPanel.add(lblTetrieve); comboDicomRetrieveType.setToolTipText(Messages.getString("DicomQrView.msg_sel_type")); //$NON-NLS-1$ sPanel.add(comboDicomRetrieveType); return sPanel; } public JPanel getCallingNodePanel() { final JPanel sPanel = new JPanel(); sPanel.setAlignmentY(Component.TOP_ALIGNMENT); sPanel.setAlignmentX(Component.LEFT_ALIGNMENT); sPanel.setLayout(new FlowLayout(FlowLayout.LEFT, 3, 3)); final JLabel lblDest = new JLabel(Messages.getString("DicomQrView.calling_node") + StringUtil.COLON); //$NON-NLS-1$ sPanel.add(lblDest); JMVUtils.setPreferredWidth(comboCallingNode, 185, 185); AbstractDicomNode.addTooltipToComboList(comboCallingNode); sPanel.add(comboCallingNode); sPanel.add(Box.createHorizontalStrut(10)); final JButton btnGerenralOptions = new JButton(Messages.getString("DicomQrView.more_opt")); //$NON-NLS-1$ btnGerenralOptions.setAlignmentX(Component.LEFT_ALIGNMENT); sPanel.add(btnGerenralOptions); btnGerenralOptions.addActionListener(e -> { PreferenceDialog dialog = new PreferenceDialog(SwingUtilities.getWindowAncestor(this)); dialog.showPage(org.weasis.dicom.explorer.Messages.getString("DicomNodeListView.node_list")); //$NON-NLS-1$ JMVUtils.showCenterScreen(dialog); initNodeList(); }); return sPanel; } public JPanel getCtrlSearchPanel() { final JPanel panel5 = new JPanel(); panel5.setAlignmentY(Component.TOP_ALIGNMENT); panel5.setAlignmentX(Component.LEFT_ALIGNMENT); panel5.setLayout(new FlowLayout(FlowLayout.LEFT, 15, 10)); panel5.add(Box.createHorizontalStrut(350)); JButton clearBtn = new JButton(Messages.getString("DicomQrView.clear")); //$NON-NLS-1$ clearBtn.setToolTipText(Messages.getString("DicomQrView.clear_search")); //$NON-NLS-1$ clearBtn.addActionListener(e -> clearItems()); panel5.add(clearBtn); JButton searchBtn = new JButton(Messages.getString("DicomQrView.search")); //$NON-NLS-1$ searchBtn.setToolTipText(Messages.getString("DicomQrView.tips_dcm_query")); //$NON-NLS-1$ searchBtn.addActionListener(e -> cfind()); panel5.add(searchBtn); return panel5; } public JPanel getSearchPanel() { final JPanel sPanel = new JPanel(); sPanel.setAlignmentY(Component.TOP_ALIGNMENT); sPanel.setAlignmentX(Component.LEFT_ALIGNMENT); sPanel.setLayout(new BoxLayout(sPanel, BoxLayout.Y_AXIS)); sPanel.setBorder(BorderFactory.createCompoundBorder(spaceY, new TitledBorder(null, Messages.getString("DicomQrView.search"), //$NON-NLS-1$ TitledBorder.DEFAULT_JUSTIFICATION, TitledBorder.DEFAULT_POSITION, FontTools.getFont12Bold(), Color.GRAY))); panelGroup.setLayout(new FlowLayout(FlowLayout.LEFT, 7, 3)); List<Object> list = Stream.of(Modality.values()).collect(Collectors.toList()); list.set(0, Messages.getString("DicomQrView.all_mod")); //$NON-NLS-1$ groupMod.setModel(list, true, true); modButton.setToolTipText(Messages.getString("DicomQrView.select_mod")); //$NON-NLS-1$ panelGroup.add(modButton); panelGroup.add(Box.createHorizontalStrut(10)); Period[] listDate = { Period.ALL, Period.TODAY, Period.YESTERDAY, Period.BEFORE_YESTERDAY, Period.CUR_WEEK, Period.CUR_MONTH, Period.CUR_YEAR, Period.LAST_DAY, Period.LAST_2_DAYS, Period.LAST_3_DAYS, Period.LAST_WEEK, Period.LAST_2_WEEKS, Period.LAST_MONTH, Period.LAST_3_MONTHS, Period.LAST_6_MONTHS, Period.LAST_YEAR }; ComboBoxModel<Period> dataModel = new DefaultComboBoxModel<>(listDate); groupDate.setModel(dataModel); panelGroup.add(dateButton); panelGroup.add(new JLabel(Messages.getString("DicomQrView.from"))); //$NON-NLS-1$ panelGroup.add(startDatePicker); panelGroup.add(new JLabel(Messages.getString("DicomQrView.to"))); //$NON-NLS-1$ panelGroup.add(endDatePicker); sPanel.add(panelGroup); final JPanel panel4 = new JPanel(); panel4.setLayout(new FlowLayout(FlowLayout.LEFT, 3, 3)); panel4.add(comboTags); comboTags.setMaximumRowCount(15); // comboTags.setFont(FontTools.getFont11()); JMVUtils.setPreferredWidth(comboTags, 180, 180); // Update UI before adding the Tooltip feature in the combobox list comboTags.updateUI(); JMVUtils.addTooltipToComboList(comboTags); StringBuilder buf = new StringBuilder("<html>"); //$NON-NLS-1$ buf.append(Messages.getString("DicomQrView.tips_wildcard")); //$NON-NLS-1$ buf.append("<br>   "); //$NON-NLS-1$ buf.append(Messages.getString("DicomQrView.tips_star")); //$NON-NLS-1$ buf.append("<br>   "); //$NON-NLS-1$ buf.append(Messages.getString("DicomQrView.tips_question")); //$NON-NLS-1$ buf.append("</html>"); //$NON-NLS-1$ tfSearch.setToolTipText(buf.toString()); JMVUtils.setPreferredWidth(tfSearch, 370, 100); panel4.add(tfSearch); sPanel.add(panel4); return sPanel; } private DatePicker buildDatePicker() { DatePicker d = new DatePicker(); d.getSettings().setFontInvalidDate(FontTools.getFont11()); d.getSettings().setFontValidDate(FontTools.getFont11()); d.getSettings().setFontVetoedDate(FontTools.getFont11()); d.getSettings().setColor(DateArea.TextFieldBackgroundValidDate, tfSearch.getBackground()); d.getSettings().setColor(DateArea.DatePickerTextValidDate, tfSearch.getForeground()); d.getSettings().setColor(DateArea.TextFieldBackgroundDisallowedEmptyDate, tfSearch.getBackground()); d.getSettings().setColor(DateArea.TextFieldBackgroundInvalidDate, tfSearch.getBackground()); // d.getSettings().setColor(DateArea.DatePickerTextInvalidDate, tfSearch.getForeground()); d.getSettings().setColor(DateArea.TextFieldBackgroundVetoedDate, tfSearch.getBackground()); // d.getSettings().setColor(DateArea.DatePickerTextVetoedDate, tfSearch.getForeground()); Color btnBack = d.getComponentToggleCalendarButton().getBackground(); d.getSettings().setColor(DateArea.BackgroundOverallCalendarPanel, tfSearch.getBackground()); d.getSettings().setColor(DateArea.BackgroundMonthAndYearNavigationButtons, btnBack); d.getSettings().setColor(DateArea.CalendarBackgroundNormalDates, btnBack); // d.getSettings().setColor(DateArea.CalendarDefaultBackgroundHighlightedDates, tfSearch.getForeground()); // d.getSettings().setColor(DateArea.CalendarDefaultTextHighlightedDates, Color.ORANGE); // d.getSettings().setColor(DateArea.CalendarBackgroundVetoedDates, Color.MAGENTA); d.getSettings().setColor(DateArea.BackgroundClearLabel, btnBack); d.getSettings().setColor(DateArea.BackgroundMonthAndYearNavigationButtons, btnBack); d.getSettings().setColor(DateArea.BackgroundTodayLabel, btnBack); d.getSettings().setColor(DateArea.BackgroundTopLeftLabelAboveWeekNumbers, btnBack); d.getSettings().setColor(DateArea.BackgroundMonthAndYearMenuLabels, btnBack); d.getSettings().setColor(DateArea.CalendarTextNormalDates, tfSearch.getForeground()); d.getSettings().setColor(DateArea.CalendarTextWeekdays, tfSearch.getForeground()); d.getSettings().setColor(DateArea.CalendarTextWeekNumbers, tfSearch.getForeground()); // d.getSettings().setColorBackgroundWeekdayLabels(Color.ORANGE, true); // d.getSettings().setColorBackgroundWeekNumberLabels(Color.ORANGE, true); // d.getSettings().setVisibleNextMonthButton(false); // d.getSettings().setVisibleNextYearButton(false); d.getSettings().setFormatForDatesCommonEra(LocalUtil.getDateFormatter()); d.getSettings().setFormatForDatesBeforeCommonEra(LocalUtil.getDateFormatter()); // JMVUtils.setPreferredWidth(d.getComponentDateTextField(), 95); JMVUtils.setPreferredWidth(d.getComponentToggleCalendarButton(), 35); d.addDateChangeListener(dateChangeListener); return d; } private void clearItems() { tfSearch.setText(null); groupMod.selectAll(); startDatePicker.setDate(null); endDatePicker.setDate(null); } private void cfind() { SearchParameters searchParams = buildCurrentSearchParameters(); List<DicomParam> p = searchParams.getParameters(); // Clear model dicomModel.dispose(); if (p.isEmpty()) { String message = Messages.getString("DicomQrView.msg_empty_query"); //$NON-NLS-1$ int response = JOptionPane.showOptionDialog(WinUtil.getParentDialog(this), message, getTitle(), JOptionPane.YES_NO_OPTION, JOptionPane.WARNING_MESSAGE, null, null, null); if (response != 0) { return; } } // see http://dicom.nema.org/medical/dicom/current/output/html/part04.html#sect_C.6 addReturnTags(p, CFind.PatientName); addReturnTags(p, CFind.PatientID); addReturnTags(p, CFind.PatientSex); addReturnTags(p, CFind.PatientBirthDate); addReturnTags(p, CFind.IssuerOfPatientID); addReturnTags(p, CFind.StudyInstanceUID); addReturnTags(p, CFind.StudyDescription); addReturnTags(p, CFind.StudyDate); addReturnTags(p, CFind.StudyTime); addReturnTags(p, CFind.AccessionNumber); addReturnTags(p, CFind.ReferringPhysicianName); addReturnTags(p, CFind.StudyID); addReturnTags(p, new DicomParam(Tag.InstitutionName)); addReturnTags(p, new DicomParam(Tag.ModalitiesInStudy)); addReturnTags(p, new DicomParam(Tag.NumberOfStudyRelatedSeries)); addReturnTags(p, new DicomParam(Tag.NumberOfStudyRelatedInstances)); AbstractDicomNode selectedItem = (AbstractDicomNode) comboDestinationNode.getSelectedItem(); AbstractDicomNode callingNode = (AbstractDicomNode) comboCallingNode.getSelectedItem(); if (selectedItem instanceof DefaultDicomNode && callingNode instanceof DefaultDicomNode) { final DefaultDicomNode node = (DefaultDicomNode) selectedItem; AdvancedParams params = new AdvancedParams(); ConnectOptions connectOptions = new ConnectOptions(); connectOptions.setConnectTimeout(3000); connectOptions.setAcceptTimeout(5000); params.setConnectOptions(connectOptions); final DicomState state = CFind.process(params, ((DefaultDicomNode) callingNode).getDicomNodeWithOnlyAET(), node.getDicomNode(), p.toArray(new DicomParam[p.size()])); if (state.getStatus() == Status.Success) { displayResult(state); } else { LOGGER.error("Dicom cfind error: {}", state.getMessage()); //$NON-NLS-1$ GuiExecutor.instance().execute(() -> JOptionPane.showMessageDialog(basePanel, state.getMessage(), null, JOptionPane.ERROR_MESSAGE)); } } else if (selectedItem instanceof DicomWebNode) { throw new IllegalAccessError("Not implemented yet"); //$NON-NLS-1$ } } private static void addReturnTags(List<DicomParam> list, DicomParam p) { if (!list.stream().anyMatch(d -> d.getTag() == p.getTag())) { list.add(p); } } private void displayResult(DicomState state) { List<Attributes> items = state.getDicomRSP(); if (items != null) { for (int i = 0; i < items.size(); i++) { Attributes item = items.get(i); LOGGER.trace("==========================================="); //$NON-NLS-1$ LOGGER.trace("CFind Item {}", (i + 1)); //$NON-NLS-1$ LOGGER.trace("==========================================="); //$NON-NLS-1$ LOGGER.trace("{}", item.toString(100, 150)); //$NON-NLS-1$ String patientPseudoUID = DicomMediaUtils.buildPatientPseudoUID(item.getString(Tag.PatientID), item.getString(Tag.IssuerOfPatientID), item.getString(Tag.PatientName)); MediaSeriesGroup patient = dicomModel.getHierarchyNode(MediaSeriesGroupNode.rootNode, patientPseudoUID); if (patient == null) { patient = new MediaSeriesGroupNode(TagW.PatientPseudoUID, patientPseudoUID, DicomModel.patient.getTagView()) { @Override public String toString() { StringBuilder buf = new StringBuilder(getDisplayValue(this, Tag.PatientName)); buf.append(" ["); //$NON-NLS-1$ buf.append(getDisplayValue(this, Tag.PatientID)); buf.append("] "); //$NON-NLS-1$ buf.append(getDisplayValue(this, Tag.PatientBirthDate)); buf.append(" "); //$NON-NLS-1$ buf.append(getDisplayValue(this, Tag.PatientSex)); return buf.toString(); } }; DicomMediaUtils.writeMetaData(patient, item); dicomModel.addHierarchyNode(MediaSeriesGroupNode.rootNode, patient); } String studyUID = item.getString(Tag.StudyInstanceUID); MediaSeriesGroup study = dicomModel.getHierarchyNode(patient, studyUID); if (study == null) { study = new MediaSeriesGroupNode(TagD.getUID(Level.STUDY), studyUID, DicomModel.study.getTagView()) { @Override public String toString() { StringBuilder buf = new StringBuilder(getDisplayValue(this, Tag.StudyDescription)); buf.append(" ["); //$NON-NLS-1$ buf.append(getDisplayValue(this, Tag.ModalitiesInStudy)); buf.append("] "); //$NON-NLS-1$ LocalDateTime studyDate = TagD.dateTime(Tag.StudyDate, Tag.StudyTime, this); if (studyDate != null) { buf.append(TagUtil.formatDateTime(studyDate)); buf.append(" "); //$NON-NLS-1$ } buf.append(getDisplayValue(this, Tag.AccessionNumber)); return buf.toString(); } }; DicomMediaUtils.writeMetaData(study, item); dicomModel.addHierarchyNode(patient, study); } } } tree.setCheckTreeModel(new RetrieveTreeModel(dicomModel)); tree.revalidate(); tree.repaint(); } private String getDisplayValue(MediaSeriesGroupNode node, int tagID) { TagW tag = TagD.get(tagID); if (tag != null) { Object value = node.getTagValue(tag); if (value != null) { return tag.getFormattedTagValue(value, null); } } return StringUtil.EMPTY_STRING; } protected void initialize(boolean afirst) { if (afirst) { initNodeList(); } } private void initNodeList() { comboCallingNode.removeAllItems(); AbstractDicomNode.loadDicomNodes(comboCallingNode, AbstractDicomNode.Type.DICOM_CALLING, AbstractDicomNode.UsageType.RETRIEVE); restoreNodeSelection(comboCallingNode.getModel(), LAST_CALLING_NODE); comboDestinationNode.removeActionListener(destNodeListener); comboDestinationNode.removeAllItems(); AbstractDicomNode.loadDicomNodes(comboDestinationNode, AbstractDicomNode.Type.DICOM, UsageType.RETRIEVE); // AbstractDicomNode.loadDicomNodes(comboNode, AbstractDicomNode.Type.WEB, UsageType.RETRIEVE); restoreNodeSelection(comboDestinationNode.getModel(), LAST_SEL_NODE); String lastType = DicomQrFactory.IMPORT_PERSISTENCE.getProperty(LAST_RETRIEVE_TYPE); if (lastType != null) { try { comboDicomRetrieveType.setSelectedItem(RetrieveType.valueOf(lastType)); } catch (Exception e) { // Do nothing } } applySelectedArchive(); comboDestinationNode.addActionListener(destNodeListener); } private void applySelectedArchive() { Object selectedItem = comboDestinationNode.getSelectedItem(); boolean dcmOption = selectedItem instanceof DefaultDicomNode; comboDicomRetrieveType.setEnabled(dcmOption); comboCallingNode.setEnabled(dcmOption); } public void resetSettingsToDefault() { initialize(false); } private SearchParameters buildCurrentSearchParameters() { SearchParameters p = new SearchParameters(Messages.getString("DicomQrView.custom")); //$NON-NLS-1$ // Get value in text field String sTagValue = tfSearch.getText(); TagW item = (TagW) comboTags.getSelectedItem(); if (StringUtil.hasText(sTagValue) && item != null) { p.getParameters().add(new DicomParam(item.getId(), sTagValue)); } // Get modalities selection if (groupMod.getModelList().stream().anyMatch(c -> !c.isSelected())) { p.getParameters() .add(new DicomParam(Tag.ModalitiesInStudy, groupMod.getModelList().stream().filter(c -> c.isSelected() && c.getObject() instanceof Modality) .map(c -> ((Modality) c.getObject()).name()).toArray(String[]::new))); } LocalDate sDate = startDatePicker.getDate(); LocalDate eDate = endDatePicker.getDate(); if (sDate != null || eDate != null) { StringBuilder range = new StringBuilder(); range.append(TagD.formatDicomDate(sDate)); range.append("-"); //$NON-NLS-1$ range.append(TagD.formatDicomDate(eDate)); p.getParameters().add(new DicomParam(Tag.StudyDate, range.toString())); } return p; } public void applyChange() { nodeSelectionPersistence((AbstractDicomNode) comboDestinationNode.getSelectedItem(), LAST_SEL_NODE); nodeSelectionPersistence((AbstractDicomNode) comboCallingNode.getSelectedItem(), LAST_CALLING_NODE); RetrieveType type = (RetrieveType) comboDicomRetrieveType.getSelectedItem(); if (type != null) { DicomQrFactory.IMPORT_PERSISTENCE.setProperty(LAST_RETRIEVE_TYPE, type.name()); } } private void nodeSelectionPersistence(AbstractDicomNode node, String key) { if (node != null) { DicomQrFactory.IMPORT_PERSISTENCE.setProperty(key, node.getDescription()); } } private void restoreNodeSelection(ComboBoxModel<AbstractDicomNode> model, String key) { if (model != null) { String desc = DicomQrFactory.IMPORT_PERSISTENCE.getProperty(key); if (StringUtil.hasText(desc)) { for (int i = 0; i < model.getSize(); i++) { if (desc.equals(model.getElementAt(i).getDescription())) { model.setSelectedItem(model.getElementAt(i)); break; } } } } } protected void updateChanges() { } @Override public void closeAdditionalWindow() { applyChange(); executor.shutdown(); } @Override public void resetoDefaultValues() { } private List<String> getCheckedStudies(TreePath[] paths) { List<String> studies = new ArrayList<>(); for (TreePath treePath : paths) { DefaultMutableTreeNode node = (DefaultMutableTreeNode) treePath.getLastPathComponent(); if (node.getUserObject() instanceof MediaSeriesGroup) { MediaSeriesGroup study = (MediaSeriesGroup) node.getUserObject(); String uid = TagD.getTagValue(study, Tag.StudyInstanceUID, String.class); if (StringUtil.hasText(uid)) { studies.add(uid); } } } return studies; } @Override public void importDICOM(DicomModel explorerDcmModel, JProgressBar info) { List<String> studies = getCheckedStudies(tree.getCheckboxTree().getCheckingPaths()); if (!studies.isEmpty()) { executor.execute(new RetrieveTask(studies, explorerDcmModel, this)); } } public JComboBox<AbstractDicomNode> getComboDestinationNode() { return comboDestinationNode; } public JComboBox<RetrieveType> getComboDicomRetrieveType() { return comboDicomRetrieveType; } public JComboBox<AbstractDicomNode> getComboCallingNode() { return comboCallingNode; } public DicomListener getDicomListener() { return dicomListener; } public JPanel getBasePanel() { return basePanel; } public DicomModel getDicomModel() { return dicomModel; } }