/**
  * Modify the current base font size
  *
  * @param s the size to add to the current size
  */
 public void modifyFont(final int s) {
   try {
     currentFontSize = Math.min(Math.max(0, currentFontSize + s), 6);
     HTMLDocument doc = (HTMLDocument) accessibleHtml.getDocument();
     StyleContext.NamedStyle style =
         (StyleContext.NamedStyle) doc.getStyleSheet().getStyle("body");
     MutableAttributeSet attr = (MutableAttributeSet) style.getResolveParent();
     if (StyleConstants.getFontSize(attr) != fontSizes[currentFontSize]) {
       ConfigManager.setHelpFontSize(currentFontSize);
       StyleConstants.setFontSize(attr, fontSizes[currentFontSize]);
       accessibleHtml.setVisible(false);
       style.setResolveParent(attr);
       accessibleHtml.setVisible(true);
     }
   } catch (NullPointerException e) {
     // Can occur if the user is changing quickly the document
     SwingUtilities.invokeLater(
         () -> {
           modifyFont(s);
         });
   }
 }
  /**
   * We customize the file chooser for the graphic export by adding format selection
   *
   * @param figureId exported figure number
   */
  public void exportCustomFileChooser(Integer figureUID) {
    Figure figure = (Figure) GraphicController.getController().getObjectFromId(figureUID);
    String defaultName = figure.getName();
    int figureId = figure.getId();
    if (defaultName != null && !defaultName.isEmpty()) {
      defaultName = defaultName.replaceFirst("%d", Integer.toString(figureId));
    } else {
      defaultName = Messages.gettext("Untitled-export");
    }

    ArrayList<FileMask> v = new ArrayList<FileMask>(NB_FILE_MASKS); /* The order does matter */
    v.add(new FileMask(png, pngDesc));
    v.add(new FileMask(jpg, jpgDesc));
    v.add(new FileMask(eps, epsDesc));
    v.add(new FileMask(ps, psDesc));
    v.add(new FileMask(pdf, pdfDesc));
    v.add(new FileMask(svg, svgDesc));
    v.add(new FileMask(emf, emfDesc));
    v.add(new FileMask(gif, gifDesc));
    v.add(new FileMask(bmp, bmpDesc));
    v.add(new FileMask(ppm, ppmDesc));
    v.add(new FileMask(allFiles, allFilesDesc)); // should always be at the last position

    super.setDialogTitle(Messages.gettext("Export"));
    super.setApproveButtonText(Messages.gettext("Export"));
    File exportFile = new File(defaultName);
    super.setSelectedFile(exportFile);
    super.setAcceptAllFileFilterUsed(false);

    this.figureUID = figureUID;

    for (int i = 0; i < v.size(); i++) {
      FileMask fm = v.get(i);
      if (i == v.size() - 1) {
        /* Last case ... all files, remove the extension */
        fm.clearExtensions();
      }
      super.addChoosableFileFilter(fm);
    }

    // Preview panel
    JPanel panelPreview = new JPanel();

    // Title for preview panel
    TitledBorder titlePreview;
    titlePreview =
        BorderFactory.createTitledBorder(Messages.gettext("Preview selected image file"));
    panelPreview.setBorder(titlePreview);

    // add preview image
    panelPreview.add(new ImagePreview(this));

    // Main panel contains extensionTable panel & preview panel
    JPanel accessoryPanel = new JPanel();

    // accessoryPanel.add(scrollPane);
    accessoryPanel.add(panelPreview);
    accessoryPanel.setVisible(true);
    super.setAccessory(accessoryPanel);

    Component c = DrawerVisitor.getVisitor(figureUID).getComponent();
    Window parentWindow = (Window) SwingUtilities.getAncestorOfClass(Window.class, c);

    int selection = super.showSaveDialog(parentWindow);
    if (selection == JFileChooser.APPROVE_OPTION && super.getSelectedFile() != null) {
      this.exportName = super.getSelectedFile().getAbsolutePath();

      /* Bug 3849 fix */
      ConfigManager.saveLastOpenedDirectory(new File(exportName).getParentFile().getPath());

      String extensionCombo = new String();
      try {
        // The try catch is necessary here when the user input the full
        // filename (foo.jpg) and press tab. It is going to update
        // the filter causing the following line to fail (cannot cast)
        // Therefor, we switch back to the allFiles (*) case.
        FileMask ft = (FileMask) super.getFileFilter();
        // get the extension from the Filter
        extensionCombo = ft.getExtensionFromFilter();
        if (extensionCombo == null) {
          extensionCombo = allFiles;
        }
      } catch (java.lang.ClassCastException e) {
        extensionCombo = allFiles;
      }

      if (extensionCombo.equals(allFiles)) {
        exportManager();
      } else if (extensionCombo.equals(emf)
          || extensionCombo.equals(eps)
          || extensionCombo.equals(ps)
          || extensionCombo.equals(pdf)
          || extensionCombo.equals(svg)) {
        vectorialExport(extensionCombo);
      } else {
        bitmapExport(extensionCombo);
      }
    } else {; // no file chosen
    }
  }
