]> gitweb.fperrin.net Git - GpsPrune.git/blobdiff - tim/prune/correlate/Correlator.java
Moved source into separate src directory due to popular request
[GpsPrune.git] / tim / prune / correlate / Correlator.java
diff --git a/tim/prune/correlate/Correlator.java b/tim/prune/correlate/Correlator.java
deleted file mode 100644 (file)
index 0aaafc3..0000000
+++ /dev/null
@@ -1,699 +0,0 @@
-package tim.prune.correlate;
-
-import java.awt.BorderLayout;
-import java.awt.Component;
-import java.awt.Dimension;
-import java.awt.FlowLayout;
-import java.awt.event.ActionEvent;
-import java.awt.event.ActionListener;
-import java.util.Iterator;
-import java.util.TimeZone;
-import java.util.TreeSet;
-
-import javax.swing.BorderFactory;
-import javax.swing.BoxLayout;
-import javax.swing.ButtonGroup;
-import javax.swing.JButton;
-import javax.swing.JComboBox;
-import javax.swing.JDialog;
-import javax.swing.JLabel;
-import javax.swing.JOptionPane;
-import javax.swing.JPanel;
-import javax.swing.JRadioButton;
-import javax.swing.JScrollPane;
-import javax.swing.JTable;
-import javax.swing.JTextField;
-
-import tim.prune.App;
-import tim.prune.GenericFunction;
-import tim.prune.I18nManager;
-import tim.prune.config.TimezoneHelper;
-import tim.prune.data.DataPoint;
-import tim.prune.data.Distance;
-import tim.prune.data.Field;
-import tim.prune.data.MediaObject;
-import tim.prune.data.MediaList;
-import tim.prune.data.TimeDifference;
-import tim.prune.data.Timestamp;
-import tim.prune.data.Track;
-import tim.prune.data.Unit;
-import tim.prune.data.UnitSetLibrary;
-import tim.prune.tips.TipManager;
-
-/**
- * Abstract superclass of the two correlator functions
- */
-public abstract class Correlator extends GenericFunction
-{
-       protected JDialog _dialog;
-       private CardStack _cards = null;
-       private JTable _selectionTable = null;
-       protected JTable _previewTable = null;
-       private boolean _previewEnabled = false; // flag required to enable preview function on final panel
-       private boolean[] _cardEnabled = null; // flag for each card
-       private TimeZone _timezone = null;
-       private JTextField _offsetHourBox = null, _offsetMinBox = null, _offsetSecBox = null;
-       private JRadioButton _mediaLaterOption = null, _pointLaterOption = null;
-       private JRadioButton _timeLimitRadio = null, _distLimitRadio = null;
-       private JTextField _limitMinBox = null, _limitSecBox = null;
-       private JTextField _limitDistBox = null;
-       private JComboBox<String> _distUnitsDropdown = null;
-       private JButton _nextButton = null, _backButton = null;
-       protected JButton _okButton = null;
-
-
-       /**
-        * Constructor
-        * @param inApp App object to report actions to
-        */
-       public Correlator(App inApp) {
-               super(inApp);
-       }
-
-       /**
-        * @return type key eg photo, audio
-        */
-       protected abstract String getMediaTypeKey();
-
-       /**
-        * @return media list
-        */
-       protected abstract MediaList getMediaList();
-
-       /**
-        * Begin the function by initialising and showing the dialog
-        */
-       public void begin()
-       {
-               // Check whether track has timestamps, exit if not
-               if (!_app.getTrackInfo().getTrack().hasData(Field.TIMESTAMP))
-               {
-                       JOptionPane.showMessageDialog(_parentFrame, I18nManager.getText("dialog.correlate.notimestamps"),
-                               I18nManager.getText(getNameKey()), JOptionPane.INFORMATION_MESSAGE);
-                       return;
-               }
-               // Show warning if no uncorrelated audios
-               if (!getMediaList().hasUncorrelatedMedia())
-               {
-                       Object[] buttonTexts = {I18nManager.getText("button.continue"), I18nManager.getText("button.cancel")};
-                       if (JOptionPane.showOptionDialog(_parentFrame,
-                                       I18nManager.getText("dialog.correlate.nouncorrelated" + getMediaTypeKey() + "s"),
-                                       I18nManager.getText(getNameKey()), JOptionPane.YES_NO_OPTION,
-                                       JOptionPane.WARNING_MESSAGE, null, buttonTexts, buttonTexts[1])
-                               == JOptionPane.NO_OPTION)
-                       {
-                               return;
-                       }
-               }
-               // Create dialog if necessary
-               if (_dialog == null)
-               {
-                       _dialog = new JDialog(_parentFrame, I18nManager.getText(getNameKey()), true);
-                       _dialog.setLocationRelativeTo(_parentFrame);
-                       _dialog.getContentPane().add(makeDialogContents());
-                       _dialog.pack();
-               }
-               _okButton.setEnabled(false);
-               // Init timezone to the currently selected one
-               _timezone = TimezoneHelper.getSelectedTimezone();
-               // Go to first available card
-               int card = 0;
-               _cardEnabled = null;
-               while (!isCardEnabled(card)) {
-                       card++;
-               }
-               _cards.showCard(card);
-               showCard(0); // does set up and next/prev enabling
-               if (!isCardEnabled(1)) {
-                       _app.showTip(TipManager.Tip_ManuallyCorrelateOne);
-               }
-               _dialog.setVisible(true);
-       }
-
-       /**
-        * Make contents of correlate dialog
-        * @return JPanel containing gui elements
-        */
-       private JPanel makeDialogContents()
-       {
-               JPanel mainPanel = new JPanel();
-               mainPanel.setLayout(new BorderLayout());
-
-               // Card panel in the middle
-               _cards = new CardStack();
-
-               // First panel (not required by photo correlator)
-               JPanel card1 = makeFirstPanel();
-               if (card1 == null) {card1 = new JPanel();}
-               _cards.addCard(card1);
-
-               // Second panel for selection of linked media
-               _cards.addCard(makeSecondPanel());
-
-               // Third panel for options and preview
-               _cards.addCard(makeThirdPanel());
-               mainPanel.add(_cards, BorderLayout.CENTER);
-
-               // Button panel at the bottom
-               JPanel buttonPanel = new JPanel();
-               _backButton = new JButton(I18nManager.getText("button.back"));
-               _backButton.addActionListener(new ActionListener() {
-                       public void actionPerformed(ActionEvent e) {
-                               showCard(-1);
-                       }
-               });
-               _backButton.setEnabled(false);
-               buttonPanel.add(_backButton);
-               _nextButton = new JButton(I18nManager.getText("button.next"));
-               _nextButton.addActionListener(new ActionListener() {
-                       public void actionPerformed(ActionEvent e) {
-                               showCard(1);
-                       }
-               });
-               buttonPanel.add(_nextButton);
-               _okButton = new JButton(I18nManager.getText("button.ok"));
-               _okButton.addActionListener(new ActionListener()
-                       {
-                               public void actionPerformed(ActionEvent e)
-                               {
-                                       finishCorrelation();
-                                       _dialog.dispose();
-                               }
-                       });
-               _okButton.setEnabled(false);
-               buttonPanel.add(_okButton);
-               JButton cancelButton = new JButton(I18nManager.getText("button.cancel"));
-               cancelButton.addActionListener(new ActionListener() {
-                       public void actionPerformed(ActionEvent e) {
-                               _dialog.dispose();
-                       }
-               });
-               buttonPanel.add(cancelButton);
-               mainPanel.add(buttonPanel, BorderLayout.SOUTH);
-               return mainPanel;
-       }
-
-       /**
-        * Construct a table model for the photo / audio selection table
-        * @return table model
-        */
-       protected MediaSelectionTableModel makeSelectionTableModel()
-       {
-               MediaList mediaList = getMediaList();
-               MediaSelectionTableModel model = new MediaSelectionTableModel(
-                       "dialog.correlate.select." + getMediaTypeKey() + "name",
-                       "dialog.correlate.select." + getMediaTypeKey() + "later");
-               int numMedia = mediaList.getNumMedia();
-               for (int i=0; i<numMedia; i++)
-               {
-                       MediaObject media = mediaList.getMedia(i);
-                       // For working out time differences, can't use media which already had point information
-                       if (media.getDataPoint() != null && media.getDataPoint().hasTimestamp()
-                               && media.getOriginalStatus() == MediaObject.Status.NOT_CONNECTED)
-                       {
-                               // Calculate time difference, add to table model
-                               long timeDiff = getMediaTimestamp(media).getSecondsSince(media.getDataPoint().getTimestamp(), _timezone);
-                               model.addMedia(media, timeDiff);
-                       }
-               }
-               return model;
-       }
-
-       /**
-        * Group the two radio buttons together with a ButtonGroup
-        * @param inButton1 first radio button
-        * @param inButton2 second radio button
-        */
-       protected static void groupRadioButtons(JRadioButton inButton1, JRadioButton inButton2)
-       {
-               ButtonGroup buttonGroup = new ButtonGroup();
-               buttonGroup.add(inButton1);
-               buttonGroup.add(inButton2);
-               inButton1.setSelected(true);
-       }
-
-
-       /**
-        * Try to parse the given string
-        * @param inText String to parse
-        * @return value if parseable, 0 otherwise
-        */
-       protected static int getValue(String inText)
-       {
-               int value = 0;
-               try {
-                       value = Integer.parseInt(inText);
-               }
-               catch (NumberFormatException nfe) {}
-               return value;
-       }
-
-
-       /**
-        * Calculate the median index to select from the table
-        * @param inModel table model
-        * @return index of entry to select from table
-        */
-       protected static int getMedianIndex(MediaSelectionTableModel inModel)
-       {
-               // make sortable list
-               TreeSet<TimeIndexPair> set = new TreeSet<TimeIndexPair>();
-               // loop through rows of table adding to list
-               int numRows = inModel.getRowCount();
-               int i;
-               for (i=0; i<numRows; i++)
-               {
-                       MediaSelectionTableRow row = inModel.getRow(i);
-                       set.add(new TimeIndexPair(row.getTimeDiff().getTotalSeconds(), i));
-               }
-               // pull out middle entry and return index
-               TimeIndexPair pair = null;
-               Iterator<TimeIndexPair> iterator = set.iterator();
-               for (i=0; i<(numRows+1)/2; i++)
-               {
-                       pair = iterator.next();
-               }
-               return pair.getIndex();
-       }
-
-
-       /**
-        * Disable the ok button
-        */
-       public void disableOkButton()
-       {
-               if (_okButton != null) {
-                       _okButton.setEnabled(false);
-               }
-       }
-
-       /**
-        * @return gui components for first panel, or null if empty
-        */
-       protected JPanel makeFirstPanel() {
-               return null;
-       }
-
-       /**
-        * Make the second panel for the selection screen
-        * @return JPanel object containing gui elements
-        */
-       private JPanel makeSecondPanel()
-       {
-               JPanel card = new JPanel();
-               card.setLayout(new BorderLayout(10, 10));
-               JLabel introLabel = new JLabel(I18nManager.getText(
-                       "dialog.correlate." + getMediaTypeKey() + "select.intro"));
-               introLabel.setBorder(BorderFactory.createEmptyBorder(6, 6, 6, 6));
-               card.add(introLabel, BorderLayout.NORTH);
-               // table doesn't have model yet - that will be attached later
-               _selectionTable = new JTable();
-               JScrollPane photoScrollPane = new JScrollPane(_selectionTable);
-               photoScrollPane.setPreferredSize(new Dimension(400, 100));
-               card.add(photoScrollPane, BorderLayout.CENTER);
-               return card;
-       }
-
-
-       /**
-        * Make contents of third panel including options and preview
-        * @return JPanel containing gui elements
-        */
-       private JPanel makeThirdPanel()
-       {
-               OptionsChangedListener optionsChangedListener = new OptionsChangedListener(this);
-               // Second panel for options
-               JPanel card2 = new JPanel();
-               card2.setLayout(new BorderLayout());
-               JPanel card2Top = new JPanel();
-               card2Top.setLayout(new BoxLayout(card2Top, BoxLayout.Y_AXIS));
-               JLabel introLabel = new JLabel(I18nManager.getText("dialog.correlate.options.intro"));
-               introLabel.setBorder(BorderFactory.createEmptyBorder(8, 6, 5, 6));
-               card2Top.add(introLabel);
-               // time offset section
-               JPanel offsetPanel = new JPanel();
-               offsetPanel.setBorder(BorderFactory.createTitledBorder(I18nManager.getText("dialog.correlate.options.offsetpanel")));
-               offsetPanel.setLayout(new BoxLayout(offsetPanel, BoxLayout.Y_AXIS));
-               JPanel offsetPanelTop = new JPanel();
-               offsetPanelTop.setLayout(new FlowLayout());
-               offsetPanelTop.setBorder(null);
-               offsetPanelTop.add(new JLabel(I18nManager.getText("dialog.correlate.options.offset") + ": "));
-               _offsetHourBox = new JTextField(3);
-               _offsetHourBox.addKeyListener(optionsChangedListener);
-               offsetPanelTop.add(_offsetHourBox);
-               offsetPanelTop.add(new JLabel(I18nManager.getText("dialog.correlate.options.offset.hours")));
-               _offsetMinBox = new JTextField(3);
-               _offsetMinBox.addKeyListener(optionsChangedListener);
-               offsetPanelTop.add(_offsetMinBox);
-               offsetPanelTop.add(new JLabel(I18nManager.getText("dialog.correlate.options.offset.minutes")));
-               _offsetSecBox = new JTextField(3);
-               _offsetSecBox.addKeyListener(optionsChangedListener);
-               offsetPanelTop.add(_offsetSecBox);
-               offsetPanelTop.add(new JLabel(I18nManager.getText("dialog.correlate.options.offset.seconds")));
-               offsetPanel.add(offsetPanelTop);
-
-               // radio buttons for photo / point later
-               JPanel offsetPanelBot = new JPanel();
-               offsetPanelBot.setLayout(new FlowLayout());
-               offsetPanelBot.setBorder(null);
-               _mediaLaterOption = new JRadioButton(I18nManager.getText("dialog.correlate.options." + getMediaTypeKey() + "later"));
-               _pointLaterOption = new JRadioButton(I18nManager.getText("dialog.correlate.options.pointlater" + getMediaTypeKey()));
-               _mediaLaterOption.addItemListener(optionsChangedListener);
-               _pointLaterOption.addItemListener(optionsChangedListener);
-               ButtonGroup laterGroup = new ButtonGroup();
-               laterGroup.add(_mediaLaterOption);
-               laterGroup.add(_pointLaterOption);
-               offsetPanelBot.add(_mediaLaterOption);
-               offsetPanelBot.add(_pointLaterOption);
-               offsetPanel.add(offsetPanelBot);
-               offsetPanel.setAlignmentX(Component.LEFT_ALIGNMENT);
-               card2Top.add(offsetPanel);
-
-               // listener for radio buttons
-               ActionListener radioListener = new ActionListener() {
-                       public void actionPerformed(ActionEvent e) {
-                               enableEditBoxes();
-                       }
-               };
-               // time limits section
-               JPanel limitsPanel = new JPanel();
-               limitsPanel.setBorder(BorderFactory.createTitledBorder(I18nManager.getText("dialog.correlate.options.limitspanel")));
-               limitsPanel.setLayout(new BoxLayout(limitsPanel, BoxLayout.Y_AXIS));
-               JPanel timeLimitPanel = new JPanel();
-               timeLimitPanel.setLayout(new FlowLayout());
-               JRadioButton noTimeLimitRadio = new JRadioButton(I18nManager.getText("dialog.correlate.options.notimelimit"));
-               noTimeLimitRadio.addItemListener(optionsChangedListener);
-               noTimeLimitRadio.addActionListener(radioListener);
-               timeLimitPanel.add(noTimeLimitRadio);
-               _timeLimitRadio = new JRadioButton(I18nManager.getText("dialog.correlate.options.timelimit") + ": ");
-               _timeLimitRadio.addItemListener(optionsChangedListener);
-               _timeLimitRadio.addActionListener(radioListener);
-               timeLimitPanel.add(_timeLimitRadio);
-               groupRadioButtons(noTimeLimitRadio, _timeLimitRadio);
-               _limitMinBox = new JTextField(3);
-               _limitMinBox.addKeyListener(optionsChangedListener);
-               timeLimitPanel.add(_limitMinBox);
-               timeLimitPanel.add(new JLabel(I18nManager.getText("dialog.correlate.options.offset.minutes")));
-               _limitSecBox = new JTextField(3);
-               _limitSecBox.addKeyListener(optionsChangedListener);
-               timeLimitPanel.add(_limitSecBox);
-               timeLimitPanel.add(new JLabel(I18nManager.getText("dialog.correlate.options.offset.seconds")));
-               limitsPanel.add(timeLimitPanel);
-               // distance limits
-               JPanel distLimitPanel = new JPanel();
-               distLimitPanel.setLayout(new FlowLayout());
-               JRadioButton noDistLimitRadio = new JRadioButton(I18nManager.getText("dialog.correlate.options.nodistancelimit"));
-               noDistLimitRadio.addItemListener(optionsChangedListener);
-               noDistLimitRadio.addActionListener(radioListener);
-               distLimitPanel.add(noDistLimitRadio);
-               _distLimitRadio = new JRadioButton(I18nManager.getText("dialog.correlate.options.distancelimit") + ": ");
-               _distLimitRadio.addItemListener(optionsChangedListener);
-               _distLimitRadio.addActionListener(radioListener);
-               distLimitPanel.add(_distLimitRadio);
-               groupRadioButtons(noDistLimitRadio, _distLimitRadio);
-               _limitDistBox = new JTextField(4);
-               _limitDistBox.addKeyListener(optionsChangedListener);
-               distLimitPanel.add(_limitDistBox);
-               String[] distUnitsOptions = {I18nManager.getText("units.kilometres"), I18nManager.getText("units.metres"),
-                       I18nManager.getText("units.miles")};
-               _distUnitsDropdown = new JComboBox<String>(distUnitsOptions);
-               _distUnitsDropdown.addItemListener(optionsChangedListener);
-               distLimitPanel.add(_distUnitsDropdown);
-               limitsPanel.add(distLimitPanel);
-               limitsPanel.setAlignmentX(Component.LEFT_ALIGNMENT);
-               card2Top.add(limitsPanel);
-
-               // preview button
-               JButton previewButton = new JButton(I18nManager.getText("button.preview"));
-               previewButton.addActionListener(new ActionListener() {
-                       public void actionPerformed(ActionEvent e) {
-                               createPreview(true);
-                       }
-               });
-               card2Top.add(previewButton);
-               card2.add(card2Top, BorderLayout.NORTH);
-               // preview
-               _previewTable = new JTable(new MediaPreviewTableModel("dialog.correlate.select." + getMediaTypeKey() + "name"));
-               JScrollPane previewScrollPane = new JScrollPane(_previewTable);
-               previewScrollPane.setPreferredSize(new Dimension(300, 100));
-               card2.add(previewScrollPane, BorderLayout.CENTER);
-               return card2;
-       }
-
-
-       /**
-        * Go to the next or previous card in the stack
-        * @param increment 1 for next, -1 for previous card
-        */
-       private void showCard(int increment)
-       {
-               int currCard = _cards.getCurrentCardIndex();
-               int next = currCard + increment;
-               if (!isCardEnabled(next)) {
-                       next += increment;
-               }
-               setupCard(next);
-               _backButton.setEnabled(next > 0 && (isCardEnabled(next-1) || isCardEnabled(next-2)));
-               _nextButton.setEnabled(next < (_cards.getNumCards()-1));
-               _cards.showCard(next);
-       }
-
-       /**
-        * @param inCardNum index of card
-        * @return true if specified card is enabled
-        */
-       private boolean isCardEnabled(int inCardNum)
-       {
-               if (_cardEnabled == null) {
-                       _cardEnabled = getCardEnabledFlags();
-               }
-               return (inCardNum >= 0 && inCardNum < _cardEnabled.length && _cardEnabled[inCardNum]);
-       }
-
-       /**
-        * @return array of boolean flags denoting availability of cards
-        */
-       protected boolean[] getCardEnabledFlags()
-       {
-               // by default first is off and third is always on; second depends on selection table
-               return new boolean[] {false, makeSelectionTableModel().getRowCount() > 0, true};
-       }
-
-       /**
-        * Set up the specified card
-        * @param inCardNum index of card
-        */
-       protected void setupCard(int inCardNum)
-       {
-               _previewEnabled = false;
-               if (inCardNum == 1)
-               {
-                       // set up photo selection card
-                       MediaSelectionTableModel model = makeSelectionTableModel();
-                       _selectionTable.setModel(model);
-                       for (int i=0; i<model.getColumnCount(); i++) {
-                               _selectionTable.getColumnModel().getColumn(i).setPreferredWidth(i==3?50:150);
-                       }
-                       // Calculate median time difference, select corresponding row of table
-                       int preselectedIndex = model.getRowCount() < 3 ? 0 : getMedianIndex(model);
-                       _selectionTable.getSelectionModel().setSelectionInterval(preselectedIndex, preselectedIndex);
-                       _nextButton.requestFocus();
-               }
-               else if (inCardNum == 2)
-               {
-                       // set up the options/preview card - first check for given time difference
-                       TimeDifference timeDiff = null;
-                       if (isCardEnabled(1))
-                       {
-                               int rowNum = _selectionTable.getSelectedRow();
-                               if (rowNum < 0) {rowNum = 0;}
-                               MediaSelectionTableRow selectedRow =
-                                       ((MediaSelectionTableModel) _selectionTable.getModel()).getRow(rowNum);
-                               timeDiff = selectedRow.getTimeDiff();
-                       }
-                       setupPreviewCard(timeDiff, getMediaList().getMedia(0));
-               }
-               // enable ok button if any photos have been selected
-               _okButton.setEnabled(inCardNum == 2 && ((MediaPreviewTableModel) _previewTable.getModel()).hasAnySelected());
-       }
-
-       /**
-        * Enable or disable the edit boxes according to the radio button selections
-        */
-       private void enableEditBoxes()
-       {
-               // enable/disable text field for distance input
-               _limitDistBox.setEnabled(_distLimitRadio.isSelected());
-               // and for time limits
-               _limitMinBox.setEnabled(_timeLimitRadio.isSelected());
-               _limitSecBox.setEnabled(_timeLimitRadio.isSelected());
-       }
-
-       /**
-        * Parse the time limit values entered and validate them
-        * @return TimeDifference object describing limit
-        */
-       protected TimeDifference parseTimeLimit()
-       {
-               if (!_timeLimitRadio.isSelected()) {return null;}
-               int mins = getValue(_limitMinBox.getText());
-               _limitMinBox.setText("" + mins);
-               int secs = getValue(_limitSecBox.getText());
-               _limitSecBox.setText("" + secs);
-               if (mins <= 0 && secs <= 0) {return null;}
-               return new TimeDifference(0, mins, secs, true);
-       }
-
-       /**
-        * Parse the distance limit value entered and validate
-        * @return angular distance in radians
-        */
-       protected double parseDistanceLimit()
-       {
-               double value = -1.0;
-               if (_distLimitRadio.isSelected())
-               {
-                       try {
-                               value = Double.parseDouble(_limitDistBox.getText());
-                       }
-                       catch (NumberFormatException nfe) {}
-               }
-               if (value <= 0.0) {
-                       _limitDistBox.setText("0");
-                       return -1.0;
-               }
-               _limitDistBox.setText("" + value);
-               return Distance.convertDistanceToRadians(value, getSelectedDistanceUnits());
-       }
-
-
-       /**
-        * @return the selected distance units from the dropdown
-        */
-       protected Unit getSelectedDistanceUnits()
-       {
-               final Unit[] distUnits = {UnitSetLibrary.UNITS_KILOMETRES, UnitSetLibrary.UNITS_METRES, UnitSetLibrary.UNITS_MILES};
-               return distUnits[_distUnitsDropdown.getSelectedIndex()];
-       }
-
-       /**
-        * Create a preview of the correlate action using the selected time difference
-        * @param inFromButton true if triggered from button press, false if automatic
-        */
-       public void createPreview(boolean inFromButton)
-       {
-               // Exit if still on first panel
-               if (!_previewEnabled) {
-                       return;
-               }
-               // Create a TimeDifference based on the edit boxes
-               int numHours = getValue(_offsetHourBox.getText());
-               int numMins = getValue(_offsetMinBox.getText());
-               int numSecs = getValue(_offsetSecBox.getText());
-               boolean isPos = _mediaLaterOption.isSelected();
-               createPreview(new TimeDifference(numHours, numMins, numSecs, isPos), inFromButton);
-       }
-
-       /**
-        * Set up the final card using the given time difference and show it
-        * @param inTimeDiff time difference to use for time offsets
-        * @param inFirstMedia first media object to use for calculating timezone
-        */
-       protected void setupPreviewCard(TimeDifference inTimeDiff, MediaObject inFirstMedia)
-       {
-               _previewEnabled = false;
-               TimeDifference timeDiff = inTimeDiff;
-               if (timeDiff == null)
-               {
-                       // No time difference available, so try with zero
-                       timeDiff = new TimeDifference(0L);
-               }
-               // Use time difference to set edit boxes
-               _offsetHourBox.setText("" + timeDiff.getNumHours());
-               _offsetMinBox.setText("" + timeDiff.getNumMinutes());
-               _offsetSecBox.setText("" + timeDiff.getNumSeconds());
-               _mediaLaterOption.setSelected(timeDiff.getIsPositive());
-               _pointLaterOption.setSelected(!timeDiff.getIsPositive());
-               _previewEnabled = true;
-               enableEditBoxes();
-               createPreview(timeDiff, true);
-       }
-
-       /**
-        * Create a preview of the correlate action using the selected time difference
-        * @param inTimeDiff TimeDifference to use for preview
-        * @param inShowWarning true to show warning if all points out of range
-        */
-       protected abstract void createPreview(TimeDifference inTimeDiff, boolean inShowWarning);
-
-
-       /**
-        * Get the timestamp of the given media
-        * @param inMedia media object
-        * @return normally just returns the media timestamp, overridden by audio correlator
-        */
-       protected Timestamp getMediaTimestamp(MediaObject inMedia)
-       {
-               return inMedia.getTimestamp();
-       }
-
-       /**
-        * Get the point pair surrounding the given media item
-        * @param inTrack track object
-        * @param inMedia media object
-        * @param inOffset time offset to apply
-        * @return point pair resulting from correlation
-        */
-       protected PointMediaPair getPointPairForMedia(Track inTrack, MediaObject inMedia, TimeDifference inOffset)
-       {
-               PointMediaPair pair = new PointMediaPair(inMedia);
-               if (inMedia.hasTimestamp())
-               {
-                       // Add/subtract offset to media timestamp
-                       Timestamp mediaStamp = getMediaTimestamp(inMedia);
-                       int numPoints = inTrack.getNumPoints();
-                       for (int i=0; i<numPoints; i++)
-                       {
-                               DataPoint point = inTrack.getPoint(i);
-                               if (point.getPhoto() == null && point.getAudio() == null)
-                               {
-                                       Timestamp pointStamp = point.getTimestamp();
-                                       if (pointStamp != null && pointStamp.isValid())
-                                       {
-                                               long numSeconds = pointStamp.getSecondsSince(mediaStamp, _timezone)
-                                                       + inOffset.getTotalSeconds();
-                                               pair.addPoint(point, numSeconds);
-                                       }
-                               }
-                       }
-               }
-               return pair;
-       }
-
-
-       /**
-        * Finish the correlation
-        */
-       protected abstract void finishCorrelation();
-
-       /**
-        * Construct an array of the point pairs to use for correlation
-        * @return array of PointMediaPair objects
-        */
-       protected PointMediaPair[] getPointPairs()
-       {
-               MediaPreviewTableModel model = (MediaPreviewTableModel) _previewTable.getModel();
-               int numMedia = model.getRowCount();
-               PointMediaPair[] pairs = new PointMediaPair[numMedia];
-               // Loop over items in preview table model
-               for (int i=0; i<numMedia; i++)
-               {
-                       MediaPreviewTableRow row = model.getRow(i);
-                       // add all selected pairs to array (other elements remain null)
-                       if (row.getCorrelateFlag().booleanValue()) {
-                               pairs[i] = row.getPointPair();
-                       }
-               }
-               return pairs;
-       }
-}