/*
  * (non-Javadoc)
  *
  * @see org.jajuk.ui.Observer#update(java.lang.String)
  */
 public void update(Event event) {
   EventSubject subject = event.getSubject();
   // Make a search after a stop period
   if (subject.equals(EventSubject.EVENT_FILE_LAUNCHED)
       || subject.equals(EventSubject.EVENT_PERPECTIVE_CHANGED)) {
     // Do not perform search if current perspective is not info for
     // perfs
     if (!(PerspectiveManager.getCurrentPerspective() instanceof InfoPerspective)) {
       return;
     }
     // If current state is stopped, reset page
     if (FIFO.getInstance().getCurrentFile() == null) {
       reset();
       return;
     }
     // Launch search
     launchSearch(false);
   }
   // Reset the page when stopping
   else if (subject.equals(EventSubject.EVENT_ZERO)) {
     reset();
   }
   // User changed current track tags, so we have to reload
   // new author wikipedia page
   else if (subject.equals(EventSubject.EVENT_AUTHOR_CHANGED)
       || subject.equals(EventSubject.EVENT_ALBUM_CHANGED)
       || subject.equals(EventSubject.EVENT_TRACK_CHANGED)) {
     update(new Event(EventSubject.EVENT_FILE_LAUNCHED));
   }
 }
 /*
  * (non-Javadoc)
  *
  * @see java.awt.event.ActionListener#actionPerformed(java.awt.event.ActionEvent)
  */
 public void actionPerformed(final ActionEvent ae) {
   // do not run this in a separate thread because Player actions would die
   // with the thread
   try {
     if (ae.getSource() == jcbHistory) {
       HistoryItem hi;
       hi = History.getInstance().getHistoryItem(jcbHistory.getSelectedIndex());
       if (hi != null) {
         org.jajuk.base.File file = FileManager.getInstance().getFileByID(hi.getFileId());
         if (file != null) {
           try {
             FIFO.getInstance()
                 .push(
                     new StackItem(file, ConfigurationManager.getBoolean(CONF_STATE_REPEAT), true),
                     ConfigurationManager.getBoolean(CONF_OPTIONS_DEFAULT_ACTION_CLICK));
           } catch (JajukException je) {
             // can be thrown if file is null
           }
         } else {
           Messages.showErrorMessage(120);
           jcbHistory.setSelectedItem(null);
         }
       }
     } else if (ae.getSource().equals(jmiNoveltiesModeSong)) {
       ConfigurationManager.setProperty(CONF_NOVELTIES_MODE, MODE_TRACK);
     } else if (ae.getSource().equals(jmiNoveltiesModeAlbum)) {
       ConfigurationManager.setProperty(CONF_NOVELTIES_MODE, MODE_ALBUM);
     } else if (ae.getSource().equals(jmiShuffleModeSong)) {
       ConfigurationManager.setProperty(CONF_GLOBAL_RANDOM_MODE, MODE_TRACK);
     } else if (ae.getSource().equals(jmiShuffleModeAlbum)) {
       ConfigurationManager.setProperty(CONF_GLOBAL_RANDOM_MODE, MODE_ALBUM);
     } else if (ae.getSource().equals(jmiShuffleModeAlbum2)) {
       ConfigurationManager.setProperty(CONF_GLOBAL_RANDOM_MODE, MODE_ALBUM2);
     } else if (ae.getSource().equals(jmiShuffleModeAlbum2)) {
       ConfigurationManager.setProperty(CONF_GLOBAL_RANDOM_MODE, MODE_ALBUM2);
     }
   } catch (Exception e) {
     Log.error(e);
   } finally {
     ObservationManager.notify(new Event(EventSubject.EVENT_PLAYLIST_REFRESH));
   }
 }
  public void initUI() {
    // Search
    double[][] sizeSearch = new double[][] {{3, TableLayout.PREFERRED, 3, 100}, {25}};
    JPanel jpSearch = new JPanel(new TableLayout(sizeSearch));
    sbSearch = new SearchBox(CommandJPanel.this);
    JLabel jlSearch = new JLabel(IconLoader.ICON_SEARCH);
    jlSearch.setToolTipText(Messages.getString("CommandJPanel.23"));
    // Clear search text when clicking on the search icon
    jlSearch.addMouseListener(
        new MouseAdapter() {
          @Override
          public void mouseClicked(MouseEvent e) {
            sbSearch.setText("");
          }
        });
    jpSearch.add(jlSearch, "1,0");
    jpSearch.add(sbSearch, "3,0");

    // History
    JPanel jpHistory = new JPanel();
    jcbHistory = new SteppedComboBox();
    JLabel jlHistory = new JLabel(IconLoader.ICON_HISTORY);
    jlHistory.setToolTipText(Messages.getString("CommandJPanel.0"));
    // - Increase rating button
    ActionBase actionIncRate = ActionManager.getAction(JajukAction.INC_RATE);
    actionIncRate.setName(null);
    final JPopupMenu jpmIncRating = new JPopupMenu();
    for (int i = 1; i <= 10; i++) {
      final int j = i;
      JMenuItem jmi = new JMenuItem("+" + i);
      if (ConfigurationManager.getInt(CONF_INC_RATING) == i) {
        jmi.setFont(FontManager.getInstance().getFont(JajukFont.BOLD));
      }
      // Store selected value
      jmi.addActionListener(
          new ActionListener() {
            public void actionPerformed(ActionEvent e) {
              ConfigurationManager.setProperty(CONF_INC_RATING, "" + j);
            }
          });
      jpmIncRating.add(jmi);
    }
    jbIncRate =
        new DropDownButton(IconLoader.ICON_INC_RATING) {
          private static final long serialVersionUID = 1L;

          @Override
          protected JPopupMenu getPopupMenu() {
            return jpmIncRating;
          }
        };
    jbIncRate.setAction(actionIncRate);
    // we use a combo box model to make sure we get good performances after
    // rebuilding the entire model like after a refresh
    jcbHistory.setModel(new DefaultComboBoxModel(History.getInstance().getHistory()));
    // None selection because if we start in stop mode, a selection of the
    // first item will not launch the track because the selected item is
    // still the same and no action event is thrown (Java >= 1.6)
    jcbHistory.setSelectedItem(null);
    int iWidth = (int) (Toolkit.getDefaultToolkit().getScreenSize().getWidth() / 2);
    // size of popup
    jcbHistory.setPopupWidth(iWidth);
    // size of the combo itself, keep it! as text can be very long
    jcbHistory.setPreferredSize(new Dimension(250, 25));
    jcbHistory.setMinimumSize(new Dimension(0, 25));
    jcbHistory.setToolTipText(Messages.getString("CommandJPanel.0"));
    jcbHistory.addActionListener(CommandJPanel.this);
    JToolBar jtbIncRate = new JToolBar();
    jtbIncRate.setFloatable(false);
    jbIncRate.addToToolBar(jtbIncRate);
    double[][] sizeHistory =
        new double[][] {
          {3, TableLayout.PREFERRED, 3, TableLayout.FILL, 10, TableLayout.PREFERRED}, {25}
        };
    jpHistory.setLayout(new TableLayout(sizeHistory));
    jpHistory.add(jlHistory, "1,0");
    jpHistory.add(jcbHistory, "3,0");
    jpHistory.add(jtbIncRate, "5,0");

    // Mode toolbar
    // we need an inner toolbar to apply size properly
    JToolBar jtbModes = new JToolBar();
    jtbModes.setBorder(null);
    // make it not floatable as this behavior is managed by vldocking
    jtbModes.setFloatable(false);
    jtbModes.setRollover(true);
    jbRepeat =
        new JajukToggleButton(ActionManager.getAction(JajukAction.REPEAT_MODE_STATUS_CHANGE));
    jbRepeat.setSelected(ConfigurationManager.getBoolean(CONF_STATE_REPEAT));
    jbRandom =
        new JajukToggleButton(ActionManager.getAction(JajukAction.SHUFFLE_MODE_STATUS_CHANGED));
    jbRandom.setSelected(ConfigurationManager.getBoolean(CONF_STATE_SHUFFLE));
    jbContinue =
        new JajukToggleButton(ActionManager.getAction(JajukAction.CONTINUE_MODE_STATUS_CHANGED));
    jbContinue.setSelected(ConfigurationManager.getBoolean(CONF_STATE_CONTINUE));
    jbIntro = new JajukToggleButton(ActionManager.getAction(JajukAction.INTRO_MODE_STATUS_CHANGED));
    jbIntro.setSelected(ConfigurationManager.getBoolean(CONF_STATE_INTRO));
    jtbModes.add(jbRepeat);
    jtbModes.addSeparator();
    jtbModes.add(jbRandom);
    jtbModes.addSeparator();
    jtbModes.add(jbContinue);
    jtbModes.addSeparator();
    jtbModes.add(jbIntro);

    // Volume
    jpVolume = new JPanel();
    ActionUtil.installKeystrokes(
        jpVolume,
        ActionManager.getAction(JajukAction.DECREASE_VOLUME),
        ActionManager.getAction(JajukAction.INCREASE_VOLUME));

    jpVolume.setLayout(new BoxLayout(jpVolume, BoxLayout.X_AXIS));
    int iVolume = (int) (100 * ConfigurationManager.getFloat(CONF_VOLUME));
    if (iVolume > 100) { // can occur in some undefined cases
      iVolume = 100;
    }
    jsVolume = new JSlider(0, 100, iVolume);
    jpVolume.add(jsVolume);
    jpVolume.add(Box.createHorizontalStrut(5));
    jpVolume.add(jbMute);
    jsVolume.setToolTipText(Messages.getString("CommandJPanel.14"));
    jsVolume.addChangeListener(CommandJPanel.this);
    jsVolume.addMouseWheelListener(CommandJPanel.this);

    // Special functions toolbar
    // Ambience combo
    ambiencesCombo = new SteppedComboBox();
    iWidth = (int) (Toolkit.getDefaultToolkit().getScreenSize().getWidth() / 4);
    ambiencesCombo.setPopupWidth(iWidth);
    ambiencesCombo.setFont(FontManager.getInstance().getFont(JajukFont.BOLD_L));
    // size of the combo itself
    ambiencesCombo.setRenderer(
        new BasicComboBoxRenderer() {
          private static final long serialVersionUID = -6943363556191659895L;

          public Component getListCellRendererComponent(
              JList list, Object value, int index, boolean isSelected, boolean cellHasFocus) {
            super.getListCellRendererComponent(list, value, index, isSelected, cellHasFocus);
            JLabel jl = (JLabel) value;
            setIcon(jl.getIcon());
            setText(jl.getText());
            return this;
          }
        });
    ambiencesCombo.setToolTipText(Messages.getString("DigitalDJWizard.66"));
    populateAmbiences();
    ambienceListener = new AmbienceListener();
    ambiencesCombo.addActionListener(ambienceListener);
    jtbSpecial = new JToolBar();
    jtbSpecial.setBorder(null);
    jtbSpecial.setRollover(true);
    jtbSpecial.setFloatable(false);
    ddbGlobalRandom =
        new DropDownButton(IconLoader.ICON_SHUFFLE_GLOBAL) {
          private static final long serialVersionUID = 1L;

          @Override
          protected JPopupMenu getPopupMenu() {
            return popupGlobalRandom;
          }
        };
    ddbGlobalRandom.setAction(ActionManager.getAction(JajukAction.SHUFFLE_GLOBAL));
    popupGlobalRandom = new JPopupMenu();
    // Global shuffle
    jmiShuffleModeSong = new JRadioButtonMenuItem(Messages.getString("CommandJPanel.20"));
    jmiShuffleModeSong.addActionListener(this);
    // album / album
    jmiShuffleModeAlbum = new JRadioButtonMenuItem(Messages.getString("CommandJPanel.21"));
    jmiShuffleModeAlbum.addActionListener(this);
    // Shuffle album / album
    jmiShuffleModeAlbum2 = new JRadioButtonMenuItem(Messages.getString("CommandJPanel.22"));
    jmiShuffleModeAlbum2.addActionListener(this);
    if (ConfigurationManager.getProperty(CONF_GLOBAL_RANDOM_MODE).equals(MODE_TRACK)) {
      jmiShuffleModeSong.setSelected(true);
    } else if (ConfigurationManager.getProperty(CONF_GLOBAL_RANDOM_MODE).equals(MODE_ALBUM2)) {
      jmiShuffleModeAlbum2.setSelected(true);
    } else {
      jmiShuffleModeAlbum.setSelected(true);
    }
    ButtonGroup bgGlobalRandom = new ButtonGroup();
    bgGlobalRandom.add(jmiShuffleModeSong);
    bgGlobalRandom.add(jmiShuffleModeAlbum);
    bgGlobalRandom.add(jmiShuffleModeAlbum2);
    popupGlobalRandom.add(jmiShuffleModeSong);
    popupGlobalRandom.add(jmiShuffleModeAlbum);
    popupGlobalRandom.add(jmiShuffleModeAlbum2);
    ddbGlobalRandom.setText(""); // no text visible

    jbBestof = new JajukButton(ActionManager.getAction(JajukAction.BEST_OF));

    ddbNovelties =
        new DropDownButton(IconLoader.ICON_NOVELTIES) {
          private static final long serialVersionUID = 1L;

          @Override
          protected JPopupMenu getPopupMenu() {
            return popupNovelties;
          }
        };
    ddbNovelties.setAction(ActionManager.getAction(JajukAction.NOVELTIES));
    popupNovelties = new JPopupMenu();
    jmiNoveltiesModeSong = new JRadioButtonMenuItem(Messages.getString("CommandJPanel.20"));
    jmiNoveltiesModeSong.addActionListener(this);
    jmiNoveltiesModeAlbum = new JRadioButtonMenuItem(Messages.getString("CommandJPanel.22"));
    jmiNoveltiesModeAlbum.addActionListener(this);
    if (ConfigurationManager.getProperty(CONF_NOVELTIES_MODE).equals(MODE_TRACK)) {
      jmiNoveltiesModeSong.setSelected(true);
    } else {
      jmiNoveltiesModeAlbum.setSelected(true);
    }
    ButtonGroup bgNovelties = new ButtonGroup();
    bgNovelties.add(jmiNoveltiesModeSong);
    bgNovelties.add(jmiNoveltiesModeAlbum);
    popupNovelties.add(jmiNoveltiesModeSong);
    popupNovelties.add(jmiNoveltiesModeAlbum);
    ddbNovelties.setText(""); // no text visible

    jbNorm = new JajukButton(ActionManager.getAction(FINISH_ALBUM));
    popupDDJ = new JPopupMenu();
    ddbDDJ =
        new DropDownButton(IconLoader.ICON_DIGITAL_DJ) {
          private static final long serialVersionUID = 1L;

          @Override
          protected JPopupMenu getPopupMenu() {
            return popupDDJ;
          }
        };
    ddbDDJ.setAction(ActionManager.getAction(JajukAction.DJ));
    populateDJs();
    // no text visible
    ddbDDJ.setText("");

    popupWebRadio = new XJPopupMenu(Main.getWindow());
    ddbWebRadio =
        new DropDownButton(IconLoader.ICON_WEBRADIO) {
          private static final long serialVersionUID = 1L;

          @Override
          protected JPopupMenu getPopupMenu() {
            return popupWebRadio;
          }
        };
    ddbWebRadio.setAction(ActionManager.getAction(JajukAction.WEB_RADIO));
    populateWebRadios();
    // no text
    ddbWebRadio.setText("");

    ddbDDJ.addToToolBar(jtbSpecial);
    ddbNovelties.addToToolBar(jtbSpecial);
    ddbGlobalRandom.addToToolBar(jtbSpecial);
    jtbSpecial.add(jbBestof);
    jtbSpecial.add(jbNorm);

    // Radio tool bar
    JToolBar jtbWebRadio = new JToolBar();
    jtbWebRadio.setBorder(null);
    jtbWebRadio.setRollover(true);
    jtbWebRadio.setFloatable(false);
    ddbWebRadio.addToToolBar(jtbWebRadio);

    // Play toolbar
    JToolBar jtbPlay = new JToolBar();
    jtbPlay.setBorder(null);
    jtbPlay.setFloatable(false);
    // add some space to get generic size
    jtbPlay.setRollover(true);
    ActionUtil.installKeystrokes(
        jtbPlay, ActionManager.getAction(NEXT_ALBUM), ActionManager.getAction(PREVIOUS_ALBUM));
    jbPrevious = new JajukButton(ActionManager.getAction(PREVIOUS_TRACK));
    jbNext = new JajukButton(ActionManager.getAction(NEXT_TRACK));
    jbRew = new JPressButton(ActionManager.getAction(REWIND_TRACK));
    jbPlayPause = new JajukButton(ActionManager.getAction(PLAY_PAUSE_TRACK));
    jbStop = new JajukButton(ActionManager.getAction(STOP_TRACK));
    jbFwd = new JPressButton(ActionManager.getAction(FAST_FORWARD_TRACK));

    jtbPlay.add(jbPrevious);
    jtbPlay.add(jbRew);
    jtbPlay.add(jbPlayPause);
    jtbPlay.add(jbStop);
    jtbPlay.add(jbFwd);
    jtbPlay.add(jbNext);

    // Add items
    FormLayout layout =
        new FormLayout(
            // --columns
            "3dlu,fill:min(10dlu;p):grow(0.5), 3dlu, "
                + // ambience
                "left:p, 2dlu"
                + // smart toolbar
                ", min(0dlu;p):grow(0.04), 3dlu,"
                + // glue
                " right:p, 10dlu, "
                + // search /modes
                "fill:p, 5dlu, "
                + // history/player
                "fill:min(60dlu;p):grow(0.2),3dlu", // volume/part of
            // history
            // --rows
            "2dlu, p, 2dlu, p, 2dlu"); // rows
    PanelBuilder builder = new PanelBuilder(layout); // , new
    // FormDebugPanel() );
    CellConstraints cc = new CellConstraints();
    // Add items
    builder.add(jtbWebRadio, cc.xyw(2, 2, 3)); // grid width = 3
    builder.add(ambiencesCombo, cc.xy(2, 4));
    builder.add(jtbSpecial, cc.xy(4, 4));
    builder.add(jpSearch, cc.xyw(6, 2, 4));
    builder.add(jpHistory, cc.xyw(10, 2, 4));
    builder.add(jtbModes, cc.xy(8, 4));
    builder.add(jtbPlay, cc.xy(10, 4));
    builder.add(jpVolume, cc.xy(12, 4));
    JPanel p = builder.getPanel();
    setLayout(new BoxLayout(this, BoxLayout.X_AXIS));
    add(p);
    // register to player events
    ObservationManager.register(CommandJPanel.this);

    // if a track is playing, display right state
    if (FIFO.getInstance().getCurrentFile() != null) {
      // update initial state
      update(
          new Event(
              EventSubject.EVENT_PLAYER_PLAY,
              ObservationManager.getDetailsLastOccurence(EventSubject.EVENT_PLAYER_PLAY)));
      // update the history bar
      update(new Event(EventSubject.EVENT_FILE_LAUNCHED));
      // check if some track has been launched before the view has been
      // displayed
      update(new Event(EventSubject.EVENT_HEART_BEAT));
    }
    // start timer
    timer.start();
  }
  /*
   * (non-Javadoc)
   *
   * @see org.jajuk.ui.views.IView#populate()
   */
  public void initUI() {
    jlLanguage = new JLabel(Messages.getString("WikipediaView.1"));
    jcbLanguage = new JComboBox();
    for (String sDesc : Messages.getDescs()) {
      jcbLanguage.addItem(sDesc);
    }
    // get stored language
    jcbLanguage.setSelectedItem(
        Messages.getDescForLocal(ConfigurationManager.getProperty(CONF_WIKIPEDIA_LANGUAGE)));
    jcbLanguage.addActionListener(this);
    // Buttons
    ActionBase aCopy = ActionManager.getAction(JajukAction.COPY_TO_CLIPBOARD);
    jbCopy = new JButton(aCopy);
    jbLaunchInExternalBrowser = new JButton(ActionManager.getAction(JajukAction.LAUNCH_IN_BROWSER));
    // Remove text inside the buttons
    jbLaunchInExternalBrowser.setText(null);
    jbCopy.setText(null);
    ButtonGroup bg = new ButtonGroup();
    jbAuthorSearch = new JToggleButton(IconLoader.ICON_AUTHOR, false);
    jbAuthorSearch.setToolTipText(Messages.getString("WikipediaView.5"));
    // Select author search (default)
    jbAuthorSearch.setSelected(true);
    jbAuthorSearch.addActionListener(this);
    jbAlbumSearch = new JToggleButton(IconLoader.ICON_ALBUM, true);
    jbAlbumSearch.setToolTipText(Messages.getString("WikipediaView.6"));
    jbAlbumSearch.addActionListener(this);
    jbTrackSearch = new JToggleButton(IconLoader.ICON_TRACK, false);
    jbTrackSearch.setToolTipText(Messages.getString("WikipediaView.7"));
    jbTrackSearch.addActionListener(this);
    // Group this three mutual exclusive buttons
    bg.add(jbAuthorSearch);
    bg.add(jbAlbumSearch);
    bg.add(jbTrackSearch);

    JToolBar jtb = new JToolBar();
    jtb.setFloatable(false);
    jtb.setRollover(true);
    jtb.setBorder(BorderFactory.createEmptyBorder(0, 5, 0, 5));
    // Add items
    jtb.add(jbAuthorSearch);
    jtb.add(jbAlbumSearch);
    jtb.add(jbTrackSearch);
    jtb.addSeparator();
    jtb.add(jbCopy);
    jtb.add(jbLaunchInExternalBrowser);
    jtb.addSeparator();
    jtb.add(jcbLanguage);

    JPanel jpCommand = new JPanel();
    jpCommand.setBorder(BorderFactory.createEtchedBorder());
    jpCommand.setLayout(new FlowLayout(FlowLayout.LEFT));
    jpCommand.add(jtb);

    // global layout
    double size[][] = {{2, TableLayout.FILL, 5}, {TableLayout.PREFERRED, 5, TableLayout.FILL}};
    setLayout(new TableLayout(size));
    browser = new JajukHtmlPanel();
    add(jpCommand, "1,0");
    add(browser, "1,2");

    // Display default page at startup is none track launch
    // avoid to launch this if a track is playing
    // to avoid thread concurrency
    if (FIFO.getInstance().getCurrentFile() == null) {
      reset();
    }

    // subscriptions to events
    ObservationManager.register(WikipediaView.this);

    // force event
    update(
        new Event(
            EventSubject.EVENT_FILE_LAUNCHED,
            ObservationManager.getDetailsLastOccurence(EventSubject.EVENT_FILE_LAUNCHED)));
  }