/*========================================================================= Program: FusionViewer Module: $RCSfile: OpenImagesDialog.java,v $ Language: Java Date: $Date: 2008/01/11 21:43:26 $ Version: $Revision: 1.4 $ Copyright (c) Insightful Corporation. All rights reserved. See Copyright.txt for details. This software is distributed WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the above copyright notice for more information. =========================================================================*/ package org.fusionviewer.ui; import java.awt.BorderLayout; import java.awt.Component; import java.awt.Dimension; import java.awt.FlowLayout; import java.awt.Frame; import java.awt.GridBagConstraints; import java.awt.GridBagLayout; import java.awt.event.ActionEvent; import java.awt.event.ActionListener; import java.awt.event.ItemEvent; import java.awt.event.ItemListener; import java.awt.event.KeyEvent; import java.awt.event.MouseAdapter; import java.awt.event.MouseEvent; import java.io.File; import java.io.IOException; import javax.swing.AbstractAction; import javax.swing.AbstractButton; import javax.swing.Action; import javax.swing.BorderFactory; import javax.swing.Box; import javax.swing.ButtonGroup; import javax.swing.JButton; import javax.swing.JCheckBox; import javax.swing.JComponent; import javax.swing.JDialog; import javax.swing.JFileChooser; import javax.swing.JLabel; import javax.swing.JMenuItem; import javax.swing.JOptionPane; import javax.swing.JPanel; import javax.swing.JPopupMenu; import javax.swing.JRadioButton; import javax.swing.JTextField; import javax.swing.KeyStroke; import javax.swing.event.PopupMenuEvent; import javax.swing.event.PopupMenuListener; import javax.swing.filechooser.FileFilter; import org.fusionviewer.io.Configuration; import org.fusionviewer.io.FilePair; import com.sun.demo.jfc.ExampleFileFilter; /**\class OpenImagesDialog *\brief Dialog box that queries the user for a pair of image files. */ public class OpenImagesDialog extends JDialog{ private boolean m_okPressed = false; private static FileFilter m_allImageFileFilter; private JTextField m_background, m_foreground; private String m_directory; private boolean is_DICOM = false; private int m_imageOrientation; private int m_displayMode; static { m_allImageFileFilter = new ExampleFileFilter( new String[] {"mhd", "h33", "hdr", "jpg", "jpeg", "tif", "tiff", "png", "dcm", "dicom"}, "Images"); } /** * Create a dialog box with the indicated owner * * @param owner parent frame of this dialog box */ public OpenImagesDialog(Frame owner) { super(owner, true); JPanel panel = new JPanel(new BorderLayout(10, 10)); panel.setBorder(BorderFactory.createEmptyBorder(10, 10, 10, 10)); panel.add(createFileList(), BorderLayout.CENTER); panel.add(createButtons(), BorderLayout.PAGE_END); panel.setOpaque(true); getContentPane().add(panel); // Install escape key listener getRootPane().registerKeyboardAction(new DialogCloseButtonListener(false), KeyStroke.getKeyStroke(KeyEvent.VK_ESCAPE, 0), JComponent.WHEN_IN_FOCUSED_WINDOW); setTitle("Open Images"); pack(); PlatformUtility.centerWindow(this); } /** * Shows the dialog and blocks until the user dismisses it. * * @return true if the user clicked OK. */ public boolean run() { setVisible(true); return m_okPressed; } /* * Create the file list and file history components */ private Component createFileList() { JPanel filesPanel = new JPanel(); filesPanel.setLayout(new GridBagLayout()); /*Set up a GridBagLayout with 4 columns and 3 rows. For the first 2 rows, * the first column contains labels, the second column contains text fields * for entering file paths, and the third column contains buttons to bring * up a file chooser to select a file path. The last column contains a buttons * to bring up a DICOM file chooser */ GridBagConstraints labelConstraints = new GridBagConstraints(); labelConstraints.fill = GridBagConstraints.NONE; labelConstraints.anchor = GridBagConstraints.LINE_START; labelConstraints.insets = new java.awt.Insets(5, 5, 5, 5); GridBagConstraints fieldConstraints = new GridBagConstraints(); fieldConstraints.fill = GridBagConstraints.HORIZONTAL; fieldConstraints.anchor = GridBagConstraints.LINE_START; fieldConstraints.insets = new java.awt.Insets(5, 5, 5, 5); GridBagConstraints buttonConstraints = new GridBagConstraints(); buttonConstraints.fill = GridBagConstraints.NONE; buttonConstraints.anchor = GridBagConstraints.LINE_START; buttonConstraints.insets = new java.awt.Insets(5, 5, 5, 5); labelConstraints.gridx = 0; fieldConstraints.gridx = 1; buttonConstraints.gridx = 2; labelConstraints.gridy = 0; fieldConstraints.gridy = 0; buttonConstraints.gridy = 0; // Number of columns for the file name text fields final int NUM_COLUMNS = 50; FileAndTextTransferHandler transferHandler = new FileAndTextTransferHandler(); filesPanel.add(new JLabel("Background/Top"), labelConstraints); m_background = new JTextField(NUM_COLUMNS); m_background.setDragEnabled(true); m_background.setTransferHandler(transferHandler); filesPanel.add(m_background, fieldConstraints); filesPanel.add(createBrowseButton(m_background), buttonConstraints); buttonConstraints.gridx++; filesPanel.add(openDICOMFormat(this, m_background), buttonConstraints); buttonConstraints.gridx--; labelConstraints.gridy++; fieldConstraints.gridy++; buttonConstraints.gridy++; filesPanel.add(new JLabel("Foreground/Bottom"), labelConstraints); m_foreground = new JTextField(NUM_COLUMNS); m_foreground.setDragEnabled(true); m_foreground.setTransferHandler(transferHandler); filesPanel.add(m_foreground, fieldConstraints); filesPanel.add(createBrowseButton(m_foreground), buttonConstraints); buttonConstraints.gridx++; filesPanel.add(openDICOMFormat(this, m_foreground), buttonConstraints); buttonConstraints.gridx--; // Create recent items list labelConstraints.gridx = 0; labelConstraints.gridy++; labelConstraints.gridwidth = 1; JPanel fileHistory = new JPanel(); fileHistory.add(new JLabel("Recent")); JButton historyIcon = new JButton(PlatformUtility.createImageIcon("images/rightarrow.gif", "Recent files")); historyIcon.setRolloverEnabled(true); historyIcon.addMouseListener(new FileHistoryHandler(historyIcon)); fileHistory.add(historyIcon); filesPanel.add(fileHistory, labelConstraints); labelConstraints.gridx++; labelConstraints.gridwidth = 2; labelConstraints.weightx = 1.0; labelConstraints.weighty = 1.0; labelConstraints.anchor = GridBagConstraints.CENTER; Box modeSelectorPanel = Box.createHorizontalBox(); modeSelectorPanel.add(createImageOrientationSelector()); modeSelectorPanel.add(Box.createHorizontalStrut(25)); modeSelectorPanel.add(createDisplayModeSelector()); filesPanel.add(modeSelectorPanel, labelConstraints); return filesPanel; } /* * Creates a button that allows the user to browse for a file. The initial * path is from field, and the path chosen by the user is written back to field. */ private JButton createBrowseButton(final JTextField field) { JButton button = new JButton("Browse"); button.setMnemonic(KeyEvent.VK_B); button.addActionListener(new ActionListener() { public void actionPerformed(ActionEvent evt) { final JFileChooser chooser = createFileChooser(field.getText()); // Create a button to select the current directory JPanel panel = new JPanel(); panel.setPreferredSize(new Dimension(170, 300)); JButton selectDirectoryButton = new JButton("Select Directory"); selectDirectoryButton.setMnemonic(KeyEvent.VK_D); panel.add(selectDirectoryButton); selectDirectoryButton.addActionListener(new ActionListener() { public void actionPerformed(ActionEvent evt) { field.setText(chooser.getCurrentDirectory().getAbsolutePath()); field.selectAll(); chooser.cancelSelection(); } }); chooser.setAccessory(panel); if (chooser.showOpenDialog(OpenImagesDialog.this) == JFileChooser.APPROVE_OPTION) { field.setText(chooser.getSelectedFile().getAbsolutePath()); field.selectAll(); } } }); return button; } private JCheckBox openDICOMFormat(final OpenImagesDialog dialog, final JTextField field) { final JCheckBox openDICOM = new JCheckBox("DICOM Format"); final JTextField tempField = field; openDICOM.setSelected(false); openDICOM.setMnemonic(KeyEvent.VK_I); openDICOM.addItemListener(new ItemListener() { public void itemStateChanged(ItemEvent e) { if (e.getStateChange() == ItemEvent.SELECTED){ is_DICOM = true; m_directory = ""; File tempFile = new File(tempField.getText()); if (tempField.getText().length() == 0){ JOptionPane.showMessageDialog(dialog, "Please Set DICOM Direcoty First!", "Warning", JOptionPane.WARNING_MESSAGE); is_DICOM = false; ((JCheckBox) e.getSource()).setSelected(false); }else{ if(tempFile.isDirectory()){ m_directory = tempFile.toString(); }else { m_directory = tempFile.getParent(); } ListDICOMDialog dicomDialog = new ListDICOMDialog(dialog, tempField); String selectedSeries = dicomDialog.showSeries(); if(selectedSeries == null){ is_DICOM = false; ((JCheckBox) e.getSource()).setSelected(false); }else{ field.setText(m_directory + System.getProperty("file.separator") + selectedSeries); field.selectAll(); } } }else{ is_DICOM = false; } } }); return openDICOM; } /* * Creates a JFileChooser that allows the user to browse for files. The * initial path is set to the argument path. */ static JFileChooser createFileChooser(String path) { JFileChooser chooser = null; if (path == null) { chooser = new JFileChooser(); } else { path = path.trim(); // Clear leading and trailing whitespace String defaultPath = ""; if (path.length() > 0) { File defaultFile = new File(path); if (!defaultFile.exists() || !defaultFile.isDirectory()) defaultFile = defaultFile.getParentFile(); if ((defaultFile != null) && defaultFile.exists()) defaultPath = defaultFile.getPath(); } if (defaultPath.length() > 0) chooser = new JFileChooser(defaultPath); else chooser = new JFileChooser(); } chooser.addChoosableFileFilter(m_allImageFileFilter); return chooser; } /* * Creates a radio button group for display mode selection. */ private Component createDisplayModeSelector() { JPanel panel = new JPanel(); panel.setBorder(BorderFactory.createTitledBorder("Display Mode")); ButtonGroup group = new ButtonGroup(); JRadioButton fusionButton = new JRadioButton("Fusion"); fusionButton.addActionListener(new ActionListener() { public void actionPerformed(ActionEvent e) { m_displayMode = ImageViewFrame.DISPLAY_FUSION; } }); panel.add(fusionButton); group.add(fusionButton); JRadioButton linkedCursorButton = new JRadioButton("Linked Cursor"); linkedCursorButton.addActionListener(new ActionListener() { public void actionPerformed(ActionEvent e) { m_displayMode = ImageViewFrame.DISPLAY_LINKEDCURSOR; } }); panel.add(linkedCursorButton); group.add(linkedCursorButton); // Set the selected mode to the last mode used int layout = Configuration.getConfiguration().getLastDisplayLayout(); if (layout == Configuration.LINKED_CURSOR_LAYOUT) { linkedCursorButton.setSelected(true); m_displayMode = ImageViewFrame.DISPLAY_LINKEDCURSOR; } else { fusionButton.setSelected(true); m_displayMode = ImageViewFrame.DISPLAY_FUSION; } return panel; } /* * Creates a combo box for image orientation selection. */ private Component createImageOrientationSelector() { JPanel panel = new JPanel(); panel.setBorder(BorderFactory.createTitledBorder("Image Orientation")); ButtonGroup group = new ButtonGroup(); JRadioButton axialButton = new JRadioButton("Axial"); axialButton.addActionListener(new ActionListener() { public void actionPerformed(ActionEvent e) { m_imageOrientation = ViewArrangement.AXIAL; } }); panel.add(axialButton); group.add(axialButton); JRadioButton sagittalButton = new JRadioButton("Sagittal"); sagittalButton.addActionListener(new ActionListener() { public void actionPerformed(ActionEvent e) { m_imageOrientation = ViewArrangement.SAGITTAL; } }); panel.add(sagittalButton); group.add(sagittalButton); JRadioButton coronalButton = new JRadioButton("Coronal"); coronalButton.addActionListener(new ActionListener() { public void actionPerformed(ActionEvent e) { m_imageOrientation = ViewArrangement.CORONAL; } }); panel.add(coronalButton); group.add(coronalButton); // Set the selected orientation m_imageOrientation = Configuration.getConfiguration().getLastImageOrientation(); switch (m_imageOrientation) { case ViewArrangement.SAGITTAL: sagittalButton.setSelected(true); break; case ViewArrangement.CORONAL: coronalButton.setSelected(true); break; default: axialButton.setSelected(true); m_imageOrientation = ViewArrangement.AXIAL; break; } return panel; } /* * Creates the OK and Cancel buttons. */ private Component createButtons() { JPanel buttonPanel = new JPanel(); buttonPanel.setLayout(new FlowLayout(FlowLayout.RIGHT)); JButton okBtn = new JButton("Open"); PlatformUtility.setMnemonic(okBtn, KeyEvent.VK_O); okBtn.addActionListener(new DialogCloseButtonListener(true)); buttonPanel.add(okBtn); getRootPane().setDefaultButton(okBtn); JButton cancelButton = new JButton("Cancel"); PlatformUtility.setMnemonic(cancelButton, KeyEvent.VK_C); cancelButton.addActionListener(new DialogCloseButtonListener(false)); buttonPanel.add(cancelButton); getRootPane().setDefaultButton(okBtn); return buttonPanel; } /** * Retrieve the entered background file path * * @return file path */ public File getForegroundFile() { return fileFromPath(m_foreground.getText()); } /** * Retrieve the entered foreground file path * * @return file path */ public File getBackgroundFile() { return fileFromPath(m_background.getText()); } /** * Orientation the images were acquired as * * @return orientation as defined in ViewArrangement */ public int getImageOrientation() { return m_imageOrientation; } /* * Create a File object from path or return null if the path is empty. */ private File fileFromPath(String path) { if (path.length() == 0) return null; else return new File(path); } /** * Retrieve the selected display mode (DISPLAY_FUSION or DISPLAY_LINKEDCURSOR) * * @return display mode */ public int getDisplayMode() { return m_displayMode; } /* * Listener for the OK and Cancel buttons. */ private class DialogCloseButtonListener implements ActionListener { private boolean m_okValue; public DialogCloseButtonListener(boolean okValue) { m_okValue = okValue; } public void actionPerformed(ActionEvent e) { m_okPressed = m_okValue; if (m_okValue) { try { Configuration config = Configuration.getConfiguration(); config.getFileHistory().addToHistory( m_background.getText(), m_foreground.getText()); if (m_displayMode == ImageViewFrame.DISPLAY_LINKEDCURSOR) config.setLastDisplayLayout(Configuration.LINKED_CURSOR_LAYOUT); else if (m_displayMode == ImageViewFrame.DISPLAY_FUSION) config.setLastDisplayLayout(Configuration.FUSION_LAYOUT); config.setLastImageOrientation(m_imageOrientation); config.save(); } catch (IOException ex) { JOptionPane.showMessageDialog(OpenImagesDialog.this, "An error occurred while saving the preferences file.\n\n" + ex.getMessage(), "Error", JOptionPane.ERROR_MESSAGE); } } dispose(); } } /* * Listener for the file history button and menu. This set of classes manages the file * history UI. */ private class FileHistoryHandler extends MouseAdapter implements PopupMenuListener { private AbstractButton m_button; private JPopupMenu m_menu; /* * Populate the popup menu with the set of recently opened files. */ public FileHistoryHandler(AbstractButton button) { m_button = button; m_menu = new JPopupMenu(); // Add a list of recent items to the menu Object[] files = Configuration.getConfiguration().getFileHistory().getHistoryList(); for (int i = 0; i < files.length; i++) { m_menu.add(new FilePairAction((FilePair) files[i])); } m_menu.addSeparator(); JMenuItem clearHistoryItem = m_menu.add("Clear Menu"); PlatformUtility.setMnemonic(clearHistoryItem, KeyEvent.VK_C); clearHistoryItem.addActionListener(new ActionListener() { /* * Clear all items from the recent file menu. */ public void actionPerformed(ActionEvent evt) { Configuration config = Configuration.getConfiguration(); Object[] files = config.getFileHistory().getHistoryList(); for (int i = 0; i < files.length; i++) { // After a removal, all items shift down by 1, // so keep removing at 0 m_menu.remove(0); } config.getFileHistory().clearHistory(); try { config.save(); } catch (IOException e) { JOptionPane.showMessageDialog(OpenImagesDialog.this, "Error saving file history.\n\n" + e.getMessage(), "Error", JOptionPane.ERROR_MESSAGE); } m_button.setEnabled(false); } }); m_menu.addPopupMenuListener(this); // If there are recent files, populate the fields with the most recently // selected pair if (files.length == 0) m_button.setEnabled(false); else setFields((FilePair) files[0]); } /* * Respond to a left mouse click by displaying the button as selected and * showing the popup menu */ public void mousePressed(MouseEvent evt) { if ((evt.getButton() == MouseEvent.BUTTON1) && m_button.isEnabled()) { m_button.setSelected(true); m_button.repaint(); m_menu.show(m_button, m_button.getWidth(), 0); } } /* * Respond to the popup menu being dismissed without a selection by * displaying the button as unselected */ public void popupMenuCanceled(PopupMenuEvent evt) { m_button.setSelected(false); m_button.repaint(); } public void popupMenuWillBecomeInvisible(PopupMenuEvent evt) { } public void popupMenuWillBecomeVisible(PopupMenuEvent evt) { } /* * Set the foreground and background fields of the dialog box with * values from the file pair */ private void setFields(FilePair pair) { m_background.setText(pair.getFile1()); m_foreground.setText(pair.getFile2()); } /* * Responds to selections from the file history menu */ private class FilePairAction extends AbstractAction { FilePair m_pair; /* * Save the file pair in this instance and set the * name of the action to the file pair's toString * representation */ public FilePairAction(FilePair pair) { m_pair = pair; putValue(Action.NAME, m_pair.toString()); } /* * Respond to a file pair being selected by setting the * foreground and background text fields to the pair and * unselecting the associated button */ public void actionPerformed(ActionEvent evt) { m_button.setSelected(false); m_button.repaint(); setFields(m_pair); } } } public boolean isOpenDICOM(){ return is_DICOM; } public void setDirectory(String dict){ m_directory = ""; m_directory = dict; } public String getDICOMDirectory(){ return m_directory; } }