Ejemplo n.º 1
0
  private void createComponents() {
    categoryLabel = new JLabel(Language.text("contrib.category"));

    categoryChooser = new JComboBox<String>();
    categoryChooser.setMaximumRowCount(20);
    categoryChooser.setFont(Toolkit.getSansFont(14, Font.PLAIN));

    updateCategoryChooser();

    categoryChooser.addItemListener(
        new ItemListener() {
          public void itemStateChanged(ItemEvent e) {
            category = (String) categoryChooser.getSelectedItem();
            if (ContributionManagerDialog.ANY_CATEGORY.equals(category)) {
              category = null;
            }
            filterLibraries(category, filterField.filters);
            contributionListPanel.updateColors();
          }
        });

    filterField = new FilterField();
  }
Ejemplo n.º 2
0
public class ContributionTab extends JPanel {
  static final String ANY_CATEGORY = Language.text("contrib.all");

  ContributionType contribType;
  ContributionManagerDialog contribDialog;

  Contribution.Filter filter;
  JComboBox<String> categoryChooser;
  JScrollPane scrollPane;
  ListPanel contributionListPanel;
  StatusPanel statusPanel;
  FilterField filterField;
  JButton restartButton;
  JLabel categoryLabel;
  JLabel loaderLabel;

  JPanel errorPanel;
  JTextPane errorMessage;
  JButton tryAgainButton;
  JButton closeButton;

  // the calling editor, so updates can be applied
  Editor editor;
  String category;
  ContributionListing contribListing;

  JProgressBar progressBar;

  public ContributionTab() {}

  public ContributionTab(ContributionType type, ContributionManagerDialog dialog) {
    this.contribType = type;
    this.contribDialog = dialog;

    /*
    if (type == ContributionType.MODE) {
      title = Language.text("contrib.manager_title.mode");
    } else if (type == ContributionType.TOOL) {
      title = Language.text("contrib.manager_title.tool");
    } else if (type == ContributionType.LIBRARY) {
      title = Language.text("contrib.manager_title.library");
    } else if (type == ContributionType.EXAMPLES) {
      title = Language.text("contrib.manager_title.examples");
    }
    */

    filter =
        new Contribution.Filter() {
          public boolean matches(Contribution contrib) {
            return contrib.getType() == contribType;
          }
        };

    contribListing = ContributionListing.getInstance();
    statusPanel = new StatusPanel(650, this);
    contributionListPanel = new ListPanel(this, filter);
    contribListing.addListener(contributionListPanel);
  }

  //  public boolean hasUpdates(Base base) {
  //    return contribListing.hasUpdates(base);
  //  }

  public void showFrame(final Editor editor, boolean activateErrorPanel, final boolean loading) {
    this.editor = editor;

    setLayout(editor, activateErrorPanel, loading);
    contributionListPanel.setVisible(!loading);
    loaderLabel.setVisible(loading);
    errorPanel.setVisible(activateErrorPanel);

    validate();
    repaint();
  }

  protected void setLayout(final Editor editor, boolean activateErrorPanel, boolean isLoading) {
    if (progressBar == null) {
      progressBar = new JProgressBar();
      progressBar.setVisible(false);

      createComponents();
      buildErrorPanel();

      loaderLabel = new JLabel(Toolkit.getLibIcon("manager/loader.gif"));
      loaderLabel.setOpaque(false);
      loaderLabel.setBackground(Color.WHITE);
    }

    int scrollBarWidth =
        contributionListPanel.scrollPane.getVerticalScrollBar().getPreferredSize().width;

    GroupLayout layout = new GroupLayout(this);
    setLayout(layout);
    //    layout.setAutoCreateContainerGaps(true);
    //    layout.setAutoCreateGaps(true);
    layout.setHorizontalGroup(
        layout
            .createParallelGroup(GroupLayout.Alignment.CENTER)
            .addGroup(
                layout
                    .createSequentialGroup()
                    .addGap(ContributionManagerDialog.STATUS_WIDTH)
                    .addComponent(
                        filterField,
                        ContributionManagerDialog.FILTER_WIDTH,
                        ContributionManagerDialog.FILTER_WIDTH,
                        ContributionManagerDialog.FILTER_WIDTH)
                    //                  .addPreferredGap(LayoutStyle.ComponentPlacement.UNRELATED)
                    .addPreferredGap(
                        LayoutStyle.ComponentPlacement.RELATED,
                        GroupLayout.PREFERRED_SIZE,
                        Short.MAX_VALUE)
                    .addComponent(
                        categoryChooser,
                        ContributionManagerDialog.AUTHOR_WIDTH,
                        ContributionManagerDialog.AUTHOR_WIDTH,
                        ContributionManagerDialog.AUTHOR_WIDTH)
                    .addGap(scrollBarWidth))
            .addComponent(loaderLabel)
            .addComponent(contributionListPanel)
            .addComponent(errorPanel)
            .addComponent(statusPanel));

    layout.setVerticalGroup(
        layout
            .createSequentialGroup()
            .addContainerGap()
            .addGroup(
                layout
                    .createParallelGroup(GroupLayout.Alignment.CENTER)
                    .addComponent(categoryChooser)
                    .addComponent(filterField))
            .addPreferredGap(LayoutStyle.ComponentPlacement.UNRELATED)
            .addGroup(
                layout
                    .createParallelGroup(GroupLayout.Alignment.CENTER)
                    .addComponent(loaderLabel)
                    .addComponent(contributionListPanel))
            .addComponent(errorPanel)
            .addComponent(
                statusPanel,
                GroupLayout.PREFERRED_SIZE,
                GroupLayout.DEFAULT_SIZE,
                GroupLayout.PREFERRED_SIZE));
    layout.linkSize(SwingConstants.VERTICAL, categoryChooser, filterField);

    // these will occupy space even if not visible
    layout.setHonorsVisibility(contributionListPanel, false);
    layout.setHonorsVisibility(categoryChooser, false);

    setBackground(Color.WHITE);
    setBorder(null);
  }

