Java tutorial
/* * jPOS Project [http://jpos.org] * Copyright (C) 2000-2018 jPOS Software SRL * * This program is free software: you can redistribute it and/or modify * it under the terms of the GNU Affero General Public License as * published by the Free Software Foundation, either version 3 of the * License, or (at your option) any later version. * * This program 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 Affero General Public License for more details. * * You should have received a copy of the GNU Affero General Public License * along with this program. If not, see <http://www.gnu.org/licenses/>. */ package org.jpos.qi.minigl; import com.vaadin.data.Binder; import com.vaadin.data.BindingValidationStatus; import com.vaadin.data.ValidationResult; import com.vaadin.data.Validator; import com.vaadin.data.converter.StringToBigDecimalConverter; import com.vaadin.data.validator.BigDecimalRangeValidator; import com.vaadin.data.validator.RegexpValidator; import com.vaadin.data.validator.StringLengthValidator; import com.vaadin.ui.*; import com.vaadin.ui.themes.ValoTheme; import org.apache.commons.lang3.StringUtils; import org.jpos.gl.*; import org.jpos.qi.QI; import java.math.BigDecimal; import java.util.ArrayList; import java.util.Collections; import java.util.List; public class NewEntryForm extends HorizontalLayout { private final static String TEXT_REGEX = "^[\\w\\s.,\\-\\']*$"; private TransactionsHelper helper; private Journal journal; private GLTransaction transaction; private QI app; private EntryGrid entryGrid; private Button addEntryBtn; private Binder<GLEntry> binder; private boolean shouldReverse; public NewEntryForm(GLTransaction transaction, TransactionsHelper helper, EntryGrid entryGrid) { super(); try { this.transaction = transaction.clone(); } catch (CloneNotSupportedException e) { // Log error and ignore. Clone should be supported. QI.getQI().getLog().error(e); } this.journal = transaction.getJournal(); this.helper = helper; this.app = QI.getQI(); this.entryGrid = entryGrid; setStyleName(ValoTheme.LAYOUT_HORIZONTAL_WRAPPING); setSpacing(true); setWidthUndefined(); GLEntry entry = new GLEntry(); binder = new Binder(GLEntry.class); createAndBindFields(binder); binder.setBean(entry); binder.setReadOnly(true); addEntryBtn = new Button(app.getMessage("addEntry")); addEntryBtn.addClickListener(addEntryClickListener(binder)); addEntryBtn.setEnabled(false); addEntryBtn.setStyleName(ValoTheme.BUTTON_FRIENDLY); addComponent(addEntryBtn); setComponentAlignment(addEntryBtn, Alignment.BOTTOM_CENTER); } private void createAndBindFields(Binder binder) { TextField accountCode = createTextField("accountCode"); ComboBox layer = createLayersSelector(); TextField detail = createTextField("detail"); TextField tags = createTextField("tags"); TextField amount = createTextField("amount"); RadioButtonGroup credit = createCreditOrDebit(); binder.forField(accountCode).withNullRepresentation("").withConverter(new AccountConverter()) .withValidator((Validator<Account>) (value, context) -> { if (value != null && !(value instanceof FinalAccount)) return ValidationResult.error(app.getMessage("errorMessage.accountNotFinal")); else if (value == null) return ValidationResult.error(app.getMessage("errorMessage.req", StringUtils.capitalize(accountCode.getCaption()))); return ValidationResult.ok(); }).asRequired(app.getMessage("errorMessage.req", StringUtils.capitalize(layer.getCaption()))) .bind("account"); binder.forField(layer).withConverter(new ShortToLayerConverter(journal)) .asRequired(app.getMessage("errorMessage.req", StringUtils.capitalize(layer.getCaption()))) .bind("layer"); binder.forField(detail) .withValidator(new StringLengthValidator( app.getMessage("errorMessage.invalidField", detail.getCaption()), 0, 255)) .withValidator(new RegexpValidator(app.getMessage("errorMessage.invalidField", detail.getCaption()), TEXT_REGEX)) .bind("detail"); binder.forField(tags) .withValidator(new StringLengthValidator( app.getMessage("errorMessage.invalidField", tags.getCaption()), 0, 255)) .withValidator(new RegexpValidator(app.getMessage("errorMessage.invalidField", tags.getCaption()), TEXT_REGEX)) .withConverter(new StringToTagConverter()).bind("tags"); binder.forField(amount) .asRequired(app.getMessage("errorMessage.req", StringUtils.capitalize(amount.getCaption()))) .withConverter(new StringToBigDecimalConverter(app.getMessage("errorMessage.invalidAmount"))) .withValidator(new BigDecimalRangeValidator(app.getMessage("errorMessage.invalidAmount"), new BigDecimal("1"), new BigDecimal("99999999999999"))) .withNullRepresentation(BigDecimal.ZERO).bind("amount"); binder.bind(credit, "credit"); addComponent(accountCode); addComponent(layer); addComponent(detail); addComponent(tags); addComponent(amount); addComponent(credit); setComponentAlignment(credit, Alignment.BOTTOM_CENTER); } private TextField createTextField(String captionId) { TextField f = new TextField(app.getMessage(captionId)); f.setWidth("150"); return f; } private RadioButtonGroup createCreditOrDebit() { RadioButtonGroup<Boolean> radio = new RadioButtonGroup<>(); radio.setItems(Boolean.FALSE, Boolean.TRUE); radio.addStyleName(ValoTheme.OPTIONGROUP_HORIZONTAL); ItemCaptionGenerator itemCaptionGenerator = (ItemCaptionGenerator) item -> Boolean.TRUE.equals(item) ? app.getMessage("credit") : app.getMessage("debit"); radio.setItemCaptionGenerator(itemCaptionGenerator); return radio; } private ComboBox createLayersSelector() { ComboBox<Layer> box = new ComboBox(app.getMessage("layer")); box.setItemCaptionGenerator(l -> l.getId() + " - " + l.getName()); List layers = helper.getLayers(journal); if (layers != null) { Collections.sort(layers); box.setItems(layers); if (layers.size() > 0) { box.setValue((Layer) layers.get(0)); } } box.setEmptySelectionAllowed(false); return box; } private Button.ClickListener addEntryClickListener(Binder binder) { return event -> { if (binder.validate().isOk()) { if (binder.writeBeanIfValid(binder.getBean())) { GLEntry entry = (GLEntry) binder.getBean(); int count = 0; List<GLEntry> newEntriesList = new ArrayList<>(); for (GLEntry e : transaction.getEntries()) { e.setId(count); newEntriesList.add(e); count++; } if (entry.isCredit()) { GLCredit credit = new GLCredit(); credit.setAccount(entry.getAccount()); credit.setAmount(entry.getAmount()); credit.setLayer(entry.getLayer()); credit.setDetail(entry.getDetail()); credit.setTags(entry.getTags()); credit.setTransaction(entry.getTransaction()); credit.setId(count); newEntriesList.add(credit); } else if (entry.isDebit()) { GLDebit debit = new GLDebit(); debit.setAccount(entry.getAccount()); debit.setAmount(entry.getAmount()); debit.setLayer(entry.getLayer()); debit.setDetail(entry.getDetail()); debit.setTags(entry.getTags()); debit.setTransaction(entry.getTransaction()); debit.setId(count); newEntriesList.add(debit); } transaction.setEntries(newEntriesList); entryGrid.setValue(transaction); clearFields(); shouldReverse = true; entryGrid.setComponentError(null); } } else { BindingValidationStatus<?> result = (BindingValidationStatus<?>) binder.validate() .getFieldValidationErrors().get(0); app.displayNotification(result.getResult().get().getErrorMessage()); } focusOnFirstField(); }; } private void focusOnFirstField() { Object o = binder.getFields().findFirst().get(); if (o != null && o instanceof TextField) ((TextField) o).focus(); } private void clearFields() { binder.setBean(new GLEntry()); } public void setReadOnly(boolean readOnly) { binder.setReadOnly(readOnly); addEntryBtn.setEnabled(!readOnly); if (readOnly) clearFields(); } public Button getAddEntryBtn() { return addEntryBtn; } public void setAddEntryBtn(Button addEntryBtn) { this.addEntryBtn = addEntryBtn; } public GLTransaction getTransaction() { return transaction; } public void setTransaction(GLTransaction transaction) { this.transaction = transaction; } public boolean isShouldReverse() { return shouldReverse; } public void setShouldReverse(boolean shouldReverse) { this.shouldReverse = shouldReverse; } }