    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}