// License: GPL. For details, see LICENSE file. package org.openstreetmap.josm.gui.dialogs; import static org.openstreetmap.josm.tools.I18n.tr; import java.awt.BorderLayout; import java.awt.Component; import java.awt.Dimension; import java.awt.FlowLayout; import java.awt.Point; import java.awt.event.ActionEvent; import java.beans.PropertyChangeEvent; import java.beans.PropertyChangeListener; import java.util.logging.Logger; import javax.swing.AbstractAction; import javax.swing.Action; import javax.swing.BorderFactory; import javax.swing.JButton; import javax.swing.JDialog; import javax.swing.JOptionPane; import javax.swing.JPanel; import javax.swing.WindowConstants; import org.openstreetmap.josm.Main; import org.openstreetmap.josm.command.Command; import org.openstreetmap.josm.data.osm.OsmPrimitive; import org.openstreetmap.josm.gui.DefaultNameFormatter; import org.openstreetmap.josm.gui.conflict.pair.ConflictResolver; import org.openstreetmap.josm.gui.conflict.pair.properties.OperationCancelledException; import org.openstreetmap.josm.gui.help.HelpBrowser; import org.openstreetmap.josm.gui.help.HelpUtil; import org.openstreetmap.josm.tools.ImageProvider; /** * This is an extended dialog for resolving conflict between {@see OsmPrimitive}s. * */ public class ConflictResolutionDialog extends JDialog implements PropertyChangeListener { private static final Logger logger = Logger.getLogger(ConflictResolutionDialog.class.getName()); public final static Dimension DEFAULT_SIZE = new Dimension(600,400); /** the conflict resolver component */ private ConflictResolver resolver; private ApplyResolutionAction applyResolutionAction; /** * restore position and size on screen from preference settings * */ protected void restorePositionAndDimension() { Point p = new Point(); Dimension d = new Dimension(); try { p.x = Integer.parseInt(Main.pref.get("conflictresolutiondialog.x", "0")); p.x = Math.max(0,p.x); } catch(Exception e) { logger.warning("unexpected value for preference conflictresolutiondialog.x, assuming 0"); p.x = 0; } try { p.y = Integer.parseInt(Main.pref.get("conflictresolutiondialog.y", "0")); p.y = Math.max(0,p.y); } catch(Exception e) { logger.warning("unexpected value for preference conflictresolutiondialog.x, assuming 0"); p.y = 0; } try { d.width = Integer.parseInt(Main.pref.get("conflictresolutiondialog.width", Integer.toString(DEFAULT_SIZE.width))); d.width = Math.max(0,d.width); } catch(Exception e) { logger.warning("unexpected value for preference conflictresolutiondialog.width, assuming " + DEFAULT_SIZE.width); p.y = 0; } try { d.height = Integer.parseInt(Main.pref.get("conflictresolutiondialog.height", Integer.toString(DEFAULT_SIZE.height))); d.height = Math.max(0,d.height); } catch(Exception e) { logger.warning("unexpected value for preference conflictresolutiondialog.height, assuming " + + DEFAULT_SIZE.height); p.y = 0; } setLocation(p); setSize(d); } /** * remember position and size on screen in the preferences * */ protected void rememberPositionAndDimension() { Point p = getLocation(); Main.pref.put("conflictresolutiondialog.x", Integer.toString(p.x)); Main.pref.put("conflictresolutiondialog.y", Integer.toString(p.y)); Dimension d = getSize(); Main.pref.put("conflictresolutiondialog.width", Integer.toString(d.width)); Main.pref.put("conflictresolutiondialog.height", Integer.toString(d.height)); } @Override public void removeNotify() { super.removeNotify(); unregisterListeners(); } @Override public void setVisible(boolean isVisible) { if (isVisible){ restorePositionAndDimension(); toFront(); } else { rememberPositionAndDimension(); unregisterListeners(); } super.setVisible(isVisible); } private void closeDialog() { setVisible(false); dispose(); } /** * builds the sub panel with the control buttons * * @return the panel */ protected JPanel buildButtonRow() { JPanel pnl = new JPanel(); pnl.setLayout(new FlowLayout(FlowLayout.CENTER)); applyResolutionAction = new ApplyResolutionAction(); JButton btn = new JButton(applyResolutionAction); btn.setName("button.apply"); pnl.add(btn); btn = new JButton(new CancelAction()); btn.setName("button.cancel"); pnl.add(btn); btn = new JButton(new HelpAction()); btn.setName("button.help"); pnl.add(btn); pnl.setBorder(BorderFactory.createLoweredBevelBorder()); return pnl; } private void registerListeners() { resolver.addPropertyChangeListener(applyResolutionAction); } private void unregisterListeners() { resolver.removePropertyChangeListener(applyResolutionAction); } /** * builds the GUI */ protected void build() { setDefaultCloseOperation(WindowConstants.DISPOSE_ON_CLOSE); updateTitle(); getContentPane().setLayout(new BorderLayout()); resolver = new ConflictResolver(); resolver.setName("panel.conflictresolver"); getContentPane().add(resolver, BorderLayout.CENTER); getContentPane().add(buildButtonRow(), BorderLayout.SOUTH); resolver.addPropertyChangeListener(this); HelpUtil.setHelpContext(this.getRootPane(), "Dialog/ConflictDialog"); registerListeners(); } public ConflictResolutionDialog(Component parent) { super(JOptionPane.getFrameForComponent(parent), true /* modal */); build(); } public ConflictResolver getConflictResolver() { return resolver; } /** * Action for canceling conflict resolution */ class CancelAction extends AbstractAction { public CancelAction() { putValue(Action.SHORT_DESCRIPTION, tr("Cancel conflict resolution and close the dialog")); putValue(Action.NAME, tr("Cancel")); putValue(Action.SMALL_ICON, ImageProvider.get("", "cancel")); setEnabled(true); } public void actionPerformed(ActionEvent arg0) { closeDialog(); } } /** * Action for canceling conflict resolution */ static class HelpAction extends AbstractAction { public HelpAction() { putValue(Action.SHORT_DESCRIPTION, tr("Show help information")); putValue(Action.NAME, tr("Help")); putValue(Action.SMALL_ICON, ImageProvider.get("help")); setEnabled(true); } public void actionPerformed(ActionEvent arg0) { HelpBrowser.setUrlForHelpTopic("/Dialog/ConflictDialog"); } } /** * Action for applying resolved differences in a conflict * */ class ApplyResolutionAction extends AbstractAction implements PropertyChangeListener { public ApplyResolutionAction() { putValue(Action.SHORT_DESCRIPTION, tr("Apply resolved conflicts and close the dialog")); putValue(Action.NAME, tr("Apply Resolution")); putValue(Action.SMALL_ICON, ImageProvider.get("dialogs", "conflict")); updateEnabledState(); } protected void updateEnabledState() { setEnabled(resolver.isResolvedCompletely()); } public void actionPerformed(ActionEvent arg0) { if (! resolver.isResolvedCompletely()) { Object[] options = { tr("Close anyway"), tr("Continue resolving")}; int ret = JOptionPane.showOptionDialog(Main.parent, tr("<html>You did not finish to merge the differences in this conflict.<br>" + "Conflict resolutions will not be applied unless all differences<br>" + "are resolved.<br>" + "Click <strong>{0}</strong> to close anyway.<strong> Already<br>" + "resolved differences will not be applied.</strong><br>" + "Click <strong>{1}</strong> to return to resolving conflicts.</html>" , options[0].toString(), options[1].toString() ), tr("Conflict not resolved completely"), JOptionPane.YES_NO_OPTION, JOptionPane.WARNING_MESSAGE, null, options, options[1] ); switch(ret) { case JOptionPane.YES_OPTION: closeDialog(); break; default: return; } } try { Command cmd = resolver.buildResolveCommand(); Main.main.undoRedo.add(cmd); closeDialog(); } catch(OperationCancelledException e) { // do nothing. Exception already reported } } public void propertyChange(PropertyChangeEvent evt) { if (evt.getPropertyName().equals(ConflictResolver.RESOLVED_COMPLETELY_PROP)) { updateEnabledState(); } } } protected void updateTitle() { updateTitle(null); } protected void updateTitle(OsmPrimitive my) { if (my == null) { setTitle(tr("Resolve conflicts")); } else { setTitle(tr("Resolve conflicts for ''{0}''", my.getDisplayName(DefaultNameFormatter.getInstance()))); } } public void propertyChange(PropertyChangeEvent evt) { if (evt.getPropertyName().equals(ConflictResolver.MY_PRIMITIVE_PROP)) { updateTitle((OsmPrimitive)evt.getNewValue()); } } }