private boolean confirmAndSave() {
    boolean continueWizard = true;

    if (confirmSave()) {
      if (validateSave()) {
        save();
        continueWizard = false;
      }
    } else {
      // 用户选择了“退出不保存”,所以要恢复原始的数据
      propSet.reloadUserProperties();
      continueWizard = false;
    }

    return continueWizard;
  }
  private void save() {
    Map modifiedProperties = propSet.getModifiedProperties();

    println();
    println("╭───────────────────────┈┈┈┈");
    println("│ 保存文件 " + getURI() + "...");
    println("│┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈");

    try {
      OutputStream os = propSet.getUserPropertiesFile().getResource().getOutputStream();
      String charset = propSet.getUserPropertiesFile().getCharset();

      fileWriter = new PrintWriter(new OutputStreamWriter(os, charset), true);
    } catch (IOException e) {
      throw new ConfigWizardException(e);
    }

    try {
      List[] keyGroups = getSortedKeys(modifiedProperties, 2);

      for (int i = 0; i < keyGroups.length; i++) {
        List keys = keyGroups[i];

        // 找出最长的名称
        int maxLength = -1;

        for (Iterator j = keys.iterator(); j.hasNext(); ) {
          String key = (String) j.next();
          int length = key.length();

          if (length > maxLength && length < MAX_ALIGN) {
            maxLength = length;
          }
        }

        // 输出property项
        for (Iterator j = keys.iterator(); j.hasNext(); ) {
          String key = (String) j.next();
          String value = (String) modifiedProperties.get(key);

          if (value == null) {
            value = "";
          }

          value = value.replaceAll("\\\\", "\\\\\\\\");

          StringBuffer buffer = new StringBuffer();

          buffer.append(key);

          for (int k = 0; k < maxLength - key.length(); k++) {
            buffer.append(' ');
          }

          buffer.append("  = ").append(value);

          println(buffer);
        }

        if (i < keyGroups.length - 1) {
          println();
        }
      }
    } finally {
      fileWriter.close();
      fileWriter = null;
    }

    println("└───────┈┈┈┈┈┈┈┈┈┈┈");
    println(" 已保存至文件: " + getURI());

    propSet.reloadUserProperties();
  }
  private void printGroup() {
    if (group.getDescription() != null) {
      println(" " + group.getDescription() + " (? - 该值在用户配置文件中不存在,* - 必填项,S - 覆盖共享默认值,s - 共享值)");
    } else {
      println(" (? - 该值在用户配置文件中不存在,* - 必填项,S - 覆盖共享默认值,s - 共享值)");
    }

    println();

    // 找出最长的名称和值
    int maxLength = -1;
    int maxLengthValue = -1;

    for (ConfigProperty prop : props) {
      int length = prop.getName().length();

      if (length > maxLength && length < MAX_ALIGN) {
        maxLength = length;
      }
    }

    for (ConfigProperty prop : props) {
      String value = getPropertyValue(prop, true);
      int length =
          Math.max(prop.getName().length(), maxLength)
              + (value == null ? 0 : "  = ".length() + value.length());

      if (length > maxLengthValue && length < MAX_ALIGN * 2) {
        maxLengthValue = length;
      }
    }

    for (int i = 0; i < props.length; i++) {
      ConfigProperty prop = props[i];

      StringBuffer buffer = new StringBuffer();

      // 如果项目在配置文件中不存在,则显示?
      boolean absent = !getKeys().contains(prop.getName());

      // 如果是必填项, 则显示*号
      boolean required = prop.isRequired();

      // 如果项目定义在shared properties中,则显示S
      boolean shared = propSet.isShared(prop.getName());

      if (shared) {
        if (absent) {
          buffer.append("s");
        } else {
          buffer.append("S");
        }
      } else {
        if (absent) {
          buffer.append("?");
        } else {
          buffer.append(" ");
        }
      }

      if (required) {
        buffer.append("* ");
      } else {
        buffer.append("  ");
      }

      // 显示property序号
      buffer.append(i + 1).append(" - ");

      // 显示property名称
      buffer.append(prop.getName());

      // 显示property值
      String value = getPropertyValue(prop, true);

      if (value != null) {
        for (int j = 0; j < maxLength - prop.getName().length(); j++) {
          buffer.append(' ');
        }

        buffer.append("  = ").append(value);
      }

      // 显示property描述
      if (prop.getDescription() != null) {
        int length =
            value == null
                ? prop.getName().length()
                : Math.max(prop.getName().length(), maxLength) + "  = ".length() + value.length();

        for (int j = 0; j < maxLengthValue - length; j++) {
          buffer.append(' ');
        }

        buffer.append("   # ").append(prop.getDescription());
      }

      // 如果值是表达式,则同时显示表达式的计算值
      String evaluatedValue = evaluatePropertyValue(prop, true);

      if (evaluatedValue != null && !ObjectUtil.equals(value, evaluatedValue)) {
        buffer.append("\n");

        for (int j = 0; j < maxLength; j++) {
          buffer.append(' ');
        }

        buffer.append("          (").append(evaluatedValue).append(")");

        if (i < props.length - 1) {
          buffer.append("\n");
        }
      }

      println(buffer);
    }

    println();
  }
 private Map getValues() {
   return propSet.getMergedProperties();
 }
 private Set getKeys() {
   return propSet.getMergedKeys();
 }
 private String getURI() {
   return propSet.getUserPropertiesFile().getURI().toString();
 }