Java tutorial
/** * This file is part of Pau's Asset Manager Project. * * Pau's Asset Manager Project 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. * * Pau's Asset Manager Project 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 Pau's Asset Manager Project. If not, see <http://www.gnu.org/licenses/>. */ package org.pau.assetmanager.viewmodel; import java.text.ParseException; import java.text.SimpleDateFormat; import java.util.Calendar; import java.util.Collections; import java.util.Comparator; import java.util.Date; import java.util.GregorianCalendar; import java.util.LinkedList; import java.util.List; import org.apache.commons.lang.time.DateUtils; import org.apache.logging.log4j.LogManager; import org.apache.logging.log4j.Logger; import org.pau.assetmanager.business.AnnotationsBusiness; import org.pau.assetmanager.business.ConceptsBusiness; import org.pau.assetmanager.business.DaoFunction; import org.pau.assetmanager.entities.Annotation; import org.pau.assetmanager.entities.Annotation.AnnotationType; import org.pau.assetmanager.entities.Book; import org.pau.assetmanager.entities.Client; import org.pau.assetmanager.entities.ExpensesAnnotation; import org.pau.assetmanager.entities.GeneralExpensesAnnotation; import org.pau.assetmanager.entities.GeneralIncomeAnnotation; import org.pau.assetmanager.entities.IncomeAnnotation; import org.pau.assetmanager.entities.MovementExpensesAnnotation; import org.pau.assetmanager.entities.PropertyExpensesAnnotation; import org.pau.assetmanager.entities.PropertyIncomeAnnotation; import org.pau.assetmanager.entities.StockExpensesAnnotation; import org.pau.assetmanager.entities.StockIncomeAnnotation; import org.pau.assetmanager.viewmodel.stocks.ConceptValidation; import org.pau.assetmanager.viewmodel.stocks.HistoricalStocksValuesDownloader; import org.pau.assetmanager.viewmodel.stocks.StocksHistory; import org.pau.assetmanager.viewmodel.stocks.StocksIncomeError; import org.pau.assetmanager.viewmodel.stocks.StocksUtils; import org.pau.assetmanager.viewmodel.type.BookSelectionType; import org.pau.assetmanager.viewmodel.utils.AnnotationsFilter; import org.pau.assetmanager.viewmodel.utils.BookSelection; import org.pau.assetmanager.viewmodel.utils.SortingCriteria; import org.zkoss.bind.BindUtils; import org.zkoss.bind.annotation.BindingParam; import org.zkoss.bind.annotation.Command; import org.zkoss.bind.annotation.ContextParam; import org.zkoss.bind.annotation.ContextType; import org.zkoss.bind.annotation.DependsOn; import org.zkoss.bind.annotation.GlobalCommand; import org.zkoss.bind.annotation.Init; import org.zkoss.bind.annotation.NotifyChange; import org.zkoss.zk.ui.event.Event; import org.zkoss.zk.ui.event.InputEvent; import org.zkoss.zk.ui.util.Clients; import com.google.common.base.Optional; /** * This class is the ViewModel class that deals with all the UI interactions * related to the editable grid of annotations. This grid has sorting and * filtering enabled for all the fields and also controls the enabling and the * visibility of the editable cells depending on its applicability. * * The UI ZUL files involved directly or indirectly (using subclasses of the * this class) are the following: - general_expenses_annotations.zul - * general_income_annotations.zul - movement_annotations.zul - * property_expenses_annotations.zul - property_income_annotations.zul - * stocks_expenses_annotations.zul - stocks_income_annotations.zul * * * @author Pau Carr Cardona * */ public class AnnotationViewModel { // book selection in the main view protected BookSelection bookSelection = null; // current year selected protected Integer currentYear = null; // filtering applied protected AnnotationsFilter annotationsFilter = new AnnotationsFilter(); // reference to the annotation that is just created protected Annotation justCreatedAnnotation = null; // reference to the last created annotation // TODO: this is not clear at all and makes confusion with the field // 'justCreatedAnnotation' --> refactor!! protected Annotation lastestCreatedAnnotation = null; // the type of annotation selected (income or expenses) protected AnnotationType annotationType; protected static Logger logger = LogManager.getLogger(MonthlyReportViewModel.class); @Init public void init(@BindingParam("annotationType") String annotationType) { Calendar calendar = GregorianCalendar.getInstance(); calendar.setTime(new Date()); this.currentYear = calendar.get(Calendar.YEAR); this.annotationType = AnnotationType.valueOf(annotationType); } public BookSelectionType getBookSelectionType() { return bookSelection.getBookSelectionType(); } public Client getSelectedClient() { return bookSelection.getSelectedClient(); } public Integer getCurrentYear() { return currentYear; } // Annotations are notified by updateCurrentYear public void setCurrentYear(Integer currentYear) { this.currentYear = currentYear; } @Command @NotifyChange({ "annotations", "currentYear" }) public void updateCurrentYear(@ContextParam(ContextType.TRIGGER_EVENT) Event event) { String value = (String) event.getData(); Integer newValue = new Integer(value); if (!newValue.equals(currentYear)) { this.currentYear = newValue; } } @Command public void saveAnnotation(@BindingParam("annotation") Annotation annotation) { if (annotation.getId() != null) { if (annotation instanceof MovementExpensesAnnotation) { MovementExpensesAnnotation movementExpensesAnnotation = (MovementExpensesAnnotation) annotation; DaoFunction.mergeFunction().apply(movementExpensesAnnotation.getMovementIncomeAnnotation()); } DaoFunction.mergeFunction().apply(annotation); HistoricalStocksValuesDownloader.updateStocksHistoricalValuesAsync(); BindUtils.postGlobalCommand(null, null, "updateReportAnnotations", null); } } @NotifyChange({ "annotations", "getConceptsForFiltering", "getConcepts" }) @Command public void saveAnnotationWithConcept(@BindingParam("annotation") Annotation annotation, @ContextParam(ContextType.TRIGGER_EVENT) InputEvent event) { if (annotation.getId() != null) { String concept = event.getValue(); annotation.setConcept(concept); if (annotation instanceof MovementExpensesAnnotation) { MovementExpensesAnnotation movementExpensesAnnotation = (MovementExpensesAnnotation) annotation; DaoFunction.mergeFunction().apply(movementExpensesAnnotation.getMovementIncomeAnnotation()); } DaoFunction.mergeFunction().apply(annotation); HistoricalStocksValuesDownloader.updateStocksHistoricalValuesAsync(); BindUtils.postGlobalCommand(null, null, "updateReportAnnotations", null); } } @DependsOn({ "selectedBook", "bookSelectionType", "selectedClient", "currentYear", "annotationsFilter" }) public List<Annotation> getAnnotations() { List<Annotation> annotations = new LinkedList<Annotation>(); if (bookSelection.getSelectedBook() != null && bookSelection.getBookSelectionType().equals(BookSelectionType.SINGLE_BOOK)) { annotations = AnnotationsBusiness.getNonMovementAnnotations(Optional.<AnnotationType>of(annotationType), bookSelection, Optional.<Integer>of(currentYear), SortingCriteria.DESCENDING, annotationsFilter); if (justCreatedAnnotation != null && annotations.contains(justCreatedAnnotation)) { annotations.remove(justCreatedAnnotation); annotations.add(0, justCreatedAnnotation); justCreatedAnnotation = null; } } Clients.clearBusy(); return annotations; } @NotifyChange({ "selectedBook", "bookSelectionType", "selectedClient" }) @GlobalCommand public void updateBookSelection(@BindingParam("bookSelection") BookSelection bookSelection) { this.bookSelection = bookSelection; } @NotifyChange({ "annotations" }) @Command public void addPropertyAnnotation() { Annotation annotation = null; if (annotationType.equals(AnnotationType.INCOME)) { PropertyIncomeAnnotation incomeAnnotation = new PropertyIncomeAnnotation(); incomeAnnotation.setUpDefaults(); annotation = incomeAnnotation; addDefaultValuesToAnnotation(annotation, bookSelection.getSelectedBook(), currentYear, annotationsFilter); } else { PropertyExpensesAnnotation expensesAnnotation = new PropertyExpensesAnnotation(); expensesAnnotation.setUpDefaults(); annotation = expensesAnnotation; addDefaultValuesToAnnotation(annotation, bookSelection.getSelectedBook(), currentYear, annotationsFilter); } addAnnotation(annotation); Clients.clearBusy(); } @NotifyChange("wrongStockConcepts") @GlobalCommand public void updateReportAnnotations() { } public Annotation getJustCreatedAnnotation() { return justCreatedAnnotation; } public AnnotationsFilter getAnnotationsFilter() { return annotationsFilter; } public void setAnnotationsFilter(AnnotationsFilter annotationsFilter) { this.annotationsFilter = annotationsFilter; } public Annotation getLastestCreatedAnnotation() { return lastestCreatedAnnotation; } // TODO: check it!! public List<String> getConceptsForFiltering(@BindingParam("type") String type) { List<String> conceptsForFiltering = new LinkedList<String>(); conceptsForFiltering.addAll(getConcepts(type)); // sort concept in a case-unsensitive way Collections.sort(conceptsForFiltering, new Comparator<String>() { @Override public int compare(String stringA, String stringB) { return stringA.compareToIgnoreCase(stringB); } }); conceptsForFiltering.add(0, AnnotationsFilter.ALL_CONCEPTS); return conceptsForFiltering; } public Book getSelectedBook() { return bookSelection.getSelectedBook(); } @NotifyChange({ "annotations" }) @Command public void addGeneralAnnotation() { Annotation annotation = null; if (annotationType.equals(AnnotationType.EXPENSES)) { ExpensesAnnotation stockExpensesAnnotation = new GeneralExpensesAnnotation(); annotation = stockExpensesAnnotation; addDefaultValuesToAnnotation(annotation, bookSelection.getSelectedBook(), currentYear, annotationsFilter); } else if (annotationType.equals(AnnotationType.INCOME)) { IncomeAnnotation stockIncomeAnnotation = new GeneralIncomeAnnotation(); annotation = stockIncomeAnnotation; addDefaultValuesToAnnotation(annotation, bookSelection.getSelectedBook(), currentYear, annotationsFilter); } addAnnotation(annotation); Clients.clearBusy(); } @NotifyChange({ "annotations" }) @Command public void addStocksAnnotation() { Annotation annotation = null; if (annotationType.equals(AnnotationType.EXPENSES)) { StockExpensesAnnotation stockExpensesAnnotation = new StockExpensesAnnotation(); annotation = stockExpensesAnnotation; } else if (annotationType.equals(AnnotationType.INCOME)) { StockIncomeAnnotation stockIncomeAnnotation = new StockIncomeAnnotation(); annotation = stockIncomeAnnotation; } addDefaultValuesToAnnotation(annotation, bookSelection.getSelectedBook(), currentYear, annotationsFilter); addAnnotation(annotation); Clients.clearBusy(); } protected Annotation addAnnotation(Annotation annotation) { annotation = AnnotationsBusiness.createAnnotation(annotation); justCreatedAnnotation = annotation; lastestCreatedAnnotation = justCreatedAnnotation; annotationsFilter.clearDateAndCostFilter(); BindUtils.postGlobalCommand(null, null, "updateReportAnnotations", null); return annotation; } protected void addDefaultValuesToAnnotation(Annotation annotation, Book selectedBook, Integer currentYear, AnnotationsFilter annotationsFilter) { annotation.setBook(selectedBook); annotation.setAmount(0.0); Calendar calendar = GregorianCalendar.getInstance(); Integer systemDateYear = calendar.get(Calendar.YEAR); if (!systemDateYear.equals(currentYear)) { String dateAsString = "01/01/" + currentYear; SimpleDateFormat simpleDateFormat = new SimpleDateFormat("dd/MM/yyyy"); try { Date dateForNewAnnotation = simpleDateFormat.parse(dateAsString); annotation.setDate(dateForNewAnnotation); } catch (ParseException e) { logger.error("Error parsing date", e); } } else { Calendar currentCalendar = GregorianCalendar.getInstance(); currentCalendar = DateUtils.truncate(currentCalendar, Calendar.DATE); annotation.setDate(currentCalendar.getTime()); } if (annotationsFilter.getConcept() != null && !annotationsFilter.getConcept().equals(AnnotationsFilter.ALL_CONCEPTS)) { annotation.setConcept(annotationsFilter.getConcept()); } else { annotation.setConcept(getDefaultConcept(annotation)); } } private String getDefaultConcept(Annotation annotation) { String concept = ConceptsBusiness.getDefaultConcept(annotation.getClass().getSimpleName()); return concept; } @NotifyChange({ "annotations" }) @Command public void deleteAnnotation(@ContextParam(ContextType.TRIGGER_EVENT) Event event) { Annotation annotation = (Annotation) event.getData(); AnnotationsBusiness.deleteAnnotation(annotation); BindUtils.postGlobalCommand(null, null, "updateReportAnnotations", null); Clients.clearBusy(); } @NotifyChange({ "annotations" }) @Command public void duplicateAnnotation(@BindingParam("annotation") Annotation annotation, @ContextParam(ContextType.TRIGGER_EVENT) Event event) { annotation.setId(null); annotation.setDate(new Date()); addAnnotation(annotation); } // TODO: check this for type public List<String> getConcepts(@BindingParam("type") String type) { List<String> concepts = new LinkedList<String>(); concepts.add(ConceptsBusiness.getDefaultConcept(type)); concepts.addAll(ConceptsBusiness.getConceptsUsedInBook(bookSelection)); Collections.sort(concepts); return concepts; } /** * @return the list of wrong/inconsistent stock concepts. The method returns * all the sold stock that were done at a time in which the number * of bought stocks is below the amount of bought stocks (i.e. it is * not possible to sell stocks one does not previously have) */ @DependsOn("annotations") public List<ConceptValidation> getWrongStockConcepts() { List<ConceptValidation> conceptValidations = new LinkedList<ConceptValidation>(); List<Annotation> annotations = StocksYearlyReportViewModel.getStocksAnnotationsUntilYear(bookSelection, currentYear); StocksHistory stocksHistory = StocksUtils.getStocksHistory(annotations); for (String currentConcept : stocksHistory.getStocksErrorsHistoryMap().keySet()) { StocksIncomeError currentError = stocksHistory.getStocksErrorsHistoryMap().get(currentConcept); ConceptValidation conceptValidation = new ConceptValidation(currentConcept, currentError.toString()); conceptValidations.add(conceptValidation); } return conceptValidations; } @Command @NotifyChange({ "annotations" }) public void refreshFilter(@ContextParam(ContextType.TRIGGER_EVENT) Event event) { } @Command @NotifyChange({ "annotations", "annotationsFilter" }) public void disableDateFilter(@ContextParam(ContextType.TRIGGER_EVENT) Event event) { annotationsFilter.setDateFrom(null); annotationsFilter.setDateTo(null); } @Command @NotifyChange({ "annotations", "annotationsFilter" }) public void disableForCompanyFilter(@ContextParam(ContextType.TRIGGER_EVENT) Event event) { annotationsFilter.setForCompany(null); } @Command @NotifyChange({ "annotations", "annotationsFilter" }) public void disableUseQuarterly(@ContextParam(ContextType.TRIGGER_EVENT) Event event) { annotationsFilter.setUseQuarterly(null); } @Command @NotifyChange({ "annotations", "annotationsFilter" }) public void disableCostFilter(@ContextParam(ContextType.TRIGGER_EVENT) Event event) { annotationsFilter.setCostFrom(null); annotationsFilter.setCostTo(null); } @Command @NotifyChange({ "annotations", "annotationsFilter" }) public void disableRetentionFilter(@ContextParam(ContextType.TRIGGER_EVENT) Event event) { annotationsFilter.setRetentionFrom(null); annotationsFilter.setRetentionTo(null); } @Command @NotifyChange({ "annotations", "annotationsFilter" }) public void disableVatFilter(@ContextParam(ContextType.TRIGGER_EVENT) Event event) { annotationsFilter.setVatFrom(null); annotationsFilter.setVatTo(null); } @Command @NotifyChange({ "annotations", "annotationsFilter" }) public void disableUseYearlyFilter(@ContextParam(ContextType.TRIGGER_EVENT) Event event) { annotationsFilter.setUseYearly(null); } @Command @NotifyChange({ "annotations", "annotationsFilter" }) public void disableDoneFilter(@ContextParam(ContextType.TRIGGER_EVENT) Event event) { annotationsFilter.setDone(null); } @Command @NotifyChange({ "annotations", "annotationsFilter" }) public void disableDeductiblePercentageFilter(@ContextParam(ContextType.TRIGGER_EVENT) Event event) { annotationsFilter.setDeductiblePercentageFrom(null); annotationsFilter.setDeductiblePercentageTo(null); } @Command @NotifyChange({ "annotations", "annotationsFilter" }) public void disableCommunityFilter(@ContextParam(ContextType.TRIGGER_EVENT) Event event) { annotationsFilter.setCommunity(null); } }