source: josm/trunk/src/org/openstreetmap/josm/gui/dialogs/DeleteFromRelationConfirmationDialog.java@ 15889

Last change on this file since 15889 was 15231, checked in by Don-vip, 5 years ago

fix more Spotbugs warnings

  • Property svn:eol-style set to native
File size: 12.4 KB
RevLine 
[2512]1// License: GPL. For details, see LICENSE file.
[8469]2package org.openstreetmap.josm.gui.dialogs;
[2512]3
[2565]4import static org.openstreetmap.josm.gui.help.HelpUtil.ht;
[2512]5import static org.openstreetmap.josm.tools.I18n.tr;
6import static org.openstreetmap.josm.tools.I18n.trn;
7
8import java.awt.BorderLayout;
9import java.awt.Dimension;
10import java.awt.FlowLayout;
11import java.awt.event.ActionEvent;
12import java.awt.event.WindowAdapter;
13import java.awt.event.WindowEvent;
[11366]14import java.io.Serializable;
[2512]15import java.util.ArrayList;
16import java.util.Collection;
17import java.util.Comparator;
18import java.util.HashSet;
[6316]19import java.util.List;
[2512]20import java.util.Set;
21
22import javax.swing.AbstractAction;
[10779]23import javax.swing.JButton;
[2512]24import javax.swing.JDialog;
25import javax.swing.JPanel;
26import javax.swing.JScrollPane;
27import javax.swing.JTable;
28import javax.swing.event.TableModelEvent;
29import javax.swing.event.TableModelListener;
30import javax.swing.table.DefaultTableColumnModel;
31import javax.swing.table.DefaultTableModel;
32import javax.swing.table.TableColumn;
33
[12663]34import org.openstreetmap.josm.data.osm.DefaultNameFormatter;
[2512]35import org.openstreetmap.josm.data.osm.NameFormatter;
36import org.openstreetmap.josm.data.osm.OsmPrimitive;
[2565]37import org.openstreetmap.josm.data.osm.RelationToChildReference;
[14153]38import org.openstreetmap.josm.gui.MainApplication;
[13564]39import org.openstreetmap.josm.gui.PrimitiveRenderer;
[2512]40import org.openstreetmap.josm.gui.help.ContextSensitiveHelpAction;
41import org.openstreetmap.josm.gui.help.HelpUtil;
[10035]42import org.openstreetmap.josm.gui.util.GuiHelper;
[12678]43import org.openstreetmap.josm.gui.util.WindowGeometry;
[5888]44import org.openstreetmap.josm.gui.widgets.HtmlPanel;
[8975]45import org.openstreetmap.josm.tools.I18n;
[2512]46import org.openstreetmap.josm.tools.ImageProvider;
47
48/**
49 * This dialog is used to get a user confirmation that a collection of primitives can be removed
50 * from their parent relations.
[5886]51 * @since 2308
[2512]52 */
53public class DeleteFromRelationConfirmationDialog extends JDialog implements TableModelListener {
54 /** the unique instance of this dialog */
[6883]55 private static DeleteFromRelationConfirmationDialog instance;
[2512]56
57 /**
58 * Replies the unique instance of this dialog
59 *
[5886]60 * @return The unique instance of this dialog
[2512]61 */
[8126]62 public static synchronized DeleteFromRelationConfirmationDialog getInstance() {
[2512]63 if (instance == null) {
64 instance = new DeleteFromRelationConfirmationDialog();
65 }
66 return instance;
67 }
68
69 /** the data model */
70 private RelationMemberTableModel model;
[10179]71 private final HtmlPanel htmlPanel = new HtmlPanel();
[2512]72 private boolean canceled;
[10779]73 private final JButton btnOK = new JButton(new OKAction());
[2512]74
75 protected JPanel buildRelationMemberTablePanel() {
76 JTable table = new JTable(model, new RelationMemberTableColumnModel());
[9543]77 JPanel pnl = new JPanel(new BorderLayout());
[2512]78 pnl.add(new JScrollPane(table));
79 return pnl;
80 }
81
82 protected JPanel buildButtonPanel() {
[9543]83 JPanel pnl = new JPanel(new FlowLayout());
[10179]84 pnl.add(btnOK);
[2512]85 btnOK.setFocusable(true);
[10779]86 pnl.add(new JButton(new CancelAction()));
87 pnl.add(new JButton(new ContextSensitiveHelpAction(ht("/Action/Delete#DeleteFromRelations"))));
[2512]88 return pnl;
89 }
90
[6890]91 protected final void build() {
[2512]92 model = new RelationMemberTableModel();
93 model.addTableModelListener(this);
94 getContentPane().setLayout(new BorderLayout());
[10179]95 getContentPane().add(htmlPanel, BorderLayout.NORTH);
[2512]96 getContentPane().add(buildRelationMemberTablePanel(), BorderLayout.CENTER);
97 getContentPane().add(buildButtonPanel(), BorderLayout.SOUTH);
98
99 HelpUtil.setHelpContext(this.getRootPane(), ht("/Action/Delete#DeleteFromRelations"));
100
101 addWindowListener(new WindowEventHandler());
102 }
103
104 protected void updateMessage() {
105 int numObjectsToDelete = model.getNumObjectsToDelete();
106 int numParentRelations = model.getNumParentRelations();
[8989]107 final String msg1 = trn(
108 "Please confirm to remove <strong>{0} object</strong>.",
109 "Please confirm to remove <strong>{0} objects</strong>.",
110 numObjectsToDelete, numObjectsToDelete);
111 final String msg2 = trn(
112 "{0} relation is affected.",
113 "{0} relations are affected.",
114 numParentRelations, numParentRelations);
[8975]115 @I18n.QuirkyPluralString
[10300]116 final String msg = "<html>" + msg1 + ' ' + msg2 + "</html>";
[5888]117 htmlPanel.getEditorPane().setText(msg);
[2512]118 invalidate();
119 }
120
121 protected void updateTitle() {
122 int numObjectsToDelete = model.getNumObjectsToDelete();
123 if (numObjectsToDelete > 0) {
124 setTitle(trn("Deleting {0} object", "Deleting {0} objects", numObjectsToDelete, numObjectsToDelete));
125 } else {
126 setTitle(tr("Delete objects"));
127 }
128 }
129
[5886]130 /**
131 * Constructs a new {@code DeleteFromRelationConfirmationDialog}.
132 */
[2512]133 public DeleteFromRelationConfirmationDialog() {
[14153]134 super(GuiHelper.getFrameForComponent(MainApplication.getMainFrame()), "", ModalityType.DOCUMENT_MODAL);
[2512]135 build();
136 }
137
138 /**
139 * Replies the data model used in this dialog
140 *
141 * @return the data model
142 */
143 public RelationMemberTableModel getModel() {
144 return model;
145 }
146
147 /**
148 * Replies true if the dialog was canceled
149 *
150 * @return true if the dialog was canceled
151 */
152 public boolean isCanceled() {
153 return canceled;
154 }
155
156 protected void setCanceled(boolean canceled) {
157 this.canceled = canceled;
158 }
159
160 @Override
161 public void setVisible(boolean visible) {
162 if (visible) {
163 new WindowGeometry(
[10378]164 getClass().getName() + ".geometry",
[2512]165 WindowGeometry.centerInWindow(
[14153]166 MainApplication.getMainFrame(),
[8510]167 new Dimension(400, 200)
[2512]168 )
169 ).applySafe(this);
170 setCanceled(false);
[5998]171 } else if (isShowing()) { // Avoid IllegalComponentStateException like in #8775
[2512]172 new WindowGeometry(this).remember(getClass().getName() + ".geometry");
173 }
174 super.setVisible(visible);
175 }
176
[6084]177 @Override
[2512]178 public void tableChanged(TableModelEvent e) {
179 updateMessage();
180 updateTitle();
181 }
182
183 /**
184 * The table model which manages the list of relation-to-child references
185 */
186 public static class RelationMemberTableModel extends DefaultTableModel {
[11366]187 private static class RelationToChildReferenceComparator implements Comparator<RelationToChildReference>, Serializable {
[15231]188 private static final long serialVersionUID = 1L;
[11357]189 @Override
190 public int compare(RelationToChildReference o1, RelationToChildReference o2) {
[11377]191 NameFormatter nf = DefaultNameFormatter.getInstance();
[11357]192 int cmp = o1.getChild().getDisplayName(nf).compareTo(o2.getChild().getDisplayName(nf));
193 if (cmp != 0) return cmp;
194 cmp = o1.getParent().getDisplayName(nf).compareTo(o2.getParent().getDisplayName(nf));
195 if (cmp != 0) return cmp;
196 return Integer.compare(o1.getPosition(), o2.getPosition());
197 }
198 }
199
[9078]200 private final transient List<RelationToChildReference> data;
[2512]201
[5886]202 /**
203 * Constructs a new {@code RelationMemberTableModel}.
204 */
[2512]205 public RelationMemberTableModel() {
[7005]206 data = new ArrayList<>();
[2512]207 }
208
209 @Override
210 public int getRowCount() {
211 if (data == null) return 0;
212 return data.size();
213 }
214
[12301]215 /**
216 * Sets the data that should be displayed in the list.
217 * @param references A list of references to display
218 */
[2512]219 public void populate(Collection<RelationToChildReference> references) {
220 data.clear();
221 if (references != null) {
222 data.addAll(references);
223 }
[11357]224 data.sort(new RelationToChildReferenceComparator());
[2512]225 fireTableDataChanged();
226 }
227
[12301]228 /**
229 * Gets the list of children that are currently displayed.
230 * @return The children.
231 */
[2512]232 public Set<OsmPrimitive> getObjectsToDelete() {
[8338]233 Set<OsmPrimitive> ret = new HashSet<>();
[2512]234 for (RelationToChildReference ref: data) {
235 ret.add(ref.getChild());
236 }
237 return ret;
238 }
239
[12301]240 /**
241 * Gets the number of elements {@link #getObjectsToDelete()} would return.
242 * @return That number.
243 */
[2512]244 public int getNumObjectsToDelete() {
245 return getObjectsToDelete().size();
246 }
247
[12301]248 /**
249 * Gets the set of parent relations
250 * @return All parent relations of the references
251 */
[2512]252 public Set<OsmPrimitive> getParentRelations() {
[8338]253 Set<OsmPrimitive> ret = new HashSet<>();
[2512]254 for (RelationToChildReference ref: data) {
255 ret.add(ref.getParent());
256 }
257 return ret;
258 }
259
[12301]260 /**
261 * Gets the number of elements {@link #getParentRelations()} would return.
262 * @return That number.
263 */
[2512]264 public int getNumParentRelations() {
265 return getParentRelations().size();
266 }
267
268 @Override
269 public Object getValueAt(int rowIndex, int columnIndex) {
270 if (data == null) return null;
271 RelationToChildReference ref = data.get(rowIndex);
272 switch(columnIndex) {
[2565]273 case 0: return ref.getChild();
274 case 1: return ref.getParent();
[4879]275 case 2: return ref.getPosition()+1;
[2565]276 case 3: return ref.getRole();
277 default:
[8510]278 assert false : "Illegal column index";
[2512]279 }
280 return null;
281 }
282
[5983]283 @Override
284 public boolean isCellEditable(int row, int column) {
285 return false;
286 }
[2512]287 }
288
[9059]289 private static class RelationMemberTableColumnModel extends DefaultTableColumnModel {
[2512]290
[6890]291 protected final void createColumns() {
[2512]292
293 // column 0 - To Delete
[10308]294 TableColumn col = new TableColumn(0);
[2512]295 col.setHeaderValue(tr("To delete"));
296 col.setResizable(true);
297 col.setWidth(100);
298 col.setPreferredWidth(100);
[13564]299 col.setCellRenderer(new PrimitiveRenderer());
[2512]300 addColumn(col);
301
302 // column 0 - From Relation
303 col = new TableColumn(1);
304 col.setHeaderValue(tr("From Relation"));
305 col.setResizable(true);
306 col.setWidth(100);
307 col.setPreferredWidth(100);
[13564]308 col.setCellRenderer(new PrimitiveRenderer());
[2512]309 addColumn(col);
310
311 // column 1 - Pos.
312 col = new TableColumn(2);
313 col.setHeaderValue(tr("Pos."));
314 col.setResizable(true);
315 col.setWidth(30);
316 col.setPreferredWidth(30);
317 addColumn(col);
318
319 // column 2 - Role
320 col = new TableColumn(3);
321 col.setHeaderValue(tr("Role"));
322 col.setResizable(true);
323 col.setWidth(50);
324 col.setPreferredWidth(50);
325 addColumn(col);
326 }
327
[8836]328 RelationMemberTableColumnModel() {
[2512]329 createColumns();
330 }
331 }
332
333 class OKAction extends AbstractAction {
[8836]334 OKAction() {
[2512]335 putValue(NAME, tr("OK"));
[10465]336 new ImageProvider("ok").getResource().attachImageIcon(this);
[2512]337 putValue(SHORT_DESCRIPTION, tr("Click to close the dialog and remove the object from the relations"));
338 }
339
[6084]340 @Override
[2512]341 public void actionPerformed(ActionEvent e) {
342 setCanceled(false);
343 setVisible(false);
344 }
345 }
346
347 class CancelAction extends AbstractAction {
[8836]348 CancelAction() {
[2512]349 putValue(NAME, tr("Cancel"));
[10465]350 new ImageProvider("cancel").getResource().attachImageIcon(this);
[2512]351 putValue(SHORT_DESCRIPTION, tr("Click to close the dialog and to abort deleting the objects"));
352 }
353
[6084]354 @Override
[2512]355 public void actionPerformed(ActionEvent e) {
356 setCanceled(true);
357 setVisible(false);
358 }
359 }
360
361 class WindowEventHandler extends WindowAdapter {
362
363 @Override
364 public void windowClosing(WindowEvent e) {
365 setCanceled(true);
366 }
367
368 @Override
369 public void windowOpened(WindowEvent e) {
370 btnOK.requestFocusInWindow();
371 }
372 }
373}
Note: See TracBrowser for help on using the repository browser.