/**
   * Convenience method that retrieves an instance of the MuAction denoted by the given {@link
   * ActionParameters} and associated with the given {@link com.mucommander.ui.main.MainFrame} and
   * calls {@link MuAction#performAction()} on it. Returns <code>true</code> if an instance of the
   * action could be retrieved and performed, <code>false</code> if the MuAction could not be found
   * or could not be instantiated.
   *
   * @param actionParameters the ActionParameters of the action to perform
   * @param mainFrame the MainFrame the action belongs to
   * @return true if the action instance could be retrieved and the action performed, false
   *     otherwise
   */
  public static boolean performAction(ActionParameters actionParameters, MainFrame mainFrame) {
    MuAction action = getActionInstance(actionParameters, mainFrame);

    if (action == null) return false;

    action.performAction();

    return true;
  }
  /**
   * Returns an instance of the MuAction class denoted by the given ActionParameters and for the
   * specified MainFrame. If an existing instance corresponding to the same ActionParameters and
   * MainFrame is found, it is simply returned. If no matching instance could be found, a new
   * instance is created, added to the internal action instances map (for further use) and returned.
   * If the action denoted by the specified ActionParameters cannot be found or cannot be
   * instantiated, <code>null</code> is returned.
   *
   * @param actionParameters a descriptor of the action to instantiate with initial properties
   * @param mainFrame the MainFrame instance the action belongs to
   * @return a MuAction instance matching the given ActionParameters and MainFrame, <code>null
   *     </code> if the MuAction action denoted by the ActionParameters could not be found or could
   *     not be instantiated.
   */
  public static MuAction getActionInstance(ActionParameters actionParameters, MainFrame mainFrame) {
    Map<ActionParameters, ActionAndIdPair> mainFrameActions = mainFrameActionsMap.get(mainFrame);
    if (mainFrameActions == null) {
      mainFrameActions = new Hashtable<ActionParameters, ActionAndIdPair>();
      mainFrameActionsMap.put(mainFrame, mainFrameActions);
    }

    // Looks for an existing MuAction instance used by the specified MainFrame
    if (mainFrameActions.containsKey(actionParameters)) {
      return mainFrameActions.get(actionParameters).getAction();
    } else {
      String actionId = actionParameters.getActionId();

      // Looks for the action's factory
      ActionFactory actionFactory = actionFactories.get(actionId);
      if (actionFactory == null) {
        LOGGER.debug("couldn't initiate action: " + actionId + ", its factory wasn't found");
        return null;
      }

      Map<String, Object> properties = actionParameters.getInitProperties();
      // If no properties hashtable is specified in the action descriptor
      if (properties == null) {
        properties = new Hashtable<String, Object>();
      }
      // else clone the hashtable to ensure that it doesn't get modified by action instances.
      // Since cloning is an expensive operation, this is done only if the hashtable is not empty.
      else if (!properties.isEmpty()) {
        Map<String, Object> buffer;

        buffer = new Hashtable<String, Object>();
        buffer.putAll(properties);
        properties = buffer;
      }

      // Instantiate the MuAction class
      MuAction action = actionFactory.createAction(mainFrame, properties);
      mainFrameActions.put(actionParameters, new ActionAndIdPair(action, actionId));

      // If the action's label has not been set yet, use the action descriptor's
      if (action.getLabel() == null) {
        // Retrieve the standard label entry from the dictionary and use it as this action's label
        String label = ActionProperties.getActionLabel(actionId);

        // Append '...' to the label if this action invokes a dialog when performed
        if (action instanceof InvokesDialog) label += "...";

        action.setLabel(label);

        // Looks for a standard label entry in the dictionary and if it is defined, use it as this
        // action's tooltip
        String tooltip = ActionProperties.getActionTooltip(actionId);
        if (tooltip != null) action.setToolTipText(tooltip);
      }

      // If the action's accelerators have not been set yet, use the ones from ActionKeymap
      if (action.getAccelerator() == null) {
        // Retrieve the standard accelerator (if any) and use it as this action's accelerator
        KeyStroke accelerator = ActionKeymap.getAccelerator(actionId);
        if (accelerator != null) action.setAccelerator(accelerator);

        // Retrieve the standard alternate accelerator (if any) and use it as this action's
        // alternate accelerator
        accelerator = ActionKeymap.getAlternateAccelerator(actionId);
        if (accelerator != null) action.setAlternateAccelerator(accelerator);
      }

      // If the action's icon has not been set yet, use the action descriptor's
      if (action.getIcon() == null) {
        // Retrieve the standard icon image (if any) and use it as the action's icon
        ImageIcon icon = ActionProperties.getActionIcon(actionId);
        if (icon != null) action.setIcon(icon);
      }

      return action;
    }
  }