  private void createComponents() {
    categoryLabel = new JLabel(Language.text("contrib.category"));

    categoryChooser = new JComboBox<String>();
    categoryChooser.setMaximumRowCount(20);
    categoryChooser.setFont(Toolkit.getSansFont(14, Font.PLAIN));

    updateCategoryChooser();

    categoryChooser.addItemListener(
        new ItemListener() {
          public void itemStateChanged(ItemEvent e) {
            category = (String) categoryChooser.getSelectedItem();
            if (ContributionManagerDialog.ANY_CATEGORY.equals(category)) {
              category = null;
            }
            filterLibraries(category, filterField.filters);
            contributionListPanel.updateColors();
          }
        });

    filterField = new FilterField();
  }

  protected void buildErrorPanel() {
    errorPanel = new JPanel();
    GroupLayout layout = new GroupLayout(errorPanel);
    layout.setAutoCreateGaps(true);
    layout.setAutoCreateContainerGaps(true);
    errorPanel.setLayout(layout);
    //    errorPanel.setBorder(BorderFactory.createMatteBorder(2, 0, 0, 0, Color.BLACK));
    errorMessage = new JTextPane();
    errorMessage.setEditable(false);
    errorMessage.setContentType("text/html");
    errorMessage.setText(
        "<html><body>Could not connect to the Processing server.<br>"
            + "Contributions cannot be installed or updated without an Internet connection.<br>"
            + "Please verify your network connection again, then try connecting again.</body></html>");
    errorMessage.setFont(Toolkit.getSansFont(14, Font.PLAIN));
    errorMessage.setMaximumSize(new Dimension(550, 50));
    errorMessage.setOpaque(false);

    StyledDocument doc = errorMessage.getStyledDocument();
    SimpleAttributeSet center = new SimpleAttributeSet();
    StyleConstants.setAlignment(center, StyleConstants.ALIGN_CENTER);
    doc.setParagraphAttributes(0, doc.getLength(), center, false);

    closeButton = new JButton("X");
    closeButton.setContentAreaFilled(false);
    closeButton.addActionListener(
        new ActionListener() {
          public void actionPerformed(ActionEvent e) {
            contribDialog.makeAndShowTab(false, false);
          }
        });
    tryAgainButton = new JButton("Try Again");
    tryAgainButton.setFont(Toolkit.getSansFont(14, Font.PLAIN));
    tryAgainButton.addActionListener(
        new ActionListener() {
          public void actionPerformed(ActionEvent e) {
            contribDialog.makeAndShowTab(false, true);
            contribDialog.downloadAndUpdateContributionListing(editor.getBase());
          }
        });
    layout.setHorizontalGroup(
        layout
            .createSequentialGroup()
            .addPreferredGap(
                LayoutStyle.ComponentPlacement.RELATED, GroupLayout.PREFERRED_SIZE, Short.MAX_VALUE)
            .addGroup(
                layout
                    .createParallelGroup(GroupLayout.Alignment.CENTER)
                    .addComponent(errorMessage)
                    .addComponent(
                        tryAgainButton,
                        StatusPanel.BUTTON_WIDTH,
                        StatusPanel.BUTTON_WIDTH,
                        StatusPanel.BUTTON_WIDTH))
            .addPreferredGap(
                LayoutStyle.ComponentPlacement.RELATED, GroupLayout.PREFERRED_SIZE, Short.MAX_VALUE)
            .addComponent(closeButton));
    layout.setVerticalGroup(
        layout
            .createSequentialGroup()
            .addGroup(
                layout.createParallelGroup().addComponent(errorMessage).addComponent(closeButton))
            .addPreferredGap(LayoutStyle.ComponentPlacement.UNRELATED)
            .addComponent(tryAgainButton));
    errorPanel.setBackground(Color.PINK);
    errorPanel.validate();
  }

