package rocks.inspectit.ui.rcp.property.control.impl; import java.util.Locale; import org.apache.commons.lang.StringUtils; import org.eclipse.swt.SWT; import org.eclipse.swt.events.FocusAdapter; import org.eclipse.swt.events.FocusEvent; import org.eclipse.swt.events.ModifyEvent; import org.eclipse.swt.events.ModifyListener; import org.eclipse.swt.events.SelectionAdapter; import org.eclipse.swt.events.SelectionEvent; import org.eclipse.swt.events.VerifyEvent; import org.eclipse.swt.events.VerifyListener; import org.eclipse.swt.layout.GridData; import org.eclipse.swt.layout.GridLayout; import org.eclipse.swt.widgets.Combo; import org.eclipse.swt.widgets.Composite; import org.eclipse.swt.widgets.Control; import org.eclipse.swt.widgets.Text; import rocks.inspectit.shared.cs.cmr.property.configuration.impl.ByteProperty; import rocks.inspectit.ui.rcp.property.IPropertyUpdateListener; import rocks.inspectit.ui.rcp.property.control.AbstractPropertyControl; /** * Property control for {@link ByteProperty}. * * @author Ivan Senic * */ public class BytePropertyControl extends AbstractPropertyControl<ByteProperty, Long> { /** * Combo displaying the available units. */ private Combo unitCombo; /** * Value being displayed. */ private Text valueText; /** * Flag to skip the modify listener when {@link #valueText} is changed by us. */ private boolean modifyMarker; /** * Default constructor. * * @param property * Property. * @param propertyUpdateListener * Property update listener to report updates to. */ public BytePropertyControl(ByteProperty property, IPropertyUpdateListener propertyUpdateListener) { super(property, propertyUpdateListener); } /** * {@inheritDoc} */ @Override protected Control createControl(Composite parent) { Composite composite = new Composite(parent, SWT.NONE); GridLayout gridLayout = new GridLayout(2, false); gridLayout.marginHeight = 0; gridLayout.marginWidth = 0; composite.setLayout(gridLayout); valueText = new Text(composite, SWT.BORDER | SWT.RIGHT); valueText.setLayoutData(new GridData(SWT.FILL, SWT.FILL, true, false)); valueText.addVerifyListener(new VerifyListener() { @Override public void verifyText(VerifyEvent e) { String oldText = valueText.getText(); String update = e.text; String newText = oldText.substring(0, e.start) + update + oldText.substring(e.end, oldText.length()); // allow blank text if (StringUtils.isNotBlank(newText)) { // otherwise prove we have a valid double number try { Double.parseDouble(newText); } catch (NumberFormatException exception) { e.doit = false; return; } } } }); valueText.addModifyListener(new ModifyListener() { @Override public void modifyText(ModifyEvent e) { if (!modifyMarker) { String text = valueText.getText(); if (!text.isEmpty() && ((text.charAt(0) != '-') || (text.length() > 1))) { long currentSize = getCurrentSize(); sendPropertyUpdateEvent(currentSize); } } else { modifyMarker = false; } } }); valueText.addFocusListener(new FocusAdapter() { @Override public void focusLost(FocusEvent e) { String text = valueText.getText(); if (text.isEmpty()) { displayValue(getLastCorrectValue()); } } }); unitCombo = new Combo(composite, SWT.BORDER); unitCombo.setItems(new String[] { "B", "KB", "MB", "GB" }); GridData unitGd = new GridData(SWT.RIGHT, SWT.FILL, false, false); unitGd.widthHint = 60; unitCombo.setLayoutData(unitGd); unitCombo.addSelectionListener(new SelectionAdapter() { @Override public void widgetSelected(SelectionEvent e) { long currentSize = getLastCorrectValue(); int exp = unitCombo.getSelectionIndex(); displayValue(currentSize, exp); }; }); displayValue(property.getValue().longValue()); return composite; } /** * {@inheritDoc} */ @Override protected void showDefaultValue() { displayValue(property.getDefaultValue().longValue()); } /** * @return Returns current size defined by spinner and unit. */ private long getCurrentSize() { return (long) (Double.parseDouble(valueText.getText()) * Math.pow(1024, unitCombo.getSelectionIndex())); } /** * Displays value in text based on default unit . * * @param bytes * Amount of bytes. */ private void displayValue(long bytes) { int exp = getUnit(bytes); unitCombo.select(exp); displayValue(bytes, exp); } /** * Displays value in text based on given exp. * * @param bytes * Amount of bytes. * @param exp * Unit index or exp. */ private void displayValue(long bytes, int exp) { int unit = 1024; double value = bytes / Math.pow(unit, exp); modifyMarker = true; valueText.setText(String.format(Locale.ENGLISH, "%.2f", value)); } /** * Unit we want to display for required amount of bytes. * * @param bytes * Amount of bytes. * @return {@link #BYTES}, {@link #KILO_BYTES} or {@link #MEGA_BYTES} */ private int getUnit(long bytes) { bytes = Math.abs(bytes); int unit = 1024; if (bytes < unit) { return 0; } else { int exp = (int) (Math.log(bytes) / Math.log(unit)); if (exp < 4) { return exp; } else { return 3; } } } }