/* PlanManager.java - created: Feb 16, 2008 * Copyright (C) 2008 Clayton Carter * * This file is part of the project "Crop Planning Software". For more * information: * website: https://github.com/claytonrcarter/cropplanning * email: [email protected] * * 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 CPS.Core.CropPlans; import CPS.Data.CPSPlanting; import CPS.Module.CPSDataModel; import CPS.Module.CPSModule; import CPS.UI.Swing.CPSDialog; import java.awt.Component; import java.awt.Dimension; import java.awt.FlowLayout; import java.awt.event.ActionEvent; import java.awt.event.ActionListener; import java.awt.event.ItemEvent; import java.awt.event.ItemListener; import java.util.ArrayList; import java.util.Calendar; import java.util.Date; import java.util.GregorianCalendar; import java.util.List; import javax.swing.BorderFactory; import javax.swing.BoxLayout; import javax.swing.ButtonGroup; import javax.swing.JButton; import javax.swing.JCheckBox; import javax.swing.JComboBox; import javax.swing.JLabel; import javax.swing.JPanel; import javax.swing.JRadioButton; import javax.swing.JSpinner; import javax.swing.JTextField; import javax.swing.SpinnerDateModel; import javax.swing.SwingUtilities; import net.miginfocom.swing.MigLayout; public class PlanManager extends CPSDialog implements ActionListener { private JButton btnNew, btnDelete, btnSave, btnSelect, btnCancel; private JComboBox cmboPlanList = null; private JTextField tfldDesc; private JSpinner spnYear; private GregorianCalendar tempCal; private String selectedPlan = null, oldSelected = null; private List<String> listOfValidCropPlans; static CPSDataModel dm = null; public PlanManager( Component parent ) { super( parent, "Manage and Select Crop Plans" ); setDescription( "Manage crop plans: create, delete, alter properties<br>and select for editting." ); tempCal = new GregorianCalendar(); listOfValidCropPlans = new ArrayList<String>(); } public void setDataModel( CPSDataModel dm ) { this.dm = dm; updateListOfPlans(); CPSModule.debug( "PlanMan", "List of plans: " + listOfValidCropPlans ); } public void selectPlan( String planName ) { if ( listOfValidCropPlans.contains(planName) ) selectedPlan = planName; else if ( listOfValidCropPlans.size() == 1 ) selectedPlan = listOfValidCropPlans.get(0); if ( contentsPanelBuilt ) cmboPlanList.setSelectedItem( planName ); } public String getSelectedPlanName() { if ( selectedPlan == null && listOfValidCropPlans.size() == 1 ) { selectedPlan = listOfValidCropPlans.get(0); CPSModule.debug( "PlanMan", "Selecting only crop plan: " + selectedPlan + ";" ); } return selectedPlan; } private String getCurrentSelection() { return (String) cmboPlanList.getSelectedItem(); } public String getSelectedPlanDescription() { return tfldDesc.getText(); } public int getSelectedPlanYear() { tempCal.setTime( (Date) spnYear.getValue() ); return tempCal.get( Calendar.YEAR ); } private void updateListOfPlans() { if ( dm != null ) listOfValidCropPlans = dm.getListOfCropPlans(); } private void updateComboBox() { if ( ! contentsPanelBuilt ) return; cmboPlanList.removeActionListener(this); cmboPlanList.removeAllItems(); for ( String s : listOfValidCropPlans ) cmboPlanList.addItem( s ); cmboPlanList.addActionListener(this); if ( selectedPlan != null && ! selectedPlan.equals( "" ) && listOfValidCropPlans.contains( selectedPlan ) ) cmboPlanList.setSelectedItem( selectedPlan ); else cmboPlanList.setSelectedIndex(-1); } private void createPlan() { CPSBasedOnDialog dia = new CPSBasedOnDialog( SwingUtilities.getWindowAncestor(this), getCurrentSelection(), listOfValidCropPlans, dm ); dia.setVisible(true); if ( dm == null ) return; // if they did not Cancel if ( dia.selectedCreate() ) { // disable the buttons while we work btnNew.setEnabled(false); btnCancel.setEnabled(false); String newPlan = getCurrentSelection(); // create a blank crop plan no matter what dm.createCropPlan( newPlan, getSelectedPlanYear(), getSelectedPlanDescription() ); // if they didn't select "blank plan" if ( ! dia.selectedBlankPlan() ) { // get old crop plan List<CPSPlanting> ps = dm.getCropPlan( dia.getPlanToBaseOn() ); // how much to bump to dates int y = getSelectedPlanYear() - dm.getCropPlanYear( dia.getPlanToBaseOn() ); String yearBump = "+" + y + "y"; // create the new keyword String fromTag = dia.getPlanToBaseOn(); fromTag = "from" + fromTag.replaceAll( "/ /", "" ); // now add new tag, bump the dates and save the planting in the new plan for ( CPSPlanting p : ps ) { // add the new tag p.setKeywords( p.getKeywords() + " " + fromTag ); // bump the planned dates if ( ! p.getDateToPlantPlannedString().equals( "" ) && ! p.getDateToPlantPlannedState().isCalculated() ) p.setDateToPlantPlanned( p.getDateToPlantPlannedString() + yearBump ); if ( ! p.getDateToTPPlannedString().equals( "" ) && ! p.getDateToTPPlannedState().isCalculated() ) p.setDateToTPPlanned( p.getDateToTPPlannedString() + yearBump ); if ( ! p.getDateToHarvestPlannedString().equals( "" ) && ! p.getDateToHarvestPlannedState().isCalculated() ) p.setDateToHarvestPlanned( p.getDateToHarvestPlannedString() + yearBump ); // blank the actual dates if ( ! p.getDateToPlantActualString().equals( "" ) ) p.setDateToPlantActual( "" ); if ( ! p.getDateToTPActualString().equals( "" ) ) p.setDateToTPActual( "" ); if ( ! p.getDateToHarvestActualString().equals( "" ) ) p.setDateToHarvestActual( "" ); // mark as not "done" p.setDonePlanting(false); p.setDoneTP(false); p.setDoneHarvest(false); // save into the new crop plan dm.createPlanting( newPlan, p ); } if ( dia.selectedLockOldPlan() ) dm.finalizeCropPlan(dia.getPlanToBaseOn()); } selectedPlan = newPlan; // these only need to be fiddled with is they did cancel updateListOfPlans(); updateComboBox(); } } private void updatePlan() { if ( dm != null ) dm.updateCropPlan( getCurrentSelection(), getSelectedPlanYear(), getSelectedPlanDescription() ); } private void deletePlan() { if ( dm != null ) dm.deleteCropPlan( getCurrentSelection() ); selectedPlan = null; updateListOfPlans(); updateComboBox(); } @Override public void setVisible( boolean arg0 ) { if ( ! contentsPanelBuilt ) buildContentsPanel(); updateListOfPlans(); updateComboBox(); super.setVisible( arg0 ); } @Override protected void buildContentsPanel() { cmboPlanList = new JComboBox(); cmboPlanList.setEditable(true); cmboPlanList.addActionListener(this); spnYear = new JSpinner(); SpinnerDateModel spnMod = new SpinnerDateModel(); spnMod.setCalendarField( Calendar.YEAR ); spnYear.setModel( spnMod ); spnYear.setEditor( new JSpinner.DateEditor( spnYear, "yyyy" ) ); spnYear.setPreferredSize( new Dimension( 70, spnYear.getPreferredSize().height )); tfldDesc = new JTextField( 20 ); JPanel jplCont = new JPanel( new MigLayout( "gapy 0px!, insets 2px", "[align right][]") ); jplCont.add( new JLabel( "Plan:" ) ); jplCont.add( cmboPlanList, "wrap" ); jplCont.add( new JLabel( "Year:" ) ); jplCont.add( spnYear, "wrap" ); jplCont.add( new JLabel( "Description:" ) ); jplCont.add( tfldDesc, "wrap" ); jplCont.setBorder( BorderFactory.createEmptyBorder( 10, 10, 0, 10)); contentsPanelBuilt = true; add( jplCont ); } @Override protected void fillButtonPanel() { JPanel jplTop = new JPanel(); JPanel jplBottom = new JPanel(); JPanel jplBtns = new JPanel(); jplTop.setLayout( new FlowLayout( FlowLayout.TRAILING )); jplBottom.setLayout( new FlowLayout( FlowLayout.TRAILING )); jplBtns.setLayout( new BoxLayout( jplBtns, BoxLayout.PAGE_AXIS )); btnNew = new JButton( "Create" ); btnNew.setToolTipText( "Create new plan w/ specified name and properties."); btnDelete = new JButton( "Delete" ); btnDelete.setToolTipText( "Delete selected crop plan." ); btnSave = new JButton( "Save" ); btnSave.setToolTipText( "Save property changes to selected crop plan." ); btnSelect = new JButton( "Select & View" ); btnSelect.setToolTipText( "Open the selected crop plan for viewing and editting." ); btnCancel = new JButton( "Cancel" ); btnCancel.setToolTipText( "Discard unsaved changes." ); btnNew.addActionListener( this ); btnDelete.addActionListener( this ); btnSave.addActionListener( this ); btnSelect.addActionListener( this ); btnCancel.addActionListener( this ); jplTop.add( btnNew ); jplTop.add( btnDelete ); jplTop.add( btnSave ); jplBottom.add( btnSelect ); jplBottom.add( btnCancel ); jplBtns.add( jplTop ); jplBtns.add( jplBottom ); addButton( jplBtns ); } public void actionPerformed( ActionEvent arg0 ) { String action = arg0.getActionCommand(); Object source = arg0.getSource(); if ( source.getClass().equals( JComboBox.class )) CPSModule.debug( "PlanMan", "Action Performed: " + action + " to " + ((JComboBox)source).getSelectedItem() ); else CPSModule.debug( "PlanMan", "Action Performed: " + action + " on " + ((JButton)source).getText() ); if ( source == btnNew ) { createPlan(); } else if ( source == btnDelete ) { deletePlan(); } else if ( source == btnSave ) { updatePlan(); } else if ( source == btnSelect ) { oldSelected = selectedPlan; selectedPlan = (String) cmboPlanList.getSelectedItem(); setVisible( false ); } else if ( source == btnCancel ) { // TODO is this right? cmboPlanList.setSelectedItem( oldSelected ); setVisible( false ); } else if ( source == cmboPlanList && dm != null ) { String planName = getCurrentSelection(); if ( listOfValidCropPlans.contains( planName ) ) { // the current selection IS a valid plan tempCal.set( Calendar.YEAR, dm.getCropPlanYear( planName ) ); spnYear.setValue( tempCal.getTime() ); tfldDesc.setText( dm.getCropPlanDescription( planName ) ); btnNew.setEnabled(false); btnSave.setEnabled(true); btnDelete.setEnabled(true); btnSelect.setEnabled(true); } else { spnYear.setValue( new Date() ); tfldDesc.setText( "" ); // the current selection isn't a valid plan btnNew.setEnabled(true); btnSave.setEnabled(false); btnDelete.setEnabled(false); btnSelect.setEnabled(false); } } } class CPSBasedOnDialog extends CPSDialog implements ActionListener, ItemListener { JRadioButton rdoBlank = null, rdoBasedOn; JComboBox cmbPlans = null; JCheckBox chkLockOld = null; JButton btnCreate, btnCancel; boolean create = false; String newPlan; List<String> oldPlans; CPSDataModel dm = null; public CPSBasedOnDialog( Component parent, String newPlan, List<String> oldPlans, CPSDataModel dm ) { super( parent, "Create New Plan"); setDescription("What kind of plan do you want<br>to create?"); this.newPlan = newPlan; this.oldPlans = oldPlans; this.dm = dm; } public boolean selectedBlankPlan() { if ( rdoBlank == null ) return true; else return rdoBlank.isSelected(); } public boolean selectedLockOldPlan() { if ( chkLockOld == null ) return false; else return chkLockOld.isSelected(); } public String getPlanToBaseOn() { if ( cmbPlans == null ) return ""; else return (String) cmbPlans.getItemAt( cmbPlans.getSelectedIndex() ); } public boolean selectedCreate() { return create; } @Override protected void buildContentsPanel() { rdoBlank = new JRadioButton("a shiney, new, blank crop plan"); rdoBlank.setSelected(true); rdoBasedOn = new JRadioButton("crop plan based on"); rdoBlank.addItemListener(this); rdoBasedOn.addItemListener(this); ButtonGroup bg = new ButtonGroup(); bg.add( rdoBlank ); bg.add( rdoBasedOn ); cmbPlans = new JComboBox( oldPlans.toArray( new String[ oldPlans.size() ]) ); cmbPlans.setEditable(false); cmbPlans.setEnabled(false); chkLockOld = new JCheckBox("Lock the old plan."); chkLockOld.setSelected(false); chkLockOld.setToolTipText("If selected, the old plan will be 'locked' so that " + "it can't be editted, but can still be " + "viewed and referenced and used to generate " + "lists." ); chkLockOld.setEnabled(false); JPanel jplCont = new JPanel( new MigLayout( "gapy 0px!, insets 2px", "[align right][]") ); JLabel lblBasedOn = new JLabel( "<html><font size=\"-2\">" + "If you select the 'based on' option, all of your<br>" + "plantings will be copied from the selected plan<br>" + "into the new plan with these changes:" + "<ol> " + "<li>'Planned' dates will be adjusted<br>" + "to the selected year." + "<li>'Actual' dates (if any) will be blanked." + "<li>The 'Done ...' checkboxes will be<br>unselected." + "<li>They will all be given a keyword<br>" + "of 'from" + newPlan +"' so that you can<br>" + "search/filter for them as you<br>update them." + "</ol></font></html>"); JLabel lblLock = new JLabel( "<html><font size=\"-2\">" + "If selected, the old plan will be 'locked' so that<br> " + "it can't be editted, but can still be viewed and<br>" + "used to generate lists and such." + "</font></html>" ); int r = 1; jplCont.add( rdoBlank, "span 2, align left, wrap" ); jplCont.add( rdoBasedOn, "align left" ); jplCont.add( cmbPlans, "wrap" ); jplCont.add( lblBasedOn, "span 2, wrap" ); jplCont.add( chkLockOld, "span 2, align center, wrap" ); jplCont.add( lblLock, "span 2, wrap" ); jplCont.setBorder( BorderFactory.createEmptyBorder( 10, 10, 0, 10)); contentsPanelBuilt = true; add( jplCont ); } @Override protected void fillButtonPanel() { btnCreate = new JButton( "Create" ); btnCancel = new JButton( "Cancel" ); btnCreate.addActionListener( this ); btnCancel.addActionListener( this ); addButton( btnCreate ); addButton( btnCancel ); } public void actionPerformed(ActionEvent e) { Object source = e.getSource(); if ( source == btnCreate ) create = true; else if ( source == btnCancel ) create = false; setVisible(false); } public void itemStateChanged(ItemEvent e) { Object source = e.getItemSelectable(); if ( source == rdoBlank ) { cmbPlans.setEnabled(false); chkLockOld.setEnabled(false); } else if ( source == rdoBasedOn ) { cmbPlans.setEnabled(true); chkLockOld.setEnabled(true); } } } // For testing. public static void main( String[] args ) { new PlanManager( new JPanel() ).setVisible( true ); System.exit( 0 ); } }