001// License: GPL. For details, see LICENSE file. 002package org.openstreetmap.josm.gui.conflict.tags; 003 004import static org.openstreetmap.josm.tools.I18n.tr; 005import static org.openstreetmap.josm.tools.I18n.trc; 006 007import java.awt.BorderLayout; 008import java.awt.FlowLayout; 009import java.awt.GridBagConstraints; 010import java.awt.GridBagLayout; 011import java.awt.Insets; 012import java.awt.event.ActionEvent; 013import java.awt.event.FocusAdapter; 014import java.awt.event.FocusEvent; 015import java.util.Collection; 016 017import javax.swing.AbstractAction; 018import javax.swing.AbstractButton; 019import javax.swing.BoxLayout; 020import javax.swing.ButtonModel; 021import javax.swing.JButton; 022import javax.swing.JCheckBox; 023import javax.swing.JLabel; 024import javax.swing.JPanel; 025import javax.swing.JScrollPane; 026import javax.swing.UIManager; 027import javax.swing.event.ChangeEvent; 028import javax.swing.event.ChangeListener; 029 030import org.openstreetmap.josm.Main; 031import org.openstreetmap.josm.command.ChangePropertyCommand; 032import org.openstreetmap.josm.command.Command; 033import org.openstreetmap.josm.data.osm.OsmPrimitive; 034import org.openstreetmap.josm.gui.tagging.ac.AutoCompletingTextField; 035import org.openstreetmap.josm.gui.tagging.ac.AutoCompletionList; 036import org.openstreetmap.josm.gui.widgets.JMultilineLabel; 037import org.openstreetmap.josm.tools.ImageProvider; 038 039public 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, e.g. <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, e.g. <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 @Override 151 public void actionPerformed(ActionEvent e) { 152 model.applyRole(tfRole.getText()); 153 } 154 } 155 156 class ToggleTagRelationsAction implements ChangeListener { 157 @Override 158 public void stateChanged(ChangeEvent e) { 159 ButtonModel buttonModel = ((AbstractButton) e.getSource()).getModel(); 160 tfKey.setEnabled(buttonModel.isSelected()); 161 tfValue.setEnabled(buttonModel.isSelected()); 162 tfKey.setBackground(buttonModel.isSelected() ? UIManager.getColor("TextField.background") : UIManager 163 .getColor("Panel.background")); 164 tfValue.setBackground(buttonModel.isSelected() ? UIManager.getColor("TextField.background") : UIManager 165 .getColor("Panel.background")); 166 } 167 } 168 169 public RelationMemberConflictResolverModel getModel() { 170 return model; 171 } 172 173 public Command buildTagApplyCommands(Collection<? extends OsmPrimitive> primitives) { 174 if (!cbTagRelations.isSelected()) 175 return null; 176 if (tfKey.getText().trim().isEmpty()) 177 return null; 178 if (tfValue.getText().trim().isEmpty()) 179 return null; 180 if (primitives == null || primitives.isEmpty()) 181 return null; 182 return new ChangePropertyCommand(primitives, tfKey.getText(), tfValue.getText()); 183 } 184 185 public void prepareForEditing() { 186 AutoCompletionList acList = new AutoCompletionList(); 187 Main.main.getEditLayer().data.getAutoCompletionManager().populateWithMemberRoles(acList); 188 tfRole.setAutoCompletionList(acList); 189 AutoCompletingTextField editor = (AutoCompletingTextField) tblResolver.getColumnModel().getColumn(2).getCellEditor(); 190 if (editor != null) { 191 editor.setAutoCompletionList(acList); 192 } 193 AutoCompletionList acList2 = new AutoCompletionList(); 194 Main.main.getEditLayer().data.getAutoCompletionManager().populateWithKeys(acList2); 195 tfKey.setAutoCompletionList(acList2); 196 } 197}