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