/* * This file is part of the aidGer project. * * Copyright (C) 2010-2013 The aidGer Team * * This program 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. * * 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 General Public License for more details. * * You should have received a copy of the GNU General Public License * along with this program. If not, see <http://www.gnu.org/licenses/>. */ package de.aidger.controller.actions; import static de.aidger.utils.Translation._; import java.awt.event.ActionEvent; import java.math.BigDecimal; import java.sql.SQLIntegrityConstraintViolationException; import java.text.MessageFormat; import java.text.ParseException; import java.util.ArrayList; import java.util.Calendar; import java.util.Date; import java.util.List; import javax.swing.AbstractAction; import javax.swing.Action; import javax.swing.JOptionPane; import de.aidger.model.AbstractModel; import de.aidger.model.Runtime; import de.aidger.model.inspectors.CostUnitBudgetLimitInspector; import de.aidger.model.inspectors.CourseBudgetLimitInspector; import de.aidger.model.inspectors.EmploymentLimitInspector; import de.aidger.model.inspectors.IdenticalAssistantInspector; import de.aidger.model.inspectors.Inspector; import de.aidger.model.inspectors.OverlapContractInspector; import de.aidger.model.inspectors.WorkingHourLimitInspector; import de.aidger.model.models.Activity; import de.aidger.model.models.Assistant; import de.aidger.model.models.Contract; import de.aidger.model.models.CostUnit; import de.aidger.model.models.Course; import de.aidger.model.models.Employment; import de.aidger.model.models.FinancialCategory; import de.aidger.model.models.HourlyWage; import de.aidger.view.UI; import de.aidger.view.forms.ActivityEditorForm; import de.aidger.view.forms.AssistantEditorForm; import de.aidger.view.forms.ContractEditorForm; import de.aidger.view.forms.CostUnitEditorForm; import de.aidger.view.forms.CourseEditorForm; import de.aidger.view.forms.EmploymentEditorForm; import de.aidger.view.forms.FinancialCategoryEditorForm; import de.aidger.view.forms.HourlyWageEditorForm; import de.aidger.view.models.TableModel; import de.aidger.view.models.UIAssistant; import de.aidger.view.tabs.DetailViewerTab; import de.aidger.view.tabs.EditorTab; import de.aidger.view.tabs.Tab; import de.aidger.view.tabs.ViewerTab; import de.aidger.view.utils.InvalidLengthException; import siena.SienaException; /** * This action saves the model and replaces the current tab with the model * viewer tab. * * @author aidGer Team */ @SuppressWarnings("serial") public class EditorSaveAction extends AbstractAction { /** * Inspectors that check models before they are saved. */ private final List<Inspector> inspectors = new ArrayList<Inspector>(); /** * Initializes the action. */ public EditorSaveAction() { putValue(Action.NAME, _("Save")); } /** * Prepares the course model stored in the models list by setting the values * of the course editor form to this model. Returns the model from the * database before it is edited. If a database error occurs the model before * it was edited is returned. * * @param models * a list that contains the course model of the editor * @param form * the course editor form * @return the model from database before it is edited */ @SuppressWarnings("unchecked") private AbstractModel prepareModels(List<AbstractModel> models, CourseEditorForm form) { Course course = (Course) models.get(0); Course courseBeforeEdit = course.clone(); course.setDescription(form.getDescription()); course.setSemester(form.getSemester()); course.setLecturer(form.getLecturer()); course.setAdvisor(form.getAdvisor()); course.setNumberOfGroups(form.getNumberOfGroups()); course.setTargetAudience(form.getTargetAudience()); course.setScope(form.getScope()); course.setGroup(form.getGroup()); course.setRemark(form.getRemark()); course.setFinancialCategoryId(form.getFinancialCategoryId()); try { course .setUnqualifiedWorkingHours(form.getUnqualifiedWorkingHours()); } catch (ParseException e) { course.setUnqualifiedWorkingHours(null); } try { course.setPart(form.getPart()); } catch (StringIndexOutOfBoundsException e) { } try { Course c = course.getById(course.getId()); return c == null ? courseBeforeEdit : new Course(c); } catch (SienaException e) { return courseBeforeEdit; } } /** * Prepares the assistant model stored in the models list by setting the * values of the assistant editor form to this model. Returns the model from * the database before it is edited. If a database error occurs the model * before it was edited is returned. * * @param models * a list that contains the assistant model of the editor * @param form * the assistant editor form * @return the model from database before it is edited */ @SuppressWarnings("unchecked") private AbstractModel prepareModels(List<AbstractModel> models, AssistantEditorForm form) { Assistant assistant = (Assistant) models.get(0); Assistant assistantBeforeEdit = assistant.clone(); assistant.setFirstName(form.getFirstName()); assistant.setLastName(form.getLastName()); assistant.setEmail(form.getEmail()); assistant.setQualification(form.getQualification()); try { Assistant a = assistant.getById(assistant.getId()); return a == null ? assistantBeforeEdit : new Assistant(a); } catch (SienaException e) { return assistantBeforeEdit; } } /** * Prepares the financial category model stored in the models list by * setting the values of the financial category editor form to this model. * Returns the model from the database before it is edited. If a database * error occurs the model before it was edited is returned. * * @param models * a list that contains the financial category model of the * editor * @param form * the financial category editor form * @return the model from database before it is edited */ @SuppressWarnings("unchecked") private AbstractModel prepareModels(List<AbstractModel> models, FinancialCategoryEditorForm form) { FinancialCategory fc = (FinancialCategory) models.get(0); FinancialCategory fcBeforeEdit = fc.clone(); fc.setName(form.getFCName()); form.sortCostUnits(); try { fc.setCostUnits(form.getCostUnits()); } catch (InvalidLengthException e) { fc.addError("costUnits", _("Cost unit"), _("has to have a length of 8")); } catch (NumberFormatException e) { fc.setCostUnits(null); } try { fc.setBudgetCosts(form.getBudgetCosts()); } catch (NumberFormatException e) { fc.setBudgetCosts(null); } try { fc.setYear(form.getYear()); } catch (NumberFormatException e) { fc.setYear(null); } try { // fc.getByKeys expects only the ID as key FinancialCategory f = fc.getByKey(fc.getId()); return f == null ? fcBeforeEdit : new FinancialCategory(f); } catch (SienaException e) { return fcBeforeEdit; } } /** * Prepares the hourly wage models by setting the values of the hourly wage * editor form to the models. Returns the model from the database before it * is edited. If a database error occurs the model before it was edited is * returned. * * @param models * a list that contains the hourly wage model of the editor * @param form * the hourly wage editor form * @return the model from database before it is edited */ @SuppressWarnings("unchecked") private AbstractModel prepareModels(List<AbstractModel> models, HourlyWageEditorForm form) { HourlyWage hw = (HourlyWage) models.get(0); HourlyWage hwBeforeEdit = hw.clone(); hw.setQualification(form.getQualification()); try { hw.setWage(round(form.getWage(), 2)); } catch (ParseException e) { hw.setWage(null); } if (form.isEditMode()) { hw.setMonth(form.getMonth()); hw.setYear(form.getYear()); } else { Calendar start = Calendar.getInstance(); start.setTime(form.getStartDate()); Calendar finish = Calendar.getInstance(); finish.setTime(form.getFinishDate()); if (start.after(finish)) { hw.addError("end date", _("End date"), _("must be after start date")); } else { models.clear(); finish.add(Calendar.MONTH, 1); while (finish.after(start)) { HourlyWage clone = hw.clone(); // add also previous errors to clone for (String error : hw.getErrors()) { clone.addError(error); } models.add(clone); clone.setMonth((byte) (start.get(Calendar.MONTH) + 1)); clone.setYear((short) start.get(Calendar.YEAR)); start.add(Calendar.MONTH, 1); } } } try { //TODO: Rewrite HourlyWage h = null;//hwBeforeEdit.getByKeys(hwBeforeEdit //.getQualification(), hwBeforeEdit.getMonth(), hwBeforeEdit //.getYear()); return h == null ? hwBeforeEdit : new HourlyWage(h); } catch (SienaException e) { return hwBeforeEdit; } } /** * Prepares the cost unit model by setting the values of the cost unit * editor form to this model. * * @param models * a list that contains the course model of the editor * @param form * the course editor form * @return the edited model */ @SuppressWarnings("unchecked") private AbstractModel prepareModels(List<AbstractModel> models, CostUnitEditorForm form) { CostUnit costUnit = (CostUnit) models.get(0); CostUnit costUnitBeforeEdit = costUnit.clone(); costUnit.setCostUnit(form.getCostUnit()); costUnit.setFunds(form.getFunds()); costUnit.setTokenDB(form.getTokenDB()); return costUnitBeforeEdit; } /** * Prepares the employment models by setting the values of the employment * editor form to this model. Returns the model from the database before it * is edited. If a database error occurs the model before it was edited is * returned. * * @param models * a list that contains the employment model of the editor * @param form * the employment editor form * @return the model from database before it is edited */ @SuppressWarnings("unchecked") private AbstractModel prepareModels(List<AbstractModel> models, EmploymentEditorForm form) { Employment employment = (Employment) models.get(0); Employment employmentBeforeEdit = employment.clone(); Long assistantId = null, courseId = null; if (form.getAssistant() != null) { assistantId = form.getAssistant().getId(); } if (form.getCourse() != null) { courseId = form.getCourse().getId(); } employment.setAssistantId(assistantId); employment.setCourseId(courseId); employment.setContractId(form.getContractId()); employment.setFunds(form.getFunds()); employment.setCostUnit(form.getCostUnit()); employment.setQualification(form.getQualification()); employment.setRemark(form.getRemark()); List<Date> dates = form.getDates(); List<Double> hcs = new ArrayList<Double>(); try { hcs = form.getHourCounts(); models.clear(); for (int i = 0; i < dates.size(); ++i) { Employment clone = employment.clone(); for (String error : employment.getErrors()) { clone.addError(error); } models.add(clone); Calendar cal = Calendar.getInstance(); cal.setTime(dates.get(i)); clone.setMonth((byte) (cal.get(Calendar.MONTH) + 1)); clone.setYear((short) cal.get(Calendar.YEAR)); clone.setHourCount(hcs.get(i)); } } catch (ParseException e) { employment.setHourCount(null); } try { Employment e = employment.getById(employment.getId()); return e == null ? employmentBeforeEdit : new Employment(e); } catch (SienaException e) { return employmentBeforeEdit; } } /** * Prepares the contract model by setting the values of the contract editor * form to this model. Returns the model from the database before it is * edited. If a database error occurs the model before it was edited is * returned. * * @param models * a list that contains the course model of the editor * @param form * the course editor form * @return the model from database before it is edited */ @SuppressWarnings("unchecked") private AbstractModel prepareModels(List<AbstractModel> models, ContractEditorForm form) { Contract contract = (Contract) models.get(0); Contract contractBeforeEdit = contract.clone(); Long assistantId = null; if (form.getAssistant() != null) { assistantId = form.getAssistant().getId(); } contract.setAssistantId(assistantId); contract.setCompletionDate(form.getCompletionDate()); contract.setConfirmationDate(form.getConfirmationDate()); contract.setStartDate(form.getStartDate()); contract.setEndDate(form.getEndDate()); contract.setType(form.getType()); contract.setDelegation(form.isDelegation()); try { Contract c = contract.getById(contract.getId()); return c == null ? contractBeforeEdit : new Contract(c); } catch (SienaException e) { return contractBeforeEdit; } } /** * Prepares the activity models by setting the values of the activity editor * form to this model. Returns the model from the database before it is * edited. If a database error occurs the model before it was edited is * returned. * * @param models * a list that contains the activity model of the editor * @param form * the activity editor form * @return the model from database before it is edited */ @SuppressWarnings("unchecked") private AbstractModel prepareModels(List<AbstractModel> models, ActivityEditorForm form) { Activity activity = (Activity) models.get(0); Activity activityBeforeEdit = activity.clone(); activity.setDate(form.getDate()); activity.setProcessor(form.getProcessor()); activity.setType(form.getType()); activity.setDocumentType(form.getDocumentType()); activity.setContent(form.getContent()); activity.setRemark(form.getRemark()); List<Course> courses = form.getCourses(); List<Assistant> assistants = form.getAssistants(); models.clear(); for (int i = 0; i < courses.size(); ++i) { for (int j = 0; j < assistants.size(); ++j) { Activity clone = activity.clone(); for (String error : activity.getErrors()) { clone.addError(error); } models.add(clone); clone.setCourseId(courses.get(i).getId()); clone.setAssistantId(assistants.get(j).getId()); if (form.isInitiatorReferenced()) { clone.setSender(new UIAssistant(assistants.get(j)) .toString()); } else { clone.setSender(form.getInitiator()); } } } try { Activity a = activity.getById(activity.getId()); return a == null ? activityBeforeEdit : new Activity(a); } catch (SienaException e) { return activityBeforeEdit; } } /** * Returns the rounded double. * * @param d * the double value * @param scale * the scale * @return the rounded double value */ public static Double round(double d, int scale) { return (new BigDecimal(d).setScale(scale, BigDecimal.ROUND_HALF_EVEN)).doubleValue(); } /* * (non-Javadoc) * * @see * java.awt.event.ActionListener#actionPerformed(java.awt.event.ActionEvent) */ @SuppressWarnings("unchecked") @Override public void actionPerformed(ActionEvent e) { EditorTab tab = (EditorTab) UI.getInstance().getCurrentTab(); // if something went wrong just the clone model is affected AbstractModel clone = (AbstractModel) tab.getModel().clone(); List<AbstractModel> models = new ArrayList<AbstractModel>(); models.add(clone); AbstractModel modelBeforeEdit = tab.getModel(); // preparation of the models (type specific) switch (tab.getType()) { case Course: modelBeforeEdit = prepareModels(models, (CourseEditorForm) tab .getEditorForm()); break; case Assistant: modelBeforeEdit = prepareModels(models, (AssistantEditorForm) tab .getEditorForm()); break; case FinancialCategory: modelBeforeEdit = prepareModels(models, (FinancialCategoryEditorForm) tab.getEditorForm()); break; case HourlyWage: modelBeforeEdit = prepareModels(models, (HourlyWageEditorForm) tab .getEditorForm()); break; case CostUnit: modelBeforeEdit = prepareModels(models, (CostUnitEditorForm) tab .getEditorForm()); break; case Employment: modelBeforeEdit = prepareModels(models, (EmploymentEditorForm) tab .getEditorForm()); break; case Contract: modelBeforeEdit = prepareModels(models, (ContractEditorForm) tab .getEditorForm()); break; case Activity: modelBeforeEdit = prepareModels(models, (ActivityEditorForm) tab .getEditorForm()); break; } // check model validation first for (AbstractModel model : models) { if (!model.validateModel()) { tab.updateHints(model); return; } } // inspector checks tab.clearHints(); inspectors.clear(); switch (tab.getType()) { case Employment: EmploymentEditorForm editorForm = (EmploymentEditorForm) tab .getEditorForm(); inspectors.add(new EmploymentLimitInspector(editorForm .getAssistant())); inspectors.add(new WorkingHourLimitInspector(editorForm .getAssistant(), editorForm.getDates())); inspectors.add(new CourseBudgetLimitInspector(editorForm .getCourse())); inspectors.add(new CostUnitBudgetLimitInspector(editorForm .getCourse(), editorForm.getCostUnit())); break; case Assistant: inspectors.add(new IdenticalAssistantInspector(new UIAssistant( (Assistant) models.get(0)))); break; case Contract: inspectors.add(new OverlapContractInspector((Contract) models .get(0))); break; } if (!inspectors.isEmpty()) { try { List<String> messages = new ArrayList<String>(); if (Inspector.isUpdatedDBRequired(inspectors)) { // save models temporarly for (AbstractModel model : models) { model.save(); } } // perform the inspector checks for (Inspector inspector : inspectors) { inspector.check(); if (inspector.isFail()) { messages.add(inspector.getResult()); } } if (Inspector.isUpdatedDBRequired(inspectors)) { // reset the changes in database if (tab.isEditMode()) { modelBeforeEdit.save(); } else { for (AbstractModel model : models) { model.remove(); } } } // has any check failed? if (!messages.isEmpty()) { String message = ""; if (messages.size() == 1) { message = messages.get(0) + "\n\n"; } else { for (String msg : messages) { message += "\u2022 " + msg + "\n\n"; } } message += _("Would you like to continue anyway?"); if (JOptionPane.showConfirmDialog(null, message, _("Confirmation"), JOptionPane.YES_NO_OPTION) == JOptionPane.NO_OPTION) { return; } } } catch (SienaException e2) { // continue as if no checks were performed } } // finally save all prepared models for (AbstractModel model : models) { boolean isNew = !model.isInDatabase(); if(!isNew) { UI.getInstance().addObserversTo(model, tab.getType()); } try { model.save(); if(isNew) { UI.getInstance().addObserversTo(model, tab.getType()); } UI.getInstance().setStatusMessage( MessageFormat.format( _("The entity {0} was saved successfully."), new Object[] { tab.getType().getDisplayName() })); } catch (SienaException e1) { if (e1.getCause().getClass() == SQLIntegrityConstraintViolationException.class) { UI .displayError(MessageFormat .format( _("Could not save the entity {0} because it already exists in the database."), new Object[] { tab.getType().getDisplayName() })); System.out.println(e1.getMessage()); } else { UI.displayError(MessageFormat.format( _("Could not save the entity {0} to database: {1}"), new Object[] { tab.getType().getDisplayName(), e1.getMessage() })); } break; } } Tab p = tab.getPredecessor(); if (p instanceof DetailViewerTab) { ViewerTab viewerTab = new ViewerTab(tab.getType()); p = viewerTab; } UI.getInstance().replaceCurrentTab(p); } }