mirror of
https://github.com/bancika/diy-layout-creator
synced 2026-11-13 02:32:09 +10:00
Added 'Value Notation' to the Config menu
This commit is contained in:
+157
-57
@@ -26,6 +26,8 @@ import java.awt.Color;
|
||||
import java.awt.Container;
|
||||
import java.awt.event.ActionEvent;
|
||||
import java.awt.event.ActionListener;
|
||||
import java.awt.event.FocusAdapter;
|
||||
import java.awt.event.FocusEvent;
|
||||
import java.awt.event.KeyListener;
|
||||
import java.beans.PropertyChangeEvent;
|
||||
import java.beans.PropertyChangeListener;
|
||||
@@ -34,12 +36,19 @@ import java.lang.reflect.Constructor;
|
||||
import java.lang.reflect.Method;
|
||||
import java.lang.reflect.ParameterizedType;
|
||||
import java.lang.reflect.Type;
|
||||
import java.util.ArrayList;
|
||||
import java.util.List;
|
||||
import java.util.function.Function;
|
||||
import javax.swing.JComboBox;
|
||||
import javax.swing.JTextField;
|
||||
import org.apache.log4j.Logger;
|
||||
import org.diylc.swingframework.DoubleArrayTextField;
|
||||
|
||||
import org.diylc.common.PropertyWrapper;
|
||||
import org.diylc.core.measures.AbstractMeasure;
|
||||
import org.diylc.core.measures.Unit;
|
||||
import org.diylc.core.measures.ValueNotation;
|
||||
import org.diylc.core.measures.ValueNotation.ParsedMeasure;
|
||||
import org.diylc.utils.Constants;
|
||||
|
||||
public class MeasureArrayEditor extends Container {
|
||||
@@ -50,52 +59,59 @@ public class MeasureArrayEditor extends Container {
|
||||
.getLogger(MeasureArrayEditor.class);
|
||||
|
||||
private Color oldBg;
|
||||
private DoubleArrayTextField valueField;
|
||||
private JTextField valueField;
|
||||
private JComboBox<Object> unitBox;
|
||||
private boolean ignoreUnitChanges = false;
|
||||
|
||||
@SuppressWarnings("unchecked")
|
||||
public MeasureArrayEditor(final PropertyWrapper property) {
|
||||
setLayout(new BorderLayout());
|
||||
final AbstractMeasure<?>[] measure = ((AbstractMeasure<?>[]) property
|
||||
.getValue());
|
||||
Double[] values = new Double[measure.length];
|
||||
for (int i = 0; i < measure.length; i++) {
|
||||
values[i] = measure[i] == null ? null : measure[i].getValue();
|
||||
}
|
||||
valueField = new DoubleArrayTextField(measure == null ? null : values);
|
||||
if (property.isReadOnly())
|
||||
valueField.setEnabled(false);
|
||||
oldBg = valueField.getBackground();
|
||||
valueField.addPropertyChangeListener(
|
||||
DoubleArrayTextField.VALUE_PROPERTY,
|
||||
new PropertyChangeListener() {
|
||||
final Function<String, Unit> unitResolver = MeasureEditor
|
||||
.getUnitResolver(property.getType().getComponentType());
|
||||
if (unitResolver == null) {
|
||||
valueField = createDoubleField(property, measure);
|
||||
} else {
|
||||
final MeasureTextField<List<ParsedMeasure<Unit>>> measureField = new MeasureTextField<List<ParsedMeasure<Unit>>>(
|
||||
formatForField(measure), text -> parseSections(text, unitResolver));
|
||||
measureField.addPropertyChangeListener(MeasureTextField.VALUE_PROPERTY,
|
||||
new PropertyChangeListener() {
|
||||
|
||||
@Override
|
||||
public void propertyChange(PropertyChangeEvent evt) {
|
||||
try {
|
||||
Constructor<?> ctor = property.getType().getComponentType()
|
||||
.getConstructors()[0];
|
||||
Double[] newValues = (Double[]) evt.getNewValue();
|
||||
AbstractMeasure<?>[] newMeasure;
|
||||
if (newValues == null)
|
||||
newMeasure = null;
|
||||
else {
|
||||
newMeasure = (AbstractMeasure<?>[]) Array.newInstance(property.getType().getComponentType(), newValues.length);
|
||||
for (int i = 0; i < newValues.length; i++) {
|
||||
newMeasure[i] = (AbstractMeasure<?>) ctor
|
||||
.newInstance(newValues[i],
|
||||
unitBox.getSelectedItem());
|
||||
@Override
|
||||
public void propertyChange(PropertyChangeEvent evt) {
|
||||
List<ParsedMeasure<Unit>> parsed = (List<ParsedMeasure<Unit>>) evt
|
||||
.getNewValue();
|
||||
// the unit box shows the unit of the first section
|
||||
if (parsed != null && !parsed.isEmpty() && parsed.get(0) != null
|
||||
&& parsed.get(0).unit() != null
|
||||
&& parsed.get(0).unit() != unitBox.getSelectedItem()) {
|
||||
ignoreUnitChanges = true;
|
||||
try {
|
||||
unitBox.setSelectedItem(parsed.get(0).unit());
|
||||
} finally {
|
||||
ignoreUnitChanges = false;
|
||||
}
|
||||
}
|
||||
|
||||
property.setValue(newMeasure);
|
||||
property.setChanged(true);
|
||||
valueField.setBackground(oldBg);
|
||||
unitBox.setBackground(oldBg);
|
||||
} catch (Exception e) {
|
||||
LOG.error("Error while updating property value", e);
|
||||
applySections(property, parsed, false);
|
||||
}
|
||||
});
|
||||
measureField.addFocusListener(new FocusAdapter() {
|
||||
|
||||
@Override
|
||||
public void focusLost(FocusEvent e) {
|
||||
if (measureField.getValue() != null) {
|
||||
measureField.setDisplayText(
|
||||
formatForField((AbstractMeasure<?>[]) property.getValue()));
|
||||
}
|
||||
});
|
||||
}
|
||||
});
|
||||
valueField = measureField;
|
||||
}
|
||||
if (property.isReadOnly()) {
|
||||
valueField.setEnabled(false);
|
||||
}
|
||||
oldBg = valueField.getBackground();
|
||||
add(valueField, BorderLayout.CENTER);
|
||||
try {
|
||||
Type type = ((ParameterizedType) property.getType().getComponentType()
|
||||
@@ -108,29 +124,18 @@ public class MeasureArrayEditor extends Container {
|
||||
|
||||
@Override
|
||||
public void actionPerformed(ActionEvent evt) {
|
||||
try {
|
||||
Constructor<?> ctor = property.getType().getComponentType()
|
||||
.getConstructors()[0];
|
||||
|
||||
AbstractMeasure<?>[] newMeasure;
|
||||
Double[] newValues = valueField.getValue();
|
||||
if (newValues == null)
|
||||
newMeasure = null;
|
||||
else {
|
||||
newMeasure = (AbstractMeasure<?>[]) Array.newInstance(property.getType().getComponentType(), newValues.length);
|
||||
for (int i = 0; i < newValues.length; i++) {
|
||||
newMeasure[i] = (AbstractMeasure<?>) ctor
|
||||
.newInstance(newValues[i],
|
||||
unitBox.getSelectedItem());
|
||||
}
|
||||
if (ignoreUnitChanges) {
|
||||
return;
|
||||
}
|
||||
if (valueField instanceof DoubleArrayTextField doubleField) {
|
||||
applyValues(property, doubleField.getValue());
|
||||
} else {
|
||||
MeasureTextField<List<ParsedMeasure<Unit>>> measureField = (MeasureTextField<List<ParsedMeasure<Unit>>>) valueField;
|
||||
if (measureField.getValue() != null) {
|
||||
applySections(property, measureField.getValue(), true);
|
||||
measureField.setDisplayText(
|
||||
formatForField((AbstractMeasure<?>[]) property.getValue()));
|
||||
}
|
||||
|
||||
property.setValue(newMeasure);
|
||||
property.setChanged(true);
|
||||
valueField.setBackground(oldBg);
|
||||
unitBox.setBackground(oldBg);
|
||||
} catch (Exception e) {
|
||||
LOG.error("Error while updating property units", e);
|
||||
}
|
||||
}
|
||||
});
|
||||
@@ -145,6 +150,101 @@ public class MeasureArrayEditor extends Container {
|
||||
}
|
||||
}
|
||||
|
||||
private DoubleArrayTextField createDoubleField(final PropertyWrapper property,
|
||||
AbstractMeasure<?>[] measure) {
|
||||
Double[] values = new Double[measure.length];
|
||||
for (int i = 0; i < measure.length; i++) {
|
||||
values[i] = measure[i] == null ? null : measure[i].getValue();
|
||||
}
|
||||
DoubleArrayTextField valueField = new DoubleArrayTextField(measure == null ? null : values);
|
||||
valueField.addPropertyChangeListener(
|
||||
DoubleArrayTextField.VALUE_PROPERTY,
|
||||
new PropertyChangeListener() {
|
||||
|
||||
@Override
|
||||
public void propertyChange(PropertyChangeEvent evt) {
|
||||
applyValues(property, (Double[]) evt.getNewValue());
|
||||
}
|
||||
});
|
||||
return valueField;
|
||||
}
|
||||
|
||||
private void applyValues(PropertyWrapper property, Double[] newValues) {
|
||||
try {
|
||||
Constructor<?> ctor = property.getType().getComponentType()
|
||||
.getConstructors()[0];
|
||||
AbstractMeasure<?>[] newMeasure;
|
||||
if (newValues == null)
|
||||
newMeasure = null;
|
||||
else {
|
||||
newMeasure = (AbstractMeasure<?>[]) Array.newInstance(property.getType().getComponentType(), newValues.length);
|
||||
for (int i = 0; i < newValues.length; i++) {
|
||||
newMeasure[i] = (AbstractMeasure<?>) ctor
|
||||
.newInstance(newValues[i],
|
||||
unitBox.getSelectedItem());
|
||||
}
|
||||
}
|
||||
|
||||
property.setValue(newMeasure);
|
||||
property.setChanged(true);
|
||||
valueField.setBackground(oldBg);
|
||||
unitBox.setBackground(oldBg);
|
||||
} catch (Exception e) {
|
||||
LOG.error("Error while updating property value", e);
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Sections typed with their own unit keep it, the others take the unit selected in the box.
|
||||
* When the box itself changed, its unit is applied to every section.
|
||||
*/
|
||||
private void applySections(PropertyWrapper property, List<ParsedMeasure<Unit>> sections,
|
||||
boolean forceBoxUnit) {
|
||||
try {
|
||||
Constructor<?> ctor = property.getType().getComponentType()
|
||||
.getConstructors()[0];
|
||||
AbstractMeasure<?>[] newMeasure = null;
|
||||
if (sections != null) {
|
||||
newMeasure = (AbstractMeasure<?>[]) Array.newInstance(property.getType().getComponentType(), sections.size());
|
||||
for (int i = 0; i < sections.size(); i++) {
|
||||
ParsedMeasure<Unit> section = sections.get(i);
|
||||
Object unit = section == null || section.unit() == null || forceBoxUnit
|
||||
? unitBox.getSelectedItem() : section.unit();
|
||||
newMeasure[i] = (AbstractMeasure<?>) ctor
|
||||
.newInstance(section == null ? null : section.value(), unit);
|
||||
}
|
||||
}
|
||||
property.setValue(newMeasure);
|
||||
property.setChanged(true);
|
||||
valueField.setBackground(oldBg);
|
||||
unitBox.setBackground(oldBg);
|
||||
} catch (Exception e) {
|
||||
LOG.error("Error while updating property value", e);
|
||||
}
|
||||
}
|
||||
|
||||
private static List<ParsedMeasure<Unit>> parseSections(String text,
|
||||
Function<String, Unit> unitResolver) {
|
||||
List<ParsedMeasure<Unit>> sections = new ArrayList<ParsedMeasure<Unit>>();
|
||||
for (String part : text.split("/", -1)) {
|
||||
sections.add(part.trim().isEmpty() ? null : ValueNotation.parse(part, unitResolver));
|
||||
}
|
||||
return sections;
|
||||
}
|
||||
|
||||
private static String formatForField(AbstractMeasure<?>[] measure) {
|
||||
if (measure == null) {
|
||||
return "";
|
||||
}
|
||||
Object boxUnit = measure.length == 0 || measure[0] == null ? null : measure[0].getUnit();
|
||||
List<String> parts = new ArrayList<String>();
|
||||
for (AbstractMeasure<?> section : measure) {
|
||||
parts.add(MeasureEditor.formatForField(section,
|
||||
section == null || section.getUnit() == boxUnit));
|
||||
}
|
||||
return String.join(" / ", parts);
|
||||
}
|
||||
|
||||
@Override
|
||||
public void requestFocus() {
|
||||
this.valueField.requestFocus();
|
||||
|
||||
@@ -26,6 +26,8 @@ import java.awt.Color;
|
||||
import java.awt.Container;
|
||||
import java.awt.event.ActionEvent;
|
||||
import java.awt.event.ActionListener;
|
||||
import java.awt.event.FocusAdapter;
|
||||
import java.awt.event.FocusEvent;
|
||||
import java.awt.event.KeyListener;
|
||||
import java.beans.PropertyChangeEvent;
|
||||
import java.beans.PropertyChangeListener;
|
||||
@@ -33,12 +35,22 @@ import java.lang.reflect.Constructor;
|
||||
import java.lang.reflect.Method;
|
||||
import java.lang.reflect.ParameterizedType;
|
||||
import java.lang.reflect.Type;
|
||||
import java.text.DecimalFormat;
|
||||
import java.text.Format;
|
||||
import java.util.function.Function;
|
||||
import javax.swing.JComboBox;
|
||||
import javax.swing.JTextField;
|
||||
import org.apache.log4j.Logger;
|
||||
import org.diylc.appframework.miscutils.ConfigurationManager;
|
||||
import org.diylc.common.IPlugInPort;
|
||||
import org.diylc.core.measures.Capacitance;
|
||||
import org.diylc.core.measures.CapacitanceUnit;
|
||||
import org.diylc.core.measures.Resistance;
|
||||
import org.diylc.core.measures.ResistanceUnit;
|
||||
import org.diylc.core.measures.Size;
|
||||
import org.diylc.core.measures.SizeUnit;
|
||||
import org.diylc.core.measures.ValueNotation;
|
||||
import org.diylc.core.measures.ValueNotation.ParsedMeasure;
|
||||
import org.diylc.swingframework.DoubleTextField;
|
||||
|
||||
import org.diylc.common.PropertyWrapper;
|
||||
@@ -52,39 +64,70 @@ public class MeasureEditor extends Container {
|
||||
|
||||
private final static Logger LOG = Logger.getLogger(MeasureEditor.class);
|
||||
|
||||
private static final Format DECIMAL_FORMAT = new DecimalFormat("0.#####");
|
||||
|
||||
private Color oldBg;
|
||||
private DoubleTextField valueField;
|
||||
private JTextField valueField;
|
||||
private JComboBox<Object> unitBox;
|
||||
private boolean ignoreUnitChanges = false;
|
||||
|
||||
@SuppressWarnings("unchecked")
|
||||
public MeasureEditor(final PropertyWrapper property) {
|
||||
setLayout(new BorderLayout());
|
||||
AbstractMeasure<?> measure = ((AbstractMeasure<?>) property.getValue());
|
||||
measure = convertUnitsIfNeeded(measure);
|
||||
valueField = new DoubleTextField(measure == null ? null : measure.getValue());
|
||||
oldBg = valueField.getBackground();
|
||||
valueField.addPropertyChangeListener(DoubleTextField.VALUE_PROPERTY, new PropertyChangeListener() {
|
||||
final Function<String, Unit> unitResolver = getUnitResolver(property.getType());
|
||||
if (unitResolver == null) {
|
||||
final DoubleTextField doubleField =
|
||||
new DoubleTextField(measure == null ? null : measure.getValue());
|
||||
doubleField.addPropertyChangeListener(DoubleTextField.VALUE_PROPERTY,
|
||||
new PropertyChangeListener() {
|
||||
|
||||
@Override
|
||||
public void propertyChange(PropertyChangeEvent evt) {
|
||||
try {
|
||||
Double newValue = (Double) evt.getNewValue();
|
||||
if (newValue == null) {
|
||||
property.setValue(null);
|
||||
} else {
|
||||
Constructor<?> ctor = property.getType().getConstructors()[0];
|
||||
AbstractMeasure<?> newMeasure =
|
||||
(AbstractMeasure<?>) ctor.newInstance(newValue, unitBox.getSelectedItem());
|
||||
property.setValue(newMeasure);
|
||||
@Override
|
||||
public void propertyChange(PropertyChangeEvent evt) {
|
||||
applyValue(property, (Double) evt.getNewValue(), unitBox.getSelectedItem());
|
||||
}
|
||||
});
|
||||
valueField = doubleField;
|
||||
} else {
|
||||
final MeasureTextField<ParsedMeasure<Unit>> measureField =
|
||||
new MeasureTextField<ParsedMeasure<Unit>>(formatForField(measure, true),
|
||||
text -> ValueNotation.parse(text, unitResolver));
|
||||
measureField.addPropertyChangeListener(MeasureTextField.VALUE_PROPERTY,
|
||||
new PropertyChangeListener() {
|
||||
|
||||
@Override
|
||||
public void propertyChange(PropertyChangeEvent evt) {
|
||||
ParsedMeasure<Unit> parsed = (ParsedMeasure<Unit>) evt.getNewValue();
|
||||
if (parsed == null) {
|
||||
applyValue(property, null, unitBox.getSelectedItem());
|
||||
return;
|
||||
}
|
||||
// a unit typed together with the value, e.g. 4K7, also switches the unit box
|
||||
if (parsed.unit() != null && parsed.unit() != unitBox.getSelectedItem()) {
|
||||
ignoreUnitChanges = true;
|
||||
try {
|
||||
unitBox.setSelectedItem(parsed.unit());
|
||||
} finally {
|
||||
ignoreUnitChanges = false;
|
||||
}
|
||||
}
|
||||
applyValue(property, parsed.value(), unitBox.getSelectedItem());
|
||||
}
|
||||
});
|
||||
measureField.addFocusListener(new FocusAdapter() {
|
||||
|
||||
@Override
|
||||
public void focusLost(FocusEvent e) {
|
||||
if (measureField.getValue() != null) {
|
||||
measureField.setDisplayText(
|
||||
formatForField((AbstractMeasure<?>) property.getValue(), true));
|
||||
}
|
||||
property.setChanged(true);
|
||||
valueField.setBackground(oldBg);
|
||||
unitBox.setBackground(oldBg);
|
||||
} catch (Exception e) {
|
||||
LOG.error("Error while updating property value", e);
|
||||
}
|
||||
}
|
||||
});
|
||||
});
|
||||
valueField = measureField;
|
||||
}
|
||||
oldBg = valueField.getBackground();
|
||||
add(valueField, BorderLayout.CENTER);
|
||||
try {
|
||||
Type type = ((ParameterizedType) property.getType().getGenericSuperclass()).getActualTypeArguments()[0];
|
||||
@@ -95,33 +138,27 @@ public class MeasureEditor extends Container {
|
||||
|
||||
@Override
|
||||
public void actionPerformed(ActionEvent evt) {
|
||||
if (ignoreUnitChanges) {
|
||||
return;
|
||||
}
|
||||
try {
|
||||
Double newValue = valueField.getValue();
|
||||
if (newValue == null) {
|
||||
property.setValue(null);
|
||||
} else {
|
||||
Constructor<?> ctor = property.getType().getConstructors()[0];
|
||||
if (property.isReadOnly()) {
|
||||
double oldFactor = ((Unit)((AbstractMeasure<?>)property.getValue()).getUnit()).getFactor();
|
||||
double newFactor = ((Unit)unitBox.getSelectedItem()).getFactor();
|
||||
newValue = newValue * oldFactor / newFactor;
|
||||
valueField.setValue(newValue);
|
||||
}
|
||||
AbstractMeasure<?> newMeasure =
|
||||
(AbstractMeasure<?>) ctor.newInstance(newValue,
|
||||
(Enum<? extends Unit>) unitBox.getSelectedItem());
|
||||
property.setValue(newMeasure);
|
||||
Double newValue = getFieldValue();
|
||||
if (newValue != null && property.isReadOnly()) {
|
||||
double oldFactor = ((Unit)((AbstractMeasure<?>)property.getValue()).getUnit()).getFactor();
|
||||
double newFactor = ((Unit)unitBox.getSelectedItem()).getFactor();
|
||||
newValue = newValue * oldFactor / newFactor;
|
||||
}
|
||||
applyValue(property, newValue, unitBox.getSelectedItem());
|
||||
if (newValue != null && (property.isReadOnly() || unitResolver != null)) {
|
||||
setFieldValue((AbstractMeasure<?>) property.getValue());
|
||||
}
|
||||
property.setChanged(true);
|
||||
valueField.setBackground(oldBg);
|
||||
unitBox.setBackground(oldBg);
|
||||
} catch (Exception e) {
|
||||
LOG.error("Error while updating property units", e);
|
||||
}
|
||||
}
|
||||
});
|
||||
add(unitBox, BorderLayout.EAST);
|
||||
|
||||
|
||||
if (property.isReadOnly()) {
|
||||
valueField.setEnabled(false);
|
||||
unitBox.setEnabled(true);
|
||||
@@ -136,6 +173,70 @@ public class MeasureEditor extends Container {
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns the function that resolves unit symbols typed together with the value, or null when
|
||||
* the measure only accepts a plain number.
|
||||
*/
|
||||
static Function<String, Unit> getUnitResolver(Class<?> measureType) {
|
||||
if (Resistance.class.equals(measureType)) {
|
||||
return ResistanceUnit::fromSymbol;
|
||||
}
|
||||
if (Capacitance.class.equals(measureType)) {
|
||||
return CapacitanceUnit::fromSymbol;
|
||||
}
|
||||
return null;
|
||||
}
|
||||
|
||||
/**
|
||||
* Text shown in the value field. It is always decimal, whatever the selected value notation,
|
||||
* because the unit box beside it already shows the unit; the unit is written out only when it
|
||||
* differs from the one in the box.
|
||||
*/
|
||||
static String formatForField(AbstractMeasure<?> measure, boolean unitShownInBox) {
|
||||
if (measure == null || measure.getValue() == null) {
|
||||
return "";
|
||||
}
|
||||
String number;
|
||||
synchronized (DECIMAL_FORMAT) {
|
||||
number = DECIMAL_FORMAT.format(measure.getValue());
|
||||
}
|
||||
return unitShownInBox || measure.getUnit() == null ? number : number + measure.getUnit();
|
||||
}
|
||||
|
||||
private void applyValue(PropertyWrapper property, Double newValue, Object unit) {
|
||||
try {
|
||||
if (newValue == null) {
|
||||
property.setValue(null);
|
||||
} else {
|
||||
Constructor<?> ctor = property.getType().getConstructors()[0];
|
||||
property.setValue((AbstractMeasure<?>) ctor.newInstance(newValue, unit));
|
||||
}
|
||||
property.setChanged(true);
|
||||
valueField.setBackground(oldBg);
|
||||
unitBox.setBackground(oldBg);
|
||||
} catch (Exception e) {
|
||||
LOG.error("Error while updating property value", e);
|
||||
}
|
||||
}
|
||||
|
||||
@SuppressWarnings("unchecked")
|
||||
private Double getFieldValue() {
|
||||
if (valueField instanceof DoubleTextField doubleField) {
|
||||
return doubleField.getValue();
|
||||
}
|
||||
ParsedMeasure<Unit> parsed = ((MeasureTextField<ParsedMeasure<Unit>>) valueField).getValue();
|
||||
return parsed == null ? null : parsed.value();
|
||||
}
|
||||
|
||||
@SuppressWarnings("unchecked")
|
||||
private void setFieldValue(AbstractMeasure<?> measure) {
|
||||
if (valueField instanceof DoubleTextField doubleField) {
|
||||
doubleField.setValue(measure == null ? null : measure.getValue());
|
||||
} else {
|
||||
((MeasureTextField<ParsedMeasure<Unit>>) valueField).setDisplayText(formatForField(measure, true));
|
||||
}
|
||||
}
|
||||
|
||||
private AbstractMeasure<?> convertUnitsIfNeeded(AbstractMeasure<?> value) {
|
||||
if (ConfigurationManager.getInstance().readBoolean(IPlugInPort.AUTO_UNIT_CONVERSION_KEY, true)
|
||||
&& value instanceof Size sizeValue) {
|
||||
|
||||
@@ -0,0 +1,131 @@
|
||||
/*
|
||||
|
||||
DIY Layout Creator (DIYLC).
|
||||
Copyright (c) 2009-2025 held jointly by the individual authors.
|
||||
|
||||
This file is part of DIYLC.
|
||||
|
||||
DIYLC is free software: you can redistribute it and/or modify
|
||||
it under the terms of the GNU General Public License as published by
|
||||
the Free Software Foundation, either version 3 of the License, or
|
||||
(at your option) any later version.
|
||||
|
||||
DIYLC is distributed in the hope that it will be useful,
|
||||
but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
GNU General Public License for more details.
|
||||
|
||||
You should have received a copy of the GNU General Public License
|
||||
along with DIYLC. If not, see <http://www.gnu.org/licenses/>.
|
||||
|
||||
*/
|
||||
package org.diylc.swing.gui.editor;
|
||||
|
||||
import java.awt.BorderLayout;
|
||||
import java.util.function.Function;
|
||||
import javax.swing.BorderFactory;
|
||||
import javax.swing.JLabel;
|
||||
import javax.swing.JTextField;
|
||||
import javax.swing.event.DocumentEvent;
|
||||
import javax.swing.event.DocumentListener;
|
||||
|
||||
import org.diylc.utils.IconLoader;
|
||||
|
||||
/**
|
||||
* {@link JTextField} that parses its text on every change and fires {@link #VALUE_PROPERTY} with
|
||||
* the result, showing a warning icon while the text cannot be parsed. Unlike
|
||||
* {@code DoubleTextField} the text is never rewritten while the user types; call
|
||||
* {@link #setDisplayText(String)} to reformat it.
|
||||
*
|
||||
* @author Branislav Stojkovic
|
||||
*
|
||||
* @param <T> type of the parsed value
|
||||
*/
|
||||
public class MeasureTextField<T> extends JTextField {
|
||||
|
||||
private static final long serialVersionUID = 1L;
|
||||
|
||||
public static final String VALUE_PROPERTY = "MeasureValue";
|
||||
|
||||
private final Function<String, T> parser;
|
||||
private final JLabel errorLabel;
|
||||
|
||||
private T value;
|
||||
private boolean ignoreChanges = false;
|
||||
|
||||
/**
|
||||
* @param text initial text
|
||||
* @param parser turns non-empty text into a value, throwing {@link IllegalArgumentException} when
|
||||
* it cannot
|
||||
*/
|
||||
public MeasureTextField(String text, Function<String, T> parser) {
|
||||
super();
|
||||
this.parser = parser;
|
||||
setLayout(new BorderLayout());
|
||||
errorLabel = new JLabel(IconLoader.Warning.getIcon());
|
||||
errorLabel.setBorder(BorderFactory.createEmptyBorder(3, 0, 0, 0));
|
||||
add(errorLabel, BorderLayout.EAST);
|
||||
setDisplayText(text);
|
||||
getDocument().addDocumentListener(new DocumentListener() {
|
||||
|
||||
@Override
|
||||
public void changedUpdate(DocumentEvent e) {
|
||||
textChanged();
|
||||
}
|
||||
|
||||
@Override
|
||||
public void insertUpdate(DocumentEvent e) {
|
||||
textChanged();
|
||||
}
|
||||
|
||||
@Override
|
||||
public void removeUpdate(DocumentEvent e) {
|
||||
textChanged();
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
public T getValue() {
|
||||
return value;
|
||||
}
|
||||
|
||||
/**
|
||||
* Replaces the text without firing {@link #VALUE_PROPERTY}.
|
||||
*/
|
||||
public void setDisplayText(String text) {
|
||||
ignoreChanges = true;
|
||||
try {
|
||||
setText(text);
|
||||
value = parseQuietly(text);
|
||||
errorLabel.setVisible(value == null);
|
||||
} finally {
|
||||
ignoreChanges = false;
|
||||
}
|
||||
}
|
||||
|
||||
private T parseQuietly(String text) {
|
||||
try {
|
||||
return text == null || text.trim().isEmpty() ? null : parser.apply(text);
|
||||
} catch (IllegalArgumentException e) {
|
||||
return null;
|
||||
}
|
||||
}
|
||||
|
||||
private void textChanged() {
|
||||
if (ignoreChanges) {
|
||||
return;
|
||||
}
|
||||
T newValue;
|
||||
try {
|
||||
newValue = getText().trim().isEmpty() ? null : parser.apply(getText());
|
||||
} catch (IllegalArgumentException e) {
|
||||
value = null;
|
||||
errorLabel.setVisible(true);
|
||||
return;
|
||||
}
|
||||
T oldValue = value;
|
||||
value = newValue;
|
||||
errorLabel.setVisible(false);
|
||||
firePropertyChange(VALUE_PROPERTY, oldValue, newValue);
|
||||
}
|
||||
}
|
||||
@@ -40,6 +40,7 @@ import org.diylc.core.Theme;
|
||||
import org.diylc.utils.FlagLoader;
|
||||
import org.diylc.lang.LangUtil;
|
||||
import org.diylc.lang.Language;
|
||||
import org.diylc.presenter.ValueNotationBinder;
|
||||
import org.diylc.swing.ActionFactory;
|
||||
import org.diylc.swing.ISwingUI;
|
||||
import org.diylc.utils.IconLoader;
|
||||
@@ -58,6 +59,7 @@ public class ConfigPlugin implements IPlugIn {
|
||||
private static final String THEME_MENU = "Theme";
|
||||
private static final String RULER_MENU = "Ruler Inch Subdivision...";
|
||||
private static final String SNAP_MENU = "Snap To";
|
||||
private static final String VALUE_NOTATION_MENU = "Value Notation";
|
||||
private static final String CATEGORIES_MENU = "Component Categories";
|
||||
private static final String COMPONENT_BROWSER_MENU = "Toolbox";
|
||||
public static final String COMPONENT_BROWSER = "componentBrowser";
|
||||
@@ -196,6 +198,17 @@ public class ConfigPlugin implements IPlugIn {
|
||||
ActionFactory.getInstance()
|
||||
.createConfigAction(plugInPort, "Sticky Points", IPlugInPort.STICKY_POINTS_KEY, true), CONFIG_MENU);
|
||||
|
||||
swingUI.injectSubmenu(VALUE_NOTATION_MENU, IconLoader.Decimal.getIcon(), CONFIG_MENU);
|
||||
swingUI.injectMenuAction(
|
||||
ActionFactory.getInstance().createToggleAction(IPlugInPort.VALUE_NOTATION_DECIMAL,
|
||||
IPlugInPort.VALUE_NOTATION_KEY, VALUE_NOTATION_MENU, IPlugInPort.VALUE_NOTATION_DEFAULT),
|
||||
VALUE_NOTATION_MENU);
|
||||
swingUI.injectMenuAction(
|
||||
ActionFactory.getInstance().createToggleAction(IPlugInPort.VALUE_NOTATION_RKM,
|
||||
IPlugInPort.VALUE_NOTATION_KEY, VALUE_NOTATION_MENU, IPlugInPort.VALUE_NOTATION_DEFAULT),
|
||||
VALUE_NOTATION_MENU);
|
||||
ValueNotationBinder.bind(ConfigurationManager.getInstance(), plugInPort::refresh);
|
||||
|
||||
Map<String, String> themeContents = ResourceUtils.getResourceContents(THEMES_DIR);
|
||||
if (!themeContents.isEmpty()) {
|
||||
XStream xStream = new XStream(new DomDriver());
|
||||
|
||||
@@ -51,8 +51,8 @@ public enum IconLoader {
|
||||
"coffeebean_edit.png"), Component("component.png"), ComponentAdd(
|
||||
"component_add.png"), ComponentLarge("component_large.png"), ComponentPreferences(
|
||||
"component_preferences.png"), ComponentReplace("component_replace.png"), Copy(
|
||||
"copy.png"), Cut("cut.png"), Dashboard("dashboard.png"), DataFind("data_find.png"), Delete(
|
||||
"delete.png"), DiskBlue("disk_blue.png"), DistributeCentersHorizontal(
|
||||
"copy.png"), Cut("cut.png"), Dashboard("dashboard.png"), DataFind("data_find.png"), Decimal(
|
||||
"decimal.png"), Delete("delete.png"), DiskBlue("disk_blue.png"), DistributeCentersHorizontal(
|
||||
"distribute_centers_horizontal.png"), DistributeCentersVertical(
|
||||
"distribute_centers_vertical.png"), DistributeSpacingHorizontal(
|
||||
"distribute_spacing_horizontal.png"), DistributeSpacingVertical(
|
||||
|
||||
Binary file not shown.
|
After Width: | Height: | Size: 769 B |
@@ -729,3 +729,6 @@ Are you sure you want to delete variant "%s"?|Möchten Sie die Variante "%s" wir
|
||||
Delete|Löschen
|
||||
Set default model|Als Standardmodell festlegen
|
||||
Remove default model|Standardmodell entfernen
|
||||
Value Notation|Wertnotation
|
||||
Decimal (4.7K, 0.22uF)|Dezimal (4.7K, 0.22uF)
|
||||
RKM (4K7, 0u22)|RKM (4K7, 0u22)
|
||||
|
||||
@@ -722,3 +722,6 @@ Are you sure you want to delete variant "%s"?
|
||||
Delete
|
||||
Set default model
|
||||
Remove default model
|
||||
Value Notation
|
||||
Decimal (4.7K, 0.22uF)
|
||||
RKM (4K7, 0u22)
|
||||
|
||||
@@ -725,3 +725,6 @@ Are you sure you want to delete variant "%s"?|¿Seguro que desea eliminar la var
|
||||
Delete|Eliminar
|
||||
Set default model|Establecer como modelo predeterminado
|
||||
Remove default model|Quitar modelo predeterminado
|
||||
Value Notation|Notación de valores
|
||||
Decimal (4.7K, 0.22uF)|Decimal (4.7K, 0.22uF)
|
||||
RKM (4K7, 0u22)|RKM (4K7, 0u22)
|
||||
|
||||
@@ -724,3 +724,6 @@ Are you sure you want to delete variant "%s"?|Voulez-vous vraiment supprimer la
|
||||
Delete|Supprimer
|
||||
Set default model|Définir comme modèle par défaut
|
||||
Remove default model|Retirer le modèle par défaut
|
||||
Value Notation|Notation des valeurs
|
||||
Decimal (4.7K, 0.22uF)|Décimale (4.7K, 0.22uF)
|
||||
RKM (4K7, 0u22)|RKM (4K7, 0u22)
|
||||
|
||||
@@ -726,3 +726,6 @@ Are you sure you want to delete variant "%s"?|Eliminare davvero la variante "%s"
|
||||
Delete|Elimina
|
||||
Set default model|Imposta come modello predefinito
|
||||
Remove default model|Rimuovi modello predefinito
|
||||
Value Notation|Notazione dei valori
|
||||
Decimal (4.7K, 0.22uF)|Decimale (4.7K, 0.22uF)
|
||||
RKM (4K7, 0u22)|RKM (4K7, 0u22)
|
||||
|
||||
@@ -730,3 +730,6 @@ Are you sure you want to delete variant "%s"?|Weet u zeker dat u variant "%s" wi
|
||||
Delete|Verwijderen
|
||||
Set default model|Instellen als standaardmodel
|
||||
Remove default model|Standaardmodel verwijderen
|
||||
Value Notation|Waardenotatie
|
||||
Decimal (4.7K, 0.22uF)|Decimaal (4.7K, 0.22uF)
|
||||
RKM (4K7, 0u22)|RKM (4K7, 0u22)
|
||||
|
||||
@@ -725,3 +725,6 @@ Are you sure you want to delete variant "%s"?|Tem certeza de que deseja excluir
|
||||
Delete|Excluir
|
||||
Set default model|Definir como modelo padrão
|
||||
Remove default model|Remover modelo padrão
|
||||
Value Notation|Notação de valores
|
||||
Decimal (4.7K, 0.22uF)|Decimal (4.7K, 0.22uF)
|
||||
RKM (4K7, 0u22)|RKM (4K7, 0u22)
|
||||
|
||||
@@ -721,3 +721,6 @@ Are you sure you want to delete variant "%s"?|Da li ste sigurni da želite da ob
|
||||
Delete|Obriši
|
||||
Set default model|Postavi kao podrazumevani model
|
||||
Remove default model|Ukloni podrazumevani model
|
||||
Value Notation|Zapis vrednosti
|
||||
Decimal (4.7K, 0.22uF)|Decimalni (4.7K, 0.22uF)
|
||||
RKM (4K7, 0u22)|RKM (4K7, 0u22)
|
||||
|
||||
@@ -723,3 +723,6 @@ Are you sure you want to delete variant "%s"?|क्या आप वाकई
|
||||
Delete|हटाएँ
|
||||
Set default model|डिफ़ॉल्ट मॉडल सेट करें
|
||||
Remove default model|डिफ़ॉल्ट मॉडल हटाएँ
|
||||
Value Notation|मान संकेतन
|
||||
Decimal (4.7K, 0.22uF)|दशमलव (4.7K, 0.22uF)
|
||||
RKM (4K7, 0u22)|RKM (4K7, 0u22)
|
||||
|
||||
@@ -723,3 +723,6 @@ Are you sure you want to delete variant "%s"?|确定要删除变体“%s”吗
|
||||
Delete|删除
|
||||
Set default model|设为默认型号
|
||||
Remove default model|取消默认型号
|
||||
Value Notation|数值表示法
|
||||
Decimal (4.7K, 0.22uF)|小数 (4.7K, 0.22uF)
|
||||
RKM (4K7, 0u22)|RKM (4K7, 0u22)
|
||||
|
||||
Reference in New Issue
Block a user