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