source: josm/trunk/src/org/openstreetmap/josm/gui/layer/gpx/ChooseTrackVisibilityAction.java@ 5815

Last change on this file since 5815 was 5815, checked in by akks, 11 years ago

Improved filtering tracks by date: more convenient (see #8416)
allow sorting track table, ignore broken timestamps for filtering and colorizing
DateEditorWithSlider widget can be reused

File size: 9.7 KB
Line 
1package org.openstreetmap.josm.gui.layer.gpx;
2
3import org.openstreetmap.josm.gui.layer.GpxLayer;
4import java.awt.Component;
5import java.awt.Dimension;
6import java.awt.GridBagLayout;
7import java.awt.event.ActionEvent;
8import java.awt.event.ActionListener;
9import java.awt.event.MouseAdapter;
10import java.awt.event.MouseEvent;
11import java.awt.event.MouseListener;
12import java.util.Map;
13import javax.swing.AbstractAction;
14import javax.swing.JComponent;
15import javax.swing.JLabel;
16import javax.swing.JPanel;
17import javax.swing.JScrollPane;
18import javax.swing.JTable;
19import javax.swing.JToggleButton;
20import javax.swing.ListSelectionModel;
21import javax.swing.event.ListSelectionEvent;
22import javax.swing.event.ListSelectionListener;
23import javax.swing.table.TableCellRenderer;
24import org.openstreetmap.josm.Main;
25import org.openstreetmap.josm.data.gpx.GpxTrack;
26import org.openstreetmap.josm.gui.ExtendedDialog;
27import org.openstreetmap.josm.gui.NavigatableComponent;
28import org.openstreetmap.josm.tools.GBC;
29import org.openstreetmap.josm.tools.ImageProvider;
30import org.openstreetmap.josm.tools.OpenBrowser;
31import org.openstreetmap.josm.tools.WindowGeometry;
32
33import static org.openstreetmap.josm.tools.I18n.tr;
34import static org.openstreetmap.josm.gui.help.HelpUtil.ht;
35
36/**
37 * allows the user to choose which of the downloaded tracks should be displayed.
38 * they can be chosen from the gpx layer context menu.
39 */
40public class ChooseTrackVisibilityAction extends AbstractAction {
41 private final GpxLayer layer;
42
43 DateFilterPanel dateFilter;
44 JTable table;
45
46 public ChooseTrackVisibilityAction(final GpxLayer layer) {
47 super(tr("Choose visible tracks"), ImageProvider.get("dialogs/filter"));
48 this.layer = layer;
49 putValue("help", ht("/Action/ChooseTrackVisibility"));
50 }
51
52 /**
53 * gathers all available data for the tracks and returns them as array of arrays
54 * in the expected column order */
55 private Object[][] buildTableContents() {
56 Object[][] tracks = new Object[layer.data.tracks.size()][5];
57 int i = 0;
58 for (GpxTrack trk : layer.data.tracks) {
59 Map<String, Object> attr = trk.getAttributes();
60 String name = (String) (attr.containsKey("name") ? attr.get("name") : "");
61 String desc = (String) (attr.containsKey("desc") ? attr.get("desc") : "");
62 String time = GpxLayer.getTimespanForTrack(trk);
63 String length = NavigatableComponent.getSystemOfMeasurement().getDistText(trk.length());
64 String url = (String) (attr.containsKey("url") ? attr.get("url") : "");
65 tracks[i] = new String[]{name, desc, time, length, url};
66 i++;
67 }
68 return tracks;
69 }
70
71 /**
72 * Builds an non-editable table whose 5th column will open a browser when double clicked.
73 * The table will fill its parent. */
74 private JTable buildTable(Object[][] content) {
75 final String[] headers = {tr("Name"), tr("Description"), tr("Timespan"), tr("Length"), tr("URL")};
76 final JTable t = new JTable(content, headers) {
77 @Override
78 public Component prepareRenderer(TableCellRenderer renderer, int row, int col) {
79 Component c = super.prepareRenderer(renderer, row, col);
80 if (c instanceof JComponent) {
81 JComponent jc = (JComponent) c;
82 jc.setToolTipText((String) getValueAt(row, col));
83 }
84 return c;
85 }
86
87 @Override
88 public boolean isCellEditable(int rowIndex, int colIndex) {
89 return false;
90 }
91 };
92 // default column widths
93 t.getColumnModel().getColumn(0).setPreferredWidth(220);
94 t.getColumnModel().getColumn(1).setPreferredWidth(300);
95 t.getColumnModel().getColumn(2).setPreferredWidth(200);
96 t.getColumnModel().getColumn(3).setPreferredWidth(50);
97 t.getColumnModel().getColumn(4).setPreferredWidth(100);
98 // make the link clickable
99 final MouseListener urlOpener = new MouseAdapter() {
100 @Override
101 public void mouseClicked(MouseEvent e) {
102 if (e.getClickCount() != 2) {
103 return;
104 }
105 JTable t = (JTable) e.getSource();
106 int col = t.convertColumnIndexToModel(t.columnAtPoint(e.getPoint()));
107 if (col != 4) {
108 return;
109 }
110 int row = t.rowAtPoint(e.getPoint());
111 String url = (String) t.getValueAt(row, col);
112 if (url == null || url.isEmpty()) {
113 return;
114 }
115 OpenBrowser.displayUrl(url);
116 }
117 };
118 t.setAutoCreateRowSorter(true);
119 t.addMouseListener(urlOpener);
120 t.setFillsViewportHeight(true);
121 return t;
122 }
123
124 boolean noUpdates=false;
125
126 /** selects all rows (=tracks) in the table that are currently visible on the layer*/
127 private void selectVisibleTracksInTable() {
128 // don't select any tracks if the layer is not visible
129 if (!layer.isVisible()) {
130 return;
131 }
132 ListSelectionModel s = table.getSelectionModel();
133 s.clearSelection();
134 for (int i = 0; i < layer.trackVisibility.length; i++) {
135 if (layer.trackVisibility[i]) {
136 s.addSelectionInterval(i, i);
137 }
138 }
139 }
140
141 /** listens to selection changes in the table and redraws the map */
142 private void listenToSelectionChanges() {
143 table.getSelectionModel().addListSelectionListener(new ListSelectionListener() {
144 @Override
145 public void valueChanged(ListSelectionEvent e) {
146 if (noUpdates || !(e.getSource() instanceof ListSelectionModel)) {
147 return;
148 }
149 updateVisibilityFromTable();
150 }
151 });
152 }
153
154 private void updateVisibilityFromTable() {
155 ListSelectionModel s = (ListSelectionModel) table.getSelectionModel();
156 for (int i = 0; i < layer.trackVisibility.length; i++) {
157 layer.trackVisibility[table.convertRowIndexToModel(i)] = s.isSelectedIndex(i);
158 }
159 Main.map.mapView.preferenceChanged(null);
160 Main.map.repaint(100);
161 }
162
163 @Override
164 public void actionPerformed(ActionEvent arg0) {
165 final JPanel msg = new JPanel(new GridBagLayout());
166
167 dateFilter = new DateFilterPanel(layer, "gpx.traces", false);
168 dateFilter.setFilterAppliedListener(new ActionListener(){
169 @Override public void actionPerformed(ActionEvent e) {
170 noUpdates = true;
171 selectVisibleTracksInTable();
172 noUpdates = false;
173 Main.map.mapView.preferenceChanged(null);
174 Main.map.repaint(100);
175 }
176 });
177 dateFilter.loadFromPrefs();
178
179 final JToggleButton b = new JToggleButton(new AbstractAction(tr("Select by date")) {
180 @Override public void actionPerformed(ActionEvent e) {
181 if (((JToggleButton) e.getSource()).isSelected()) {
182 dateFilter.setEnabled(true);
183 dateFilter.applyFilter();
184 } else {
185 dateFilter.setEnabled(false);
186 }
187 }
188 });
189 dateFilter.setEnabled(false);
190 msg.add(b, GBC.std().insets(0,0,5,0));
191 msg.add(dateFilter, GBC.eol().insets(0,0,10,0).fill(GBC.HORIZONTAL));
192
193 msg.add(new JLabel(tr("<html>Select all tracks that you want to be displayed. You can drag select a " + "range of tracks or use CTRL+Click to select specific ones. The map is updated live in the " + "background. Open the URLs by double clicking them.</html>")), GBC.eop().fill(GBC.HORIZONTAL));
194 // build table
195 final boolean[] trackVisibilityBackup = layer.trackVisibility.clone();
196 table = buildTable(buildTableContents());
197 selectVisibleTracksInTable();
198 listenToSelectionChanges();
199 // make the table scrollable
200 JScrollPane scrollPane = new JScrollPane(table);
201 msg.add(scrollPane, GBC.eol().fill(GBC.BOTH));
202
203 // build dialog
204 ExtendedDialog ed = new ExtendedDialog(Main.parent, tr("Set track visibility for {0}", layer.getName()), new String[]{tr("Show all"), tr("Show selected only"), tr("Cancel")});
205 ed.setButtonIcons(new String[]{"dialogs/layerlist/eye", "dialogs/filter", "cancel"});
206 ed.setContent(msg, false);
207 ed.setDefaultButton(2);
208 ed.setCancelButton(3);
209 ed.configureContextsensitiveHelp("/Action/ChooseTrackVisibility", true);
210 ed.setRememberWindowGeometry(getClass().getName() + ".geometry", WindowGeometry.centerInWindow(Main.parent, new Dimension(1000, 500)));
211 ed.showDialog();
212 dateFilter.saveInPrefs();
213 int v = ed.getValue();
214 // cancel for unknown buttons and copy back original settings
215 if (v != 1 && v != 2) {
216 for (int i = 0; i < layer.trackVisibility.length; i++) {
217 layer.trackVisibility[i] = trackVisibilityBackup[i];
218 }
219 Main.map.repaint();
220 return;
221 }
222 // set visibility (1 = show all, 2 = filter). If no tracks are selected
223 // set all of them visible and...
224 ListSelectionModel s = table.getSelectionModel();
225 final boolean all = v == 1 || s.isSelectionEmpty();
226 for (int i = 0; i < layer.trackVisibility.length; i++) {
227 layer.trackVisibility[table.convertRowIndexToModel(i)] = all || s.isSelectedIndex(i);
228 }
229 // ...sync with layer visibility instead to avoid having two ways to hide everything
230 layer.setVisible(v == 1 || !s.isSelectionEmpty());
231
232 Main.map.mapView.preferenceChanged(null);
233 Main.map.repaint();
234 }
235
236}
Note: See TracBrowser for help on using the repository browser.