/**
 * This class inherits from BasicContentViewerUI from Javahelp. Through this class, we are adding
 * some features on the javahelp browser We are adding a popup menu on the right click of the mouse
 * In this menu, we are providing: - Execute in Scilab - Edit in the text editor - Copy - Select all
 * - History
 *
 * @author Sylvestre LEDRU
 * @author Calixte DENIZET
 */
@SuppressWarnings(value = {"serial"})
public class SwingScilabHelpBrowserViewer extends BasicContentViewerUI
    implements MouseWheelListener {

  private static final String SCILAB_PROTO = "scilab://";
  private static final String FILE_PROTO = "file://";
  private static final String SCI = ScilabConstants.SCI.getPath().replaceAll("\\\\", "/");;
  private static final String SHIFTEQ = "shiftEquals";
  private static final long serialVersionUID = -2593697956426596790L;
  private static final int[] fontSizes = new int[] {8, 10, 12, 14, 18, 24, 36};
  private static final boolean isMac = System.getProperty("os.name").toLowerCase().contains("mac");

  private static int currentFontSize = ConfigManager.getHelpFontSize();

  /* This field is a copy of BasicContentViewerUI which is privated.
   * Therefor, I am changing the permission here to make it available
   * to the methods of this object
   */
  private JEditorPane accessibleHtml;

  private final JHelpContentViewer x;
  private List<HelpSet> helpSets;

  public SwingScilabHelpBrowserViewer(JHelpContentViewer x) {
    super(x);
    this.x = x;
  }

  public static javax.swing.plaf.ComponentUI createUI(JComponent x) {
    return new SwingScilabHelpBrowserViewer((JHelpContentViewer) x);
  }

  /** @return the JEditorPane used in the HTML view */
  public JEditorPane getAccessibleHTML() {
    return accessibleHtml;
  }

  /**
   * Update the browser links
   *
   * @param event on hyperlink event
   */
  @Override
  public void hyperlinkUpdate(HyperlinkEvent event) {
    if (event.getEventType() == HyperlinkEvent.EventType.ACTIVATED) {
      if (event.getDescription().startsWith("http://")
          || event.getDescription().startsWith("https://")
          || event.getDescription().startsWith("ftp://")) {
        WebBrowser.openUrl(event.getURL(), event.getDescription());
      } else if (event.getDescription().startsWith(SCILAB_PROTO)) {
        if (helpSets == null) {
          initHelpSets(x.getModel().getHelpSet());
        }
        URL url = resolvScilabLink(event);
        if (url != null) {
          super.hyperlinkUpdate(
              new HyperlinkEvent(event.getSource(), event.getEventType(), url, ""));
        }
      } else if (event.getDescription().startsWith(FILE_PROTO)) {
        String url = event.getDescription();
        url = url.replaceFirst("SCI", Matcher.quoteReplacement(SCI));
        WebBrowser.openUrl(url);
      } else {
        super.hyperlinkUpdate(event);
      }
    }
  }

  private void initHelpSets(HelpSet hs) {
    helpSets = new ArrayList();
    helpSets.add(hs);
    for (Enumeration<HelpSet> e = hs.getHelpSets(); e.hasMoreElements(); ) {
      helpSets.add(e.nextElement());
    }
  }

  /**
   * Try to find an id
   *
   * @param id the id to find
   * @return the URL corresponding to the id
   */
  public URL getURLFromID(String id) {
    URL url = null;
    try {
      for (HelpSet hs : helpSets) {
        javax.help.Map map = hs.getLocalMap();
        if (map.isValidID(id, hs)) {
          url = map.getURLFromID(javax.help.Map.ID.create(id, hs));
          if (url != null) {
            return url;
          }
        }
      }
      url =
          new URL(
              helpSets
                  .get(0)
                  .getHelpSetURL()
                  .toString()
                  .replace("jhelpset.hs", "ScilabErrorPage.html"));
    } catch (MalformedURLException ex) {
    }

    return url;
  }

  /**
   * Try to find an id in a toolbox
   *
   * @param tbxName the toolbox's name
   * @param id the id to find
   * @return the URL corresponding to the id
   */
  public URL getURLFromID(String tbxName, String id) {
    if (tbxName == null) {
      return getURLFromID(id);
    }
    URL url = null;
    try {
      for (HelpSet hs : helpSets) {
        if (hs.getHelpSetURL().toString().replaceAll("\\\\", "/").contains("/" + tbxName + "/")) {
          javax.help.Map map = hs.getLocalMap();
          if (map.isValidID(id, hs)) {
            url = map.getURLFromID(javax.help.Map.ID.create(id, hs));
            if (url != null) {
              return url;
            }
          }
        }
      }
      url =
          new URL(
              helpSets
                  .get(0)
                  .getHelpSetURL()
                  .toString()
                  .replace("jhelpset.hs", "ScilabErrorPage.html"));
    } catch (MalformedURLException ex) {
    }

    return url;
  }

  /**
   * Try to transform an address such as scilab://scilab.help/bvode into a conform URL pointing to
   * the corresponding file in using jar: protocol. E.g. scilab://scilab.help/bvode will be
   * transform into
   * jar:file:SCI/modules/helptools/jar/scilab_fr_FR_help.jar!/scilab_fr_FR_help/bvode.html (where
   * SCI has the good value)
   *
   * @param event the yperlink event
   * @return the correct address in using jar:// protocol
   */
  public URL resolvScilabLink(HyperlinkEvent event) {
    int pos = SCILAB_PROTO.length();
    String addr = event.getDescription();
    addr = addr.trim().replaceAll("\\\\", "/");
    addr = addr.substring(pos);

    pos = addr.indexOf("/");
    String location;
    String path = "";
    if (pos != -1) {
      location = addr.substring(0, pos);
      if (pos != addr.length()) {
        path = addr.substring(pos + 1);
      }
    } else {
      return getURLFromID(addr);
    }

    String[] splitLoc = location.split("\\.");
    String mainLocation = null;
    String subLocation;

    if (splitLoc.length >= 1) {
      mainLocation = splitLoc[0];
    }
    if (splitLoc.length >= 2) {
      subLocation = splitLoc[1];
    } else {
      System.err.println("Unable decode the Scilab content type\n" + event.getDescription());
      return null;
    }

    switch (subLocation) {
      case "help":
        if ("scilab".equals(mainLocation)) {
          return getURLFromID(path);
        } else {
          return getURLFromID(mainLocation, path);
        }
      case "xcos":
      case "scinotes":
        if ("scilab".equals(mainLocation)) {
          exec(subLocation, SCI + "/modules/" + path);
        } else {
          exec(subLocation, getToolboxPath() + "/" + path);
        }
        break;
      case "demos":
        if ("scilab".equals(mainLocation)) {
          exec(SCI + "/modules/" + path + ".sce");
        } else {
          exec(getToolboxPath() + "/demos/" + path + ".sce");
        }
        break;
      case "execexample":
        execExample(
            event
                .getSourceElement()
                .getParentElement()
                .getParentElement()
                .getParentElement()
                .getElement(0)
                .getElement(0));
        break;
      case "editexample":
        editExample(
            event
                .getSourceElement()
                .getParentElement()
                .getParentElement()
                .getParentElement()
                .getElement(0)
                .getElement(0));
        break;
      case "exec":
        if (mainLocation.equals("scilab")) {
          exec(SCI + "/modules/" + path);
        } else {
          exec(getToolboxPath() + "/" + path);
        }
        break;
    }

    return null;
  }

  /** @return the path of the toolbox */
  public String getToolboxPath() {
    try {
      URL url = ((JarURLConnection) x.getCurrentURL().openConnection()).getJarFileURL();
      return new File(url.toURI()).getParentFile().getParent();
    } catch (Exception e) {
    }

    return "";
  }

  /** @return the current URL as String being displayed */
  public String getCurrentURL() {
    return x.getCurrentURL().toString();
  }

  /**
   * Execute the code in example
   *
   * @param pre the preformatted Element containing Scilab's code
   */
  public void execExample(Element pre) {
    String code = getCode(pre);
    try {
      ScilabConsole.getConsole()
          .getAsSimpleConsole()
          .sendCommandsToScilab(code, true /* display */, false /* store in history */);
    } catch (NoClassDefFoundError e) {
      ScilabModalDialog.show(
          (SimpleTab) SwingUtilities.getAncestorOfClass(SimpleTab.class, x),
          Messages.gettext("Feature not available in this mode..."));
    }
  }

  /**
   * Edit the code in example
   *
   * @param pre the preformatted Element containing Scilab's code
   */
  public static void editExample(Element pre) {
    edit(getCode(pre));
  }

  /**
   * Edit the code
   *
   * @param code the code to edit
   */
  private static void edit(String code) {
    try {
      /* Dynamic load of the SciNotes class.
       * This is done to avoid a cyclic dependency on gui <=> scinotes
       */
      Class scinotesClass = Class.forName("org.scilab.modules.scinotes.SciNotes");
      Class[] arguments = new Class[] {String.class};
      Method method = scinotesClass.getMethod("scinotesWithText", arguments);
      method.invoke(scinotesClass, new Object[] {code});

    } catch (ClassNotFoundException e) {
      System.err.println("Could not find SciNotes class");
      e.printStackTrace();
    } catch (SecurityException e) {
      System.err.println("Security error: Could not access to SciNotes class");
      e.printStackTrace();
    } catch (NoSuchMethodException e) {
      System.err.println("Could not access to scinotesWithText method from object SciNotes");
      e.printStackTrace();
    } catch (IllegalArgumentException e) {
      System.err.println("Wrong argument used with scinotesWithText method from object SciNotes");
      e.printStackTrace();
    } catch (IllegalAccessException e) {
      System.err.println("Illegal access with scinotesWithText method from object SciNotes");
      e.printStackTrace();
    } catch (InvocationTargetException e) {
      System.err.println("Error of invocation with scinotesWithText method from object SciNotes");
      e.printStackTrace();
    }
  }

  /**
   * @param pre the preformatted Element containing Scilab's code
   * @return the code
   */
  private static String getCode(Element pre) {
    int size = pre.getElementCount();
    Document doc = pre.getDocument();
    StringBuilder buffer = new StringBuilder();
    for (int i = 0; i < size; i++) {
      Element line = pre.getElement(i);
      int ssize = line.getElementCount();
      for (int j = 0; j < ssize; j++) {
        Element content = line.getElement(j);
        if (content.isLeaf()) {
          try {
            buffer.append(
                doc.getText(
                    content.getStartOffset(), content.getEndOffset() - content.getStartOffset()));
          } catch (BadLocationException e) {
          }
        }
      }
    }

    return buffer.toString().trim();
  }

  /**
   * Execute a file given by its path
   *
   * @param path the file path
   */
  public void exec(String path) {
    String cmd = "exec('" + path + "', -1)";
    try {
      ScilabInterpreterManagement.asynchronousScilabExec(null, cmd);
    } catch (Exception e) {
    }
  }

  /**
   * Execute with the command and a file given by its path
   *
   * @param command the command to execute
   * @param path the file path
   */
  public void exec(String command, String path) {
    String cmd = command + "('" + path + "')";
    try {
      ScilabInterpreterManagement.asynchronousScilabExec(null, cmd);
    } catch (Exception e) {
    }
  }

  /**
   * Create the UI interface
   *
   * @see javax.help.plaf.basic.BasicContentViewerUI#installUI(javax.swing.JComponent)
   * @param c The component
   */
  @Override
  public void installUI(JComponent c) {
    super.installUI(c);
    this.retrievePrivateFieldFromBasicContentViewerUI();
    this.createPopupMenu(c);
  }

  /**
   * Retrieve the field "html" from BasicContentViewerUI and change permission (it is private by
   * default)
   */
  private void retrievePrivateFieldFromBasicContentViewerUI() {
    Field privateField = null;
    try {
      privateField = BasicContentViewerUI.class.getDeclaredField("html");
      privateField.setAccessible(true);
    } catch (SecurityException e) {
      System.err.println(
          "Security error: Could not change the accessibility on the html component of the help browser.");
      System.err.println("Please submit a bug report: http://bugzilla.scilab.org");
      e.printStackTrace();
    } catch (NoSuchFieldException e) {
      System.err.println("Could not find the field of the html component of the help browser.");
      System.err.println("Please submit a bug report: http://bugzilla.scilab.org");
      e.printStackTrace();
    }

    try {
      this.accessibleHtml = (javax.swing.JEditorPane) privateField.get(this);
      accessibleHtml.setMinimumSize(new Dimension(0, 0));
      accessibleHtml.setPreferredSize(new Dimension(Short.MAX_VALUE, Short.MAX_VALUE));
      accessibleHtml.addPropertyChangeListener(
          new PropertyChangeListener() {
            public void propertyChange(PropertyChangeEvent evt) {
              // Crappy workaround to avoid bad html display (the icons play and edit can be
              // misplaced)
              // To improve... (it doesn't always work)
              if (SwingUtilities.isEventDispatchThread()) {
                if (evt.getPropertyName().equals("document")) {
                  accessibleHtml.setVisible(false);
                }
                if (evt.getPropertyName().equals("page")) {
                  modifyFontInEDT(0);
                  if (!accessibleHtml.isVisible()) {
                    accessibleHtml.setVisible(true);
                  }
                }
              }
            }
          });

      // The previous workaround hides the component accessibleHtml
      // and consequently the focus is given to an other component.
      // So we force the accessibleHtml to keep the focus.
      accessibleHtml.setFocusTraversalPolicy(
          new DefaultFocusTraversalPolicy() {
            @Override
            public Component getFirstComponent(Container aContainer) {
              return x;
            }
          });
      accessibleHtml.setFocusCycleRoot(true);

      String keyModifier = "alt ";
      if (isMac) {
        keyModifier = "meta ";
      }

      InputMap inputmap = accessibleHtml.getInputMap(JComponent.WHEN_IN_FOCUSED_WINDOW);
      inputmap.put(ScilabKeyStroke.getKeyStroke("OSSCKEY shift EQUALS"), SHIFTEQ);
      accessibleHtml
          .getActionMap()
          .put(
              SHIFTEQ,
              new AbstractAction() {
                @Override
                public void actionPerformed(ActionEvent e) {
                  SwingScilabHelpBrowserViewer.this.increaseFont();
                }
              });
      inputmap.put(ScilabKeyStroke.getKeyStroke(keyModifier + "LEFT"), "Previous-page");
      accessibleHtml
          .getActionMap()
          .put(
              "Previous-page",
              new AbstractAction() {
                @Override
                public void actionPerformed(ActionEvent e) {
                  DefaultHelpHistoryModel history = SwingScilabHelpBrowser.getHelpHistory();
                  if (history.getIndex() > 0) {
                    history.goBack();
                  }
                }
              });
      inputmap.put(ScilabKeyStroke.getKeyStroke(keyModifier + "RIGHT"), "Next-page");
      accessibleHtml
          .getActionMap()
          .put(
              "Next-page",
              new AbstractAction() {
                @Override
                public void actionPerformed(ActionEvent e) {
                  DefaultHelpHistoryModel history = SwingScilabHelpBrowser.getHelpHistory();
                  if (history.getHistory().size() != (history.getIndex() + 1)) {
                    history.goForward();
                  }
                }
              });

      inputmap = accessibleHtml.getInputMap(JComponent.WHEN_FOCUSED);
      inputmap.put(ScilabKeyStroke.getKeyStroke(keyModifier + "LEFT"), new Object());
      inputmap.put(ScilabKeyStroke.getKeyStroke(keyModifier + "RIGHT"), new Object());
      inputmap.put(
          ScilabKeyStroke.getKeyStroke("shift SPACE"),
          inputmap.get(ScilabKeyStroke.getKeyStroke("PAGE_UP")));
      inputmap.put(
          ScilabKeyStroke.getKeyStroke("SPACE"),
          inputmap.get(ScilabKeyStroke.getKeyStroke("PAGE_DOWN")));

      SwingUtilities.getAncestorOfClass(JScrollPane.class, accessibleHtml)
          .addMouseWheelListener(this);
    } catch (IllegalArgumentException e) {
      System.err.println("Illegal argument in the retrieval of the html component of Javahelp");
      e.printStackTrace();
    } catch (IllegalAccessException e) {
      System.err.println("Illegal access in the retrieval of the html component of Javahelp");
      e.printStackTrace();
    }
  }

  /**
   * Create the popup menu on the help
   *
   * @param c The graphic component
   */
  private void createPopupMenu(JComponent c) {
    final JPopupMenu popup = new JPopupMenu();

    JMenuItem menuItem;

    /* Execute into Scilab */
    ActionListener actionListenerExecuteIntoScilab =
        (ActionEvent actionEvent) -> {
          String selection = accessibleHtml.getSelectedText();
          if (selection == null) {
            ScilabHelpBrowser.getHelpBrowser()
                .getInfoBar()
                .setText(Messages.gettext("No text selected"));
          } else {
            ScilabConsole.getConsole()
                .getAsSimpleConsole()
                .sendCommandsToScilab(selection, true /* display */, true /* store in history */);
          }
        };
    menuItem = new JMenuItem(Messages.gettext("Execute into Scilab"));
    menuItem.addActionListener(actionListenerExecuteIntoScilab);
    if (!ScilabConsole.isExistingConsole()) {
      /* Only available in STD mode */
      menuItem.setEnabled(false);
    }
    popup.add(menuItem);

    /* Edit in the Scilab Text Editor */
    ActionListener actionListenerLoadIntoTextEditor =
        (ActionEvent actionEvent) -> {
          String selection = accessibleHtml.getSelectedText();
          if (selection == null) {
            ScilabHelpBrowser.getHelpBrowser()
                .getInfoBar()
                .setText(Messages.gettext("No text selected"));
          } else {
            edit(selection);
          }
        };

    menuItem = new JMenuItem(Messages.gettext("Edit in the Scilab Text Editor"));
    try {
      Class scinotesClass = Class.forName("org.scilab.modules.scinotes.SciNotes");
    } catch (ClassNotFoundException e) {
      /* SciNotes not available */
      menuItem.setEnabled(false);
    }
    menuItem.addActionListener(actionListenerLoadIntoTextEditor);
    popup.add(menuItem);
    popup.addSeparator();

    /* Back in the history*/
    ActionListener actionListenerBackHistory =
        (ActionEvent actionEvent) -> {
          DefaultHelpHistoryModel history = SwingScilabHelpBrowser.getHelpHistory();
          /* Not at the first position */
          if (history.getIndex() > 0) {
            SwingScilabHelpBrowser.getHelpHistory().goBack();
          }
        };

    menuItem = new JMenuItem(Messages.gettext("Back"));
    menuItem.addActionListener(actionListenerBackHistory);
    popup.add(menuItem);

    /* Forward in the history*/
    ActionListener actionListenerForwardHistory =
        (ActionEvent actionEvent) -> {
          DefaultHelpHistoryModel history = SwingScilabHelpBrowser.getHelpHistory();
          /* Not at the last position */
          if (history.getHistory().size() != (history.getIndex() + 1)) {
            SwingScilabHelpBrowser.getHelpHistory().goForward();
          }
        };

    menuItem = new JMenuItem(Messages.gettext("Forward"));
    menuItem.addActionListener(actionListenerForwardHistory);
    popup.add(menuItem);
    popup.addSeparator();

    /* Copy */
    menuItem = new JMenuItem(new DefaultEditorKit.CopyAction());
    menuItem.setText(Messages.gettext("Copy"));
    popup.add(menuItem);
    popup.addSeparator();

    /* Select all */
    ActionListener actionListenerSelectAll =
        (ActionEvent actionEvent) -> {
          accessibleHtml.selectAll();
        };
    menuItem = new JMenuItem(Messages.gettext("Select All"));
    menuItem.addActionListener(actionListenerSelectAll);
    popup.add(menuItem);

    /* Edit in the Scilab Text Editor */
    final JMenuItem helpMenuItem = new JMenuItem("Help on the selected text");

    ActionListener actionListenerHelpOnKeyword =
        (ActionEvent actionEvent) -> {
          String selection = accessibleHtml.getSelectedText();
          if (selection == null) {
            ScilabHelpBrowser.getHelpBrowser()
                .getInfoBar()
                .setText(Messages.gettext("No text selected"));
          } else {
            ScilabHelpBrowser.getHelpBrowser().searchKeywork(selection);
          }
        };
    PropertyChangeListener listenerTextItem =
        (PropertyChangeEvent arg0) -> {
          String keyword = accessibleHtml.getSelectedText();
          if (keyword == null) {
            helpMenuItem.setText(Messages.gettext("Help about a selected text"));
          } else {
            int nbOfDisplayedOnlyXChar = 10;
            if (keyword.length() > nbOfDisplayedOnlyXChar) {
              keyword = keyword.substring(0, nbOfDisplayedOnlyXChar) + "...";
            }
            helpMenuItem.setText(Messages.gettext("Help about '") + keyword + "'");
          }
        };
    helpMenuItem.addPropertyChangeListener(listenerTextItem);
    helpMenuItem.addActionListener(actionListenerHelpOnKeyword);
    popup.add(helpMenuItem);

    /* Creates the Popupmenu on the component */
    accessibleHtml.setComponentPopupMenu(popup);
  }

  /**
   * {@inheritedDoc}
   *
   * @param e the mouse event
   */
  @Override
  public void mouseWheelMoved(MouseWheelEvent e) {
    if ((isMac && e.isMetaDown()) || e.isControlDown()) {
      int n = e.getWheelRotation();
      if (currentFontSize != Math.min(Math.max(0, currentFontSize + n), 6)) {
        modifyFontInEDT(n);
      }
      e.consume();
    }
  }

  /**
   * Modify the current base font size
   *
   * @param s the size to add to the current size
   */
  public void modifyFont(final int s) {
    try {
      currentFontSize = Math.min(Math.max(0, currentFontSize + s), 6);
      HTMLDocument doc = (HTMLDocument) accessibleHtml.getDocument();
      StyleContext.NamedStyle style =
          (StyleContext.NamedStyle) doc.getStyleSheet().getStyle("body");
      MutableAttributeSet attr = (MutableAttributeSet) style.getResolveParent();
      if (StyleConstants.getFontSize(attr) != fontSizes[currentFontSize]) {
        ConfigManager.setHelpFontSize(currentFontSize);
        StyleConstants.setFontSize(attr, fontSizes[currentFontSize]);
        accessibleHtml.setVisible(false);
        style.setResolveParent(attr);
        accessibleHtml.setVisible(true);
      }
    } catch (NullPointerException e) {
      // Can occur if the user is changing quickly the document
      SwingUtilities.invokeLater(
          () -> {
            modifyFont(s);
          });
    }
  }

  public void modifyFontInEDT(final int s) {
    if (SwingUtilities.isEventDispatchThread()) {
      modifyFont(s);
    } else {
      SwingUtilities.invokeLater(
          () -> {
            modifyFont(s);
          });
    }
  }

  /** Increase the font size +1 */
  public void increaseFont() {
    if (currentFontSize != Math.min(Math.max(0, currentFontSize + 1), 6)) {
      modifyFontInEDT(1);
    }
  }

  /** Decrease the font size -1 */
  public void decreaseFont() {
    if (currentFontSize != Math.min(Math.max(0, currentFontSize - 1), 6)) {
      modifyFontInEDT(-1);
    }
  }
}