/*
GanttProject is an opensource project management tool. License: GPL3
Copyright (C) 2005-2011 GanttProject 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, write to the Free Software
Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
*/
package net.sourceforge.ganttproject.gui;
import java.awt.BorderLayout;
import java.awt.Dimension;
import java.awt.event.ActionEvent;
import java.util.ArrayList;
import java.util.Date;
import java.util.List;
import javax.swing.AbstractListModel;
import javax.swing.BorderFactory;
import javax.swing.Box;
import javax.swing.JButton;
import javax.swing.JComponent;
import javax.swing.JList;
import javax.swing.JPanel;
import javax.swing.JScrollPane;
import javax.swing.ListSelectionModel;
import javax.swing.event.ListSelectionEvent;
import javax.swing.event.ListSelectionListener;
import biz.ganttproject.core.option.DateOption;
import biz.ganttproject.core.option.DefaultDateOption;
import biz.ganttproject.core.option.GPOption;
import biz.ganttproject.core.option.GPOptionGroup;
import biz.ganttproject.core.time.impl.GPTimeUnitStack;
import net.sourceforge.ganttproject.action.GPAction;
import net.sourceforge.ganttproject.gui.options.OptionsPageBuilder;
import net.sourceforge.ganttproject.language.GanttLanguage;
public class DateIntervalListEditor extends JPanel {
public static class DateInterval {
public final Date start;
private final Date myVisibleEnd;
private final Date myModelEnd;
private DateInterval(Date start, Date visibleEnd, Date modelEnd) {
this.start = start;
myVisibleEnd = visibleEnd;
myModelEnd = modelEnd;
}
@Override
public boolean equals(Object obj) {
if (false == obj instanceof DateInterval) {
return false;
}
DateInterval rvalue = (DateInterval) obj;
return this.start.equals(rvalue.start) && this.getEnd().equals(rvalue.getEnd());
}
@Override
public int hashCode() {
return this.start.hashCode();
}
public Date getVisibleEnd() {
return myVisibleEnd;
}
public Date getEnd() {
return myModelEnd;
}
public static DateInterval createFromModelDates(Date start, Date end) {
return new DateInterval(start, GPTimeUnitStack.DAY.adjustLeft(GPTimeUnitStack.DAY.jumpLeft(end)), end);
}
public static DateInterval createFromVisibleDates(Date start, Date end) {
return new DateInterval(start, end, GPTimeUnitStack.DAY.adjustRight(end));
}
}
public static interface DateIntervalModel {
DateInterval[] getIntervals();
void remove(DateInterval interval);
void add(DateInterval interval);
int getMaxIntervalLength();
boolean canRemove(DateInterval interval);
String format(DateInterval interval);
}
public static class DefaultDateIntervalModel implements DateIntervalModel {
private List<DateInterval> myIntervals = new ArrayList<DateInterval>();
@Override
public DateInterval[] getIntervals() {
return myIntervals.toArray(new DateInterval[myIntervals.size()]);
}
@Override
public void remove(DateInterval interval) {
myIntervals.remove(interval);
}
@Override
public void add(DateInterval interval) {
myIntervals.add(interval);
}
@Override
public int getMaxIntervalLength() {
return 1;
}
@Override
public boolean canRemove(DateInterval interval) {
return true;
}
@Override
public String format(DateInterval interval) {
StringBuffer result = new StringBuffer(GanttLanguage.getInstance().getDateFormat().format(interval.start));
if (!interval.getEnd().equals(interval.start)) {
result.append("...");
result.append(GanttLanguage.getInstance().getDateFormat().format(interval.getVisibleEnd()));
}
return result.toString();
}
}
private final DateIntervalModel myIntervalsModel;
private final DateOption myStart;
private final DateOption myFinish;
private final GPAction myAddAction;
private final GPAction myDeleteAction;
private class MyListModel extends AbstractListModel {
@Override
public int getSize() {
return myIntervalsModel.getIntervals().length;
}
@Override
public Object getElementAt(int index) {
DateInterval interval = myIntervalsModel.getIntervals()[index];
return myIntervalsModel.format(interval);
}
public void update() {
fireContentsChanged(this, 0, myIntervalsModel.getIntervals().length);
}
};
private MyListModel myListModel = new MyListModel();
private ListSelectionModel myListSelectionModel;
public DateIntervalListEditor(final DateIntervalModel intervalsModel) {
super(new BorderLayout());
myIntervalsModel = intervalsModel;
myStart = new DefaultDateOption("generic.startDate") {
@Override
public void setValue(Date value) {
super.setValue(value);
if (intervalsModel.getMaxIntervalLength() == 1) {
DateIntervalListEditor.this.myFinish.setValue(value);
}
DateIntervalListEditor.this.updateActions();
}
};
myFinish = new DefaultDateOption("generic.endDate") {
@Override
public void setValue(Date value) {
super.setValue(value);
DateIntervalListEditor.this.updateActions();
}
};
myAddAction = new GPAction("add") {
@Override
public void actionPerformed(ActionEvent e) {
myIntervalsModel.add(DateInterval.createFromVisibleDates(myStart.getValue(), myFinish.getValue()));
myListModel.update();
}
};
myDeleteAction = new GPAction("delete") {
@Override
public void actionPerformed(ActionEvent e) {
int selected = myListSelectionModel.getMinSelectionIndex();
myIntervalsModel.remove(myIntervalsModel.getIntervals()[selected]);
myListModel.update();
myListSelectionModel.removeIndexInterval(selected, selected);
updateActions();
}
};
JPanel topPanel = new JPanel(new BorderLayout());
OptionsPageBuilder builder = new OptionsPageBuilder();
builder.setOptionKeyPrefix("");
GPOptionGroup group = myIntervalsModel.getMaxIntervalLength() == 1 ? new GPOptionGroup("",
new GPOption[] { myStart }) : new GPOptionGroup("", new GPOption[] { myStart, myFinish });
group.setTitled(false);
JComponent datesBox = builder.buildPlanePage(new GPOptionGroup[] { group });
topPanel.add(datesBox, BorderLayout.CENTER);
Box buttonBox = Box.createHorizontalBox();
buttonBox.setBorder(BorderFactory.createEmptyBorder(3, 0, 3, 0));
buttonBox.add(new JButton(myAddAction));
buttonBox.add(Box.createHorizontalStrut(5));
buttonBox.add(new JButton(myDeleteAction));
topPanel.add(buttonBox, BorderLayout.SOUTH);
topPanel.setBorder(BorderFactory.createEmptyBorder(5, 5, 0, 5));
add(topPanel, BorderLayout.NORTH);
JList list = new JList(myListModel);
list.setName("list");
list.setBorder(BorderFactory.createLoweredBevelBorder());
myListSelectionModel = list.getSelectionModel();
myListSelectionModel.addListSelectionListener(new ListSelectionListener() {
@Override
public void valueChanged(ListSelectionEvent e) {
updateActions();
}
});
JScrollPane scrollPane = new JScrollPane(list);
scrollPane.setBorder(BorderFactory.createEmptyBorder(5, 5, 5, 5));
scrollPane.setPreferredSize(new Dimension(120, 200));
add(scrollPane, BorderLayout.CENTER);
updateActions();
}
private void updateActions() {
if (myStart.getValue() != null && myFinish.getValue() != null
&& false == myFinish.getValue().before(myStart.getValue())) {
myAddAction.setEnabled(true);
} else {
myAddAction.setEnabled(false);
}
if (myListSelectionModel.isSelectionEmpty()) {
myDeleteAction.setEnabled(false);
} else {
int idxSelected = myListSelectionModel.getMinSelectionIndex();
if (idxSelected >= 0 && idxSelected < myIntervalsModel.getIntervals().length) {
myDeleteAction.setEnabled(myIntervalsModel.canRemove(myIntervalsModel.getIntervals()[idxSelected]));
}
}
}
}