source: josm/trunk/src/org/openstreetmap/josm/gui/history/VersionTable.java@ 6524

Last change on this file since 6524 was 6520, checked in by simon04, 10 years ago

History dialog: make versions navigable with arrow keys up/down

  • Property svn:eol-style set to native
File size: 10.2 KB
Line 
1// License: GPL. For details, see LICENSE file.
2package org.openstreetmap.josm.gui.history;
3
4import static org.openstreetmap.josm.tools.I18n.tr;
5
6import java.awt.Component;
7import java.awt.Dimension;
8import java.awt.Point;
9import java.awt.Rectangle;
10import java.awt.event.ActionEvent;
11import java.awt.event.ItemEvent;
12import java.awt.event.ItemListener;
13import java.awt.event.KeyAdapter;
14import java.awt.event.KeyEvent;
15import java.awt.event.MouseEvent;
16import java.util.Observable;
17import java.util.Observer;
18
19import javax.swing.DefaultCellEditor;
20import javax.swing.JCheckBox;
21import javax.swing.JLabel;
22import javax.swing.JPopupMenu;
23import javax.swing.JRadioButton;
24import javax.swing.JTable;
25import javax.swing.SwingConstants;
26import javax.swing.UIManager;
27import javax.swing.event.TableModelEvent;
28import javax.swing.event.TableModelListener;
29import javax.swing.table.TableCellRenderer;
30
31import org.openstreetmap.josm.Main;
32import org.openstreetmap.josm.actions.AbstractInfoAction;
33import org.openstreetmap.josm.data.osm.history.HistoryOsmPrimitive;
34import org.openstreetmap.josm.gui.widgets.PopupMenuLauncher;
35import org.openstreetmap.josm.tools.ImageProvider;
36
37/**
38 * VersionTable shows a list of version in a {@link org.openstreetmap.josm.data.osm.history.History}
39 * of an {@link org.openstreetmap.josm.data.osm.OsmPrimitive}.
40 *
41 */
42public class VersionTable extends JTable implements Observer{
43 private VersionTablePopupMenu popupMenu;
44 private final HistoryBrowserModel model;
45
46 protected void build() {
47 getTableHeader().setFont(getTableHeader().getFont().deriveFont(9f));
48 setRowSelectionAllowed(false);
49 setShowGrid(false);
50 setAutoResizeMode(JTable.AUTO_RESIZE_OFF);
51 setBackground(UIManager.getColor("Button.background"));
52 setIntercellSpacing(new Dimension(6, 0));
53 putClientProperty("terminateEditOnFocusLost", true);
54 popupMenu = new VersionTablePopupMenu();
55 addMouseListener(new MouseListener());
56 addKeyListener(new KeyAdapter() {
57 @Override
58 public void keyReleased(KeyEvent e) {
59 // navigate history down/up using the corresponding arrow keys.
60 try {
61 final HistoryOsmPrimitive ref = model.getReferencePointInTime();
62 final HistoryOsmPrimitive cur = model.getCurrentPointInTime();
63 if (e.getKeyCode() == KeyEvent.VK_DOWN) {
64 // compute both values first and set them afterwards such that nothing is changed in case of an exception (e.g., reached top/bottom)
65 final HistoryOsmPrimitive refNext = model.getHistory().from(ref.getVersion()).sortAscending().get(1);
66 final HistoryOsmPrimitive curNext = model.getHistory().from(cur.getVersion()).sortAscending().get(1);
67 model.setReferencePointInTime(refNext);
68 model.setCurrentPointInTime(curNext);
69 } else if (e.getKeyCode() == KeyEvent.VK_UP) {
70 // compute both values first and set them afterwards such that nothing is changed in case of an exception (e.g., reached top/bottom)
71 final HistoryOsmPrimitive refNext = model.getHistory().until(ref.getVersion()).sortDescending().get(1);
72 final HistoryOsmPrimitive curNext = model.getHistory().until(cur.getVersion()).sortDescending().get(1);
73 model.setReferencePointInTime(refNext);
74 model.setCurrentPointInTime(curNext);
75 }
76 } catch (NullPointerException ignore) {
77 } catch (IndexOutOfBoundsException ignore) {
78 }
79 }
80 });
81 getModel().addTableModelListener(new TableModelListener() {
82 @Override
83 public void tableChanged(TableModelEvent e) {
84 adjustColumnWidth(VersionTable.this, 0, 0);
85 adjustColumnWidth(VersionTable.this, 1, -8);
86 adjustColumnWidth(VersionTable.this, 2, -8);
87 adjustColumnWidth(VersionTable.this, 3, 0);
88 adjustColumnWidth(VersionTable.this, 4, 0);
89 }
90 });
91 }
92
93 public VersionTable(HistoryBrowserModel model) {
94 super(model.getVersionTableModel(), new VersionTableColumnModel());
95 model.addObserver(this);
96 build();
97 this.model = model;
98 }
99
100 // some kind of hack to prevent the table from scrolling to the
101 // right when clicking on the cells
102 @Override
103 public void scrollRectToVisible(Rectangle aRect) {
104 super.scrollRectToVisible(new Rectangle(0, aRect.y, aRect.width, aRect.height));
105 }
106
107 protected HistoryBrowserModel.VersionTableModel getVersionTableModel() {
108 return (HistoryBrowserModel.VersionTableModel) getModel();
109 }
110
111 @Override
112 public void update(Observable o, Object arg) {
113 repaint();
114 }
115
116 class MouseListener extends PopupMenuLauncher {
117 public MouseListener() {
118 super(popupMenu);
119 }
120 @Override
121 public void mousePressed(MouseEvent e) {
122 super.mousePressed(e);
123 if (!e.isPopupTrigger() && e.getButton() == MouseEvent.BUTTON1) {
124 int row = rowAtPoint(e.getPoint());
125 int col = columnAtPoint(e.getPoint());
126 if (row > 0 && (col == VersionTableColumnModel.COL_DATE || col == VersionTableColumnModel.COL_USER)) {
127 model.getVersionTableModel().setCurrentPointInTime(row);
128 model.getVersionTableModel().setReferencePointInTime(row - 1);
129 }
130 }
131 }
132 @Override
133 protected int checkTableSelection(JTable table, Point p) {
134 HistoryBrowserModel.VersionTableModel model = getVersionTableModel();
135 int row = rowAtPoint(p);
136 if (row > -1 && !model.isLatest(row)) {
137 popupMenu.prepare(model.getPrimitive(row));
138 }
139 return row;
140 }
141 }
142
143 static class ChangesetInfoAction extends AbstractInfoAction {
144 private HistoryOsmPrimitive primitive;
145
146 public ChangesetInfoAction() {
147 super(true);
148 putValue(NAME, tr("Changeset info"));
149 putValue(SHORT_DESCRIPTION, tr("Launch browser with information about the changeset"));
150 putValue(SMALL_ICON, ImageProvider.get("about"));
151 }
152
153 @Override
154 protected String createInfoUrl(Object infoObject) {
155 HistoryOsmPrimitive primitive = (HistoryOsmPrimitive) infoObject;
156 return getBaseBrowseUrl() + "/changeset/" + primitive.getChangesetId();
157 }
158
159 @Override
160 public void actionPerformed(ActionEvent e) {
161 if (!isEnabled())
162 return;
163 String url = createInfoUrl(primitive);
164 launchBrowser(url);
165 }
166
167 public void prepare(HistoryOsmPrimitive primitive) {
168 putValue(NAME, tr("Show changeset {0}", primitive.getChangesetId()));
169 this.primitive = primitive;
170 }
171 }
172
173 static class VersionTablePopupMenu extends JPopupMenu {
174
175 private ChangesetInfoAction changesetInfoAction;
176
177 protected void build() {
178 changesetInfoAction = new ChangesetInfoAction();
179 add(changesetInfoAction);
180 }
181 public VersionTablePopupMenu() {
182 super();
183 build();
184 }
185
186 public void prepare(HistoryOsmPrimitive primitive) {
187 changesetInfoAction.prepare(primitive);
188 invalidate();
189 }
190 }
191
192 public static class RadioButtonRenderer extends JRadioButton implements TableCellRenderer {
193
194 @Override
195 public Component getTableCellRendererComponent(JTable table, Object value, boolean isSelected, boolean hasFocus,int row,int column) {
196 setSelected(value != null && (Boolean)value);
197 setHorizontalAlignment(SwingConstants.CENTER);
198 return this;
199 }
200 }
201
202 public static class RadioButtonEditor extends DefaultCellEditor implements ItemListener {
203
204 private JRadioButton btn;
205
206 public RadioButtonEditor() {
207 super(new JCheckBox());
208 btn = new JRadioButton();
209 btn.setHorizontalAlignment(SwingConstants.CENTER);
210 }
211
212 @Override
213 public Component getTableCellEditorComponent(JTable table, Object value, boolean isSelected, int row, int column) {
214 if (value == null) return null;
215 boolean val = (Boolean) value;
216 btn.setSelected(val);
217 btn.addItemListener(this);
218 return btn;
219 }
220
221 @Override
222 public Object getCellEditorValue() {
223 btn.removeItemListener(this);
224 return btn.isSelected();
225 }
226
227 @Override
228 public void itemStateChanged(ItemEvent e) {
229 fireEditingStopped();
230 }
231 }
232
233 public static class AlignedRenderer extends JLabel implements TableCellRenderer {
234 public AlignedRenderer(int hAlignment) {
235 setHorizontalAlignment(hAlignment);
236 }
237 @Override
238 public Component getTableCellRendererComponent(JTable table, Object value, boolean isSelected, boolean hasFocus,int row,int column) {
239 String v = value.toString();
240 setText(v);
241 return this;
242 }
243 }
244
245 private static void adjustColumnWidth(JTable tbl, int col, int cellInset) {
246 int maxwidth = 0;
247
248 for (int row=0; row<tbl.getRowCount(); row++) {
249 TableCellRenderer tcr = tbl.getCellRenderer(row, col);
250 Object val = tbl.getValueAt(row, col);
251 Component comp = tcr.getTableCellRendererComponent(tbl, val, false, false, row, col);
252 maxwidth = Math.max(comp.getPreferredSize().width + cellInset, maxwidth);
253 }
254 TableCellRenderer tcr = tbl.getTableHeader().getDefaultRenderer();
255 Object val = tbl.getColumnModel().getColumn(col).getHeaderValue();
256 Component comp = tcr.getTableCellRendererComponent(tbl, val, false, false, -1, col);
257 maxwidth = Math.max(comp.getPreferredSize().width + Main.pref.getInteger("table.header-inset", 0), maxwidth);
258
259 int spacing = tbl.getIntercellSpacing().width;
260 tbl.getColumnModel().getColumn(col).setPreferredWidth(maxwidth + spacing);
261 }
262
263}
Note: See TracBrowser for help on using the repository browser.