001// License: GPL. For details, see LICENSE file.
002package org.openstreetmap.josm.gui.datatransfer.importers;
003
004import static org.openstreetmap.josm.gui.help.HelpUtil.ht;
005import static org.openstreetmap.josm.tools.I18n.tr;
006
007import java.awt.GridBagLayout;
008import java.awt.datatransfer.DataFlavor;
009import java.awt.datatransfer.UnsupportedFlavorException;
010import java.io.IOException;
011import java.util.Map;
012
013import javax.swing.JLabel;
014import javax.swing.JOptionPane;
015import javax.swing.JPanel;
016import javax.swing.TransferHandler.TransferSupport;
017
018import org.openstreetmap.josm.Main;
019import org.openstreetmap.josm.gui.ExtendedDialog;
020import org.openstreetmap.josm.gui.datatransfer.ClipboardUtils;
021import org.openstreetmap.josm.gui.help.HelpUtil;
022import org.openstreetmap.josm.gui.widgets.UrlLabel;
023import org.openstreetmap.josm.io.XmlWriter;
024import org.openstreetmap.josm.tools.GBC;
025import org.openstreetmap.josm.tools.LanguageInfo.LocaleType;
026import org.openstreetmap.josm.tools.Logging;
027import org.openstreetmap.josm.tools.TextTagParser;
028import org.openstreetmap.josm.tools.TextTagParser.TagWarningCallback;
029
030/**
031 * This transfer support allows us to import tags from the text that was copied to the clipboard.
032 * @author Michael Zangl
033 * @since 10604
034 */
035public final class TextTagPaster extends AbstractTagPaster {
036    private static final String HELP = ht("/Action/PasteTags");
037
038    /**
039     * Create a new {@link TextTagPaster}
040     */
041    public TextTagPaster() {
042        super(DataFlavor.stringFlavor);
043    }
044
045    @Override
046    public boolean supports(TransferSupport support) {
047        try {
048            return super.supports(support) && containsValidTags(support);
049        } catch (UnsupportedFlavorException | IOException e) {
050            Logging.warn(e);
051            return false;
052        }
053    }
054
055    private boolean containsValidTags(TransferSupport support) throws UnsupportedFlavorException, IOException {
056        return !getTagsImpl(support).isEmpty();
057    }
058
059    @Override
060    protected Map<String, String> getTags(TransferSupport support) throws UnsupportedFlavorException, IOException {
061        Map<String, String> tags = getTagsImpl(support);
062        if (tags.isEmpty()) {
063            showBadBufferMessage(HELP);
064            throw new IOException("Invalid tags to paste.");
065        }
066        if (!TextTagParser.validateTags(tags, TextTagPaster::warning)) {
067            throw new IOException("Tags to paste are not valid.");
068        }
069        return tags;
070    }
071
072    private Map<String, String> getTagsImpl(TransferSupport support) throws UnsupportedFlavorException, IOException {
073        return TextTagParser.readTagsFromText((String) support.getTransferable().getTransferData(df));
074    }
075
076    /**
077     * Default {@link TagWarningCallback} implementation.
078     * Displays a warning about a problematic tag and ask user what to do about it.
079     * @param text Message to display
080     * @param data Tag key and/or value
081     * @param code to use with {@code ExtendedDialog#toggleEnable(String)}
082     * @return 1 to validate and display next warnings if any, 2 to cancel operation, 3 to clear buffer, 4 to paste tags
083     * @since 12683
084     */
085    public static int warning(String text, String data, String code) {
086        ExtendedDialog ed = new ExtendedDialog(
087                    Main.parent,
088                    tr("Do you want to paste these tags?"),
089                    tr("Ok"), tr("Cancel"), tr("Clear buffer"), tr("Ignore warnings"));
090        ed.setButtonIcons("ok", "cancel", "dialogs/delete", "pastetags");
091        ed.setContent("<html><b>"+text + "</b><br/><br/><div width=\"300px\">"+XmlWriter.encode(data, true)+"</html>");
092        ed.setDefaultButton(2);
093        ed.setCancelButton(2);
094        ed.setIcon(JOptionPane.WARNING_MESSAGE);
095        ed.toggleEnable(code);
096        ed.showDialog();
097        int r = ed.getValue();
098        if (r == 0) r = 2;
099        // clean clipboard if user asked
100        if (r == 3) ClipboardUtils.copyString("");
101        return r;
102    }
103
104    /**
105     * Shows message that the buffer can not be pasted, allowing user to clean the buffer
106     * @param helpTopic the help topic of the parent action
107     * TODO: Replace by proper HelpAwareOptionPane instead of self-made help link
108     */
109    public static void showBadBufferMessage(String helpTopic) {
110        String msg = tr("<html><p> Sorry, it is impossible to paste tags from buffer. It does not contain any JOSM object"
111            + " or suitable text. </p></html>");
112        JPanel p = new JPanel(new GridBagLayout());
113        p.add(new JLabel(msg), GBC.eop());
114        String helpUrl = HelpUtil.getHelpTopicUrl(HelpUtil.buildAbsoluteHelpTopic(helpTopic, LocaleType.DEFAULT));
115        if (helpUrl != null) {
116            p.add(new UrlLabel(helpUrl), GBC.eop());
117        }
118
119        ExtendedDialog ed = new ExtendedDialog(
120                    Main.parent,
121                    tr("Warning"),
122                    tr("Ok"), tr("Clear buffer"))
123            .setButtonIcons("ok", "dialogs/delete")
124            .setContent(p)
125            .setDefaultButton(1)
126            .setCancelButton(1)
127            .setIcon(JOptionPane.WARNING_MESSAGE)
128            .toggleEnable("tags.paste.cleanbadbuffer");
129
130        ed.showDialog();
131
132        // clean clipboard if user asked
133        if (ed.getValue() == 2) ClipboardUtils.copyString("");
134    }
135}