Esempio n. 1
0
  /** Shows a swing dialog to eit the available settings. */
  public static void showSettingsDialog() {
    // Create a tabbed panel, one tab per category.
    JTabbedPane categoriesPane = new JTabbedPane();

    // A list of actions taken when validating, i.e. when setting all settings to the input values.
    List<Supplier<Boolean>> actions = new ArrayList<>();

    // Create a panel.
    // For each available setting:
    for (Field settingField : getSettableFields()) {
      // Retrieve the annotation.
      SettingsField fieldInfo = settingField.getAnnotation(SettingsField.class);

      // Search for an existing category panel.
      Integer categoryIndex = null;
      for (int candidateCategoryIndex = 0;
          candidateCategoryIndex < categoriesPane.getTabCount();
          candidateCategoryIndex++) {
        if (categoriesPane.getTitleAt(candidateCategoryIndex).equals(fieldInfo.category())) {
          categoryIndex = candidateCategoryIndex;
          break;
        }
      }

      // If the category exists, retrieve its pane, otherwise create it.
      JPanel categoryPanel = null;
      if (categoryIndex != null) {
        categoryPanel = (JPanel) categoriesPane.getComponentAt(categoryIndex);
      } else {
        categoryPanel = new JPanel();
        categoryPanel.setLayout(new BoxLayout(categoryPanel, BoxLayout.Y_AXIS));
        categoriesPane.add(categoryPanel, fieldInfo.category());
      }

      // If the name wasn't set, get the field's declared name.
      String actualName = fieldInfo.name().isEmpty() ? settingField.getName() : fieldInfo.name();

      // Prepare a label text.
      String labelText = fieldInfo.description().isEmpty() ? actualName : fieldInfo.description();
      // Create an optional label for component that need it.
      JLabel label = new JLabel(labelText);

      JComponent editionComponent;

      // Handle enums.
      if (settingField.getType().isEnum()) {
        JComboBox<?> comboBox = new JComboBox<>(settingField.getType().getEnumConstants());
        comboBox.setSelectedItem(get(settingField));
        actions.add(
            () -> {
              set(settingField, comboBox.getSelectedItem());
              return true;
            });
        // Add a label then the component.
        editionComponent = new JPanel();
        editionComponent.add(label);
        editionComponent.add(comboBox);
      } else {
        // Handle primitive types
        switch (settingField.getType().getSimpleName().toLowerCase()) {
          case "boolean":
            JCheckBox checkbox = new JCheckBox(labelText, (boolean) get(settingField));
            editionComponent = checkbox;
            actions.add(
                () -> {
                  set(settingField, checkbox.isSelected());
                  return true;
                });
            break;
          case "string":
            // If there are possible values, use a combobox.
            if (fieldInfo.possibleValues().length != 0) {
              JComboBox<String> comboBox = new JComboBox<>(fieldInfo.possibleValues());
              actions.add(
                  () -> {
                    set(settingField, comboBox.getSelectedItem());
                    return true;
                  });
              // Add a label then the component.
              editionComponent = new JPanel();
              editionComponent.add(label);
              editionComponent.add(comboBox);
            } else {
              // Otherwise, use a simple text field.
              JTextField textField = new JTextField((String) get(settingField));
              actions.add(
                  () -> {
                    set(settingField, textField.getText());
                    return true;
                  });
              // Add a label then the component.
              editionComponent = new JPanel();
              editionComponent.add(label);
              editionComponent.add(textField);
            }
            break;
          case "int":
          case "integer":
            int currentIntValue = (int) get(settingField);
            SpinnerModel spinnerModel =
                new SpinnerNumberModel(
                    currentIntValue, fieldInfo.minValue(), fieldInfo.maxValue(), 1);
            JSpinner spinner = new JSpinner(spinnerModel);

            spinner.setValue(currentIntValue);
            actions.add(
                () -> {
                  set(settingField, spinner.getValue());
                  return true;
                });
            // Add a label then the component.
            editionComponent = new JPanel();
            editionComponent.add(label);
            editionComponent.add(spinner);
            break;
          default:
            editionComponent = new JTextField("Unknown setting type");
            editionComponent.setEnabled(false);
            break;
        }
      }

      categoryPanel.add(editionComponent);

      // Add a fancy tooltip.
      if (fieldInfo.description() != null && !fieldInfo.description().isEmpty()) {
        editionComponent.setToolTipText(fieldInfo.description());
      }
    }

    // Put the panel in a modal frame.
    JDialog dialog = new JDialog((Frame) null, "Settings", true);
    dialog.add(categoriesPane);

    // Add a validation and cancel button.
    JPanel bottomButtons = new JPanel(new FlowLayout(TRAILING));
    dialog.add(bottomButtons, BorderLayout.SOUTH);
    JButton okButton = new JButton("OK");
    {
      okButton.addActionListener(
          e -> {
            for (Supplier<Boolean> action : actions) {
              action.get();
            }
            saveToFile();
            // Call all callbacks on all categories.
            Set<Method> callbacks = getSettingsCallbacks();
            callbacks
                .stream()
                .forEach(
                    m -> {
                      try {
                        m.invoke(null);
                      } catch (IllegalAccessException
                          | IllegalArgumentException
                          | InvocationTargetException ex) {
                        Logger.getLogger(SettingsHandler.class.getName())
                            .log(Level.SEVERE, null, ex);
                      }
                    });

            dialog.dispose();
          });
    }
    bottomButtons.add(okButton);
    JButton cancelButton = new JButton("Cancel");
    {
      cancelButton.addActionListener(
          e -> {
            dialog.dispose();
          });
    }
    bottomButtons.add(cancelButton);

    dialog.pack();
    dialog.setVisible(true);
  }