001// License: GPL. For details, see LICENSE file. 002package org.openstreetmap.josm.plugins.streetside.gui; 003 004import java.awt.BorderLayout; 005import java.awt.Color; 006import java.awt.GridBagConstraints; 007import java.awt.GridBagLayout; 008import java.awt.event.ActionEvent; 009import java.io.IOException; 010import java.io.InputStream; 011 012import javax.imageio.ImageIO; 013import javax.swing.AbstractAction; 014import javax.swing.BorderFactory; 015import javax.swing.Box; 016import javax.swing.BoxLayout; 017import javax.swing.ImageIcon; 018import javax.swing.JButton; 019import javax.swing.JCheckBox; 020import javax.swing.JComboBox; 021import javax.swing.JLabel; 022import javax.swing.JPanel; 023import javax.swing.JScrollPane; 024import javax.swing.JSpinner; 025import javax.swing.SpinnerNumberModel; 026import javax.swing.SwingUtilities; 027 028import org.apache.log4j.Logger; 029import org.openstreetmap.josm.actions.ExpertToggleAction; 030import org.openstreetmap.josm.gui.preferences.PreferenceTabbedPane; 031import org.openstreetmap.josm.gui.preferences.SubPreferenceSetting; 032import org.openstreetmap.josm.gui.preferences.TabPreferenceSetting; 033import org.openstreetmap.josm.gui.preferences.plugin.PluginPreference; 034import org.openstreetmap.josm.plugins.streetside.StreetsidePlugin; 035import org.openstreetmap.josm.plugins.streetside.gui.boilerplate.StreetsideButton; 036import org.openstreetmap.josm.plugins.streetside.io.download.StreetsideDownloader.DOWNLOAD_MODE; 037import org.openstreetmap.josm.plugins.streetside.oauth.OAuthPortListener; 038import org.openstreetmap.josm.plugins.streetside.oauth.StreetsideLoginListener; 039import org.openstreetmap.josm.plugins.streetside.oauth.StreetsideUser; 040import org.openstreetmap.josm.plugins.streetside.utils.StreetsideColorScheme; 041import org.openstreetmap.josm.plugins.streetside.utils.StreetsideProperties; 042import org.openstreetmap.josm.tools.GBC; 043import org.openstreetmap.josm.tools.I18n; 044import org.openstreetmap.josm.tools.ImageProvider; 045 046/** 047 * Creates the preferences panel for the plugin. 048 * 049 * @author nokutu 050 * 051 */ 052public class StreetsidePreferenceSetting implements SubPreferenceSetting, StreetsideLoginListener { 053 054 static final Logger logger = Logger.getLogger(StreetsidePreferenceSetting.class); 055 056 private final JComboBox<String> downloadModeComboBox = new JComboBox<>(new String[]{ 057 DOWNLOAD_MODE.VISIBLE_AREA.getLabel(), 058 DOWNLOAD_MODE.OSM_AREA.getLabel(), 059 DOWNLOAD_MODE.MANUAL_ONLY.getLabel() 060 }); 061 062 private final JCheckBox displayHour = 063 new JCheckBox(I18n.tr("Display hour when the picture was taken"), StreetsideProperties.DISPLAY_HOUR.get()); 064 private final JCheckBox format24 = 065 new JCheckBox(I18n.tr("Use 24 hour format"), StreetsideProperties.TIME_FORMAT_24.get()); 066 private final JCheckBox moveTo = 067 new JCheckBox(I18n.tr("Move to picture''s location with next/previous buttons"), StreetsideProperties.MOVE_TO_IMG.get()); 068 private final JCheckBox hoverEnabled = 069 new JCheckBox(I18n.tr("Preview images when hovering its icon"), StreetsideProperties.HOVER_ENABLED.get()); 070 private final JCheckBox cutOffSeq = 071 new JCheckBox(I18n.tr("Cut off sequences at download bounds"), StreetsideProperties.CUT_OFF_SEQUENCES_AT_BOUNDS.get()); 072 private final JCheckBox imageLinkToBlurEditor = 073 new JCheckBox( 074 I18n.tr("When opening Streetside image in web browser, show the blur editor instead of the image viewer"), 075 StreetsideProperties.IMAGE_LINK_TO_BLUR_EDITOR.get() 076 ); 077 private final JCheckBox developer = 078 new JCheckBox(I18n.tr("Enable experimental beta-features (might be unstable)"), StreetsideProperties.DEVELOPER.get()); 079 private final SpinnerNumberModel preFetchSize = new SpinnerNumberModel( 080 StreetsideProperties.PRE_FETCH_IMAGE_COUNT.get().intValue(), 081 0, 082 Integer.MAX_VALUE, 083 1 084 ); 085 private final JButton loginButton = new StreetsideButton(new LoginAction(this)); 086 private final JButton logoutButton = new StreetsideButton(new LogoutAction()); 087 private final JLabel loginLabel = new JLabel(); 088 private final JPanel loginPanel = new JPanel(); 089 090 @Override 091 public TabPreferenceSetting getTabPreferenceSetting(PreferenceTabbedPane gui) { 092 return gui.getPluginPreference(); 093 } 094 095 @Override 096 public void addGui(PreferenceTabbedPane gui) { 097 JPanel container = new JPanel(new BorderLayout()); 098 099 loginPanel.setLayout(new BoxLayout(loginPanel, BoxLayout.LINE_AXIS)); 100 loginPanel.setBorder(BorderFactory.createEmptyBorder(10, 10, 10, 10)); 101 loginPanel.setBackground(StreetsideColorScheme.TOOLBAR_DARK_GREY); 102 JLabel brandImage = new JLabel(); 103 try (InputStream is = StreetsidePreferenceSetting.class.getResourceAsStream("/images/streetside-logo-white.png")) { 104 if (is != null) { 105 brandImage.setIcon(new ImageIcon(ImageIO.read(is))); 106 } else { 107 logger.warn("Could not load Streetside brand image!"); 108 } 109 } catch (IOException e) { 110 logger.warn("While reading Streetside brand image, an IO-exception occured!"); 111 } 112 loginPanel.add(brandImage, 0); 113 loginPanel.add(Box.createHorizontalGlue(), 1); 114 loginLabel.setForeground(Color.WHITE); 115 loginLabel.setBorder(BorderFactory.createEmptyBorder(0, 10, 0, 10)); 116 loginPanel.add(loginLabel, 2); 117 loginPanel.add(loginButton, 3); 118 onLogout(); 119 container.add(loginPanel, BorderLayout.NORTH); 120 121 JPanel mainPanel = new JPanel(); 122 mainPanel.setLayout(new GridBagLayout()); 123 mainPanel.setBorder(BorderFactory.createEmptyBorder(5, 5, 5, 5)); 124 125 downloadModeComboBox.setSelectedItem(DOWNLOAD_MODE.fromPrefId(StreetsideProperties.DOWNLOAD_MODE.get()).getLabel()); 126 127 JPanel downloadModePanel = new JPanel(); 128 downloadModePanel.add(new JLabel(I18n.tr("Download mode"))); 129 downloadModePanel.add(downloadModeComboBox); 130 mainPanel.add(downloadModePanel, GBC.eol()); 131 132 mainPanel.add(displayHour, GBC.eol()); 133 mainPanel.add(format24, GBC.eol()); 134 mainPanel.add(moveTo, GBC.eol()); 135 mainPanel.add(hoverEnabled, GBC.eol()); 136 mainPanel.add(cutOffSeq, GBC.eol()); 137 mainPanel.add(imageLinkToBlurEditor, GBC.eol()); 138 139 final JPanel preFetchPanel = new JPanel(); 140 preFetchPanel.add(new JLabel(I18n.tr("Number of images to be pre-fetched (forwards and backwards)"))); 141 final JSpinner spinner = new JSpinner(preFetchSize); 142 final JSpinner.DefaultEditor editor = new JSpinner.NumberEditor(spinner); 143 editor.getTextField().setColumns(3); 144 spinner.setEditor(editor); 145 preFetchPanel.add(spinner); 146 mainPanel.add(preFetchPanel, GBC.eol()); 147 148 if (ExpertToggleAction.isExpert() || developer.isSelected()) { 149 mainPanel.add(developer, GBC.eol()); 150 } 151 StreetsideColorScheme.styleAsDefaultPanel( 152 mainPanel, downloadModePanel, displayHour, format24, moveTo, hoverEnabled, cutOffSeq, imageLinkToBlurEditor, developer, preFetchPanel 153 ); 154 mainPanel.add(Box.createVerticalGlue(), GBC.eol().fill(GridBagConstraints.BOTH)); 155 156 container.add(mainPanel, BorderLayout.CENTER); 157 158 final PluginPreference pluginPreference = gui.getPluginPreference(); 159 pluginPreference.addSubTab(this, "Streetside", new JScrollPane(container)); 160 pluginPreference.getTabPane().setIconAt(pluginPreference.getTabPane().getTabCount()-1, StreetsidePlugin.LOGO.setSize(ImageProvider.ImageSizes.MENU).get()); 161 162 163 SwingUtilities.invokeLater(() -> { 164 String username = StreetsideUser.getUsername(); 165 if (username != null) { 166 SwingUtilities.invokeLater(() -> onLogin(StreetsideUser.getUsername())); 167 } 168 }); 169 } 170 171 @Override 172 public void onLogin(final String username) { 173 loginPanel.remove(loginButton); 174 loginPanel.add(logoutButton, 3); 175 loginLabel.setText(I18n.tr("You are logged in as ''{0}''.", username)); 176 loginPanel.revalidate(); 177 loginPanel.repaint(); 178 } 179 180 @Override 181 public void onLogout() { 182 loginPanel.remove(logoutButton); 183 loginPanel.add(loginButton, 3); 184 loginLabel.setText(I18n.tr("You are currently not logged in.")); 185 loginPanel.revalidate(); 186 loginPanel.repaint(); 187 } 188 189 @SuppressWarnings("PMD.ShortMethodName") 190 @Override 191 public boolean ok() { 192 StreetsideProperties.DOWNLOAD_MODE.put(DOWNLOAD_MODE.fromLabel(downloadModeComboBox.getSelectedItem().toString()).getPrefId()); 193 StreetsideProperties.DISPLAY_HOUR.put(displayHour.isSelected()); 194 StreetsideProperties.TIME_FORMAT_24.put(format24.isSelected()); 195 StreetsideProperties.MOVE_TO_IMG.put(moveTo.isSelected()); 196 StreetsideProperties.HOVER_ENABLED.put(hoverEnabled.isSelected()); 197 StreetsideProperties.CUT_OFF_SEQUENCES_AT_BOUNDS.put(cutOffSeq.isSelected()); 198 StreetsideProperties.IMAGE_LINK_TO_BLUR_EDITOR.put(imageLinkToBlurEditor.isSelected()); 199 StreetsideProperties.DEVELOPER.put(developer.isSelected()); 200 StreetsideProperties.PRE_FETCH_IMAGE_COUNT.put(preFetchSize.getNumber().intValue()); 201 202 //Restart is never required 203 return false; 204 } 205 206 @Override 207 public boolean isExpert() { 208 return false; 209 } 210 211 /** 212 * Opens the StreetsideOAuthUI window and lets the user log in. 213 * 214 * @author nokutu 215 * 216 */ 217 private static class LoginAction extends AbstractAction { 218 219 private static final long serialVersionUID = 8743119160917296506L; 220 221 private final transient StreetsideLoginListener callback; 222 223 LoginAction(StreetsideLoginListener loginCallback) { 224 super(I18n.tr("Login")); 225 callback = loginCallback; 226 } 227 228 @Override 229 public void actionPerformed(ActionEvent arg0) { 230 OAuthPortListener portListener = new OAuthPortListener(callback); 231 portListener.start(); 232 // user authentication not supported for Streetside (Mapillary relic) 233 } 234 } 235 236 /** 237 * Logs the user out. 238 * 239 * @author nokutu 240 * 241 */ 242 private class LogoutAction extends AbstractAction { 243 244 private static final long serialVersionUID = -4146587895393766981L; 245 246 private LogoutAction() { 247 super(I18n.tr("Logout")); 248 } 249 250 @Override 251 public void actionPerformed(ActionEvent arg0) { 252 StreetsideUser.reset(); 253 onLogout(); 254 } 255 } 256}