  @Override
  protected void paintComponent(Graphics g) {
    super.paintComponent(g);
    g.setColor(new Color(0xe0fffd));
    g.fillRect(getX(), getY() - ContributionManagerDialog.TAB_HEIGHT - 2, getWidth(), 2);
  }

  protected void updateCategoryChooser() {
    if (categoryChooser != null) {
      ArrayList<String> categories;
      categoryChooser.removeAllItems();
      categories = new ArrayList<String>(contribListing.getCategories(filter));
      //      for (int i = 0; i < categories.size(); i++) {
      //        System.out.println(i + " category: " + categories.get(i));
      //      }
      Collections.sort(categories);
      //    categories.add(0, ContributionManagerDialog.ANY_CATEGORY);
      boolean categoriesFound = false;
      categoryChooser.addItem(ContributionManagerDialog.ANY_CATEGORY);
      for (String s : categories) {
        categoryChooser.addItem(s);
        if (!s.equals(Contribution.UNKNOWN_CATEGORY)) {
          categoriesFound = true;
        }
      }
      categoryChooser.setVisible(categoriesFound);
    }
  }

  protected void filterLibraries(String category, List<String> filters) {
    List<Contribution> filteredLibraries = contribListing.getFilteredLibraryList(category, filters);
    contributionListPanel.filterLibraries(filteredLibraries);
  }

  protected void updateContributionListing() {
    if (editor != null) {
      List<Contribution> contributions = new ArrayList<Contribution>();

      List<Library> libraries = new ArrayList<Library>(editor.getMode().contribLibraries);

      // Only add core libraries that are installed in the sketchbook
      // https://github.com/processing/processing/issues/3688
      // libraries.addAll(editor.getMode().coreLibraries);
      final String sketchbookPath = Base.getSketchbookLibrariesFolder().getAbsolutePath();
      for (Library lib : editor.getMode().coreLibraries) {
        if (lib.getLibraryPath().startsWith(sketchbookPath)) {
          libraries.add(lib);
        }
      }

      contributions.addAll(libraries);

      Base base = editor.getBase();

      List<ToolContribution> tools = base.getToolContribs();
      contributions.addAll(tools);

      List<ModeContribution> modes = base.getModeContribs();
      contributions.addAll(modes);

      List<ExamplesContribution> examples = base.getExampleContribs();
      contributions.addAll(examples);

      //    ArrayList<LibraryCompilation> compilations = LibraryCompilation.list(libraries);
      //
      //    // Remove libraries from the list that are part of a compilations
      //    for (LibraryCompilation compilation : compilations) {
      //      Iterator<Library> it = libraries.iterator();
      //      while (it.hasNext()) {
      //        Library current = it.next();
      //        if (compilation.getFolder().equals(current.getFolder().getParentFile())) {
      //          it.remove();
      //        }
      //      }
      //    }

      contribListing.updateInstalledList(contributions);
    }
  }

  protected void setFilterText(String filter) {
    if (filter == null || filter.isEmpty()) {
      filterField.setText("");
    } else {
      filterField.setText(filter);
    }
    filterField.applyFilter();
  }

  // TODO: this is causing a lot of bugs as the hint is wrongly firing applyFilter()
  class FilterField extends JTextField {
    Icon searchIcon;
    List<String> filters;
    JLabel filterLabel;

