/*
Copyright 2014 BarD Software s.r.o
Copyright 2003-2013 GanttProject Team
This file is part of GanttProject, an opensource project management tool.
GanttProject 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.
GanttProject 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 GanttProject. If not, see <http://www.gnu.org/licenses/>.
*/
package net.sourceforge.ganttproject.gui.projectwizard;
import java.awt.BorderLayout;
import java.awt.Component;
import java.awt.event.ActionEvent;
import java.util.Arrays;
import java.util.Calendar;
import java.util.Collection;
import java.util.List;
import javax.swing.AbstractAction;
import javax.swing.BorderFactory;
import javax.swing.Box;
import javax.swing.ButtonModel;
import javax.swing.JCheckBox;
import javax.swing.JComponent;
import javax.swing.JLabel;
import javax.swing.JPanel;
import net.sourceforge.ganttproject.IGanttProject;
import net.sourceforge.ganttproject.calendar.CalendarEditorPanel;
import net.sourceforge.ganttproject.calendar.GPCalendarProvider;
import net.sourceforge.ganttproject.gui.UIFacade;
import net.sourceforge.ganttproject.gui.options.OptionsPageBuilder;
import net.sourceforge.ganttproject.language.GanttLanguage;
import biz.ganttproject.core.calendar.AlwaysWorkingTimeCalendarImpl;
import biz.ganttproject.core.calendar.CalendarEvent;
import biz.ganttproject.core.calendar.GPCalendar;
import biz.ganttproject.core.calendar.GPCalendar.DayType;
import biz.ganttproject.core.calendar.GPCalendarCalc;
import biz.ganttproject.core.calendar.WeekendCalendarImpl;
import biz.ganttproject.core.option.ChangeValueEvent;
import biz.ganttproject.core.option.ChangeValueListener;
import biz.ganttproject.core.option.DefaultEnumerationOption;
import com.google.common.base.Predicate;
import com.google.common.base.Supplier;
import com.google.common.collect.Collections2;
import com.google.common.collect.Lists;
import com.google.common.collect.Sets;
/**
* This page provides UI for configuring project weekend days and public holidays
*
* @author dbarashev (Dmitry Barashev)
*/
public class WeekendConfigurationPage implements WizardPage {
private final JPanel myPanel;
private final JLabel myBasedOnLabel = new JLabel();
{
myBasedOnLabel.setBorder(BorderFactory.createEmptyBorder(0, 0, 10, 0));
}
private final I18N myI18N;
private final CalendarOption myCalendarOption;
private final WeekendCalendarImpl myCustomCalendar = new WeekendCalendarImpl() {
{
setName(GanttLanguage.getInstance().getText("calendar.editor.custom.name"));
}
};
private final WeekendSchedulingOption myRenderWeekendOption;
private CalendarEditorPanel myCalendarEditorPanel;
private static <T> List<T> append(List<T> list, T... s) {
List<T> result = Lists.newArrayList(list);
result.addAll(Arrays.asList(s));
return result;
}
static class CalendarOption extends DefaultEnumerationOption<GPCalendar> {
public CalendarOption(GPCalendar calendar, List<GPCalendar> allCalendars) {
super("project.calendar", allCalendars.toArray(new GPCalendar[0]));
resetValue(i18n("none"), true);
}
@Override
protected String objectToString(GPCalendar obj) {
return obj.getName();
}
}
static enum SchedulingEnum {
SCHEDULE_NONE, SCHEDULE_ALL
}
static class WeekendSchedulingOption extends DefaultEnumerationOption<SchedulingEnum> {
WeekendSchedulingOption(SchedulingEnum initialValue) {
super("project.weekendScheduling", SchedulingEnum.values());
resetValue(objectToString(initialValue), true);
}
@Override
protected String objectToString(SchedulingEnum obj) {
return getID() + "." + obj.name().toLowerCase();
}
}
public WeekendConfigurationPage(final GPCalendarCalc calendar, I18N i18n, UIFacade uiFacade) {
OptionsPageBuilder builder = new OptionsPageBuilder();
myI18N = i18n;
myPanel = new JPanel(new BorderLayout());
JPanel panel = new JPanel();
{
panel.add(new JLabel(GanttLanguage.getInstance().getText("chooseWeekend")));
Box weekendBox = Box.createHorizontalBox();
for (JCheckBox checkBox : createWeekendCheckBoxes(calendar, i18n.getDayNames())) {
weekendBox.add(checkBox);
weekendBox.add(Box.createHorizontalStrut(10));
}
weekendBox.add(Box.createHorizontalGlue());
panel.add(weekendBox);
myRenderWeekendOption = new WeekendSchedulingOption(calendar.getOnlyShowWeekends() ? SchedulingEnum.SCHEDULE_ALL
: SchedulingEnum.SCHEDULE_NONE) {
@Override
public void commit() {
super.commit();
if (stringToObject(getValue()) == SchedulingEnum.SCHEDULE_ALL) {
calendar.setOnlyShowWeekends(true);
} else {
calendar.setOnlyShowWeekends(false);
}
}
};
panel.add(builder.createOptionLabel(null, myRenderWeekendOption));
panel.add(builder.createOptionComponent(null, myRenderWeekendOption));
panel.add(new JPanel());
panel.add(new JPanel());
}
{
myCalendarOption = createCalendarOption(calendar);
panel.add(builder.createOptionLabel(null, myCalendarOption));
panel.add(builder.createOptionComponent(null, myCalendarOption));
panel.add(new JPanel());
panel.add(myBasedOnLabel);
}
OptionsPageBuilder.TWO_COLUMN_LAYOUT.layout(panel, 5);
myPanel.add(panel, BorderLayout.NORTH);
myCalendarEditorPanel = new CalendarEditorPanel(uiFacade, calendar, new Runnable() {
@Override public void run() {
fillCustomCalendar(myCalendarEditorPanel.getEvents(), myCalendarOption.getSelectedValue());
if (myCalendarOption.getSelectedValue() != myCustomCalendar) {
updateBasedOnLabel(myCalendarOption.getSelectedValue());
}
myCalendarOption.setSelectedValue(myCustomCalendar);
}
});
myCalendarOption.addChangeValueListener(new ChangeValueListener() {
@Override
public void changeValue(ChangeValueEvent event) {
if (myCalendarOption.getSelectedValue() != null) {
if (myCalendarOption.getSelectedValue() == myCustomCalendar) {
calendar.setBaseCalendarID(myCustomCalendar.getBaseCalendarID());
} else {
updateBasedOnLabel(null);
calendar.setBaseCalendarID(myCalendarOption.getSelectedValue().getID());
}
calendar.setPublicHolidays(myCalendarOption.getSelectedValue().getPublicHolidays());
}
myCalendarEditorPanel.reload(calendar);
}
});
JComponent editorComponent = myCalendarEditorPanel.createComponent();
editorComponent.setBorder(BorderFactory.createCompoundBorder(
BorderFactory.createEmptyBorder(5, 0, 0, 0),
editorComponent.getBorder()));
myPanel.add(editorComponent, BorderLayout.CENTER);
}
private void updateBasedOnLabel(GPCalendar calendar) {
if (calendar == null) {
myBasedOnLabel.setText("");
} else {
myBasedOnLabel.setText(GanttLanguage.getInstance().formatText("calendar.editor.basedOn", calendar.getName()));
}
}
private void fillCustomCalendar(List<CalendarEvent> events, GPCalendar base) {
myCustomCalendar.setPublicHolidays(events);
if (!GanttLanguage.getInstance().getText("calendar.editor.custom.name").equals(base.getID())) {
myCustomCalendar.setBaseCalendarID(base.getID());
}
}
private CalendarOption createCalendarOption(final GPCalendar calendar) {
AlwaysWorkingTimeCalendarImpl emptyCalendar = new AlwaysWorkingTimeCalendarImpl();
emptyCalendar.setName(GanttLanguage.getInstance().getText("none"));
List<GPCalendar> allCalendars = append(GPCalendarProvider.getInstance().getCalendars(), emptyCalendar, myCustomCalendar);
CalendarOption result = new CalendarOption(calendar, allCalendars);
if (calendar.getBaseCalendarID() != null) {
Collection<GPCalendar> filtered = Collections2.filter(allCalendars, new Predicate<GPCalendar>() {
public boolean apply(GPCalendar cal) {
return cal.getID().equals(calendar.getBaseCalendarID());
}
});
if (!filtered.isEmpty()) {
GPCalendar baseCalendar = filtered.iterator().next();
if (Sets.newHashSet(baseCalendar.getPublicHolidays()).equals(Sets.newHashSet(calendar.getPublicHolidays()))) {
result.setSelectedValue(baseCalendar);
} else {
fillCustomCalendar(Lists.newArrayList(calendar.getPublicHolidays()), baseCalendar);
result.setSelectedValue(myCustomCalendar);
updateBasedOnLabel(baseCalendar);
}
}
}
return result;
}
private List<JCheckBox> createWeekendCheckBoxes(final GPCalendar calendar, String[] names) {
Supplier<Integer> counter = new Supplier<Integer>() {
@Override
public Integer get() {
int count = 0;
for (int i = 1; i <= 7; i++) {
if (calendar.getWeekDayType(i) == DayType.WEEKEND) {
count++;
}
}
return count;
}
};
List<JCheckBox> result = Lists.newArrayListWithExpectedSize(7);
int day = Calendar.MONDAY;
for (int i = 0; i < 7; i++) {
JCheckBox nextCheckBox = new JCheckBox();
nextCheckBox.setSelected(calendar.getWeekDayType(day) == GPCalendar.DayType.WEEKEND);
nextCheckBox.setAction(new CheckBoxAction(calendar, day, names[day - 1], nextCheckBox.getModel(), counter));
result.add(nextCheckBox);
if (++day >= 8) {
day = 1;
}
}
return result;
}
@Override
public String getTitle() {
return myI18N.getProjectWeekendPageTitle();
}
@Override
public Component getComponent() {
return myPanel;
}
@Override
public void setActive(boolean active) {
if (!active) {
myCalendarOption.commit();
myRenderWeekendOption.commit();
}
}
public boolean isChanged() {
return true;
}
private static class CheckBoxAction extends AbstractAction {
private final int myDay;
private final ButtonModel myModelButton;
private final GPCalendar myCalendar;
private final Supplier<Integer> myCounter;
CheckBoxAction(GPCalendar calendar, int day, String dayName, ButtonModel model, Supplier<Integer> checkedDaysCounter) {
super(dayName);
myCalendar = calendar;
myDay = day;
myModelButton = model;
myCounter = checkedDaysCounter;
}
@Override
public void actionPerformed(ActionEvent e) {
if (myCounter.get() == 7) {
// If all days of the week are marked as weekend unmark selected the
// last.
myModelButton.setSelected(false);
} else {
myCalendar.setWeekDayType(myDay, myModelButton.isSelected() ? GPCalendar.DayType.WEEKEND
: GPCalendar.DayType.WORKING);
}
}
}
}