001// License: GPL. For details, see LICENSE file.
002package org.openstreetmap.josm.gui.preferences.imagery;
003
004import java.awt.GridBagLayout;
005import java.awt.LayoutManager;
006import java.util.ArrayList;
007import java.util.Collection;
008
009import javax.swing.AbstractButton;
010import javax.swing.JPanel;
011import javax.swing.event.ChangeEvent;
012import javax.swing.event.ChangeListener;
013import javax.swing.event.DocumentEvent;
014import javax.swing.event.DocumentListener;
015import javax.swing.text.JTextComponent;
016
017import org.openstreetmap.josm.data.imagery.ImageryInfo;
018import org.openstreetmap.josm.data.imagery.ImageryInfo.ImageryType;
019import org.openstreetmap.josm.gui.widgets.JosmTextArea;
020import org.openstreetmap.josm.gui.widgets.JosmTextField;
021
022/**
023 * An abstract imagery panel used to add WMS/TMS imagery sources. See implementations.
024 * @see AddTMSLayerPanel
025 * @see AddWMSLayerPanel
026 * @since 5617
027 */
028public abstract class AddImageryPanel extends JPanel {
029
030    protected final JosmTextArea rawUrl = new JosmTextArea(3, 40);
031    protected final JosmTextField name = new JosmTextField();
032
033    protected final transient Collection<ContentValidationListener> listeners = new ArrayList<>();
034
035    /**
036     * A listener notified when the validation status of this panel change.
037     */
038    public interface ContentValidationListener {
039        /**
040         * Called when the validation status of this panel changed
041         * @param isValid true if the conditions required to close this panel are met
042         */
043        void contentChanged(boolean isValid);
044    }
045
046    protected AddImageryPanel() {
047        this(new GridBagLayout());
048    }
049
050    protected AddImageryPanel(LayoutManager layout) {
051        super(layout);
052        registerValidableComponent(name);
053    }
054
055    protected final void registerValidableComponent(AbstractButton component) {
056        component.addChangeListener(new ChangeListener() {
057            @Override
058            public void stateChanged(ChangeEvent e) {
059                notifyListeners();
060            }
061        });
062    }
063
064    protected final void registerValidableComponent(JTextComponent component) {
065        component.getDocument().addDocumentListener(new DocumentListener() {
066            @Override
067            public void removeUpdate(DocumentEvent e) {
068                notifyListeners();
069            }
070
071            @Override
072            public void insertUpdate(DocumentEvent e) {
073                notifyListeners();
074            }
075
076            @Override
077            public void changedUpdate(DocumentEvent e) {
078                notifyListeners();
079            }
080        });
081    }
082
083    protected abstract ImageryInfo getImageryInfo();
084
085    protected static String sanitize(String s) {
086        return s.replaceAll("[\r\n]+", "").trim();
087    }
088
089    protected static String sanitize(String s, ImageryType type) {
090        String ret = s;
091        String imageryType = type.getTypeString() + ':';
092        if (ret.startsWith(imageryType)) {
093            // remove ImageryType from URL
094            ret = ret.substring(imageryType.length());
095        }
096        return sanitize(ret);
097    }
098
099    protected final String getImageryName() {
100        return sanitize(name.getText());
101    }
102
103    protected final String getImageryRawUrl() {
104        return sanitize(rawUrl.getText());
105    }
106
107    protected abstract boolean isImageryValid();
108
109    /**
110     * Registers a new ContentValidationListener
111     * @param l The new ContentValidationListener that will be notified of validation status changes
112     */
113    public final void addContentValidationListener(ContentValidationListener l) {
114        if (l != null) {
115            listeners.add(l);
116        }
117    }
118
119    private void notifyListeners() {
120        for (ContentValidationListener l : listeners) {
121            l.contentChanged(isImageryValid());
122        }
123    }
124}