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