    public FilterField() {
      super("");

      filterLabel = new JLabel("Filter");
      filterLabel.setFont(Toolkit.getSansFont(14, Font.PLAIN));
      filterLabel.setOpaque(false);

      setFont(Toolkit.getSansFont(14, Font.PLAIN));
      searchIcon = Toolkit.getLibIconX("manager/search");
      filterLabel.setIcon(searchIcon);
      // searchIcon = new
      // ImageIcon(java.awt.Toolkit.getDefaultToolkit().getImage("NSImage://NSComputerTemplate"));
      setOpaque(false);
      // setBorder(BorderFactory.createMatteBorder(0, 33, 0, 0, searchIcon));

      GroupLayout fl = new GroupLayout(this);
      setLayout(fl);
      fl.setHorizontalGroup(fl.createSequentialGroup().addComponent(filterLabel));
      fl.setVerticalGroup(
          fl.createSequentialGroup()
              .addPreferredGap(
                  LayoutStyle.ComponentPlacement.RELATED,
                  GroupLayout.PREFERRED_SIZE,
                  Short.MAX_VALUE)
              .addComponent(filterLabel)
              .addPreferredGap(
                  LayoutStyle.ComponentPlacement.RELATED,
                  GroupLayout.PREFERRED_SIZE,
                  Short.MAX_VALUE));

      filters = new ArrayList<String>();

      addFocusListener(
          new FocusListener() {
            public void focusLost(FocusEvent focusEvent) {
              if (getText().isEmpty()) {
                //            setBorder(BorderFactory.createMatteBorder(0, 33, 0, 0, searchIcon));
                filterLabel.setVisible(true);
              }
            }

            public void focusGained(FocusEvent focusEvent) {
              //          setBorder(BorderFactory.createEmptyBorder(0, 3, 0, 0));
              filterLabel.setVisible(false);
            }
          });

      getDocument()
          .addDocumentListener(
              new DocumentListener() {
                public void removeUpdate(DocumentEvent e) {
                  applyFilter();
                }

                public void insertUpdate(DocumentEvent e) {
                  applyFilter();
                }

                public void changedUpdate(DocumentEvent e) {
                  applyFilter();
                }
              });
    }

    public void applyFilter() {
      String filter = getText();
      filter = filter.toLowerCase();

      // Replace anything but 0-9, a-z, or : with a space
      filter = filter.replaceAll("[^\\x30-\\x39^\\x61-\\x7a^\\x3a]", " ");
      filters = Arrays.asList(filter.split(" "));
      filterLibraries(category, filters);

      contributionListPanel.updateColors();
    }
  }

  //  public boolean hasAlreadyBeenOpened() {
  //    return panel != null;
  //  }

  public void updateStatusPanel(DetailPanel contributionPanel) {
    statusPanel.update(contributionPanel);
  }
}
/**
 * This class is the main Contribution Manager Dialog. It contains all the contributions tab and the
 * update tab.
 */
public class ContributionManagerDialog {
  static final String ANY_CATEGORY = Language.text("contrib.all");
  static final int TAB_WIDTH = 100;
  static final int TAB_HEIGHT = 34;
  static final int AUTHOR_WIDTH = 240;
  static final int STATUS_WIDTH = 66;
  static final int FILTER_WIDTH = 180;
  static final int ICON_WIDTH = 50;

  static final String title = "Manager";

  JFrame dialog;
  JTabbedPane tabbedPane;
  JButton restartButton;

  // the calling editor, so updates can be applied
  Editor editor;

  ContributionTab toolsContributionTab;
  ContributionTab librariesContributionTab;
  ContributionTab examplesContributionTab;
  ContributionTab modesContributionTab;
  UpdateContributionTab updatesContributionTab;
  JLabel numberLabel;

  ContributionListing contributionListing = ContributionListing.getInstance();

  private JLabel[] tabLabels;
  private JPanel updateTabPanel;
  private JLabel updateTabLabel;

  static Font font;

  public ContributionManagerDialog() {
    font = Toolkit.getSansFont(14, Font.PLAIN);
    numberLabel = new JLabel(Toolkit.getLibIconX("manager/notification"), SwingConstants.CENTER);
    librariesContributionTab = new ContributionTab(ContributionType.LIBRARY, this);
    modesContributionTab = new ContributionTab(ContributionType.MODE, this);
    toolsContributionTab = new ContributionTab(ContributionType.TOOL, this);
    examplesContributionTab = new ContributionTab(ContributionType.EXAMPLES, this);
    updatesContributionTab = new UpdateContributionTab(null, this);
  }

  /*
  public boolean hasUpdates(Base base) {
    return librariesContributionTab.hasUpdates(base)
      || modesContributionTab.hasUpdates(base)
      || toolsContributionTab.hasUpdates(base)
      || examplesContributionTab.hasUpdates(base);
  }
   */

  public void showFrame(Editor editor, ContributionType contributionType) {
    this.editor = editor;

    // Calculating index to switch to the required tab
    int index = getIndex(contributionType);
    if (dialog == null) {
      makeFrame(editor);
      // done before as downloadAndUpdateContributionListing()
      // requires the current selected tab
      tabbedPane.setSelectedIndex(index);
      downloadAndUpdateContributionListing(editor.getBase());
      if (index != 4) {
        Component selected = tabbedPane.getTabComponentAt(tabbedPane.getSelectedIndex());
        selected.setBackground(new Color(0xe0fffd));
        selected.setForeground(Color.BLACK);
      } else {
        updateTabPanel.setBackground(new Color(0xe0fffd));
        updateTabLabel.setForeground(Color.BLACK);
      }
    }
    tabbedPane.setSelectedIndex(index);
    dialog.setVisible(true);
  }

