source: osm/applications/editors/josm/plugins/reltoolbox/src/relcontext/actions/AddRemoveMemberAction.java@ 36217

Last change on this file since 36217 was 36217, checked in by GerdP, 16 months ago

fix #23521: fix some memory leaks

  • dispose dialogs
  • either avoid to create clones of ways or relations or use setNodes(null) / setMembers(null)
  • replaces most ChangeCommand instances by better specialized alternatives
  • add some comments
  • fix some checkstyle / sonar issues
File size: 6.3 KB
Line 
1// License: GPL. For details, see LICENSE file.
2package relcontext.actions;
3
4import static org.openstreetmap.josm.tools.I18n.tr;
5
6import java.awt.event.ActionEvent;
7import java.awt.event.KeyEvent;
8import java.util.ArrayList;
9import java.util.Collection;
10
11import org.openstreetmap.josm.actions.JosmAction;
12import org.openstreetmap.josm.command.ChangeMembersCommand;
13import org.openstreetmap.josm.command.Command;
14import org.openstreetmap.josm.data.UndoRedoHandler;
15import org.openstreetmap.josm.data.osm.DataSet;
16import org.openstreetmap.josm.data.osm.Node;
17import org.openstreetmap.josm.data.osm.OsmPrimitive;
18import org.openstreetmap.josm.data.osm.OsmPrimitiveType;
19import org.openstreetmap.josm.data.osm.Relation;
20import org.openstreetmap.josm.data.osm.RelationMember;
21import org.openstreetmap.josm.data.osm.Way;
22import org.openstreetmap.josm.gui.util.GuiHelper;
23import org.openstreetmap.josm.tools.ImageProvider;
24import org.openstreetmap.josm.tools.Shortcut;
25
26import relcontext.ChosenRelation;
27import relcontext.ChosenRelationListener;
28
29/**
30 * An action to add or remove (or both) member(s) from the chosen relation.
31 * In time should be able to determine correct position for new members.
32 * Also, there should be some support for entering a role for new members.
33 *
34 * @author Zverik
35 */
36public class AddRemoveMemberAction extends JosmAction implements ChosenRelationListener {
37 private final ChosenRelation rel;
38 private final SortAndFixAction sortAndFix;
39
40 public AddRemoveMemberAction(ChosenRelation rel, SortAndFixAction sortAndFix) {
41 super(null, "relcontext/addremove", tr("Add/remove members from the chosen relation"),
42 Shortcut.registerShortcut("reltoolbox:addremove", tr("Relation Toolbox: {0}", tr("Add/remove members from the chosen relation")),
43 KeyEvent.VK_EQUALS, Shortcut.DIRECT), false);
44 this.rel = rel;
45 this.sortAndFix = sortAndFix;
46 rel.addChosenRelationListener(this);
47 updateEnabledState();
48 }
49
50 @Override
51 public void actionPerformed(ActionEvent e) {
52 if (rel.get() == null)
53 return;
54
55 Relation r = new Relation(rel.get());
56
57 Collection<OsmPrimitive> toAdd = new ArrayList<>(getLayerManager().getEditDataSet().getSelected());
58 toAdd.remove(rel.get());
59 toAdd.removeAll(r.getMemberPrimitives());
60
61 // 0. check if relation is broken (temporary)
62 boolean isBroken = !toAdd.isEmpty() && sortAndFix.needsFixing(r);
63
64 // 1. remove all present members
65 r.removeMembersFor(getLayerManager().getEditDataSet().getSelected());
66
67 // 2. add all new members
68 for (OsmPrimitive p : toAdd) {
69 int pos = -1; //p instanceof Way ? findAdjacentMember(p, r) : -1;
70 if (pos < 0) {
71 r.addMember(new RelationMember("", p));
72 } else {
73 r.addMember(pos, new RelationMember("", p));
74 }
75 }
76
77 // 3. check for roles again (temporary)
78 Command roleFix = !isBroken && sortAndFix.needsFixing(r) ? sortAndFix.fixRelation(r) : null;
79 if (roleFix != null) {
80 roleFix.executeCommand();
81 }
82
83 if (!r.getMemberPrimitives().equals(rel.get().getMemberPrimitives())) {
84 UndoRedoHandler.getInstance().add(new ChangeMembersCommand(rel.get(), r.getMembers()));
85 }
86 r.setMembers(null); // See #19885
87 }
88
89 /**
90 * Finds two relation members between which to place given way. Incomplete.
91 * @see org.openstreetmap.josm.gui.dialogs.relation.MemberTableModel#determineDirection
92 */
93 protected int findAdjacentMember(Way w, Relation r) {
94 Node firstNode = w.firstNode();
95 Node lastNode = w.lastNode();
96
97 if (firstNode != null && !firstNode.equals(lastNode)) {
98 for (int i = 0; i < r.getMembersCount(); i++) {
99 if (r.getMember(i).getType() == OsmPrimitiveType.WAY) {
100 Way rw = (Way) r.getMember(i).getMember();
101 Node firstNodeR = rw.firstNode();
102 Node lastNodeR = rw.lastNode();
103 if (firstNode.equals(firstNodeR) || firstNode.equals(lastNodeR) || lastNode.equals(firstNodeR) || lastNode.equals(lastNodeR))
104 return i + 1;
105 }
106 }
107 }
108 return -1;
109 }
110
111 @Override
112 public void chosenRelationChanged(Relation oldRelation, Relation newRelation) {
113 updateEnabledState();
114 }
115
116 @Override
117 protected void updateEnabledState() {
118 updateEnabledState(getLayerManager().getEditDataSet() == null ? null : getLayerManager().getEditDataSet().getSelected());
119 }
120
121 @Override
122 protected void updateEnabledState(Collection<? extends OsmPrimitive> selection) {
123 updateIcon();
124 if (rel == null || rel.get() == null || selection == null || selection.isEmpty()) {
125 setEnabled(false);
126 return;
127 }
128 if (selection.size() == 1 && selection.contains(rel.get())) {
129 setEnabled(false);
130 return;
131 }
132 setEnabled(true);
133 }
134
135 protected void updateIcon() {
136 final int state; // 0=unknown, 1=add, 2=remove, 3=both
137 DataSet ds = getLayerManager().getEditDataSet();
138 if (ds == null || ds.getSelected().isEmpty() || rel == null || rel.get() == null) {
139 state = 0;
140 } else {
141 Collection<OsmPrimitive> toAdd = new ArrayList<>(ds.getSelected());
142 toAdd.remove(rel.get());
143 int selectedSize = toAdd.size();
144 if (selectedSize == 0) {
145 state = 0;
146 } else {
147 toAdd.removeAll(rel.get().getMemberPrimitives());
148 if (toAdd.isEmpty()) {
149 state = 2;
150 } else if (toAdd.size() < selectedSize) {
151 state = 3;
152 } else {
153 state = 1;
154 }
155 }
156 }
157 GuiHelper.runInEDT(() -> {
158 if (state == 0) {
159 putValue(LARGE_ICON_KEY, ImageProvider.get("relcontext", "addremove"));
160 } else {
161 String iconName = state == 1 ? "add" : state == 2 ? "remove" : "addremove";
162 putValue(NAME, null);
163 putValue(LARGE_ICON_KEY, ImageProvider.get("relcontext", iconName));
164 }
165 });
166 }
167}
Note: See TracBrowser for help on using the repository browser.