void updateGui() {
    final Font sysFont = pluginAuthorLabel.getFont();
    final Image img = plugin.getImage();
    final String description = plugin.getDescription();
    final String changesLog = plugin.getChangeLog();
    final String author = plugin.getAuthor();
    final String email = plugin.getEmail();
    final String web = plugin.getWeb();

    if (img == null) pluginImage.setImage(PluginDescriptor.DEFAULT_IMAGE);
    else pluginImage.setImage(img);

    if (StringUtil.isEmpty(description)) pluginDescriptionText.setText("No description");
    else {
      if (StringUtil.containHtmlCR(description))
        pluginDescriptionText.setText(StringUtil.removeCR(description));
      else pluginDescriptionText.setText(StringUtil.toHtmlCR(description));

      pluginDescriptionText.setCaretPosition(0);
    }

    ComponentUtil.setJTextPaneFont(pluginDescriptionText, sysFont, Color.black);

    if (StringUtil.isEmpty(changesLog)) pluginChangeLogText.setText("---");
    else {
      pluginChangeLogText.setText(StringUtil.toHtmlCR(changesLog));
      pluginChangeLogText.setCaretPosition(0);
    }
    ComponentUtil.setJTextPaneFont(
        pluginChangeLogText, new Font("courier", Font.PLAIN, 11), Color.black);
    if (StringUtil.isEmpty(author)) pluginAuthorLabel.setText("---");
    else pluginAuthorLabel.setText(author);
    if (StringUtil.isEmpty(email)) pluginEmailLabel.setText("---");
    else pluginEmailLabel.setText(email);
    if (StringUtil.isEmpty(web)) pluginWebsiteLabel.setText("---");
    else pluginWebsiteLabel.setText(web);

    pack();
  }
  private void refreshGUI() {
    spvp.getScrollPanel().removeAll();

    for (SwimmingObject result : Icy.getMainInterface().getSwimmingPool().getObjects()) {
      JPanel panel = new SwimmingPoolObjectPanel(result);
      ComponentUtil.setFixedHeight(panel, 40);
      spvp.getScrollPanel().add(panel);
    }

    spvp.getScrollPanel().add(Box.createVerticalGlue());

    String text = "No object in swimming pool.";

    int numberOfSwimmingObject = Icy.getMainInterface().getSwimmingPool().getObjects().size();
    if (numberOfSwimmingObject > 0) {
      text = "" + numberOfSwimmingObject + " objects in swimming pool.";
    }

    spvp.getNumberOfSwimmingObjectLabel().setText(text);

    spvp.getScrollPane().invalidate();
    spvp.getScrollPane().repaint();
  }
  @Override
  public void fillInterface(JPanel mainPanel) {
    setUIDisplayEnabled(true);

    flickr = new PluginFlickrFrontend(APP_KEY);
    provider = new FlickrThumbnailProvider(flickr);

    // Random
    ButtonGroup bgRandomSource = new ButtonGroup();
    rbInterestingness = new JRadioButton("Interestingness");
    bgRandomSource.add(rbInterestingness);
    rbRecent = new JRadioButton("Recent");
    bgRandomSource.add(rbRecent);
    rbInterestingness.setSelected(true);

    btGrabRandom = new JButton("Grab");
    btGrabRandom.addActionListener(this);

    JPanel randomPanel =
        GuiUtil.createLineBoxPanel(
            rbInterestingness,
            Box.createHorizontalGlue(),
            rbRecent,
            Box.createHorizontalGlue(),
            btGrabRandom);
    randomPanel.setBorder(new TitledBorder("Random image"));

    // Search
    tfTag = new JTextField();
    tfTag.addKeyListener(
        new KeyAdapter() {
          public void keyPressed(KeyEvent e) {
            int key = e.getKeyCode();
            if (key == KeyEvent.VK_ENTER) {
              grab(FlickrWorker.TYPE_TAGS, tfTag.getText());
            }
          }
        });
    ComponentUtil.setFixedSize(tfTag, new Dimension(300, 25));
    btGrabByTag = new JButton("Grab");
    btGrabByTag.addActionListener(this);

    JPanel searchPanel = GuiUtil.createLineBoxPanel(tfTag, Box.createHorizontalGlue(), btGrabByTag);
    searchPanel.setBorder(new TitledBorder("Search image"));

    // Expert
    tfExpert = new JTextField();
    tfExpert.addKeyListener(
        new KeyAdapter() {
          public void keyPressed(KeyEvent e) {
            int key = e.getKeyCode();
            if (key == KeyEvent.VK_ENTER) {
              grab(FlickrWorker.TYPE_EXPERT, tfExpert.getText());
            }
          }
        });
    ComponentUtil.setFixedSize(tfExpert, new Dimension(300, 25));
    btGrabByExpertQuery = new JButton("Grab");
    btGrabByExpertQuery.addActionListener(this);

    JPanel expertPanel =
        GuiUtil.createLineBoxPanel(tfExpert, Box.createHorizontalGlue(), btGrabByExpertQuery);
    expertPanel.setBorder(new TitledBorder("Expert query"));

    // Log window
    taLog = new JTextArea();
    taLog.setEditable(false);
    taLog.setLineWrap(true);
    taLog.setColumns(35);
    taLog.setRows(10);
    JScrollPane taLogScroll = new JScrollPane(taLog);
    taLogScroll.setVerticalScrollBarPolicy(JScrollPane.VERTICAL_SCROLLBAR_ALWAYS);

    // Progress bar
    btHelp = new JButton(NherveToolbox.questionIcon);
    btHelp.setToolTipText("About this plugin");
    btHelp.addActionListener(this);
    tfMaxToGrab = new JTextField("100");
    ComponentUtil.setFixedSize(tfMaxToGrab, new Dimension(50, 25));
    cbSingleImage = new JCheckBox("Single");
    pbProgress = new JProgressBar();
    JPanel progressPanel =
        GuiUtil.createLineBoxPanel(btHelp, tfMaxToGrab, cbSingleImage, pbProgress);

    // Frame stuff
    int spacing = 10;
    JPanel myPanel =
        GuiUtil.createPageBoxPanel(
            Box.createVerticalGlue(),
            randomPanel,
            Box.createVerticalStrut(spacing),
            searchPanel,
            Box.createVerticalStrut(spacing),
            expertPanel,
            Box.createVerticalStrut(spacing),
            progressPanel,
            Box.createVerticalStrut(spacing),
            taLogScroll,
            Box.createVerticalGlue());
    mainPanel.add(myPanel);
  }
 /** Implement setMaximized method */
 public void setMaximized(final boolean value) {
   ComponentUtil.setMaximized(this, value);
 }
 /** Implement isMaximized method */
 public boolean isMaximized() {
   return ComponentUtil.isMaximized(this);
 }
  /** @param plugin */
  public PluginDetailPanel(PluginDescriptor plugin) {
    super(plugin.getName() + " " + plugin.getVersion(), false, true);

    this.plugin = plugin;

    // changesLogButton = new ChangesLogActionButton();
    executeButton = new ExecuteActionButton();
    closeButton = new CloseActionButton();

    setPreferredSize(new Dimension(640, 480));

    // build top panel
    pluginDescriptionText = new JTextPane();
    pluginDescriptionText.setContentType("text/html");
    pluginDescriptionText.setEditable(false);
    pluginDescriptionText.setOpaque(false);
    pluginDescriptionText.addHyperlinkListener(this);
    ComponentUtil.setFixedHeight(pluginDescriptionText, 256);

    final JScrollPane scDescription = new JScrollPane(pluginDescriptionText);
    scDescription.setBorder(BorderFactory.createEmptyBorder(0, 4, 0, 4));

    pluginImage =
        new ImageComponent(
            plugin.isImageLoaded() ? plugin.getImage() : PluginDescriptor.DEFAULT_IMAGE);

    imagePanel = new JPanel(new BorderLayout());
    imagePanel.setBorder(BorderFactory.createEmptyBorder(4, 4, 4, 4));
    imagePanel.add(pluginImage, BorderLayout.CENTER);

    final JPanel topPanel = new JPanel(new BorderLayout());

    topPanel.add(imagePanel, BorderLayout.WEST);
    topPanel.add(scDescription, BorderLayout.CENTER);

    // center panel
    pluginAuthorLabel = new JLabel();
    pluginWebsiteLabel = new JLabel();
    pluginEmailLabel = new JLabel();

    final JPanel infosPanel = new JPanel();
    infosPanel.setBorder(BorderFactory.createEmptyBorder(0, 4, 0, 8));
    infosPanel.setLayout(new BoxLayout(infosPanel, BoxLayout.PAGE_AXIS));

    infosPanel.add(GuiUtil.createTabBoldLabel("Author", 1));
    infosPanel.add(GuiUtil.createTabLabel(pluginAuthorLabel, 32));
    infosPanel.add(Box.createVerticalStrut(4));
    infosPanel.add(GuiUtil.createTabBoldLabel("Web site", 1));
    infosPanel.add(GuiUtil.createTabLabel(pluginWebsiteLabel, 32));
    infosPanel.add(Box.createVerticalStrut(4));
    infosPanel.add(GuiUtil.createTabBoldLabel("Email", 1));
    infosPanel.add(GuiUtil.createTabLabel(pluginEmailLabel, 32));
    infosPanel.add(Box.createVerticalStrut(4));
    infosPanel.add(Box.createVerticalGlue());

    pluginChangeLogText = new JTextPane();
    pluginChangeLogText.setContentType("text/html");
    pluginChangeLogText.setEditable(false);
    pluginChangeLogText.setOpaque(false);
    pluginChangeLogText.addHyperlinkListener(this);

    final JScrollPane scChangeLog = new JScrollPane(pluginChangeLogText);
    scChangeLog.setBorder(BorderFactory.createEmptyBorder(4, 0, 0, 0));

    final JPanel changeLogPanel = new JPanel(new BorderLayout());
    changeLogPanel.setBorder(BorderFactory.createEmptyBorder(0, 8, 4, 4));

    changeLogPanel.add(GuiUtil.createTabBoldLabel("ChangeLog", 1), BorderLayout.NORTH);
    changeLogPanel.add(
        GuiUtil.createLineBoxPanel(Box.createHorizontalStrut(32), scChangeLog),
        BorderLayout.CENTER);

    final JPanel centerPanel = new JPanel(new BorderLayout());

    centerPanel.add(new JSeparator(SwingConstants.HORIZONTAL), BorderLayout.NORTH);
    centerPanel.add(infosPanel, BorderLayout.WEST);
    centerPanel.add(changeLogPanel, BorderLayout.CENTER);

    // bottom panel
    final JPanel buttonsPanel = new JPanel();
    buttonsPanel.setLayout(new BoxLayout(buttonsPanel, BoxLayout.LINE_AXIS));
    buttonsPanel.setBorder(BorderFactory.createEmptyBorder(8, 8, 8, 8));

    buttonsPanel.add(executeButton);
    buttonsPanel.add(Box.createHorizontalGlue());
    buttonsPanel.add(Box.createHorizontalStrut(4));
    buttonsPanel.add(closeButton);

    final JPanel bottomPanel = new JPanel(new BorderLayout());

    bottomPanel.add(new JSeparator(SwingConstants.HORIZONTAL), BorderLayout.NORTH);
    bottomPanel.add(buttonsPanel, BorderLayout.CENTER);

    setLayout(new BorderLayout());

    add(topPanel, BorderLayout.NORTH);
    add(centerPanel, BorderLayout.CENTER);
    add(bottomPanel, BorderLayout.SOUTH);

    updateGui();

    addToDesktopPane();
    // random position for more fun
    setLocation(10 * Random.nextInt(20) + 40, 10 * Random.nextInt(10) + 40);
    setVisible(true);
    requestFocus();

    // some parts of the descriptor are not loaded --> async update
    if (!plugin.isAllLoaded()) {
      ThreadUtil.bgRun(
          new Runnable() {
            @Override
            public void run() {
              PluginDetailPanel.this.plugin.loadAll();

              // rebuild interface
              ThreadUtil.invokeLater(
                  new Runnable() {
                    @Override
                    public void run() {
                      updateGui();
                    }
                  });
            }
          });
    }
  }