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

Last change on this file since 6717 was 6717, checked in by Don-vip, 10 years ago

where applicable, replace System.arraycopy by Arrays.copyOf

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