001// License: GPL. For details, see LICENSE file. 002package org.openstreetmap.josm.plugins.streetside.gui.imageinfo; 003 004import java.awt.GridBagConstraints; 005import java.awt.GridBagLayout; 006import java.awt.Insets; 007import java.awt.datatransfer.StringSelection; 008import java.util.Collection; 009 010import javax.swing.JLabel; 011import javax.swing.JPanel; 012import javax.swing.JTextPane; 013 014import org.apache.log4j.Logger; 015import org.openstreetmap.josm.data.osm.DataSelectionListener; 016import org.openstreetmap.josm.data.osm.OsmPrimitive; 017import org.openstreetmap.josm.data.osm.Tag; 018import org.openstreetmap.josm.data.osm.event.SelectionEventManager; 019import org.openstreetmap.josm.data.preferences.AbstractProperty.ValueChangeListener; 020import org.openstreetmap.josm.gui.dialogs.ToggleDialog; 021import org.openstreetmap.josm.plugins.streetside.StreetsideAbstractImage; 022import org.openstreetmap.josm.plugins.streetside.StreetsideDataListener; 023import org.openstreetmap.josm.plugins.streetside.StreetsideImage; 024import org.openstreetmap.josm.plugins.streetside.gui.boilerplate.SelectableLabel; 025import org.openstreetmap.josm.plugins.streetside.gui.boilerplate.StreetsideButton; 026import org.openstreetmap.josm.plugins.streetside.utils.StreetsideProperties; 027import org.openstreetmap.josm.plugins.streetside.utils.StreetsideURL; 028import org.openstreetmap.josm.tools.I18n; 029 030public final class ImageInfoPanel extends ToggleDialog implements StreetsideDataListener, DataSelectionListener { 031 private static final long serialVersionUID = 4141847503072417190L; 032 033 final static Logger logger = Logger.getLogger(ImageInfoPanel.class); 034 035 private static ImageInfoPanel instance; 036 037 private final JTextPane imgKeyValue; 038 private final WebLinkAction imgLinkAction; 039 private final ClipboardAction copyImgKeyAction; 040 private final AddTagToPrimitiveAction addStreetsideTagAction; 041 private final JTextPane seqKeyValue; 042 043 private ValueChangeListener<Boolean> imageLinkChangeListener; 044 045 private ImageInfoPanel() { 046 super( 047 I18n.tr("Streetside 360° image info"), 048 "streetside-info", 049 I18n.tr("Displays detail information on the currently selected Streetside image"), 050 null, 051 150 052 ); 053 SelectionEventManager.getInstance().addSelectionListener(this); 054 055 imgKeyValue = new SelectableLabel(); 056 057 imgLinkAction = new WebLinkAction(I18n.tr("View in browser"), null); 058 059 copyImgKeyAction = new ClipboardAction(I18n.tr("Copy key"), null); 060 StreetsideButton copyButton = new StreetsideButton(copyImgKeyAction, true); 061 copyImgKeyAction.setPopupParent(copyButton); 062 063 addStreetsideTagAction = new AddTagToPrimitiveAction(I18n.tr("Add Streetside tag")); 064 065 seqKeyValue = new SelectableLabel(); 066 067 JPanel root = new JPanel(new GridBagLayout()); 068 069 GridBagConstraints gbc = new GridBagConstraints(); 070 gbc.insets = new Insets(0, 5, 0, 5); 071 072 gbc.fill = GridBagConstraints.HORIZONTAL; 073 gbc.gridx = 0; 074 gbc.gridy = 0; 075 root.add(new JLabel(I18n.tr("Image actions")), gbc); 076 077 gbc.fill = GridBagConstraints.HORIZONTAL; 078 gbc.weightx = 0.5; 079 gbc.gridx = 0; 080 gbc.gridy = 1; 081 root.add(new JLabel(I18n.tr("Image key")), gbc); 082 083 gbc.fill = GridBagConstraints.HORIZONTAL; 084 gbc.weightx = 0.5; 085 gbc.gridx = 0; 086 gbc.gridy = 2; 087 root.add(new JLabel(I18n.tr("Sequence key")), gbc); 088 089 gbc.fill = GridBagConstraints.HORIZONTAL; 090 gbc.gridx = 1; 091 gbc.gridy = 0; 092 root.add(new StreetsideButton(imgLinkAction, true), gbc); 093 094 gbc.fill = GridBagConstraints.HORIZONTAL; 095 gbc.weightx = 0.5; 096 gbc.gridx = 1; 097 gbc.gridy = 1; 098 root.add(imgKeyValue, gbc); 099 100 gbc.fill = GridBagConstraints.HORIZONTAL; 101 gbc.weightx = 0.5; 102 gbc.gridx = 1; 103 gbc.gridy = 2; 104 root.add(seqKeyValue, gbc); 105 106 gbc.fill = GridBagConstraints.HORIZONTAL; 107 gbc.weightx = 0.5; 108 gbc.gridx = 2; 109 gbc.gridy = 1; 110 root.add(copyButton, gbc); 111 112 createLayout(root, true, null); 113 selectedImageChanged(null, null); 114 } 115 116 public static ImageInfoPanel getInstance() { 117 synchronized (ImageInfoPanel.class) { 118 if (instance == null) { 119 instance = new ImageInfoPanel(); 120 } 121 return instance; 122 } 123 } 124 125 /** 126 * Destroys the unique instance of the class. 127 */ 128 public static synchronized void destroyInstance() { 129 instance = null; 130 } 131 132 /* (non-Javadoc) 133 * @see org.openstreetmap.josm.gui.dialogs.ToggleDialog#stateChanged() 134 */ 135 @Override 136 protected void stateChanged() { 137 super.stateChanged(); 138 if (isDialogShowing()) { // If the user opens the dialog once, no longer show the help message 139 StreetsideProperties.IMAGEINFO_HELP_COUNTDOWN.put(0); 140 } 141 } 142 143 /* (non-Javadoc) 144 * @see org.openstreetmap.josm.plugins.streetside.StreetsideDataListener#imagesAdded() 145 */ 146 @Override 147 public void imagesAdded() { 148 // Method is not needed, but enforcesd by the interface StreetsideDataListener 149 } 150 151 /* (non-Javadoc) 152 * @see org.openstreetmap.josm.plugins.streetside.StreetsideDataListener#selectedImageChanged(org.openstreetmap.josm.plugins.streetside.StreetsideAbstractImage, org.openstreetmap.josm.plugins.streetside.StreetsideAbstractImage) 153 */ 154 @Override 155 public synchronized void selectedImageChanged(final StreetsideAbstractImage oldImage, final StreetsideAbstractImage newImage) { 156 logger.info(String.format( 157 "Selected Streetside image changed from %s to %s.", 158 oldImage instanceof StreetsideImage ? ((StreetsideImage) oldImage).getId() : "‹none›", 159 newImage instanceof StreetsideImage ? ((StreetsideImage) newImage).getId() : "‹none›" 160 )); 161 162 imgKeyValue.setEnabled(newImage instanceof StreetsideImage); 163 final String newImageKey = newImage instanceof StreetsideImage ? ((StreetsideImage) newImage).getId(): null; 164 if (newImageKey != null) { 165 imageLinkChangeListener = b -> imgLinkAction.setURL( 166 StreetsideURL.MainWebsite.browseImage(newImageKey) 167 ); 168 imageLinkChangeListener.valueChanged(null); 169 StreetsideProperties.IMAGE_LINK_TO_BLUR_EDITOR.addListener(imageLinkChangeListener); 170 171 imgKeyValue.setText(newImageKey); 172 copyImgKeyAction.setContents(new StringSelection(newImageKey)); 173 addStreetsideTagAction.setTag(new Tag("streetside", newImageKey)); 174 } else { 175 if (imageLinkChangeListener != null) { 176 StreetsideProperties.IMAGE_LINK_TO_BLUR_EDITOR.removeListener(imageLinkChangeListener); 177 imageLinkChangeListener = null; 178 } 179 imgLinkAction.setURL(null); 180 181 imgKeyValue.setText('‹' + I18n.tr("image has no key") + '›'); 182 copyImgKeyAction.setContents(null); 183 addStreetsideTagAction.setTag(null); 184 } 185 186 final boolean partOfSequence = newImage != null && newImage.getSequence() != null && newImage.getSequence().getId() != null; 187 seqKeyValue.setEnabled(partOfSequence); 188 if (partOfSequence) { 189 seqKeyValue.setText(newImage.getSequence().getId()); 190 } else { 191 seqKeyValue.setText('‹' + I18n.tr("sequence has no id") + '›'); 192 } 193 } 194 195 /* (non-Javadoc) 196 * @see org.openstreetmap.josm.data.SelectionChangedListener#selectionChanged(java.util.Collection) 197 */ 198 @Override 199 public synchronized void selectionChanged(final SelectionChangeEvent event) { 200 final Collection<? extends OsmPrimitive> sel = event.getSelection(); 201 if (StreetsideProperties.DEBUGING_ENABLED.get()) { 202 logger.debug(String.format("Selection changed. %d primitives are selected.", sel == null ? 0 : sel.size())); 203 } 204 addStreetsideTagAction.setTarget(sel != null && sel.size() == 1 ? sel.iterator().next() : null); 205 } 206}