  int getIndex(ContributionType contributionType) {
    int index;
    if (contributionType == ContributionType.LIBRARY) {
      index = 0;
    } else if (contributionType == ContributionType.MODE) {
      index = 1;
    } else if (contributionType == ContributionType.TOOL) {
      index = 2;
    } else if (contributionType == ContributionType.EXAMPLES) {
      index = 3;
    } else {
      index = 4;
    }
    return index;
  }

  ContributionTab getTab(ContributionType contributionType) {
    if (contributionType == ContributionType.LIBRARY) {
      return librariesContributionTab;
    } else if (contributionType == ContributionType.MODE) {
      return modesContributionTab;
    } else if (contributionType == ContributionType.TOOL) {
      return toolsContributionTab;
    } else if (contributionType == ContributionType.EXAMPLES) {
      return examplesContributionTab;
    }
    return updatesContributionTab;
  }

  private void makeFrame(final Editor editor) {
    dialog = new JFrame(title);
    dialog.setMinimumSize(new Dimension(750, 500));
    tabbedPane = new JTabbedPane();

    makeAndShowTab(false, true);

    tabbedPane.addTab("Libraries", null, librariesContributionTab.panel, "Libraries");
    tabbedPane.setMnemonicAt(0, KeyEvent.VK_1);

    tabbedPane.addTab("Modes", null, modesContributionTab.panel, "Modes");
    tabbedPane.setMnemonicAt(1, KeyEvent.VK_2);

    tabbedPane.addTab("Tools", null, toolsContributionTab.panel, "Tools");
    tabbedPane.setMnemonicAt(2, KeyEvent.VK_3);

    tabbedPane.addTab("Examples", null, examplesContributionTab.panel, "Examples");
    tabbedPane.setMnemonicAt(3, KeyEvent.VK_4);

    tabbedPane.addTab("Updates", null, updatesContributionTab.panel, "Updates");
    tabbedPane.setMnemonicAt(4, KeyEvent.VK_5);

    tabbedPane.setUI(new SpacedTabbedPaneUI());
    tabbedPane.setBackground(new Color(0x132638));
    tabbedPane.setOpaque(true);

    for (int i = 0; i < 5; i++) {
      tabbedPane.setToolTipTextAt(i, null);
    }

    makeAndSetTabComponents();

    tabbedPane.addChangeListener(
        new ChangeListener() {

          @Override
          public void stateChanged(ChangeEvent e) {
            for (int i = 0; i < 4; i++) {
              tabLabels[i].setBackground(new Color(0x2d4251));
              tabLabels[i].setForeground(Color.WHITE);
            }
            updateTabPanel.setBackground(new Color(0x2d4251));
            updateTabLabel.setForeground(Color.WHITE);
            int currentIndex = tabbedPane.getSelectedIndex();
            if (currentIndex != 4) {
              tabbedPane
                  .getTabComponentAt(tabbedPane.getSelectedIndex())
                  .setBackground(new Color(0xe0fffd));
              tabbedPane
                  .getTabComponentAt(tabbedPane.getSelectedIndex())
                  .setForeground(Color.BLACK);
            } else {
              updateTabPanel.setBackground(new Color(0xe0fffd));
              updateTabLabel.setForeground(Color.BLACK);
            }
            getActiveTab().contributionListPanel.scrollPane.requestFocusInWindow();
            //        // When the tab is changed update status to the current selected panel
            //        ContributionPanel currentPanel = getActiveTab().contributionListPanel
            //          .getSelectedPanel();
            //        if (currentPanel != null) {
            //          getActiveTab().contributionListPanel.setSelectedPanel(currentPanel);
            //        }
          }
        });

    //    tabbedPane.setSize(450, 400);
    setLayout();

    restartButton = new JButton(Language.text("contrib.restart"));
    restartButton.setVisible(false);
    restartButton.addActionListener(
        new ActionListener() {

          @Override
          public void actionPerformed(ActionEvent arg0) {

            Iterator<Editor> iter = editor.getBase().getEditors().iterator();
            while (iter.hasNext()) {
              Editor ed = iter.next();
              if (ed.getSketch().isModified()) {
                int option =
                    Messages.showYesNoQuestion(
                        editor,
                        title,
                        Language.text("contrib.unsaved_changes"),
                        Language.text("contrib.unsaved_changes.prompt"));

                if (option == JOptionPane.NO_OPTION) return;
                else break;
              }
            }

            // Thanks to http://stackoverflow.com/a/4160543
            StringBuilder cmd = new StringBuilder();
            cmd.append(
                System.getProperty("java.home")
                    + File.separator
                    + "bin"
                    + File.separator
                    + "java ");
            for (String jvmArg : ManagementFactory.getRuntimeMXBean().getInputArguments()) {
              cmd.append(jvmArg + " ");
            }
            cmd.append("-cp ")
                .append(ManagementFactory.getRuntimeMXBean().getClassPath())
                .append(" ");
            cmd.append(Base.class.getName());

            try {
              Runtime.getRuntime().exec(cmd.toString());
              System.exit(0);
            } catch (IOException e) {
              e.printStackTrace();
            }
          }
        });

    Toolkit.setIcon(dialog);
    registerDisposeListeners();

    dialog.pack();
    dialog.setLocationRelativeTo(null);
  }

