]> gitweb.fperrin.net Git - GpsPrune.git/blob - src/tim/prune/function/deletebydate/DeleteByDateFunction.java
Extend Delete by date function with extra buttons
[GpsPrune.git] / src / tim / prune / function / deletebydate / DeleteByDateFunction.java
1 package tim.prune.function.deletebydate;
2
3 import java.awt.BorderLayout;
4 import java.awt.Component;
5 import java.awt.Dimension;
6 import java.awt.FlowLayout;
7 import java.awt.event.ActionEvent;
8 import java.awt.event.ActionListener;
9 import java.awt.event.KeyAdapter;
10 import java.awt.event.KeyEvent;
11 import java.awt.event.MouseAdapter;
12 import java.awt.event.MouseEvent;
13 import java.util.Date;
14
15 import javax.swing.BorderFactory;
16 import javax.swing.JButton;
17 import javax.swing.JDialog;
18 import javax.swing.JLabel;
19 import javax.swing.JPanel;
20 import javax.swing.JScrollPane;
21 import javax.swing.JTable;
22 import javax.swing.border.EtchedBorder;
23 import javax.swing.event.ListSelectionEvent;
24 import javax.swing.event.ListSelectionListener;
25 import javax.swing.table.AbstractTableModel;
26
27 import tim.prune.App;
28 import tim.prune.DataSubscriber;
29 import tim.prune.I18nManager;
30 import tim.prune.UpdateMessageBroker;
31 import tim.prune.config.TimezoneHelper;
32 import tim.prune.data.DataPoint;
33 import tim.prune.function.compress.MarkAndDeleteFunction;
34
35 /**
36  * Function to select a date or dates,
37  * and mark the corresponding points for deletion
38  */
39 public class DeleteByDateFunction extends MarkAndDeleteFunction
40 {
41         /** dialog for selecting dates */
42         private JDialog _dialog = null;
43         /** table */
44         private JTable _infoTable = null;
45         /** Ok button */
46         private JButton _okButton = null;
47         // panel for selection buttons
48         private JPanel _selButtonPanel = null;
49         private JButton _keepSelectedButton = null;
50         private JButton _delSelectedButton = null;
51         /** date info list */
52         private DateInfoList _infoList = new DateInfoList();
53
54
55         /**
56          * Constructor
57          * @param inApp App object
58          */
59         public DeleteByDateFunction(App inApp)
60         {
61                 super(inApp);
62         }
63
64         @Override
65         public String getNameKey() {
66                 return "function.deletebydate";
67         }
68
69         @Override
70         public void begin()
71         {
72                 // Select the current timezone
73                 DateInfo.setTimezone(TimezoneHelper.getSelectedTimezone());
74
75                 // Make a list of which dates are present in the track
76                 _infoList.clearAll();
77                 final int numPoints = _app.getTrackInfo().getTrack().getNumPoints();
78                 for (int i=0; i<numPoints; i++)
79                 {
80                         DataPoint point = _app.getTrackInfo().getTrack().getPoint(i);
81                         if (point != null)
82                         {
83                                 if (point.hasTimestamp()) {
84                                         _infoList.addPoint(point.getTimestamp()
85                                                 .getCalendar(TimezoneHelper.getSelectedTimezone()).getTime());
86                                 }
87                                 else {
88                                         _infoList.addPoint(null); // no timestamp available
89                                 }
90                         }
91                 }
92
93                 // Complain if there is only one entry in the list - this means all points are on the same day
94                 if (_infoList.getNumEntries() < 2)
95                 {
96                         _app.showErrorMessage(getNameKey(), "dialog.deletebydate.onlyonedate");
97                 }
98                 else
99                 {
100                         // Create and build dialog if necessary
101                         if (_dialog == null)
102                         {
103                                 _dialog = new JDialog(_parentFrame, I18nManager.getText(getNameKey()), true);
104                                 _dialog.setLocationRelativeTo(_parentFrame);
105                                 _dialog.setDefaultCloseOperation(JDialog.DISPOSE_ON_CLOSE);
106                                 _dialog.getContentPane().add(makeDialogComponents());
107                                 _dialog.pack();
108                         }
109                         _selButtonPanel.setVisible(_infoList.getNumEntries() > 4);
110                         enableButtons();
111                         // Show dialog
112                         _dialog.setVisible(true);
113                 }
114         }
115
116         /**
117          * Create dialog components
118          * @return Panel containing all gui elements in dialog
119          */
120         private Component makeDialogComponents()
121         {
122                 JPanel dialogPanel = new JPanel();
123                 dialogPanel.setLayout(new BorderLayout(5, 5));
124                 // Label at top
125                 JLabel topLabel = new JLabel(I18nManager.getText("dialog.deletebydate.intro"));
126                 topLabel.setBorder(BorderFactory.createEmptyBorder(5, 5, 5, 5));
127                 dialogPanel.add(topLabel, BorderLayout.NORTH);
128
129                 // close window if escape pressed
130                 KeyAdapter escListener = new KeyAdapter() {
131                         public void keyReleased(KeyEvent inE) {
132                                 if (inE.getKeyCode() == KeyEvent.VK_ESCAPE) {
133                                         _dialog.dispose();
134                                 }
135                         }
136                 };
137
138                 _infoTable = new JTable(new DeletionTableModel(_infoList));
139                 _infoTable.getTableHeader().addMouseListener(new MouseAdapter() {
140                         public void mouseClicked(MouseEvent mouseEvent) {
141                                 int index = _infoTable.convertColumnIndexToModel(_infoTable.columnAtPoint(mouseEvent.getPoint()));
142                                 if (index >= 2) {
143                                         modifyAllCheckboxes(index == 3); // parameter is true for delete, false for keep
144                                 }
145                         }
146                 });
147                 _infoTable.getSelectionModel().addListSelectionListener(
148                         new ListSelectionListener() {
149                                 public void valueChanged(ListSelectionEvent e) {
150                                         enableButtons();
151                                 }
152                 });
153
154                 JScrollPane pane = new JScrollPane(_infoTable);
155                 pane.setPreferredSize(new Dimension(300, 180));
156                 pane.setBorder(BorderFactory.createEmptyBorder(2, 50, 2, 50));
157                 JPanel middlePanel = new JPanel();
158                 middlePanel.setLayout(new BorderLayout());
159                 middlePanel.add(pane, BorderLayout.CENTER);
160                 _selButtonPanel = new JPanel();
161                 _selButtonPanel.setBorder(BorderFactory.createCompoundBorder(
162                         BorderFactory.createEtchedBorder(EtchedBorder.LOWERED), BorderFactory.createEmptyBorder(4, 4, 4, 4))
163                 );
164                 _selButtonPanel.setLayout(new FlowLayout(FlowLayout.LEFT));
165                 _keepSelectedButton = new JButton(I18nManager.getText("button.keepselected"));
166                 _keepSelectedButton.addActionListener(new ActionListener() {
167                         public void actionPerformed(ActionEvent e) {
168                                 changeSelectedRowsToKeep();
169                         }
170                 });
171                 _selButtonPanel.add(_keepSelectedButton);
172                 _delSelectedButton = new JButton(I18nManager.getText("button.deleteselected"));
173                 _delSelectedButton.addActionListener(new ActionListener() {
174                         public void actionPerformed(ActionEvent e) {
175                                 changeSelectedRowsToDelete();
176                         }
177                 });
178                 _selButtonPanel.add(_delSelectedButton);
179                 middlePanel.add(_selButtonPanel, BorderLayout.SOUTH);
180                 dialogPanel.add(middlePanel, BorderLayout.CENTER);
181
182                 // button panel at bottom
183                 JPanel buttonPanel = new JPanel();
184                 buttonPanel.setLayout(new FlowLayout(FlowLayout.RIGHT));
185                 // OK button
186                 _okButton = new JButton(I18nManager.getText("button.ok"));
187                 _okButton.addActionListener(new ActionListener() {
188                         public void actionPerformed(ActionEvent e) {
189                                 performDelete();
190                         }
191                 });
192                 buttonPanel.add(_okButton);
193                 _okButton.addKeyListener(escListener);
194                 // Cancel button
195                 JButton cancelButton = new JButton(I18nManager.getText("button.cancel"));
196                 cancelButton.addActionListener(new ActionListener() {
197                         public void actionPerformed(ActionEvent e) {
198                                 _dialog.dispose();
199                         }
200                 });
201                 cancelButton.addKeyListener(new KeyAdapter() {
202                         public void keyPressed(KeyEvent inE) {
203                                 if (inE.getKeyCode() == KeyEvent.VK_ESCAPE) {_dialog.dispose();}
204                         }
205                 });
206                 buttonPanel.add(cancelButton);
207                 dialogPanel.add(buttonPanel, BorderLayout.SOUTH);
208                 return dialogPanel;
209         }
210
211         /**
212          * Select a column of checkboxes
213          * @param isDelete true for delete all, false for keep all
214          */
215         private void modifyAllCheckboxes(boolean isDelete)
216         {
217                 for (int rowIndex=0; rowIndex<_infoList.getNumEntries(); rowIndex++)
218                 {
219                         _infoList.getDateInfo(rowIndex).setDeleteFlag(isDelete);
220                 }
221                 enableButtons();
222         }
223
224         private void changeSelectedRowsToKeep()
225         {
226                 changeSelectedRows(false);
227         }
228         private void changeSelectedRowsToDelete()
229         {
230                 changeSelectedRows(true);
231         }
232
233         /**
234          * Change the selected rows to either all keep or all delete
235          * @param isDelete true for delete, false for keep
236          */
237         private void changeSelectedRows(boolean isDelete)
238         {
239                 int firstRow = -1, lastRow = -1;
240                 for (int rowIndex : _infoTable.getSelectedRows())
241                 {
242                         if (firstRow == -1) {firstRow = rowIndex;}
243                         _infoList.getDateInfo(rowIndex).setDeleteFlag(isDelete);
244                         lastRow = rowIndex;
245                 }
246                 // Make sure all rows between first and last updated ones are updated in the table
247                 ((AbstractTableModel) _infoTable.getModel()).fireTableRowsUpdated(firstRow, lastRow);
248                 enableButtons();
249         }
250
251         /**
252          * Enable or disable the keepSelected and deleteSelected buttons
253          * according to the current selection
254          */
255         private void enableButtons()
256         {
257                 boolean hasKeep = false, hasDelete = false;
258                 for (int rowIndex : _infoTable.getSelectedRows())
259                 {
260                         if (_infoList.getDateInfo(rowIndex).getDeleteFlag()) {
261                                 hasDelete = true;
262                         }
263                         else {
264                                 hasKeep = true;
265                         }
266                 }
267                 _delSelectedButton.setEnabled(hasKeep);
268                 _keepSelectedButton.setEnabled(hasDelete);
269         }
270
271         /**
272          * Do the actual point deletion according to the
273          * selected rows in the table
274          */
275         private void performDelete()
276         {
277                 int numMarked = 0;
278                 final int numPoints = _app.getTrackInfo().getTrack().getNumPoints();
279                 final int numDates = _infoList.getNumEntries();
280                 // Loop over all points to mark each one for deletion or not
281                 for (int p=0; p<numPoints; p++)
282                 {
283                         DataPoint point = _app.getTrackInfo().getTrack().getPoint(p);
284                         if (point != null)
285                         {
286                                 final Date date = (point.hasTimestamp() ?
287                                         point.getTimestamp().getCalendar(TimezoneHelper.getSelectedTimezone()).getTime()
288                                         : null);
289                                 boolean pointMarked = false;
290                                 // Try to match each of the date info objects in the list
291                                 for (int d=0; d<numDates; d++)
292                                 {
293                                         DateInfo info = _infoList.getDateInfo(d);
294                                         if ( (info.isDateless() && date == null) // matches dateless
295                                           || (!info.isDateless() && date != null && info.isSameDate(date)))
296                                         {
297                                                 pointMarked = info.getDeleteFlag();
298                                                 break;
299                                         }
300                                 }
301                                 point.setMarkedForDeletion(pointMarked);
302                                 if (pointMarked) {
303                                         numMarked++;
304                                 }
305                         }
306                 }
307                 // Now points have been marked, we can ask user to delete them (or delete automatically)
308                 if (numMarked > 0) {
309                         optionallyDeleteMarkedPoints(numMarked);
310                 }
311                 else
312                 {
313                         // Nothing to be deleted
314                         // Delete flags might have been reset, so refresh display
315                         UpdateMessageBroker.informSubscribers(DataSubscriber.SELECTION_CHANGED);
316                 }
317                 _dialog.dispose();
318         }
319 }