/* * Created on 02.04.2005 */ package net.sourceforge.ganttproject.gui.options; import biz.ganttproject.core.option.BooleanOption; import biz.ganttproject.core.option.ChangeValueEvent; import biz.ganttproject.core.option.ChangeValueListener; import biz.ganttproject.core.option.ColorOption; import biz.ganttproject.core.option.DateOption; import biz.ganttproject.core.option.DefaultBooleanOption; import biz.ganttproject.core.option.DefaultEnumerationOption; import biz.ganttproject.core.option.DoubleOption; import biz.ganttproject.core.option.EnumerationOption; import biz.ganttproject.core.option.FileOption; import biz.ganttproject.core.option.FontOption; import biz.ganttproject.core.option.FontSpec; import biz.ganttproject.core.option.GPOption; import biz.ganttproject.core.option.GPOptionGroup; import biz.ganttproject.core.option.IntegerOption; import biz.ganttproject.core.option.MoneyOption; import biz.ganttproject.core.option.StringOption; import biz.ganttproject.core.option.ValidationException; import com.google.common.base.Function; import com.google.common.base.Objects; import com.google.common.base.Strings; import com.google.common.base.Supplier; import net.sourceforge.ganttproject.action.CancelAction; import net.sourceforge.ganttproject.action.OkAction; import net.sourceforge.ganttproject.gui.GPColorChooser; import net.sourceforge.ganttproject.gui.TextFieldAndFileChooserComponent; import net.sourceforge.ganttproject.gui.UIFacade; import net.sourceforge.ganttproject.gui.UIFacade.Dialog; import net.sourceforge.ganttproject.gui.UIUtil; import net.sourceforge.ganttproject.language.GanttLanguage; import org.jdesktop.swingx.JXDatePicker; import org.jdesktop.swingx.JXHyperlink; import javax.swing.*; import javax.swing.event.ChangeEvent; import javax.swing.event.ChangeListener; import javax.swing.event.DocumentEvent; import javax.swing.event.DocumentListener; import java.awt.*; import java.awt.event.ActionEvent; import java.awt.event.ActionListener; import java.awt.event.FocusAdapter; import java.awt.event.FocusEvent; import java.beans.PropertyChangeEvent; import java.beans.PropertyChangeListener; import java.io.File; import java.math.BigDecimal; import java.text.DecimalFormat; import java.text.NumberFormat; import java.text.ParseException; import java.util.Date; import java.util.Hashtable; import java.util.List; import java.util.Map; import java.util.concurrent.atomic.AtomicReference; /** * @author bard */ public class OptionsPageBuilder { I18N myi18n = new I18N(); private Component myParentComponent; private final LayoutApi myLayoutApi; private UIFacade myUiFacade; private DecimalFormat myFormat; public static interface LayoutApi { void layout(JPanel panel, int componentsCount); } public static LayoutApi TWO_COLUMN_LAYOUT = new LayoutApi() { @Override public void layout(JPanel panel, int componentsCount) { panel.setLayout(new SpringLayout()); SpringUtilities.makeCompactGrid(panel, componentsCount, 2, 0, 0, 5, 3); } }; public static LayoutApi ONE_COLUMN_LAYOUT = new LayoutApi() { @Override public void layout(JPanel panel, int componentsCount) { panel.setLayout(new SpringLayout()); SpringUtilities.makeCompactGrid(panel, componentsCount*2, 1, 0, 0, 5, new Function<Integer, Integer>() { @Override public Integer apply(Integer input) { return input % 2 == 0 ? 5 : 3; } }); } }; public OptionsPageBuilder() { this(null, TWO_COLUMN_LAYOUT); } public OptionsPageBuilder(Component parentComponent, LayoutApi layoutApi) { myParentComponent = parentComponent; myLayoutApi = layoutApi; } public void setUiFacade(UIFacade uiFacade) { myUiFacade = uiFacade; } public void setI18N(I18N i18n) { myi18n = i18n; } public I18N getI18N() { return myi18n; } public void setOptionKeyPrefix(String optionKeyPrefix) { myi18n.myOptionKeyPrefix = optionKeyPrefix; } public JComponent buildPage(GPOptionGroup[] optionGroups, String pageID) { JComponent topPanel = TopPanel.create(myi18n.getPageTitle(pageID), myi18n.getPageDescription(pageID)); JComponent planePage = buildPlanePage(optionGroups); return UIUtil.createTopAndCenter(topPanel, planePage); } public JComponent buildPlanePage(GPOptionGroup[] optionGroups) { final JComponent optionsPanel = new JPanel(new SpringLayout()); for (int i = 0; i < optionGroups.length; i++) { optionsPanel.add(createGroupComponent(optionGroups[i])); } SpringUtilities.makeCompactGrid(optionsPanel, optionGroups.length, 1, 0, 0, 5, 15); JPanel resultPanel = new JPanel(new BorderLayout()); resultPanel.add(optionsPanel, BorderLayout.NORTH); resultPanel.addFocusListener(new FocusAdapter() { @Override public void focusGained(FocusEvent e) { optionsPanel.getComponent(0).requestFocus(); } }); return resultPanel; } public JComponent createLabeledComponent(GPOption<?> option) { GPOptionGroup fake = new GPOptionGroup("", new GPOption[] { option }); fake.setTitled(false); return createGroupComponent(fake); } public JComponent createGroupComponent(GPOptionGroup group) { GPOption<?>[] options = group.getOptions(); final JComponent optionsPanel = createGroupComponent(group, options); if (group.isTitled()) { UIUtil.createTitle(optionsPanel, myi18n.getOptionGroupLabel(group)); } JPanel result = new JPanel(new BorderLayout()); result.add(optionsPanel, BorderLayout.NORTH); result.addFocusListener(new FocusAdapter() { @Override public void focusGained(FocusEvent e) { optionsPanel.requestFocus(); } }); return result; } public JComponent createGroupComponent(GPOptionGroup group, GPOption<?>... options) { JPanel optionsPanel = new JPanel(); int hasUiCount = 0; for (int i = 0; i < options.length; i++) { GPOption<?> nextOption = options[i]; if (!nextOption.hasUi()) { continue; } hasUiCount++; final Component nextComponent = createOptionComponent(group, nextOption); if (needsLabel(group, nextOption)) { Component nextLabel = createOptionLabel(group, options[i]); optionsPanel.add(nextLabel); optionsPanel.add(nextComponent); } else { optionsPanel.add(nextComponent); optionsPanel.add(new JPanel()); } if (i == 0) { optionsPanel.addFocusListener(new FocusAdapter() { @Override public void focusGained(FocusEvent e) { super.focusGained(e); nextComponent.requestFocus(); } }); } } if (hasUiCount > 0) { myLayoutApi.layout(optionsPanel, hasUiCount); } return optionsPanel; } private boolean needsLabel(GPOptionGroup group, GPOption<?> nextOption) { // if (nextOption instanceof BooleanOption) { // return !isCheckboxOption(group, nextOption); // } return true; } public Component createStandaloneOptionPanel(GPOption<?> option) { JPanel optionPanel = new JPanel(new BorderLayout()); Component optionComponent = createOptionComponent(null, option); if (needsLabel(null, option)) { optionPanel.add(createOptionLabel(null, option), BorderLayout.WEST); optionPanel.add(optionComponent, BorderLayout.CENTER); } else { optionPanel.add(optionComponent, BorderLayout.WEST); } JPanel result = new JPanel(new BorderLayout()); result.add(optionPanel, BorderLayout.NORTH); return result; } public Component createWaitIndicatorComponent(DefaultBooleanOption controller) { final JProgressBar progressBar = new JProgressBar(); JPanel placeholder = new JPanel(); final JPanel result = new JPanel(new CardLayout()); result.add(placeholder, "placeholder"); result.add(progressBar, "progressBar"); controller.addChangeValueListener(new ChangeValueListener() { @Override public void changeValue(ChangeValueEvent event) { if (Boolean.TRUE.equals(event.getNewValue())) { progressBar.setIndeterminate(true); ((CardLayout) result.getLayout()).show(result, "progressBar"); } else { progressBar.setIndeterminate(false); ((CardLayout) result.getLayout()).show(result, "placeholder"); } } }); return result; } public Component createOptionLabel(GPOptionGroup group, GPOption<?> option) { JLabel nextLabel = new JLabel(myi18n.getOptionLabel(group, option)); nextLabel.setVerticalAlignment(SwingConstants.TOP); nextLabel.setBorder(BorderFactory.createEmptyBorder(2, 0, 0, 0)); return nextLabel; } public Component createOptionComponent(GPOptionGroup group, GPOption<?> option) { Component result = null; if (option instanceof EnumerationOption) { result = createEnumerationComponent((EnumerationOption) option, group); } else if (option instanceof FileOption) { result = createFileComponent((FileOption) option); } else if (option instanceof BooleanOption) { result = createBooleanComponent(group, (BooleanOption) option); } else if (option instanceof ColorOption) { result = createColorComponent((ColorOption) option).getJComponent(); } else if (option instanceof DateOption) { result = createDateComponent((DateOption) option); } else if (option instanceof GPOptionGroup) { result = createButtonComponent((GPOptionGroup) option); } else if (option instanceof StringOption) { result = createStringComponent((StringOption) option); } else if (option instanceof IntegerOption) { result = createValidatingComponent((IntegerOption) option, new ValueValidator<Integer>() { @Override public Integer parse(String text) { return Integer.valueOf(text); } }); } else if (option instanceof DoubleOption) { result = createValidatingComponent((DoubleOption) option, new ValueValidator<Double>() { @Override public Double parse(String text) { return Double.valueOf(text); } }); } else if (option instanceof MoneyOption) { result = createValidatingComponent((MoneyOption) option, new ValueValidator<BigDecimal>() { private NumberFormat myFormat; { DecimalFormat format = (DecimalFormat) NumberFormat.getNumberInstance(GanttLanguage.getInstance().getLocale()); format.setParseBigDecimal(true); myFormat = format; } @Override public BigDecimal parse(String text) throws ValidationException { try { return Strings.isNullOrEmpty(text) ? BigDecimal.ZERO : (BigDecimal) myFormat.parse(text); } catch (ParseException e) { e.printStackTrace(); throw new ValidationException(e); } } }); } else if (option instanceof FontOption) { result = createFontComponent((FontOption)option); } if (result == null) { result = new JLabel("Unknown option class=" + option.getClass()); } result.setEnabled(option.isWritable()); final Component finalResult = result; option.addPropertyChangeListener(new PropertyChangeListener() { @Override public void propertyChange(PropertyChangeEvent evt) { if ("isWritable".equals(evt.getPropertyName())) { assert evt.getNewValue() instanceof Boolean : "Unexpected value of property isWritable: " + evt.getNewValue(); finalResult.setEnabled((Boolean) evt.getNewValue()); } } }); return result; } private static Color getValidFieldColor() { return UIUtil.getValidFieldColor(); } private static void updateTextField(final JTextField textField, final DocumentListener listener, final ChangeValueEvent event) { SwingUtilities.invokeLater(new Runnable() { @Override public void run() { textField.getDocument().removeDocumentListener(listener); if (!textField.getText().equals(event.getNewValue())) { String newText = String.valueOf(event.getNewValue()); textField.setText(newText); } textField.getDocument().addDocumentListener(listener); } }); } private Component createFileComponent(final FileOption option) { final TextFieldAndFileChooserComponent result = new TextFieldAndFileChooserComponent(myUiFacade, myi18n.getValue(myi18n.myOptionKeyPrefix + option.getID() + ".dialogTitle")) { @Override protected void onFileChosen(File file) { option.setValue(file.getAbsolutePath()); } }; if (option.getValue() != null) { result.setFile(new File(option.getValue())); } option.addChangeValueListener(new ChangeValueListener() { @Override public void changeValue(ChangeValueEvent event) { result.setFile(new File(String.valueOf(event.getNewValue()))); } }); return result; } private Component createStringComponent(final StringOption option) { final JTextField result = option.isScreened() ? new JPasswordField(option.getValue()) : new JTextField(option.getValue()); final DocumentListener documentListener = new DocumentListener() { private void saveValue() { try { option.setValue(result.getText()); result.setBackground(getValidFieldColor()); } catch (ValidationException ex) { result.setBackground(UIUtil.INVALID_FIELD_COLOR); } } @Override public void insertUpdate(DocumentEvent e) { saveValue(); } @Override public void removeUpdate(DocumentEvent e) { saveValue(); } @Override public void changedUpdate(DocumentEvent e) { saveValue(); } }; result.getDocument().addDocumentListener(documentListener); option.addChangeValueListener(new ChangeValueListener() { @Override public void changeValue(final ChangeValueEvent event) { updateTextField(result, documentListener, event); } }); return result; } private Component createButtonComponent(GPOptionGroup optionGroup) { Action action = new AbstractAction(myi18n.getAdvancedActionTitle()) { @Override public void actionPerformed(ActionEvent e) { System.err.println("[OptionsPageBuilder] createButtonComponent: "); } }; JButton result = new JButton(action); return result; } private Component createBooleanComponent(GPOptionGroup group, final BooleanOption option) { if (!isCheckboxOption(group, option)) { return createRadioButtonBooleanComponent(group, option); } final JCheckBox result = new JCheckBox(new BooleanOptionAction(option)); String trailingLabel = getTrailingLabel(option); if (trailingLabel != null) { result.setText(trailingLabel); } result.setHorizontalAlignment(JCheckBox.LEFT); result.setHorizontalTextPosition(SwingConstants.TRAILING); result.setSelected(option.isChecked()); ComponentOrientation componentOrientation = GanttLanguage.getInstance().getComponentOrientation(); result.setComponentOrientation(componentOrientation); option.addChangeValueListener(new ChangeValueListener() { @Override public void changeValue(ChangeValueEvent event) { result.setSelected(option.getValue()); } }); return result; } private String getTrailingLabel(BooleanOption option) { String trailingLabelKey = myi18n.getCanonicalOptionLabelKey(option) + ".trailing"; return myi18n.hasValue(trailingLabelKey) ? myi18n.getValue(trailingLabelKey) : null; } private boolean isCheckboxOption(GPOptionGroup group, GPOption<?> option) { String yesKey = myi18n.getCanonicalOptionLabelKey(option) + ".yes"; if ((group == null || group.getI18Nkey(yesKey) == null) && !myi18n.hasValue(yesKey)) { return true; } String noKey = myi18n.getCanonicalOptionLabelKey(option) + ".no"; if ((group == null || group.getI18Nkey(noKey) == null) && !myi18n.hasValue(noKey)) { return true; } return false; } public static class BooleanOptionRadioUi { private final JRadioButton myYesButton; private final JRadioButton myNoButton; private BooleanOptionRadioUi(final BooleanOption option) { myYesButton = new JRadioButton(new AbstractAction("") { @Override public void actionPerformed(ActionEvent e) { if (!option.isChecked()) { option.setValue(true); } } }); myYesButton.setVerticalAlignment(SwingConstants.CENTER); myYesButton.setSelected(option.isChecked()); myNoButton = new JRadioButton(new AbstractAction("") { @Override public void actionPerformed(ActionEvent e) { if (option.isChecked()) { option.setValue(false); } } }); myNoButton.setSelected(!option.isChecked()); ButtonGroup buttonGroup = new ButtonGroup(); buttonGroup.add(myYesButton); buttonGroup.add(myNoButton); option.addChangeValueListener(new ChangeValueListener() { @Override public void changeValue(ChangeValueEvent event) { if (Boolean.TRUE.equals(event.getNewValue())) { myYesButton.setSelected(true); } else { myNoButton.setSelected(true); } } }); } public JRadioButton getYesButton() { return myYesButton; } public JRadioButton getNoButton() { return myNoButton; } public Component getComponent() { Box result = Box.createVerticalBox(); result.add(myYesButton); result.add(Box.createVerticalStrut(2)); result.add(myNoButton); result.add(Box.createVerticalGlue()); return result; } } public static BooleanOptionRadioUi createBooleanOptionRadioUi(BooleanOption option) { return new BooleanOptionRadioUi(option); } private Component createRadioButtonBooleanComponent(GPOptionGroup group, final BooleanOption option) { BooleanOptionRadioUi radioUi = createBooleanOptionRadioUi(option); radioUi.getYesButton().setText(myi18n.getValue(group, myi18n.getCanonicalOptionLabelKey(option) + ".yes")); radioUi.getNoButton().setText(myi18n.getValue(group, myi18n.getCanonicalOptionLabelKey(option) + ".no")); return radioUi.getComponent(); } private JComboBox createEnumerationComponent(final EnumerationOption option, final GPOptionGroup group) { return createEnumerationComponent(option, new Supplier<EnumerationOptionComboBoxModel>() { @Override public EnumerationOptionComboBoxModel get() { return new EnumerationOptionComboBoxModel(option, group); } }); } private JComboBox createEnumerationComponent(final EnumerationOption option, final Supplier<EnumerationOptionComboBoxModel> modelFactory) { final JComboBox result = new JComboBox(modelFactory.get()); option.addChangeValueListener(new ChangeValueListener() { @Override public void changeValue(ChangeValueEvent event) { EnumerationOptionComboBoxModel model = (EnumerationOptionComboBoxModel) result.getModel(); model.onValueChange(); result.setSelectedItem(model.getSelectedItem()); } }); option.addPropertyChangeListener(new PropertyChangeListener() { @Override public void propertyChange(PropertyChangeEvent evt) { if (EnumerationOption.VALUE_SET.equals(evt.getPropertyName())) { EnumerationOptionComboBoxModel model = modelFactory.get(); result.setModel(model); result.setSelectedItem(model.getSelectedItem()); } } }); return result; } public static interface ColorComponent { JComponent getJComponent(); void openChooser(); void setOnCancelCallback(Runnable onCancel); void setOnOkCallback(Runnable runnable); } public ColorComponent createColorComponent(final ColorOption option) { final JXHyperlink colorButton = new JXHyperlink(); final JPanel label = new JPanel(); label.setPreferredSize(new Dimension(16, 16)); label.setBackground(option.getValue()); option.addChangeValueListener(new ChangeValueListener() { @Override public void changeValue(ChangeValueEvent event) { label.setBackground(option.getValue()); } }); final AtomicReference<Runnable> onOk = new AtomicReference<>(); final AtomicReference<Runnable> onCancel = new AtomicReference<>(); final Action action = new AbstractAction(myi18n.getColorButtonText(option)) { @Override public void actionPerformed(ActionEvent e) { final GPColorChooser colorChooser = new GPColorChooser(); OkAction okAction = new OkAction() { @Override public void actionPerformed(ActionEvent arg0) { Color color = colorChooser.getColor(); label.setBackground(color); option.setValue(color); List<Color> recentColors = GPColorChooser.getRecentColors(); // If we already have such color in the recent list then we remove it // If we failed to remove selected color (=> it was not in the list) // and the list is long enough then we remove colors from the tail if (!recentColors.remove(color) && recentColors.size() == 10) { recentColors.remove(9); } recentColors.add(0, color); GPColorChooser.setRecentColors(recentColors); if (onOk.get() != null) { onOk.get().run(); } } }; final CancelAction cancelAction = new CancelAction() { @Override public void actionPerformed(ActionEvent e) { super.actionPerformed(e); if (onCancel.get() != null) { onCancel.get().run(); } } }; colorChooser.setColor(colorButton.getBackground()); Dialog dialog = myUiFacade.createDialog( colorChooser.buildComponent(), new Action[] {okAction, cancelAction}, myi18n.getColorChooserTitle(option)); dialog.show(); }; }; colorButton.setAction(action); final JPanel buttonPanel = new JPanel(new FlowLayout(FlowLayout.LEADING, 0, 0)); buttonPanel.add(label); buttonPanel.add(new JLabel(" ")); buttonPanel.add(colorButton); return new ColorComponent() { @Override public void openChooser() { action.actionPerformed(null); } @Override public JComponent getJComponent() { return buttonPanel; } @Override public void setOnCancelCallback(Runnable runnable) { onCancel.set(runnable); } @Override public void setOnOkCallback(Runnable runnable) { onOk.set(runnable); } }; } public Component createFontComponent(final FontOption option) { final Object CLIENT_ID = new Object(); final DefaultEnumerationOption<String> familiesOption = new DefaultEnumerationOption<>("", option.getFontFamilies()); if (option.getValue() != null) { familiesOption.setValue(option.getValue().getFamily()); } JComboBox comboBox = createEnumerationComponent(familiesOption, new Supplier<EnumerationOptionComboBoxModel>() { @Override public EnumerationOptionComboBoxModel get() { return new EnumerationOptionComboBoxModel(familiesOption, option.getFontFamilies().toArray(new String[0])); } }); final JSlider slider = new JSlider(0, 4); slider.setPaintTicks(false); Hashtable<Integer, JComponent> labels = new Hashtable<Integer, JComponent>(); for (Map.Entry<FontSpec.Size, String> label : option.getSizeLabels().entrySet()) { labels.put(label.getKey().ordinal(), new JLabel(label.getValue())); } slider.setLabelTable(labels); slider.setPaintLabels(true); if (option.getValue() != null) { slider.setValue(option.getValue().getSize().ordinal()); } ChangeValueListener uiChangeListener = new ChangeValueListener() { @Override public void changeValue(ChangeValueEvent event) { option.setValue(new FontSpec(familiesOption.getValue(), FontSpec.Size.values()[slider.getValue()]), CLIENT_ID); } }; familiesOption.addChangeValueListener(uiChangeListener); slider.addChangeListener(new ChangeListener() { public void stateChanged(ChangeEvent arg0) { option.setValue(new FontSpec(familiesOption.getValue(), FontSpec.Size.values()[slider.getValue()]), CLIENT_ID); } }); final Box buttonPanel = Box.createVerticalBox(); buttonPanel.add(comboBox); buttonPanel.add(slider); buttonPanel.setBorder(BorderFactory.createEmptyBorder(0, 0, 5, 0)); return buttonPanel; } public JComponent createDateComponent(final DateOption option) { class OptionValueUpdater implements ActionListener, PropertyChangeListener { @Override public void actionPerformed(ActionEvent e) { option.setValue(((JXDatePicker) e.getSource()).getDate()); } @Override public void propertyChange(PropertyChangeEvent evt) { if (evt.getNewValue() instanceof Date && !evt.getNewValue().equals(option.getValue())) { option.setValue((Date) evt.getNewValue()); } } } OptionValueUpdater valueUpdater = new OptionValueUpdater(); final JXDatePicker result = UIUtil.createDatePicker(); UIUtil.setupDatePicker(result, option.getValue(), null, valueUpdater); result.setDate(option.getValue()); result.getEditor().addPropertyChangeListener("value", valueUpdater); option.addChangeValueListener(new ChangeValueListener() { @Override public void changeValue(ChangeValueEvent event) { assert event.getNewValue() == null || event.getNewValue() instanceof Date : "value=" + event.getNewValue(); result.setDate((Date) event.getNewValue()); } }); return result; } public interface ValueValidator<T> { T parse(String text) throws ValidationException; } /** * Create JTextField component in options that allows user to input only * integer values. * * @param option * @return */ public static <T extends Number> Component createValidatingComponent(final GPOption<T> option, final ValueValidator<T> parser) { final JTextField result = new JTextField(String.valueOf(option.getValue())); final DocumentListener listener = UIUtil.attachValidator(result, parser, option); option.addChangeValueListener(new ChangeValueListener() { @Override public void changeValue(final ChangeValueEvent event) { if (!Objects.equal(parser, event.getTriggerID())) { updateTextField(result, listener, event); } } }); return result; } public static class I18N { private String myOptionKeyPrefix = "option."; private String myOptionGroupKeyPrefix = "optionGroup."; private String myOptionPageKeyPrefix = "optionPage."; public I18N() { } protected boolean hasValue(String key) { return GanttLanguage.getInstance().getText(key) != null; } protected String getValue(String key) { String result = GanttLanguage.getInstance().getText(key); return result == null ? key : result; } public String getValue(GPOptionGroup group, String canonicalKey) { String key = group == null ? null : group.getI18Nkey(canonicalKey); return getValue(key == null ? canonicalKey : key); } public String getPageTitle(String pageID) { return getValue(getCanonicalOptionPageTitleKey(pageID)); } public String getPageDescription(String pageID) { return GanttLanguage.getInstance().getText(myOptionPageKeyPrefix + pageID + ".description"); } public String getOptionGroupLabel(GPOptionGroup group) { String canonicalKey = getCanonicalOptionGroupLabelKey(group); return getValue(group, canonicalKey); } public String getOptionLabel(GPOptionGroup group, GPOption<?> option) { String result = null; if (group != null) { String keyWithGroup = String.format("%s%s.%s.label", myOptionKeyPrefix, group.getID(), option.getID()); result = getValue(group, keyWithGroup); if (!Objects.equal(result, keyWithGroup)) { return result; } } String canonicalKey = getCanonicalOptionLabelKey(option); return getValue(group, canonicalKey); } public final String getCanonicalOptionPageLabelKey(String pageID) { return myOptionPageKeyPrefix + pageID + ".label"; } public final String getCanonicalOptionPageTitleKey(String pageID) { return myOptionPageKeyPrefix + pageID + ".title"; } public String getCanonicalOptionPageDescriptionKey(String pageID) { return myOptionPageKeyPrefix + pageID + ".description"; } public final String getCanonicalOptionGroupLabelKey(GPOptionGroup group) { return myOptionGroupKeyPrefix + group.getID() + ".label"; } public final String getCanonicalOptionLabelKey(GPOption<?> option) { return myOptionKeyPrefix + option.getID() + ".label"; } public static final String getCanonicalOptionValueLabelKey(String valueID) { return "optionValue." + valueID + ".label"; } String getAdvancedActionTitle() { return GanttLanguage.getInstance().getText("optionAdvanced.label"); } String getColorButtonText(ColorOption colorOption) { return GanttLanguage.getInstance().getText("colorButton"); } String getColorChooserTitle(ColorOption colorOption) { return GanttLanguage.getInstance().getText("selectColor"); } } //private static GPColorChooser ourColorChooser = new GPColorChooser(ImmutableList.of(Color.BLACK, Color.RED, Color.GREEN, Color.BLUE)); }