  private void makeAndSetTabComponents() {
    final String[] tabTitles = {"Libraries", "Modes", "Tools", "Examples", "Updates"};
    tabLabels = new JLabel[4];

    for (int i = 0; i < 4; i++) {
      final int temp = i;
      tabLabels[i] =
          new JLabel(tabTitles[i]) {
            @Override
            protected void paintComponent(Graphics g) {
              g.setClip(
                  Toolkit.createRoundRect(
                      0, 0, getWidth(), getHeight(), temp == 0 ? 6 : 0, temp == 3 ? 6 : 0, 0, 0));
              super.paintComponent(g);
            }
          };
      tabLabels[i].setForeground(Color.WHITE);
      tabLabels[i].setBackground(new Color(0x2d4251));
      tabLabels[i].setOpaque(true);
      tabLabels[i].setBorder(BorderFactory.createEmptyBorder(6, 6, 6, 6));
      tabLabels[i].setPreferredSize(new Dimension(TAB_WIDTH, TAB_HEIGHT));
      tabLabels[i].setHorizontalAlignment(SwingConstants.CENTER);
      tabLabels[i].setFont(Toolkit.getSansFont(14, Font.BOLD));
      tabbedPane.setTabComponentAt(i, tabLabels[i]);
    }

    updateTabPanel =
        new JPanel() {
          @Override
          protected void paintComponent(Graphics g) {
            g.setClip(Toolkit.createRoundRect(0, 0, getWidth(), getHeight(), 6, 6, 0, 0));
            super.paintComponent(g);
          }
        };
    ;
    updateTabLabel = new JLabel("Updates");
    updateTabLabel.setFont(Toolkit.getSansFont(14, Font.BOLD));
    numberLabel.setVerticalTextPosition(SwingConstants.CENTER);
    numberLabel.setHorizontalTextPosition(SwingConstants.CENTER);
    numberLabel.setFont(Toolkit.getSansFont(14, Font.BOLD));
    numberLabel.setForeground(Color.WHITE);
    updateTabPanel.setOpaque(true);
    updateTabPanel.setBackground(new Color(0x2d4251));
    updateTabLabel.setForeground(Color.WHITE);
    updateTabPanel.setBorder(BorderFactory.createEmptyBorder(6, 6, 6, 6));
    updateTabPanel.setPreferredSize(new Dimension(TAB_WIDTH, TAB_HEIGHT));
    tabbedPane.setTabComponentAt(4, updateTabPanel);

    GroupLayout tabLayout = new GroupLayout(updateTabPanel);
    tabLayout.setAutoCreateGaps(true);
    updateTabPanel.setLayout(tabLayout);
    tabLayout.setHorizontalGroup(
        tabLayout
            .createSequentialGroup()
            .addPreferredGap(
                LayoutStyle.ComponentPlacement.RELATED, GroupLayout.PREFERRED_SIZE, Short.MAX_VALUE)
            .addComponent(updateTabLabel)
            .addComponent(numberLabel)
            .addPreferredGap(
                LayoutStyle.ComponentPlacement.RELATED,
                GroupLayout.PREFERRED_SIZE,
                Short.MAX_VALUE));
    tabLayout.setVerticalGroup(
        tabLayout
            .createParallelGroup(GroupLayout.Alignment.CENTER)
            .addComponent(numberLabel)
            .addComponent(updateTabLabel));

    numberLabel.setVisible(false);
  }

  // . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . .

  public class SpacedTabbedPaneUI extends BasicTabbedPaneUI {

    @Override
    protected void installDefaults() {
      UIManager.put("TabbedPane.selected", Color.BLACK);
      UIManager.put("TabbedPane.tabsOverlapBorder", true);
      super.installDefaults();
      tabInsets = new Insets(0, 0, 0, 0);
      contentBorderInsets = new Insets(0, 0, 0, 0);
      tabAreaInsets = new Insets(0, 0, 0, 0);
      selectedTabPadInsets = new Insets(0, 0, 0, 0);
    }

