001    // License: GPL. For details, see LICENSE file.
002    package org.openstreetmap.josm.gui.conflict.tags;
003    
004    import static org.openstreetmap.josm.tools.I18n.tr;
005    import static org.openstreetmap.josm.tools.I18n.trc;
006    
007    import java.awt.BorderLayout;
008    import java.awt.FlowLayout;
009    import java.awt.GridBagConstraints;
010    import java.awt.GridBagLayout;
011    import java.awt.Insets;
012    import java.awt.event.ActionEvent;
013    import java.awt.event.FocusAdapter;
014    import java.awt.event.FocusEvent;
015    import java.util.Collection;
016    
017    import javax.swing.AbstractAction;
018    import javax.swing.AbstractButton;
019    import javax.swing.BoxLayout;
020    import javax.swing.ButtonModel;
021    import javax.swing.JButton;
022    import javax.swing.JCheckBox;
023    import javax.swing.JLabel;
024    import javax.swing.JPanel;
025    import javax.swing.JScrollPane;
026    import javax.swing.UIManager;
027    import javax.swing.event.ChangeEvent;
028    import javax.swing.event.ChangeListener;
029    
030    import org.openstreetmap.josm.Main;
031    import org.openstreetmap.josm.command.ChangePropertyCommand;
032    import org.openstreetmap.josm.command.Command;
033    import org.openstreetmap.josm.data.osm.OsmPrimitive;
034    import org.openstreetmap.josm.gui.JMultilineLabel;
035    import org.openstreetmap.josm.gui.tagging.ac.AutoCompletingTextField;
036    import org.openstreetmap.josm.gui.tagging.ac.AutoCompletionList;
037    import org.openstreetmap.josm.tools.ImageProvider;
038    
039    public class RelationMemberConflictResolver extends JPanel {
040    
041        private AutoCompletingTextField tfRole;
042        private AutoCompletingTextField tfKey;
043        private AutoCompletingTextField tfValue;
044        private JCheckBox cbTagRelations;
045        private RelationMemberConflictResolverModel model;
046        private RelationMemberConflictResolverTable tblResolver;
047        private JMultilineLabel lblHeader;
048    
049        protected void build() {
050            setLayout(new GridBagLayout());
051            JPanel pnl = new JPanel();
052            pnl.setLayout(new BorderLayout());
053            pnl.add(lblHeader = new JMultilineLabel(""));
054            GridBagConstraints gc = new GridBagConstraints();
055            gc.fill = GridBagConstraints.HORIZONTAL;
056            gc.weighty = 0.0;
057            gc.weightx = 1.0;
058            gc.insets = new Insets(5,5,5,5);
059            add(pnl, gc);
060            model = new RelationMemberConflictResolverModel();
061    
062            gc.gridy = 1;
063            gc.weighty = 1.0;
064            gc.fill = GridBagConstraints.BOTH;
065            gc.insets = new Insets(0,0,0,0);
066            add(new JScrollPane(tblResolver = new RelationMemberConflictResolverTable(model)), gc);
067            pnl = new JPanel();
068            pnl.setLayout(new BoxLayout(pnl, BoxLayout.Y_AXIS));
069            pnl.add(buildRoleEditingPanel());
070            pnl.add(buildTagRelationsPanel());
071            gc.gridy = 2;
072            gc.weighty = 0.0;
073            gc.fill = GridBagConstraints.HORIZONTAL;
074            add(pnl,gc);
075        }
076    
077        protected JPanel buildRoleEditingPanel() {
078            JPanel pnl = new JPanel();
079            pnl.setLayout(new FlowLayout(FlowLayout.LEFT));
080            pnl.add(new JLabel(tr("Role:")));
081            pnl.add(tfRole = new AutoCompletingTextField(10));
082            tfRole.setToolTipText(tr("Enter a role for all relation memberships"));
083            pnl.add(new JButton(new ApplyRoleAction()));
084            tfRole.addActionListener(new ApplyRoleAction());
085            tfRole.addFocusListener(
086                    new FocusAdapter() {
087                        @Override
088                        public void focusGained(FocusEvent e) {
089                            tfRole.selectAll();
090                        }
091                    }
092            );
093            return pnl;
094        }
095    
096        protected JPanel buildTagRelationsPanel() {
097            JPanel pnl = new JPanel();
098            pnl.setLayout(new FlowLayout(FlowLayout.LEFT));
099            cbTagRelations = new JCheckBox(tr("Tag modified relations with "));
100            cbTagRelations.addChangeListener(new ToggleTagRelationsAction());
101            cbTagRelations.setToolTipText(
102                    tr("<html>Select to enable entering a tag which will be applied<br>"
103                            + "to all modified relations.</html>"));
104            pnl.add(cbTagRelations);
105            pnl.add(new JLabel(trc("tag", "Key:")));
106            pnl.add(tfKey = new AutoCompletingTextField(10));
107            tfKey.setToolTipText(tr("<html>Enter a tag key, i.e. <strong><tt>fixme</tt></strong></html>"));
108            pnl.add(new JLabel(tr("Value:")));
109            pnl.add(tfValue = new AutoCompletingTextField(10));
110            tfValue.setToolTipText(tr("<html>Enter a tag value, i.e. <strong><tt>check members</tt></strong></html>"));
111            cbTagRelations.setSelected(false);
112            tfKey.setEnabled(false);
113            tfValue.setEnabled(false);
114            return pnl;
115        }
116    
117        public RelationMemberConflictResolver() {
118            build();
119        }
120    
121        public void initForWayCombining() {
122            lblHeader.setText(tr("<html>The combined ways are members in one ore more relations. "
123                    + "Please decide whether you want to <strong>keep</strong> these memberships "
124                    + "for the combined way or whether you want to <strong>remove</strong> them.<br>"
125                    + "The default is to <strong>keep</strong> the first way and <strong>remove</strong> "
126                    + "the other ways that are members of the same relation: the combined way will "
127                    + "take the place of the original way in the relation."
128                    + "</html>"));
129            invalidate();
130        }
131    
132        public void initForNodeMerging() {
133            lblHeader.setText(tr("<html>The merged nodes are members in one ore more relations. "
134                    + "Please decide whether you want to <strong>keep</strong> these memberships "
135                    + "for the target node or whether you want to <strong>remove</strong> them.<br>"
136                    + "The default is to <strong>keep</strong> the first node and <strong>remove</strong> "
137                    + "the other nodes that are members of the same relation: the target node will "
138                    + "take the place of the original node in the relation."
139                    + "</html>"));
140            invalidate();
141        }
142    
143        class ApplyRoleAction extends AbstractAction {
144            public ApplyRoleAction() {
145                putValue(NAME, tr("Apply"));
146                putValue(SMALL_ICON, ImageProvider.get("ok"));
147                putValue(SHORT_DESCRIPTION, tr("Apply this role to all members"));
148            }
149    
150            public void actionPerformed(ActionEvent e) {
151                model.applyRole(tfRole.getText());
152            }
153        }
154    
155        class ToggleTagRelationsAction implements ChangeListener {
156            public void stateChanged(ChangeEvent e) {
157                ButtonModel buttonModel = ((AbstractButton) e.getSource()).getModel();
158                tfKey.setEnabled(buttonModel.isSelected());
159                tfValue.setEnabled(buttonModel.isSelected());
160                tfKey.setBackground(buttonModel.isSelected() ? UIManager.getColor("TextField.background") : UIManager
161                        .getColor("Panel.background"));
162                tfValue.setBackground(buttonModel.isSelected() ? UIManager.getColor("TextField.background") : UIManager
163                        .getColor("Panel.background"));
164            }
165        }
166    
167        public RelationMemberConflictResolverModel getModel() {
168            return model;
169        }
170    
171        public Command buildTagApplyCommands(Collection<? extends OsmPrimitive> primitives) {
172            if (!cbTagRelations.isSelected())
173                return null;
174            if (tfKey.getText().trim().equals(""))
175                return null;
176            if (tfValue.getText().trim().equals(""))
177                return null;
178            if (primitives == null || primitives.isEmpty())
179                return null;
180            return new ChangePropertyCommand(primitives, tfKey.getText(), tfValue.getText());
181        }
182    
183        public void prepareForEditing() {
184            AutoCompletionList acList = new AutoCompletionList();
185            Main.main.getEditLayer().data.getAutoCompletionManager().populateWithMemberRoles(acList);
186            tfRole.setAutoCompletionList(acList);
187            AutoCompletingTextField editor = (AutoCompletingTextField) tblResolver.getColumnModel().getColumn(2).getCellEditor();
188            if (editor != null) {
189                editor.setAutoCompletionList(acList);
190            }
191            AutoCompletionList acList2 = new AutoCompletionList();
192            Main.main.getEditLayer().data.getAutoCompletionManager().populateWithKeys(acList2);
193            tfKey.setAutoCompletionList(acList2);
194        }
195    }