Main Page | Packages | Class Hierarchy | Class List | Directories | File List | Namespace Members | Class Members | File Members | Related Pages

MeasurementSequencePanel.java

Go to the documentation of this file.
00001 /*
00002  * MeasurementSequencePanel.java
00003  *
00004  * Copyright (C) 2005 Project SQUID, http://www.cs.helsinki.fi/group/squid/
00005  *
00006  * This file is part of Ikayaki.
00007  *
00008  * Ikayaki is free software; you can redistribute it and/or modify
00009  * it under the terms of the GNU General Public License as published by
00010  * the Free Software Foundation; either version 2 of the License, or
00011  * (at your option) any later version.
00012  *
00013  * Ikayaki is distributed in the hope that it will be useful,
00014  * but WITHOUT ANY WARRANTY; without even the implied warranty of
00015  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
00016  * GNU General Public License for more details.
00017  *
00018  * You should have received a copy of the GNU General Public License
00019  * along with Ikayaki; if not, write to the Free Software
00020  * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
00021  */
00022 
00023 package ikayaki.gui;
00024 
00025 import com.intellij.uiDesigner.core.GridConstraints;
00026 import com.intellij.uiDesigner.core.GridLayoutManager;
00027 import com.intellij.uiDesigner.core.Spacer;
00028 import ikayaki.*;
00029 
00030 import javax.swing.*;
00031 import javax.swing.event.*;
00032 import javax.swing.table.TableColumnModel;
00033 import javax.swing.text.NumberFormatter;
00034 import java.awt.*;
00035 import java.awt.event.*;
00036 import java.text.DecimalFormat;
00037 import java.util.ArrayList;
00038 import java.util.List;
00039 
00040 import static ikayaki.gui.SequenceColumn.*;
00041 
00047 public class MeasurementSequencePanel extends ProjectComponent {
00048 
00049     /* Measurement Sequence Table */
00050     private JTable sequenceTable;
00051     private MeasurementSequenceTableModel sequenceTableModel;
00052 
00053     /* Add Sequence Controls */
00054     private JFormattedTextField sequenceStartField;
00055     private JFormattedTextField sequenceStepField;
00056     private JFormattedTextField sequenceStopField;
00057     private ComponentFlasher sequenceStartFieldFlasher;
00058     private ComponentFlasher sequenceStepFieldFlasher;
00059     private ComponentFlasher sequenceStopFieldFlasher;
00060     private JButton addSequenceButton;
00061     private JComboBox loadSequenceBox;
00062 
00063     private JLabel stepValueTypeLabel;  // stepValue's type depends on the project's type
00064     private JLabel sequenceStartLabel;
00065     private JLabel sequenceStepLabel;
00066     private JLabel sequenceStopLabel;
00067     private JLabel loadSequenceLabel;
00068 
00069     private JPanel controlsPane;
00070 
00071     /* Details Panel */
00072     private MeasurementDetailsPanel detailsPanel;
00073 
00074 
00078     public MeasurementSequencePanel() {
00079 
00080         /* Sequence Table */
00081         sequenceTableModel = new MeasurementSequenceTableModel();
00082         sequenceTable = new JTable(sequenceTableModel);
00083         sequenceTable.getTableHeader().setReorderingAllowed(false);
00084         sequenceTable.getTableHeader().setResizingAllowed(false);
00085         sequenceTable.setDefaultRenderer(StyledWrapper.class, new StyledTableCellRenderer());
00086         sequenceTable.setDefaultEditor(StyledWrapper.class, new StyledCellEditor(new JTextField()));
00087 
00088         /* Add Sequence Controls */
00089         MyFormatterFactory factory = new MyFormatterFactory();
00090         sequenceStartField.setFormatterFactory(factory);
00091         sequenceStepField.setFormatterFactory(factory);
00092         sequenceStopField.setFormatterFactory(factory);
00093         sequenceStartFieldFlasher = new ComponentFlasher(sequenceStartField);
00094         sequenceStepFieldFlasher = new ComponentFlasher(sequenceStepField);
00095         sequenceStopFieldFlasher = new ComponentFlasher(sequenceStopField);
00096 
00097         /* Build Layout */
00098         controlsPane.setBorder(BorderFactory.createEmptyBorder(0, 4, 4, 4));
00099         JScrollPane scrollPane = new JScrollPane(sequenceTable);
00100         scrollPane.setVerticalScrollBarPolicy(JScrollPane.VERTICAL_SCROLLBAR_AS_NEEDED);
00101         scrollPane.setHorizontalScrollBarPolicy(JScrollPane.HORIZONTAL_SCROLLBAR_NEVER);
00102         scrollPane.getViewport().setBackground(Color.WHITE);
00103 
00104         setLayout(new BorderLayout());
00105         add(controlsPane, "North");
00106         add(scrollPane);
00107 
00108         /* Event Listeners */
00109 
00110         // resize the table columns to be always the right size
00111         sequenceTable.getColumnModel().addColumnModelListener(new TableColumnModelListener() {
00112             public void columnAdded(TableColumnModelEvent e) {
00113                 updateColumns();
00114             }
00115 
00116             public void columnRemoved(TableColumnModelEvent e) {
00117                 updateColumns();
00118             }
00119 
00120             public void columnMoved(TableColumnModelEvent e) {
00121                 updateColumns();
00122             }
00123 
00124             public void columnMarginChanged(ChangeEvent e) {
00125                 // DO NOTHING
00126             }
00127 
00128             public void columnSelectionChanged(ListSelectionEvent e) {
00129                 // DO NOTHING
00130             }
00131         });
00132 
00133         // show the column's description in the header as a tooltip
00134         sequenceTable.getTableHeader().addMouseMotionListener(new MouseMotionAdapter() {
00135 
00136             private int currentColumn;
00137 
00138             @Override public void mouseMoved(MouseEvent e) {
00139                 int column = sequenceTable.getColumnModel().getColumnIndexAtX(e.getX());
00140 
00141                 if (column != currentColumn) {
00142                     sequenceTable.getTableHeader().setToolTipText(sequenceTableModel.getColumnToolTip(column));
00143                     currentColumn = column;     // avoin unnecessary setToolTipText() calls
00144                 }
00145             }
00146         });
00147 
00148         // show the details of the selected step in the details panel
00149         sequenceTable.getSelectionModel().addListSelectionListener(new ListSelectionListener() {
00150             public void valueChanged(ListSelectionEvent e) {
00151                 if (getProject() == null) {
00152                     return;
00153                 }
00154 
00155                 // if there is exactly one step selected, show that one
00156                 if (sequenceTable.getSelectedRowCount() == 1) {
00157                     int index = sequenceTable.getSelectedRow();
00158                     if (index < getProject().getSteps()) {
00159                         getDetailsPanel().setStep(getProject().getStep(index));
00160                         return;
00161                     }
00162                 }
00163 
00164                 // if it is unclear that which step to show, show the measuring step (might be null)
00165                 getDetailsPanel().setStep(getProject().getCurrentStep());
00166             }
00167         });
00168 
00169         // adding a sequence with the add sequence controls
00170         addSequenceButton.addActionListener(new ActionListener() {
00171             public void actionPerformed(ActionEvent e) {
00172                 addSequence();
00173             }
00174         });
00175         KeyListener keyListener = new KeyAdapter() {
00176             @Override public void keyTyped(KeyEvent e) {
00177                 if (e.getKeyChar() == KeyEvent.VK_ENTER) {
00178                     addSequence();
00179                 }
00180             }
00181         };
00182         sequenceStartField.addKeyListener(keyListener);
00183         sequenceStepField.addKeyListener(keyListener);
00184         sequenceStopField.addKeyListener(keyListener);
00185 
00186         // reset the add sequence controls when new rows are added, removed or stepValues are changed
00187         sequenceTableModel.addTableModelListener(new TableModelListener() {
00188             public void tableChanged(TableModelEvent e) {
00189                 resetAddSequence();
00190             }
00191         });
00192 
00193         // drop down menu for adding preset sequences
00194         loadSequenceBox.addActionListener(new ActionListener() {
00195             public void actionPerformed(ActionEvent e) {
00196                 if (getProject() == null || !getProject().isSequenceEditEnabled()) {
00197                     return;
00198                 }
00199 
00200                 // append saved sequences when they are selected from the list
00201                 Object obj = loadSequenceBox.getSelectedItem();
00202                 if (obj != null && obj instanceof MeasurementSequence) {
00203                     MeasurementSequence sequence = (MeasurementSequence) obj;
00204                     getProject().addSequence(sequence);
00205 
00206                     // select the just added steps
00207                     final int addedSteps = sequence.getSteps();
00208                     SwingUtilities.invokeLater(new Runnable() {
00209                         public void run() {
00210                             scrollToRow(getProject().getSteps());
00211                             int start = getProject().getSteps() - addedSteps;
00212                             int end = getProject().getSteps() - 1;
00213                             sequenceTable.getSelectionModel().clearSelection();
00214                             sequenceTable.getSelectionModel().setSelectionInterval(start, end);
00215                         }
00216                     });
00217                 }
00218             }
00219         });
00220         loadSequenceBox.addPopupMenuListener(new PopupMenuListener() {
00221             public void popupMenuWillBecomeVisible(PopupMenuEvent e) {
00222 
00223                 // clear the previous selection when the menu is opened
00224                 if (loadSequenceBox.getSelectedItem() != null) {
00225                     loadSequenceBox.setSelectedItem(null);
00226                 }
00227             }
00228 
00229             public void popupMenuWillBecomeInvisible(PopupMenuEvent e) {
00230                 // DO NOTHING
00231             }
00232 
00233             public void popupMenuCanceled(PopupMenuEvent e) {
00234                 // DO NOTHING
00235             }
00236         });
00237 
00238         // on table cell right-click: show a popup menu for adding/removing steps and saving sequences
00239         sequenceTable.addMouseListener(new MouseAdapter() {
00240             @Override public void mouseClicked(MouseEvent e) {
00241                 if (getProject() == null) {
00242                     return;
00243                 }
00244                 if (e.getButton() == MouseEvent.BUTTON3) {
00245                     int[] rows = sequenceTable.getSelectedRows();
00246                     List<MeasurementStep> steps = new ArrayList<MeasurementStep>();
00247                     for (int i : rows) {
00248                         if (i < getProject().getSteps()) {
00249                             steps.add(getProject().getStep(i));
00250                         }
00251                     }
00252                     JPopupMenu popup = new SequencePopupMenu(steps.toArray(new MeasurementStep[steps.size()]));
00253                     popup.show(e.getComponent(), e.getX(), e.getY());
00254                 }
00255             }
00256         });
00257 
00258         // on table header right-click: show a popup menu for choosing the table columns
00259         sequenceTable.getTableHeader().addMouseListener(new MouseAdapter() {
00260             @Override public void mouseClicked(MouseEvent e) {
00261                 if (getProject() == null) {
00262                     return;
00263                 }
00264                 if (e.getButton() == MouseEvent.BUTTON3) {
00265                     JPopupMenu popup = new HeaderPopupMenu();
00266                     popup.show(e.getComponent(), e.getX(), e.getY());
00267                 }
00268             }
00269         });
00270 
00271         // initialize with no project
00272         setProject(null);
00273     }
00274 
00278     public MeasurementDetailsPanel getDetailsPanel() {
00279         if (detailsPanel == null) {
00280             detailsPanel = new MeasurementDetailsPanel();
00281         }
00282         return detailsPanel;
00283     }
00284 
00288     public JTable getSequenceTable() {
00289         return this.sequenceTable;
00290     }
00291 
00295     private void resetLoadSequenceBox() {
00296         // remove old and get new items
00297         loadSequenceBox.removeAllItems();
00298         MeasurementSequence[] sequences = Settings.getSequences();
00299 
00300         // insert new items and restore old selection
00301         loadSequenceBox.addItem(null);  // the first item is empty
00302         for (MeasurementSequence sequence : sequences) {
00303             loadSequenceBox.addItem(sequence);
00304         }
00305     }
00306 
00310     private void updateColumns() {
00311         TableColumnModel columnModel = sequenceTable.getColumnModel();
00312         for (int col = 0; col < columnModel.getColumnCount(); col++) {
00313             if (columnModel.getColumn(col).getHeaderValue().equals(COUNT.getColumnName(null))) {
00314 
00315                 // find out the column's preferred width using the actual cell contents
00316                 int width = 20;
00317                 Component comp;
00318                 for (int row = 0; row < sequenceTable.getRowCount(); row++) {
00319                     comp = sequenceTable.getCellRenderer(row, col).getTableCellRendererComponent(sequenceTable,
00320                             sequenceTable.getValueAt(row, col), false, false, row, col);
00321                     width = Math.max(width, comp.getPreferredSize().width);
00322                 }
00323                 width += 5;
00324                 columnModel.getColumn(col).setMinWidth(width);
00325                 columnModel.getColumn(col).setMaxWidth(width);
00326                 return;
00327             }
00328         }
00329     }
00330 
00334     private double getLastPositiveStepValue() {
00335         for (int i = getProject().getSteps() - 1; i >= 0; i--) {
00336             double stepValue = getProject().getStep(i).getStepValue();
00337             if (stepValue > 0.0) {
00338                 return stepValue;
00339             }
00340         }
00341         return 0.0;
00342     }
00343 
00347     private double getLastStepValue() {
00348         double stepValue = 0.0;
00349         if (getProject().getSteps() > 0) {
00350             stepValue = getProject().getStep(getProject().getSteps() - 1).getStepValue();
00351         }
00352         return Math.max(0.0, stepValue);
00353     }
00354 
00358     private void resetAddSequence() {
00359         sequenceStartField.setValue(null);
00360         sequenceStepField.setValue(null);
00361         sequenceStopField.setValue(null);
00362         if (getProject() == null) {
00363             return;
00364         }
00365 
00366         // set the latest step value to the Start field
00367         double stepValue = getLastPositiveStepValue();
00368         sequenceStartField.setValue(new Double(stepValue));
00369     }
00370 
00375     private void addSequence() {
00376         if (getProject() == null || !getProject().isSequenceEditEnabled()) {
00377             return;
00378         }
00379 
00380         // verify the values of the fields, flash them red if errors are found
00381         double startVal;
00382         double stepVal;
00383         double stopVal;
00384         if (sequenceStartField.getValue() != null
00385                 && sequenceStepField.getValue() == null
00386                 && sequenceStopField.getValue() == null) {
00387             // only start entered, add only one step
00388             startVal = Math.max(((Number) sequenceStartField.getValue()).doubleValue(), 0.0);
00389             startVal = Math.min(startVal, Settings.getDegausserMaximumField());
00390             stepVal = Settings.getDegausserMinimumFieldIncrement();
00391             stopVal = startVal;
00392 
00393         } else if (sequenceStartField.getValue() != null
00394                 && sequenceStepField.getValue() != null
00395                 && sequenceStopField.getValue() != null) {
00396             // all values entered, check their sizes
00397             startVal = Math.max(((Number) sequenceStartField.getValue()).doubleValue(), 0.0);
00398             stepVal = Math.max(((Number) sequenceStepField.getValue()).doubleValue(),
00399                     Settings.getDegausserMinimumFieldIncrement());
00400             stopVal = Math.min(((Number) sequenceStopField.getValue()).doubleValue(),
00401                     Settings.getDegausserMaximumField());
00402 
00403             JTextField fixThisField = null;
00404             if (startVal > stopVal) {
00405                 sequenceStopFieldFlasher.flash();
00406                 fixThisField = sequenceStopField;
00407             }
00408             if (stepVal < Settings.getDegausserMinimumFieldIncrement()) {
00409                 sequenceStepFieldFlasher.flash();
00410                 fixThisField = sequenceStepField;
00411             }
00412             if (fixThisField != null) {
00413                 fixThisField.grabFocus();
00414                 final JTextField f = fixThisField;
00415                 SwingUtilities.invokeLater(new Runnable() {
00416                     public void run() {
00417                         // needs to use invokeLater because it won't be possible to select text from a field which has no focus
00418                         f.setSelectionStart(0);
00419                         f.setSelectionEnd(f.getText().length());
00420                     }
00421                 });
00422                 return;
00423             }
00424 
00425         } else {
00426             // some required values have not been entered, so flash them
00427             if (sequenceStopField.getValue() == null) {
00428                 sequenceStopFieldFlasher.flash();
00429                 sequenceStopField.grabFocus();
00430             }
00431             if (sequenceStepField.getValue() == null) {
00432                 sequenceStepFieldFlasher.flash();
00433                 sequenceStepField.grabFocus();
00434             }
00435             if (sequenceStartField.getValue() == null) {
00436                 sequenceStartFieldFlasher.flash();
00437                 sequenceStartField.grabFocus();
00438             }
00439             return;
00440         }
00441 
00442         // must use integers for added accuracy
00443         final double ratio = Settings.getDegausserMinimumFieldIncrement();
00444         int istartVal = (int) Math.round(startVal / ratio);
00445         int istepVal = (int) Math.round(stepVal / ratio);
00446         int istopVal = (int) Math.round(stopVal / ratio);
00447         int imin = (int) Math.round(Settings.getDegausserMinimumField() / ratio);
00448         int imax = (int) Math.round(Settings.getDegausserMaximumField() / ratio);
00449 
00450         // add the steps to the sequence
00451         MeasurementStep step = new MeasurementStep();
00452         for (int i = istartVal; i <= istopVal; i += istepVal) {
00453             int value = i;
00454             if (value > 0 && value < imin) {
00455                 value = imin;
00456             }
00457             if (getLastStepValue() > 0 && Math.abs(value - (int) Math.round(getLastStepValue() / ratio)) < 1) {
00458                 continue;
00459             }
00460             step.setStepValue(value * ratio);
00461             getProject().addStep(step);
00462         }
00463 
00464         // finally reset the fields, move focus to the Start field and show the added steps
00465         resetAddSequence();
00466         sequenceStartField.grabFocus();
00467         SwingUtilities.invokeLater(new Runnable() {
00468             public void run() {
00469                 scrollToRow(sequenceTableModel.getRowCount() - 1);
00470                 sequenceStartField.setSelectionStart(0);
00471                 sequenceStartField.setSelectionEnd(sequenceStartField.getText().length());
00472             }
00473         });
00474     }
00475 
00481     @Override public void setEnabled(boolean enabled) {
00482         super.setEnabled(enabled);
00483 
00484         sequenceStartField.setEnabled(enabled);
00485         sequenceStepField.setEnabled(enabled);
00486         sequenceStopField.setEnabled(enabled);
00487         addSequenceButton.setEnabled(enabled);
00488         loadSequenceBox.setEnabled(enabled);
00489 
00490         stepValueTypeLabel.setEnabled(enabled);
00491         sequenceStartLabel.setEnabled(enabled);
00492         sequenceStepLabel.setEnabled(enabled);
00493         sequenceStopLabel.setEnabled(enabled);
00494         loadSequenceLabel.setEnabled(enabled);
00495     }
00496 
00501     public void setProject(final Project project) {
00502 
00503         // either select the last row, or keep the old selection
00504         final boolean autoSelect = getProject() != project;
00505         final int[] selectedRows = sequenceTable.getSelectedRows();
00506 
00507         super.setProject(project);
00508         sequenceTableModel.setProject(project);
00509         loadSequenceBox.setSelectedItem(null);
00510         setEnabled(project != null && project.isSequenceEditEnabled());
00511         resetAddSequence();
00512         resetLoadSequenceBox();
00513 
00514         /* HACK:
00515          * Must use invokeLater or otherwise the scrolling does not work at the start of the program, when the sizes
00516          * of the components are not known. Causes the GUI to blink some.
00517          */
00518         SwingUtilities.invokeLater(new Runnable() {
00519             public void run() {
00520 
00521                 // scroll the table so that as many measuments as possible are visible, plus a couple of empty rows
00522                 scrollToRow(0);
00523                 if (project != null) {
00524                     scrollToRow(Math.min(project.getCompletedSteps() + 5, sequenceTableModel.getRowCount() - 1));
00525                 } else {
00526                     scrollToRow(sequenceTableModel.getRowCount() - 1);
00527                 }
00528 
00529                 if (project != null) {
00530                     if (autoSelect) {
00531                         // automatically select the last completed step
00532                         int i = project.getCompletedSteps() - 1;
00533                         if (i >= 0) {
00534                             sequenceTable.getSelectionModel().clearSelection();
00535                             sequenceTable.getSelectionModel().setSelectionInterval(i, i);
00536                         }
00537                     } else {
00538                         // restore the old selection
00539                         sequenceTable.getSelectionModel().clearSelection();
00540                         for (int i : selectedRows) {
00541                             sequenceTable.getSelectionModel().addSelectionInterval(i, i);
00542                         }
00543                     }
00544                 }
00545             }
00546         });
00547     }
00548 
00552     private void scrollToRow(int rowIndex) {
00553         sequenceTable.scrollRectToVisible(sequenceTable.getCellRect(rowIndex, rowIndex, true));
00554     }
00555 
00559     public void projectUpdated(ProjectEvent event) {
00560         if (event.getType() == ProjectEvent.Type.DATA_CHANGED) {
00561 
00562             // refresh the table header, in case the header names have changed.
00563             for (int i = 0; i < sequenceTable.getColumnCount(); i++) {
00564                 sequenceTable.getColumnModel().getColumn(i).setHeaderValue(sequenceTableModel.getColumnName(i));
00565             }
00566             sequenceTable.getTableHeader().repaint();
00567 
00568             // save the selected rows and update the table data
00569             int[] rows = sequenceTable.getSelectedRows();
00570             sequenceTableModel.fireTableDataChanged();
00571             for (int i : rows) {
00572                 sequenceTable.getSelectionModel().addSelectionInterval(i, i);
00573             }
00574         }
00575     }
00576 
00577     public void measurementUpdated(MeasurementEvent event) {
00578         if (event.getType() == MeasurementEvent.Type.STEP_START) {
00579 
00580             // scroll the row visible, and select it to show the measurement's details
00581             for (int i = getProject().getSteps() - 1; i >= 0; i--) {
00582                 if (getProject().getStep(i) == event.getStep()) {
00583                     sequenceTable.getSelectionModel().setSelectionInterval(i, i);
00584                     scrollToRow(i);
00585                     scrollToRow(Math.min(i + 2, sequenceTableModel.getRowCount() - 1));
00586                     break;
00587                 }
00588             }
00589 //        } else if (event.getType() == MeasurementEvent.Type.VALUE_MEASURED) {
00590 //
00591 //            // show the details of the latest measurement
00592 //            getDetailsPanel().setStep(event.getStep());
00593         }
00594     }
00595 
00596     {
00597 // GUI initializer generated by IntelliJ IDEA GUI Designer
00598 // !!! IMPORTANT !!!
00599 // DO NOT EDIT OR ADD ANY CODE HERE!
00600         $$$setupUI$$$();
00601     }
00602 
00607     private void $$$setupUI$$$() {
00608         controlsPane = new JPanel();
00609         controlsPane.setLayout(new GridLayoutManager(2, 7, new Insets(0, 0, 0, 0), 5, 0));
00610         sequenceStartField = new JFormattedTextField();
00611         sequenceStartField.setHorizontalAlignment(11);
00612         controlsPane.add(sequenceStartField,
00613                 new GridConstraints(1, 0, 1, 1, GridConstraints.ANCHOR_WEST, GridConstraints.FILL_HORIZONTAL,
00614                         GridConstraints.SIZEPOLICY_CAN_GROW, GridConstraints.SIZEPOLICY_FIXED, null,
00615                         new Dimension(35, -1), null));
00616         sequenceStepField = new JFormattedTextField();
00617         sequenceStepField.setHorizontalAlignment(11);
00618         controlsPane.add(sequenceStepField,
00619                 new GridConstraints(1, 1, 1, 1, GridConstraints.ANCHOR_WEST, GridConstraints.FILL_HORIZONTAL,
00620                         GridConstraints.SIZEPOLICY_CAN_GROW, GridConstraints.SIZEPOLICY_FIXED, null,
00621                         new Dimension(35, -1), null));
00622         sequenceStopField = new JFormattedTextField();
00623         sequenceStopField.setHorizontalAlignment(11);
00624         controlsPane.add(sequenceStopField,
00625                 new GridConstraints(1, 2, 1, 1, GridConstraints.ANCHOR_WEST, GridConstraints.FILL_HORIZONTAL,
00626                         GridConstraints.SIZEPOLICY_CAN_GROW, GridConstraints.SIZEPOLICY_FIXED, null,
00627                         new Dimension(35, -1), null));
00628         sequenceStartLabel = new JLabel();
00629         sequenceStartLabel.setText("Start");
00630         controlsPane.add(sequenceStartLabel,
00631                 new GridConstraints(0, 0, 1, 1, GridConstraints.ANCHOR_WEST, GridConstraints.FILL_NONE,
00632                         GridConstraints.SIZEPOLICY_FIXED, GridConstraints.SIZEPOLICY_FIXED, null, null, null));
00633         sequenceStepLabel = new JLabel();
00634         sequenceStepLabel.setText("Step");
00635         controlsPane.add(sequenceStepLabel,
00636                 new GridConstraints(0, 1, 1, 1, GridConstraints.ANCHOR_WEST, GridConstraints.FILL_NONE,
00637                         GridConstraints.SIZEPOLICY_FIXED, GridConstraints.SIZEPOLICY_FIXED, null, null, null));
00638         sequenceStopLabel = new JLabel();
00639         sequenceStopLabel.setText("Stop");
00640         controlsPane.add(sequenceStopLabel,
00641                 new GridConstraints(0, 2, 1, 1, GridConstraints.ANCHOR_WEST, GridConstraints.FILL_NONE,
00642                         GridConstraints.SIZEPOLICY_FIXED, GridConstraints.SIZEPOLICY_FIXED, null, null, null));
00643         addSequenceButton = new JButton();
00644         addSequenceButton.setText("Add Sequence");
00645         controlsPane.add(addSequenceButton,
00646                 new GridConstraints(1, 4, 1, 1, GridConstraints.ANCHOR_CENTER, GridConstraints.FILL_HORIZONTAL,
00647                         GridConstraints.SIZEPOLICY_CAN_SHRINK | GridConstraints.SIZEPOLICY_CAN_GROW,
00648                         GridConstraints.SIZEPOLICY_FIXED, null, null, null));
00649         stepValueTypeLabel = new JLabel();
00650         stepValueTypeLabel.setText("mT");
00651         controlsPane.add(stepValueTypeLabel,
00652                 new GridConstraints(1, 3, 1, 1, GridConstraints.ANCHOR_WEST, GridConstraints.FILL_NONE,
00653                         GridConstraints.SIZEPOLICY_FIXED, GridConstraints.SIZEPOLICY_FIXED, null, null, null));
00654         final Spacer spacer1 = new Spacer();
00655         controlsPane.add(spacer1,
00656                 new GridConstraints(1, 5, 1, 1, GridConstraints.ANCHOR_CENTER, GridConstraints.FILL_HORIZONTAL,
00657                         GridConstraints.SIZEPOLICY_FIXED, 1, null, new Dimension(30, -1), null));
00658         loadSequenceBox = new JComboBox();
00659         controlsPane.add(loadSequenceBox,
00660                 new GridConstraints(1, 6, 1, 1, GridConstraints.ANCHOR_WEST, GridConstraints.FILL_HORIZONTAL,
00661                         GridConstraints.SIZEPOLICY_WANT_GROW, GridConstraints.SIZEPOLICY_FIXED, null, null, null));
00662         loadSequenceLabel = new JLabel();
00663         loadSequenceLabel.setText("Load Set");
00664         controlsPane.add(loadSequenceLabel,
00665                 new GridConstraints(0, 6, 1, 1, GridConstraints.ANCHOR_WEST, GridConstraints.FILL_NONE,
00666                         GridConstraints.SIZEPOLICY_FIXED, GridConstraints.SIZEPOLICY_FIXED, null, null, null));
00667     }
00668 
00674     private class MyFormatterFactory extends JFormattedTextField.AbstractFormatterFactory {
00675         public JFormattedTextField.AbstractFormatter getFormatter(JFormattedTextField tf) {
00676             DecimalFormat format = new DecimalFormat();
00677             format.setGroupingUsed(false);
00678             format.setMaximumFractionDigits(1);
00679 
00680             NumberFormatter formatter = new NumberFormatter(format);
00681             if (tf == sequenceStepField) {
00682                 formatter.setMinimum(new Double(Settings.getDegausserMinimumFieldIncrement()));
00683             } else {
00684                 formatter.setMinimum(new Double(0.0));
00685             }
00686             formatter.setMaximum(new Double(999.0));
00687             return formatter;
00688         }
00689     }
00690 
00697     private class SequencePopupMenu extends JPopupMenu {
00698 
00702         private MeasurementStep[] steps;
00703 
00710         public SequencePopupMenu(MeasurementStep[] steps) {
00711             if (steps == null) {
00712                 throw new NullPointerException();
00713             }
00714             this.steps = steps;
00715 
00716             add(getInsertBeforeAction());
00717             add(getInsertAfterAction());
00718             add(getDeleteSelectedAction());
00719             add(new JSeparator());
00720             add(getSaveSelectedAsAction());
00721             add(getSaveAllAsAction());
00722         }
00723 
00724         // TODO: Put these same actions to the program's main menu. Each action might then need to find out the selected rows itself and monitor the ListSelectionModel.
00725 
00726         private Action getInsertBeforeAction() {
00727             Action action = new AbstractAction() {
00728                 public void actionPerformed(ActionEvent e) {
00729                     int index = getFirstIndex();
00730                     for (int i = 0; i < steps.length; i++) {
00731                         getProject().addStep(index, new MeasurementStep());
00732                     }
00733                     // the new steps are get automatically selected, if we just leave the selection untouched
00734                 }
00735             };
00736             action.putValue(Action.NAME, "Insert Before");
00737             action.putValue(Action.SHORT_DESCRIPTION,
00738                     "Inserts the selected number of new steps " +
00739                     "in front of the selected steps.");
00740             action.putValue(Action.MNEMONIC_KEY, KeyEvent.VK_I);
00741 
00742             if (getProject() == null || !getProject().isSequenceEditEnabled()) {
00743                 action.setEnabled(false);
00744             } else if (steps.length == 0 || getFirstIndex() < getProject().getCompletedSteps()) {
00745                 action.setEnabled(false);
00746             }
00747             return action;
00748         }
00749 
00750         private Action getInsertAfterAction() {
00751             Action action = new AbstractAction() {
00752                 public void actionPerformed(ActionEvent e) {
00753                     int index = getLastIndex() + 1;
00754                     for (int i = 0; i < steps.length; i++) {
00755                         getProject().addStep(index, new MeasurementStep());
00756                     }
00757                     sequenceTable.clearSelection();
00758                     sequenceTable.getSelectionModel().addSelectionInterval(index, index + steps.length - 1);
00759                 }
00760             };
00761             action.putValue(Action.NAME, "Insert After");
00762             action.putValue(Action.SHORT_DESCRIPTION,
00763                     "Inserts the selected number of new steps " +
00764                     "after the selected steps.");
00765             action.putValue(Action.MNEMONIC_KEY, KeyEvent.VK_N);
00766 
00767             if (getProject() == null || !getProject().isSequenceEditEnabled()) {
00768                 action.setEnabled(false);
00769             } else if (steps.length == 0 || getLastIndex() < getProject().getCompletedSteps() - 1) {
00770                 action.setEnabled(false);
00771             }
00772             return action;
00773         }
00774 
00775         private Action getDeleteSelectedAction() {
00776             Action action = new AbstractAction() {
00777                 public void actionPerformed(ActionEvent e) {
00778                     // can not use removeStep(int,int) here because the selection might not be contiguous
00779                     int index;
00780                     while ((index = getLastIndex()) >= 0) {
00781                         getProject().removeStep(index);
00782                     }
00783                     sequenceTable.clearSelection();
00784                 }
00785             };
00786             action.putValue(Action.NAME, "Delete Selected");
00787             action.putValue(Action.SHORT_DESCRIPTION,
00788                     "Removes the selected steps from the sequence.");
00789             action.putValue(Action.MNEMONIC_KEY, KeyEvent.VK_D);
00790 
00791             if (getProject() == null || !getProject().isSequenceEditEnabled()) {
00792                 action.setEnabled(false);
00793             } else if (steps.length == 0 || getFirstIndex() < getProject().getCompletedSteps()) {
00794                 action.setEnabled(false);
00795             }
00796             return action;
00797         }
00798 
00799         private Action getSaveSelectedAsAction() {
00800             Action action = new AbstractAction() {
00801                 public void actionPerformed(ActionEvent e) {
00802 
00803                     // make a copy of the selected steps
00804                     MeasurementSequence sequence = new MeasurementSequence();
00805                     for (MeasurementStep step : steps) {
00806                         MeasurementStep copy = new MeasurementStep();
00807                         copy.setStepValue(step.getStepValue());
00808                         sequence.addStep(copy);
00809                     }
00810 
00811                     // ask for a name for the sequence
00812                     String name = showSequenceNameDialog("Enter a name for the sequence", "Save Selected As...");
00813                     if (name == null) {
00814                         return;
00815                     }
00816 
00817                     // save the sequence
00818                     sequence.setName(name);
00819                     Settings.addSequence(sequence);
00820                     resetLoadSequenceBox();
00821                 }
00822             };
00823             action.putValue(Action.NAME, "Save Selected As...");
00824             action.putValue(Action.SHORT_DESCRIPTION,
00825                     "Saves the selected steps as a new preset sequence.");
00826             action.putValue(Action.MNEMONIC_KEY, KeyEvent.VK_S);
00827 
00828             if (steps.length == 0) {
00829                 action.setEnabled(false);
00830             }
00831             return action;
00832         }
00833 
00834         private Action getSaveAllAsAction() {
00835             Action action = new AbstractAction() {
00836                 public void actionPerformed(ActionEvent e) {
00837 
00838                     // make a copy of all the steps
00839                     MeasurementSequence sequence = getProject().copySequence(0, getProject().getSteps() - 1);
00840 
00841                     // ask for a name for the sequence
00842                     String name = showSequenceNameDialog("Enter a name for the sequence", "Save All As...");
00843                     if (name == null) {
00844                         return;
00845                     }
00846 
00847                     // save the sequence
00848                     sequence.setName(name);
00849                     Settings.addSequence(sequence);
00850                     resetLoadSequenceBox();
00851                 }
00852             };
00853             action.putValue(Action.NAME, "Save All As...");
00854             action.putValue(Action.SHORT_DESCRIPTION,
00855                     "Saves all of the steps as a new preset sequence.");
00856             action.putValue(Action.MNEMONIC_KEY, KeyEvent.VK_A);
00857 
00858             if (getProject() == null || getProject().getSteps() == 0) {
00859                 action.setEnabled(false);
00860             }
00861             return action;
00862         }
00863 
00864         private String showSequenceNameDialog(String message, String title) {
00865             String name = null;
00866             boolean ok = false;
00867 
00868             while (!ok) {
00869 
00870                 // ask for a name for the sequence
00871                 name = (String) JOptionPane.showInputDialog(getParentFrame(),
00872                         message, title, JOptionPane.PLAIN_MESSAGE, null, null, name);
00873                 if (name == null) {
00874                     return null;
00875                 } else if (name.equals("")) {
00876                     continue;
00877                 }
00878 
00879                 // check for a duplicate name
00880                 ok = true;
00881                 MeasurementSequence[] savedSequences = Settings.getSequences();
00882                 for (MeasurementSequence savedSequence : savedSequences) {
00883 
00884                     if (savedSequence.getName().equals(name)) {
00885 
00886                         // duplicate name found, ask for how to continue
00887                         int response = JOptionPane.showConfirmDialog(getParentFrame(),
00888                                 "Another sequence with the name \"" + name + "\" exists. Do you wish to overwrite it?",
00889                                 "Overwrite?", JOptionPane.YES_NO_CANCEL_OPTION);
00890 
00891                         if (response == JOptionPane.YES_OPTION) {
00892                             // overwrite the old sequence
00893                             Settings.removeSequence(savedSequence);
00894                             ok = true;
00895                             break;
00896 
00897                         } else if (response == JOptionPane.NO_OPTION) {
00898                             // ask for a new name
00899                             ok = false;
00900                             break;
00901 
00902                         } else if (response == JOptionPane.CANCEL_OPTION) {
00903                             // cancel the operation
00904                             return null;
00905 
00906                         } else {
00907                             throw new IllegalArgumentException("response = " + response);
00908                         }
00909                     }
00910                 }
00911             }
00912             return name;
00913         }
00914 
00918         private int getFirstIndex() {
00919             for (int i = 0; i < getProject().getSteps(); i++) {
00920                 MeasurementStep current = getProject().getStep(i);
00921                 for (MeasurementStep step : steps) {
00922                     if (current == step) {
00923                         return i;
00924                     }
00925                 }
00926             }
00927             return -1;
00928         }
00929 
00933         private int getLastIndex() {
00934             for (int i = getProject().getSteps() - 1; i >= 0; i--) {
00935                 MeasurementStep current = getProject().getStep(i);
00936                 for (MeasurementStep step : steps) {
00937                     if (current == step) {
00938                         return i;
00939                     }
00940                 }
00941             }
00942             return -1;
00943         }
00944     }
00945 
00952     private class HeaderPopupMenu extends JPopupMenu {
00953 
00954         public HeaderPopupMenu() {
00955             JMenuItem header = new JMenuItem("Visible Columns");
00956             header.setFont(header.getFont().deriveFont(Font.BOLD));
00957             header.setEnabled(false);
00958             add(header);
00959 
00960             SequenceColumn[] columns = sequenceTableModel.getPossibleColumns();
00961             for (final SequenceColumn column : columns) {
00962 
00963                 // add all of the columns to the menu as checkboxes
00964                 final JCheckBox checkBox = new JCheckBox(column.getColumnName(getProject()));
00965                 checkBox.addActionListener(new ActionListener() {
00966                     public void actionPerformed(ActionEvent e) {
00967                         sequenceTableModel.setColumnVisible(column, checkBox.isSelected());
00968                     }
00969                 });
00970                 checkBox.setSelected(sequenceTableModel.isColumnVisible(column));
00971                 checkBox.setToolTipText(column.getToolTipText(getProject()));
00972                 add(checkBox);
00973             }
00974         }
00975     }
00976 }

Generated on Fri May 6 16:00:32 2005 for Squid by  doxygen 1.4.1