]> gitweb.fperrin.net Git - GpsPrune.git/blob - src/tim/prune/gui/SelectorDisplay.java
Add a panel to select by segment
[GpsPrune.git] / src / tim / prune / gui / SelectorDisplay.java
1 package tim.prune.gui;
2
3 import java.awt.BorderLayout;
4 import java.awt.Component;
5 import java.awt.Dimension;
6 import java.awt.Font;
7 import java.awt.GridLayout;
8 import java.awt.event.AdjustmentEvent;
9 import java.awt.event.AdjustmentListener;
10
11 import javax.swing.BorderFactory;
12 import javax.swing.Box;
13 import javax.swing.BoxLayout;
14 import javax.swing.JLabel;
15 import javax.swing.JList;
16 import javax.swing.JPanel;
17 import javax.swing.JScrollBar;
18 import javax.swing.JScrollPane;
19 import javax.swing.ListSelectionModel;
20 import javax.swing.border.EtchedBorder;
21 import javax.swing.event.ListSelectionEvent;
22 import javax.swing.event.ListSelectionListener;
23
24 import tim.prune.DataSubscriber;
25 import tim.prune.I18nManager;
26 import tim.prune.data.TrackInfo;
27
28 /**
29  * Class to allow selection of points and photos
30  * as a visual component
31  */
32 public class SelectorDisplay extends GenericDisplay
33 {
34         // Track details
35         private JLabel _trackpointsLabel = null;
36         private JLabel _filenameLabel = null;
37         // Scroll bar
38         private JScrollBar _scroller = null;
39         private boolean _ignoreScrollEvents = false;
40
41         // Panel containing lists
42         private JPanel _listsPanel = null;
43         private int _visiblePanels = 1;
44         // Waypoints
45         private JPanel _waypointListPanel = null;
46         private JList<String> _waypointList = null;
47         private WaypointListModel _waypointListModel = null;
48         // Photos
49         private JPanel _photoListPanel = null;
50         private JList<String> _photoList = null;
51         private MediaListModel _photoListModel = null;
52         // Audio files
53         private JPanel _audioListPanel = null;
54         private JList<String> _audioList = null;
55         private MediaListModel _audioListModel = null;
56         // Segments
57         private JPanel _segmentListPanel = null;
58         private JList<String> _segmentList = null;
59         private SegmentListModel _segmentListModel = null;
60
61         // scrollbar interval
62         private static final int SCROLLBAR_INTERVAL = 50;
63         // number of rows in lists
64         private static final int NUM_LIST_ENTRIES = 7;
65
66
67         /**
68          * Constructor
69          * @param inTrackInfo Track info object
70          */
71         public SelectorDisplay(TrackInfo inTrackInfo)
72         {
73                 super(inTrackInfo);
74                 setLayout(new BorderLayout());
75
76                 JPanel mainPanel = new JPanel();
77                 mainPanel.setLayout(new BoxLayout(mainPanel, BoxLayout.Y_AXIS));
78                 mainPanel.setBorder(BorderFactory.createEmptyBorder(3, 3, 3, 3));
79
80                 // Track details panel
81                 JPanel trackDetailsPanel = new JPanel();
82                 trackDetailsPanel.setLayout(new BoxLayout(trackDetailsPanel, BoxLayout.Y_AXIS));
83                 trackDetailsPanel.setBorder(BorderFactory.createCompoundBorder(
84                         BorderFactory.createEtchedBorder(EtchedBorder.LOWERED), BorderFactory.createEmptyBorder(3, 3, 3, 3))
85                 );
86                 JLabel trackDetailsLabel = new JLabel(I18nManager.getText("details.trackdetails"));
87                 Font biggerFont = trackDetailsLabel.getFont();
88                 biggerFont = biggerFont.deriveFont(Font.BOLD, biggerFont.getSize2D() + 2.0f);
89                 trackDetailsLabel.setFont(biggerFont);
90                 trackDetailsPanel.add(trackDetailsLabel);
91                 _trackpointsLabel = new JLabel(I18nManager.getText("details.notrack"));
92                 trackDetailsPanel.add(_trackpointsLabel);
93                 _filenameLabel = new JLabel("");
94                 _filenameLabel.setMinimumSize(new Dimension(120, 10));
95                 trackDetailsPanel.add(_filenameLabel);
96
97                 // Scroll bar
98                 _scroller = new JScrollBar(JScrollBar.HORIZONTAL, 0, SCROLLBAR_INTERVAL, 0, 100);
99                 _scroller.addAdjustmentListener(new AdjustmentListener() {
100                         public void adjustmentValueChanged(AdjustmentEvent e) {
101                                 selectPoint(e.getValue());
102                         }
103                 });
104                 _scroller.setEnabled(false);
105
106                 // Add panel for waypoints / photos
107                 _listsPanel = new JPanel();
108                 _listsPanel.setLayout(new GridLayout(0, 1));
109                 _listsPanel.setBorder(BorderFactory.createCompoundBorder(
110                         BorderFactory.createEtchedBorder(EtchedBorder.LOWERED), BorderFactory.createEmptyBorder(3, 3, 3, 3))
111                 );
112                 _waypointListModel = new WaypointListModel(_trackInfo.getTrack());
113                 _waypointList = new JList<String>(_waypointListModel);
114                 _waypointList.setVisibleRowCount(NUM_LIST_ENTRIES);
115                 _waypointList.addListSelectionListener(new ListSelectionListener() {
116                         public void valueChanged(ListSelectionEvent e)
117                         {
118                                 if (!e.getValueIsAdjusting()) selectWaypoint(_waypointList.getSelectedIndex());
119                         }
120                 });
121                 _waypointListPanel = makeListPanel("details.lists.waypoints", _waypointList);
122                 _listsPanel.add(_waypointListPanel);
123                 // photo list
124                 _photoListModel = new MediaListModel(_trackInfo.getPhotoList());
125                 _photoList = new JList<String>(_photoListModel);
126                 _photoList.setVisibleRowCount(NUM_LIST_ENTRIES);
127                 _photoList.addListSelectionListener(new ListSelectionListener() {
128                         public void valueChanged(ListSelectionEvent e)
129                         {
130                                 if (!e.getValueIsAdjusting()) {
131                                         selectPhoto(_photoList.getSelectedIndex());
132                                 }
133                         }});
134                 _photoListPanel = makeListPanel("details.lists.photos", _photoList);
135                 // don't add photo list (because there aren't any photos yet)
136
137                 // List for audio clips
138                 _audioListModel = new MediaListModel(_trackInfo.getAudioList());
139                 _audioList = new JList<String>(_audioListModel);
140                 _audioList.addListSelectionListener(new ListSelectionListener() {
141                         public void valueChanged(ListSelectionEvent e)
142                         {
143                                 if (!e.getValueIsAdjusting()) {
144                                         selectAudio(_audioList.getSelectedIndex());
145                                 }
146                         }});
147                 _audioListPanel = makeListPanel("details.lists.audio", _audioList);
148                 // don't add audio list either
149                 _listsPanel.setAlignmentX(Component.LEFT_ALIGNMENT);
150
151                 // Segment list
152                 _segmentListModel = new SegmentListModel(_trackInfo.getTrack());
153                 _segmentList = new JList<String>(_segmentListModel);
154                 _segmentList.addListSelectionListener(new ListSelectionListener() {
155                         public void valueChanged(ListSelectionEvent e)
156                         {
157                                 if (!e.getValueIsAdjusting()) {
158                                         selectSegment(_segmentList.getSelectedIndex());
159                                 }
160                         }});
161                 _segmentListPanel = makeListPanel("details.lists.segments", _segmentList);
162
163                 // add the controls to the main panel
164                 mainPanel.add(trackDetailsPanel);
165                 mainPanel.add(Box.createVerticalStrut(5));
166                 mainPanel.add(_scroller);
167                 mainPanel.add(Box.createVerticalStrut(5));
168
169                 // add the main panel at the top
170                 add(mainPanel, BorderLayout.NORTH);
171                 // and lists in the centre
172                 add(_listsPanel, BorderLayout.CENTER);
173                 // set preferred width to be small
174                 setPreferredSize(new Dimension(100, 100));
175         }
176
177
178         /**
179          * Select the specified point
180          * @param inValue value to select
181          */
182         private void selectPoint(int inValue)
183         {
184                 if (_track != null && !_ignoreScrollEvents) {
185                         _trackInfo.selectPoint(inValue);
186                 }
187         }
188
189
190         /**
191          * Select the specified photo
192          * @param inPhotoIndex index of selected photo
193          */
194         private void selectPhoto(int inPhotoIndex)
195         {
196                 _trackInfo.selectPhoto(inPhotoIndex);
197         }
198
199         /**
200          * Select the specified audio clip
201          * @param inIndex index of selected audio clip
202          */
203         private void selectAudio(int inIndex)
204         {
205                 _trackInfo.selectAudio(inIndex);
206         }
207
208         /**
209          *
210          */
211         private void selectSegment(int inIndex)
212         {
213                 if (inIndex >= 0) {
214                         int start = _segmentListModel.getSegmentStart(inIndex);
215                         int end = _segmentListModel.getSegmentEnd(inIndex);
216                         _trackInfo.getSelection().selectRange(start, end);
217                 }
218         }
219
220         /**
221          * Select the specified waypoint
222          * @param inWaypointIndex index of selected waypoint
223          */
224         private void selectWaypoint(int inWaypointIndex)
225         {
226                 if (inWaypointIndex >= 0) {
227                         _trackInfo.selectPoint(_waypointListModel.getWaypoint(inWaypointIndex));
228                 }
229         }
230
231
232         /**
233          * Notification that Track has been updated
234          */
235         public void dataUpdated(byte inUpdateType)
236         {
237                 // Update track data
238                 if (_track == null || _track.getNumPoints() <= 0)
239                 {
240                         _trackpointsLabel.setText(I18nManager.getText("details.notrack"));
241                         _filenameLabel.setText("");
242                         _filenameLabel.setToolTipText("");
243                 }
244                 else
245                 {
246                         _trackpointsLabel.setText(I18nManager.getText("details.track.points") + ": "
247                                 + _track.getNumPoints());
248                         int numFiles = _trackInfo.getFileInfo().getNumFiles();
249                         if (numFiles == 1)
250                         {
251                                 final String filenameString = _trackInfo.getFileInfo().getFilename();
252                                 _filenameLabel.setText(I18nManager.getText("details.track.file") + ": "
253                                         + filenameString);
254                                 _filenameLabel.setToolTipText(filenameString);
255                         }
256                         else if (numFiles > 1)
257                         {
258                                 final String labelText = I18nManager.getText("details.track.numfiles") + ": " + numFiles;
259                                 final String filenameString = String.join(", ", _trackInfo.getFileInfo().getFilenames());
260                                 _filenameLabel.setText(labelText);
261                                 _filenameLabel.setToolTipText(filenameString);
262                         }
263                         else
264                         {
265                                 _filenameLabel.setText("");
266                                 _filenameLabel.setToolTipText("");
267                         }
268                 }
269
270                 // Update scroller settings
271                 int currentPointIndex = _trackInfo.getSelection().getCurrentPointIndex();
272                 _ignoreScrollEvents = true;
273                 if (_track == null || _track.getNumPoints() < 2)
274                 {
275                         // careful to avoid event loops here
276                         // _scroller.setValue(0);
277                         _scroller.setEnabled(false);
278                 }
279                 else
280                 {
281                         _scroller.setMaximum(_track.getNumPoints() -1 + SCROLLBAR_INTERVAL);
282                         if (currentPointIndex >= 0)
283                                 _scroller.setValue(currentPointIndex);
284                         _scroller.setEnabled(true);
285                 }
286                 _ignoreScrollEvents = false;
287
288                 // update waypoints and photos if necessary
289                 if ((inUpdateType &
290                         (DataSubscriber.DATA_ADDED_OR_REMOVED | DataSubscriber.DATA_EDITED | DataSubscriber.WAYPOINTS_MODIFIED)) > 0)
291                 {
292                         _waypointListModel.fireChanged();
293                 }
294                 if ((inUpdateType &
295                         (DataSubscriber.DATA_ADDED_OR_REMOVED | DataSubscriber.DATA_EDITED | DataSubscriber.PHOTOS_MODIFIED)) > 0)
296                 {
297                         _photoListModel.fireChanged();
298                         _audioListModel.fireChanged();
299                 }
300                 // Deselect selected waypoint if selected point has since changed
301                 if (_waypointList.getSelectedIndex() >= 0)
302                 {
303                         if (_trackInfo.getCurrentPoint() == null
304                          || _waypointList.getSelectedIndex() >= _waypointListModel.getSize()
305                          || !_waypointListModel.getWaypoint(_waypointList.getSelectedIndex()).equals(_trackInfo.getCurrentPoint()))
306                         {
307                                 // point is selected in list but different from current point - deselect
308                                 _waypointList.clearSelection();
309                         }
310                 }
311                 if ((inUpdateType & (DataSubscriber.DATA_ADDED_OR_REMOVED | DataSubscriber.DATA_EDITED)) > 0)
312                 {
313                         _segmentListModel.fireChanged();
314                         if (_segmentListModel.getSize() > 1)
315                         {
316                                 _listsPanel.add(_segmentListPanel);
317                         }
318                 }
319                 // Deselect segment if selection goes beyond the selected
320                 // segment
321                 if ((inUpdateType & DataSubscriber.SELECTION_CHANGED) > 0)
322                 {
323                         int segmentSelected = _segmentList.getSelectedIndex();
324                         if (segmentSelected >= 0)
325                         {
326                                 if (_trackInfo.getSelection().getStart() != _segmentListModel.getSegmentStart(segmentSelected) ||
327                                     _trackInfo.getSelection().getEnd() != _segmentListModel.getSegmentEnd(segmentSelected))
328                                 {
329                                         _segmentList.clearSelection();
330                                 }
331                         }
332                 }
333                 // Hide photo list if no photos loaded, same for audio
334                 redrawLists(_photoListModel.getSize() > 0, _audioListModel.getSize() > 0);
335
336                 // Make sure correct photo is selected
337                 if (_photoListModel.getSize() > 0)
338                 {
339                         int photoIndex = _trackInfo.getSelection().getCurrentPhotoIndex();
340                         int listSelection = _photoList.getSelectedIndex();
341                         // Change listbox selection if indexes not equal
342                         if (listSelection != photoIndex)
343                         {
344                                 if (photoIndex < 0) {
345                                         _photoList.clearSelection();
346                                 }
347                                 else {
348                                         _photoList.setSelectedIndex(photoIndex);
349                                 }
350                         }
351                 }
352                 // Same for audio clips
353                 if (_audioListModel.getSize() > 0)
354                 {
355                         int audioIndex = _trackInfo.getSelection().getCurrentAudioIndex();
356                         int listSelection = _audioList.getSelectedIndex();
357                         // Change listbox selection if indexes not equal
358                         if (listSelection != audioIndex)
359                         {
360                                 if (audioIndex < 0) {
361                                         _audioList.clearSelection();
362                                 }
363                                 else {
364                                         _audioList.setSelectedIndex(audioIndex);
365                                 }
366                         }
367                 }
368         }
369
370         /**
371          * Make one of the three list panels
372          * @param inNameKey key for heading text
373          * @param inList list object
374          * @return panel object
375          */
376         private static JPanel makeListPanel(String inNameKey, JList<String> inList)
377         {
378                 JPanel panel = new JPanel();
379                 panel.setLayout(new BorderLayout());
380                 panel.add(new JLabel(I18nManager.getText(inNameKey)), BorderLayout.NORTH);
381                 inList.setSelectionMode(ListSelectionModel.SINGLE_SELECTION);
382                 panel.add(new JScrollPane(inList), BorderLayout.CENTER);
383                 return panel;
384         }
385
386         /**
387          * Redraw the list panels in the display according to which ones should be shown
388          * @param inShowPhotos true to show photo list
389          * @param inShowAudio true to show audio list
390          */
391         private void redrawLists(boolean inShowPhotos, boolean inShowAudio)
392         {
393                 // exit if same as last time
394                 int panels = 1 + (inShowPhotos?2:0) + (inShowAudio?4:0);
395                 if (panels == _visiblePanels) return;
396                 _visiblePanels = panels;
397                 // remove all panels and re-add them
398                 _listsPanel.removeAll();
399                 _listsPanel.setLayout(new GridLayout(0, 1));
400                 _listsPanel.add(_waypointListPanel);
401                 _listsPanel.add(_segmentListPanel);
402                 if (inShowPhotos) {
403                         _listsPanel.add(_photoListPanel);
404                 }
405                 if (inShowAudio) {
406                         _listsPanel.add(_audioListPanel);
407                 }
408                 _listsPanel.invalidate();
409                 _listsPanel.getParent().validate();
410         }
411 }