    @Override
    protected int getTabLabelShiftY(int tabPlacement, int tabIndex, boolean isSelected) {
      return 1;
    }

    @Override
    protected void paintTabBackground(
        Graphics g,
        int tabPlacement,
        int tabIndex,
        int x,
        int y,
        int w,
        int h,
        boolean isSelected) {}

    @Override
    protected void paintTabBorder(
        Graphics g,
        int tabPlacement,
        int tabIndex,
        int x,
        int y,
        int w,
        int h,
        boolean isSelected) {}

    @Override
    protected void paintFocusIndicator(
        Graphics g,
        int tabPlacement,
        Rectangle[] rects,
        int tabIndex,
        Rectangle iconRect,
        Rectangle textRect,
        boolean isSelected) {}

    @Override
    protected LayoutManager createLayoutManager() {
      return new BasicTabbedPaneUI.TabbedPaneLayout() {

        /*
        @Override
        public void addLayoutComponent(String name, Component comp) {
          super.addLayoutComponent(name, comp);
        }
        */

        @Override
        protected void calculateTabRects(int tabPlacement, int tabCount) {
          super.calculateTabRects(tabPlacement, tabCount);
          rects[0].x -= 2;
          rects[1].x -= 1;
          rects[2].x -= 1;
          rects[3].x -= 1;
          rects[4].x = tabbedPane.getWidth() - rects[4].width + 1;
        }
      };
    }
  }

  // . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . .

  private void setLayout() {
    GroupLayout layout = new GroupLayout(dialog.getContentPane());
    dialog.getContentPane().setLayout(layout);
    dialog.setResizable(true);
    layout.setAutoCreateContainerGaps(true);
    layout.setHorizontalGroup(layout.createParallelGroup().addComponent(tabbedPane));
    layout.setVerticalGroup(layout.createParallelGroup().addComponent(tabbedPane));
    layout.setHonorsVisibility(tabbedPane, true);
    // TODO set color here
    dialog.getContentPane().setBackground(new Color(0x132638));
    dialog.validate();
    dialog.repaint();
  }

  /** Close the window after an OK or Cancel. */
  protected void disposeFrame() {
    dialog.dispose();
    editor = null;
  }

  private void registerDisposeListeners() {
    dialog.addWindowListener(
        new WindowAdapter() {
          public void windowClosing(WindowEvent e) {
            disposeFrame();
          }
        });
    // handle window closing commands for ctrl/cmd-W or hitting ESC.
    Toolkit.registerWindowCloseKeys(
        dialog.getRootPane(),
        new ActionListener() {
          public void actionPerformed(ActionEvent actionEvent) {
            disposeFrame();
          }
        });

    dialog
        .getContentPane()
        .addKeyListener(
            new KeyAdapter() {
              public void keyPressed(KeyEvent e) {
                // System.out.println(e);
                KeyStroke wc = Toolkit.WINDOW_CLOSE_KEYSTROKE;
                if ((e.getKeyCode() == KeyEvent.VK_ESCAPE)
                    || (KeyStroke.getKeyStrokeForEvent(e).equals(wc))) {
                  disposeFrame();
                }
              }
            });
  }

  void downloadAndUpdateContributionListing(Base base) {
    // activeTab is required now but should be removed
    // as there is only one instance of contribListing and it should be present in this class
    final ContributionTab activeTab = getActiveTab();

    ContribProgressMonitor progress =
        new ContribProgressBar(activeTab.progressBar) {

          @Override
          public void startTask(String name, int maxValue) {
            super.startTask(name, maxValue);
            progressBar.setVisible(true);
            progressBar.setString(null);
          }

          @Override
          public void setProgress(int value) {
            super.setProgress(value);
            //        int percent = 100 * value / this.max;
            progressBar.setValue(value);
          }

          @Override
          public void finishedAction() {
            progressBar.setVisible(false);
            activeTab.updateContributionListing();
            activeTab.updateCategoryChooser();

            if (error) {
              exception.printStackTrace();
              makeAndShowTab(true, false);
            } else {
              makeAndShowTab(false, false);
            }
          }
        };
    activeTab.contribListing.downloadAvailableList(base, progress);
  }

  void makeAndShowTab(boolean activateErrorPanel, boolean isLoading) {
    librariesContributionTab.showFrame(editor, activateErrorPanel, isLoading);
    modesContributionTab.showFrame(editor, activateErrorPanel, isLoading);
    toolsContributionTab.showFrame(editor, activateErrorPanel, isLoading);
    examplesContributionTab.showFrame(editor, activateErrorPanel, isLoading);
    updatesContributionTab.showFrame(editor, activateErrorPanel, isLoading);
  }

