1 package tim.prune.function;
3 import java.awt.BorderLayout;
4 import java.awt.FlowLayout;
5 import java.awt.event.ActionEvent;
6 import java.awt.event.ActionListener;
7 import java.util.Arrays;
8 import java.util.Comparator;
10 import javax.swing.BoxLayout;
11 import javax.swing.ButtonGroup;
12 import javax.swing.JButton;
13 import javax.swing.JDialog;
14 import javax.swing.JLabel;
15 import javax.swing.JOptionPane;
16 import javax.swing.JPanel;
17 import javax.swing.JRadioButton;
20 import tim.prune.GenericFunction;
21 import tim.prune.I18nManager;
22 import tim.prune.data.DataPoint;
23 import tim.prune.data.Track;
24 import tim.prune.undo.UndoRearrangePhotos;
27 * Class to provide the function for rearranging photo points
29 public class RearrangePhotosFunction extends GenericFunction
31 /** Function dialog */
32 private JDialog _dialog = null;
33 /** Radio buttons for start/end */
34 private JRadioButton[] _positionRadios = null;
35 /** Radio buttons for sorting */
36 private JRadioButton[] _sortRadios = null;
41 * @param inApp app object
43 public RearrangePhotosFunction(App inApp)
48 /** Begin the rearrange */
54 _dialog = new JDialog(_parentFrame, I18nManager.getText(getNameKey()), true);
55 _dialog.setLocationRelativeTo(_parentFrame);
56 _dialog.setDefaultCloseOperation(JDialog.DISPOSE_ON_CLOSE);
57 _dialog.getContentPane().add(makeDialogComponents());
60 // Reset dialog and show
61 _dialog.setVisible(true);
64 /** Get the name key (not needed) */
65 public String getNameKey() {
66 return "function.rearrangephotos";
71 * Create dialog components
72 * @return Panel containing all gui elements in dialog
74 private JPanel makeDialogComponents()
76 JPanel dialogPanel = new JPanel();
77 dialogPanel.setLayout(new BorderLayout());
78 dialogPanel.add(new JLabel(I18nManager.getText("dialog.rearrangephotos.desc")), BorderLayout.NORTH);
79 // Radios for position (start / end)
80 _positionRadios = new JRadioButton[2];
81 final String[] posNames = {"tostart", "toend"};
82 ButtonGroup posGroup = new ButtonGroup();
83 JPanel posPanel = new JPanel();
84 posPanel.setLayout(new FlowLayout(FlowLayout.CENTER));
85 for (int i=0; i<2; i++)
87 _positionRadios[i] = new JRadioButton(I18nManager.getText("dialog.rearrangephotos." + posNames[i]));
88 posGroup.add(_positionRadios[i]);
89 posPanel.add(_positionRadios[i]);
91 _positionRadios[0].setSelected(true);
92 // Radios for sort (none / filename / time)
93 _sortRadios = new JRadioButton[3];
94 final String[] sortNames = {"nosort", "sortbyfilename", "sortbytime"};
95 ButtonGroup sortGroup = new ButtonGroup();
96 JPanel sortPanel = new JPanel();
97 sortPanel.setLayout(new FlowLayout(FlowLayout.CENTER));
98 for (int i=0; i<3; i++)
100 _sortRadios[i] = new JRadioButton(I18nManager.getText("dialog.rearrangephotos." + sortNames[i]));
101 sortGroup.add(_sortRadios[i]);
102 sortPanel.add(_sortRadios[i]);
104 _sortRadios[0].setSelected(true);
105 // add to middle of dialog
106 JPanel centrePanel = new JPanel();
107 centrePanel.setLayout(new BoxLayout(centrePanel, BoxLayout.Y_AXIS));
108 centrePanel.add(posPanel);
109 centrePanel.add(sortPanel);
110 dialogPanel.add(centrePanel, BorderLayout.CENTER);
111 // button panel at bottom
112 JPanel buttonPanel = new JPanel();
113 buttonPanel.setLayout(new FlowLayout(FlowLayout.RIGHT));
114 JButton okButton = new JButton(I18nManager.getText("button.ok"));
115 okButton.addActionListener(new ActionListener() {
116 public void actionPerformed(ActionEvent e) {
121 buttonPanel.add(okButton);
122 JButton cancelButton = new JButton(I18nManager.getText("button.cancel"));
123 cancelButton.addActionListener(new ActionListener() {
124 public void actionPerformed(ActionEvent e) {
128 buttonPanel.add(cancelButton);
129 dialogPanel.add(buttonPanel, BorderLayout.SOUTH);
134 * Perform the rearrange
136 private void finish()
138 Track track = _app.getTrackInfo().getTrack();
139 UndoRearrangePhotos undo = new UndoRearrangePhotos(track);
140 // Loop through track collecting non-photo points and photo points
141 final int numPoints = track.getNumPoints();
142 DataPoint[] nonPhotos = new DataPoint[numPoints];
143 DataPoint[] photos = new DataPoint[numPoints];
144 int numNonPhotos = 0;
146 for (int i=0; i<numPoints; i++)
148 DataPoint point = track.getPoint(i);
149 if (point.getPhoto() != null) {
150 photos[numPhotos] = point;
154 nonPhotos[numNonPhotos] = point;
158 // Sort photos if necessary
159 if (!_sortRadios[0].isSelected() && numPhotos > 1) {
160 sortPhotos(photos, _sortRadios[1].isSelected());
162 // Put the non-photo points and photo points together
163 DataPoint[] neworder = new DataPoint[numPoints];
164 if (_positionRadios[0].isSelected()) {
166 System.arraycopy(photos, 0, neworder, 0, numPhotos);
167 System.arraycopy(nonPhotos, 0, neworder, numPhotos, numNonPhotos);
171 System.arraycopy(nonPhotos, 0, neworder, 0, numNonPhotos);
172 System.arraycopy(photos, 0, neworder, numNonPhotos, numPhotos);
174 // Give track the new point order
175 if (track.replaceContents(neworder))
177 _app.getTrackInfo().getSelection().clearAll();
178 _app.completeFunction(undo, I18nManager.getText("confirm.rearrangephotos"));
179 // Note: subscribers are informed up to three times now
183 JOptionPane.showMessageDialog(_parentFrame, I18nManager.getText("error.rearrange.noop"),
184 I18nManager.getText("error.function.noop.title"), JOptionPane.WARNING_MESSAGE);
189 * Sort the given photo list either by filename or by time
190 * @param inPhotos array of DataPoint objects to sort
191 * @param inSortByFile true to sort by filename, false to sort by timestamp
192 * @return sorted array
194 private static void sortPhotos(DataPoint[] inPhotos, boolean inSortByFile)
196 Comparator<DataPoint> comparator = null;
200 comparator = new Comparator<DataPoint>() {
201 public int compare(DataPoint inP1, DataPoint inP2) {
202 if (inP2 == null) return -1; // all nulls at end
203 if (inP1 == null) return 1;
204 if (inP1.getPhoto().getFile() == null || inP2.getPhoto().getFile() == null)
205 return inP1.getPhoto().getName().compareTo(inP2.getPhoto().getName());
206 return inP1.getPhoto().getFile().compareTo(inP2.getPhoto().getFile());
212 // sort by photo timestamp
213 comparator = new Comparator<DataPoint>() {
214 public int compare(DataPoint inP1, DataPoint inP2) {
215 if (inP2 == null) return -1; // all nulls at end
216 if (inP1 == null) return 1;
217 long secDiff = inP1.getPhoto().getTimestamp().getSecondsSince(inP2.getPhoto().getTimestamp());
218 return (secDiff<0?-1:(secDiff==0?0:1));
222 Arrays.sort(inPhotos, comparator);