/**
   * Add a file to the sketch.
   *
   * <p>Supported code files will be copied to the sketch folder. All other files will be copied to
   * the "data" folder (which is created if it does not exist yet).
   *
   * @return true if successful.
   */
  public boolean addFile(File sourceFile) {
    String filename = sourceFile.getName();
    File destFile = null;
    boolean isData = false;
    boolean replacement = false;

    if (FileUtils.hasExtension(sourceFile, Sketch.EXTENSIONS)) {
      destFile = new File(sketch.getFolder(), filename);
    } else {
      sketch.prepareDataFolder();
      destFile = new File(sketch.getDataFolder(), filename);
      isData = true;
    }

    // check whether this file already exists
    if (destFile.exists()) {
      Object[] options = {tr("OK"), tr("Cancel")};
      String prompt = I18n.format(tr("Replace the existing version of {0}?"), filename);
      int result =
          JOptionPane.showOptionDialog(
              editor,
              prompt,
              tr("Replace"),
              JOptionPane.YES_NO_OPTION,
              JOptionPane.QUESTION_MESSAGE,
              null,
              options,
              options[0]);
      if (result == JOptionPane.YES_OPTION) {
        replacement = true;
      } else {
        return false;
      }
    }

    // If it's a replacement, delete the old file first,
    // otherwise case changes will not be preserved.
    // http://dev.processing.org/bugs/show_bug.cgi?id=969
    if (replacement) {
      boolean muchSuccess = destFile.delete();
      if (!muchSuccess) {
        Base.showWarning(
            tr("Error adding file"),
            I18n.format(tr("Could not delete the existing ''{0}'' file."), filename),
            null);
        return false;
      }
    }

    // make sure they aren't the same file
    if (isData && sourceFile.equals(destFile)) {
      Base.showWarning(
          tr("You can't fool me"),
          tr(
              "This file has already been copied to the\n"
                  + "location from which where you're trying to add it.\n"
                  + "I ain't not doin nuthin'."),
          null);
      return false;
    }

    // in case the user is "adding" the code in an attempt
    // to update the sketch's tabs
    if (!sourceFile.equals(destFile)) {
      try {
        Base.copyFile(sourceFile, destFile);

      } catch (IOException e) {
        Base.showWarning(
            tr("Error adding file"),
            I18n.format(tr("Could not add ''{0}'' to the sketch."), filename),
            e);
        return false;
      }
    }

    if (!isData) {
      int tabIndex;
      if (replacement) {
        tabIndex = editor.findTabIndex(destFile);
        editor.getTabs().get(tabIndex).reload();
      } else {
        SketchFile sketchFile;
        try {
          sketchFile = sketch.addFile(destFile.getName());
          editor.addTab(sketchFile, null);
        } catch (IOException e) {
          // This does not pass on e, to prevent showing a backtrace for
          // "normal" errors.
          Base.showWarning(tr("Error"), e.getMessage(), null);
          return false;
        }
        tabIndex = editor.findTabIndex(sketchFile);
      }
      editor.selectTab(tabIndex);
    }
    return true;
  }