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 }