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

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

sonar - Immutable Field

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