  ContributionTab getActiveTab() {
    switch (tabbedPane.getSelectedIndex()) {
      case 0:
        return librariesContributionTab;
      case 1:
        return modesContributionTab;
      case 2:
        return toolsContributionTab;
      case 3:
        return examplesContributionTab;
      default:
        return updatesContributionTab;
    }
  }
}
  private void makeFrame(final Editor editor) {
    dialog = new JFrame(title);
    dialog.setMinimumSize(new Dimension(750, 500));
    tabbedPane = new JTabbedPane();

    makeAndShowTab(false, true);

    tabbedPane.addTab("Libraries", null, librariesContributionTab.panel, "Libraries");
    tabbedPane.setMnemonicAt(0, KeyEvent.VK_1);

    tabbedPane.addTab("Modes", null, modesContributionTab.panel, "Modes");
    tabbedPane.setMnemonicAt(1, KeyEvent.VK_2);

    tabbedPane.addTab("Tools", null, toolsContributionTab.panel, "Tools");
    tabbedPane.setMnemonicAt(2, KeyEvent.VK_3);

    tabbedPane.addTab("Examples", null, examplesContributionTab.panel, "Examples");
    tabbedPane.setMnemonicAt(3, KeyEvent.VK_4);

    tabbedPane.addTab("Updates", null, updatesContributionTab.panel, "Updates");
    tabbedPane.setMnemonicAt(4, KeyEvent.VK_5);

    tabbedPane.setUI(new SpacedTabbedPaneUI());
    tabbedPane.setBackground(new Color(0x132638));
    tabbedPane.setOpaque(true);

    for (int i = 0; i < 5; i++) {
      tabbedPane.setToolTipTextAt(i, null);
    }

    makeAndSetTabComponents();

    tabbedPane.addChangeListener(
        new ChangeListener() {

          @Override
          public void stateChanged(ChangeEvent e) {
            for (int i = 0; i < 4; i++) {
              tabLabels[i].setBackground(new Color(0x2d4251));
              tabLabels[i].setForeground(Color.WHITE);
            }
            updateTabPanel.setBackground(new Color(0x2d4251));
            updateTabLabel.setForeground(Color.WHITE);
            int currentIndex = tabbedPane.getSelectedIndex();
            if (currentIndex != 4) {
              tabbedPane
                  .getTabComponentAt(tabbedPane.getSelectedIndex())
                  .setBackground(new Color(0xe0fffd));
              tabbedPane
                  .getTabComponentAt(tabbedPane.getSelectedIndex())
                  .setForeground(Color.BLACK);
            } else {
              updateTabPanel.setBackground(new Color(0xe0fffd));
              updateTabLabel.setForeground(Color.BLACK);
            }
            getActiveTab().contributionListPanel.scrollPane.requestFocusInWindow();
            //        // When the tab is changed update status to the current selected panel
            //        ContributionPanel currentPanel = getActiveTab().contributionListPanel
            //          .getSelectedPanel();
            //        if (currentPanel != null) {
            //          getActiveTab().contributionListPanel.setSelectedPanel(currentPanel);
            //        }
          }
        });

    //    tabbedPane.setSize(450, 400);
    setLayout();

    restartButton = new JButton(Language.text("contrib.restart"));
    restartButton.setVisible(false);
    restartButton.addActionListener(
        new ActionListener() {

          @Override
          public void actionPerformed(ActionEvent arg0) {

            Iterator<Editor> iter = editor.getBase().getEditors().iterator();
            while (iter.hasNext()) {
              Editor ed = iter.next();
              if (ed.getSketch().isModified()) {
                int option =
                    Messages.showYesNoQuestion(
                        editor,
                        title,
                        Language.text("contrib.unsaved_changes"),
                        Language.text("contrib.unsaved_changes.prompt"));

                if (option == JOptionPane.NO_OPTION) return;
                else break;
              }
            }

            // Thanks to http://stackoverflow.com/a/4160543
            StringBuilder cmd = new StringBuilder();
            cmd.append(
                System.getProperty("java.home")
                    + File.separator
                    + "bin"
                    + File.separator
                    + "java ");
            for (String jvmArg : ManagementFactory.getRuntimeMXBean().getInputArguments()) {
              cmd.append(jvmArg + " ");
            }
            cmd.append("-cp ")
                .append(ManagementFactory.getRuntimeMXBean().getClassPath())
                .append(" ");
            cmd.append(Base.class.getName());

            try {
              Runtime.getRuntime().exec(cmd.toString());
              System.exit(0);
            } catch (IOException e) {
              e.printStackTrace();
            }
          }
        });

    Toolkit.setIcon(dialog);
    registerDisposeListeners();

    dialog.pack();
    dialog.setLocationRelativeTo(null);
  }