    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}