All Downloads are FREE. Search and download functionalities are using the official Maven repository.

com.calendarfx.view.AllDayView Maven / Gradle / Ivy

There is a newer version: 11.12.7
Show newest version
/*
 *  Copyright (C) 2017 Dirk Lemmermann Software & Consulting (dlsc.com)
 *
 *  Licensed under the Apache License, Version 2.0 (the "License");
 *  you may not use this file except in compliance with the License.
 *  You may obtain a copy of the License at
 *
 *          http://www.apache.org/licenses/LICENSE-2.0
 *
 *  Unless required by applicable law or agreed to in writing, software
 *  distributed under the License is distributed on an "AS IS" BASIS,
 *  WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
 *  See the License for the specific language governing permissions and
 *  limitations under the License.
 */

package com.calendarfx.view;

import com.calendarfx.model.Entry;
import com.calendarfx.util.Util;
import impl.com.calendarfx.view.AllDayViewSkin;
import javafx.beans.property.BooleanProperty;
import javafx.beans.property.DoubleProperty;
import javafx.beans.property.IntegerProperty;
import javafx.beans.property.ObjectProperty;
import javafx.beans.property.SimpleBooleanProperty;
import javafx.beans.property.SimpleIntegerProperty;
import javafx.beans.property.SimpleObjectProperty;
import javafx.beans.value.ObservableValue;
import javafx.collections.ObservableList;
import javafx.css.CssMetaData;
import javafx.css.StyleConverter;
import javafx.css.Styleable;
import javafx.css.StyleableDoubleProperty;
import javafx.css.StyleableObjectProperty;
import javafx.css.StyleableProperty;
import javafx.geometry.Insets;
import javafx.scene.control.Skin;
import javafx.scene.layout.Region;
import javafx.util.Callback;
import org.controlsfx.control.PropertySheet.Item;

import java.time.LocalDate;
import java.time.LocalTime;
import java.time.ZoneId;
import java.time.ZonedDateTime;
import java.util.ArrayList;
import java.util.Collections;
import java.util.List;
import java.util.Optional;

import static java.util.Objects.requireNonNull;

/**
 * A date control used on top of a {@link DayView} or a {@link DetailedWeekView} for
 * showing "full day" calendar entries. This view can be configured to span a
 * given number of days. One day is sufficient when used with a {@link DayView}
 * and seven days when used with a {@link DetailedWeekView}.
 *
 * All Day View
 *
 * @see Entry#isFullDay()
 */
public class AllDayView extends DateControl implements ZonedDateTimeProvider {

    private static final String ALL_DAY_VIEW = "all-day-view";

    /**
     * Constructs a new view for the given number of days.
     *
     * @param numberOfDays
     *            the number of days to be shown by this view
     */
    public AllDayView(int numberOfDays) {
        if (numberOfDays <= 0) {
            throw new IllegalArgumentException(
                    "number of days must be larger than zero");
        }

        getStyleClass().add(ALL_DAY_VIEW);
        setNumberOfDays(numberOfDays);

        new CreateDeleteHandler(this);
    }

    /**
     * Constructs a new view for seven days.
     */
    public AllDayView() {
        this(7);
    }

    @Override
    public final ZonedDateTime getZonedDateTimeAt(double x, double y) {
        int day = (int) (x / (getWidth() / getNumberOfDays()));

        LocalDate date = getDate();

        if (isAdjustToFirstDayOfWeek()) {
            date = Util.adjustToFirstDayOfWeek(date, getFirstDayOfWeek());
        }

        date = date.plusDays(day);

        LocalTime time = LocalTime.NOON;
        ZoneId zoneId = getZoneId();
        return ZonedDateTime.of(date, time, zoneId);
    }

    @Override
    protected Skin createDefaultSkin() {
        return new AllDayViewSkin(this);
    }

    private StyleableObjectProperty extraPadding;

    /**
     * Extra padding to be used inside of the view above and below the full day
     * entries. This is required as the regular padding is already used for
     * other styling purposes.
     *
     * @return insets for extra padding
     */
    public final ObjectProperty extraPaddingProperty() {
        if (extraPadding == null) {
            extraPadding = new StyleableObjectProperty(new Insets(2, 0,
                    9, 0)) {

                @Override
                public CssMetaData getCssMetaData() {
                    return StyleableProperties.EXTRA_PADDING;
                }

                @Override
                public Object getBean() {
                    return AllDayView.this;
                }

                @Override
                public String getName() {
                    return "extraPadding";
                }
            };
        }

        return extraPadding;
    }

    /**
     * Returns the value of {@link #extraPaddingProperty()}.
     *
     * @return extra padding insets
     */
    public final Insets getExtraPadding() {
        return extraPaddingProperty().get();
    }

    /**
     * Sets the value of {@link #extraPaddingProperty()}.
     *
     * @param padding
     *            padding insets
     */
    public final void setExtraPadding(Insets padding) {
        requireNonNull(padding);
        extraPaddingProperty().set(padding);
    }

    private StyleableDoubleProperty rowHeight;

    /**
     * The height for each row shown by the view. This value determines the
     * total height of the view.
     *
     * @return the row height property
     */
    public final DoubleProperty rowHeightProperty() {
        if (rowHeight == null) {
            rowHeight = new StyleableDoubleProperty(20) {

                @Override
                public CssMetaData getCssMetaData() {
                    return StyleableProperties.ROW_HEIGHT;
                }

                @Override
                public Object getBean() {
                    return AllDayView.this;
                }

                @Override
                public String getName() {
                    return "rowHeight";
                }
            };
        }

        return rowHeight;
    }

    /**
     * Returns the value of {@link #rowHeightProperty()}.
     *
     * @return the row height
     */
    public final double getRowHeight() {
        return rowHeightProperty().get();
    }

    /**
     * Sets the value of the {@link #rowHeightProperty()}.
     *
     * @param height
     *            the new row height
     */
    public final void setRowHeight(double height) {
        rowHeightProperty().set(height);
    }

    private StyleableDoubleProperty rowSpacing;

    /**
     * Stores the spacing between rows in the view.
     *
     * @return the spacing between rows in pixels
     */
    public final DoubleProperty rowSpacingProperty() {
        if (rowSpacing == null) {
            rowSpacing = new StyleableDoubleProperty(2) {

                @Override
                public CssMetaData getCssMetaData() {
                    return StyleableProperties.ROW_SPACING;
                }

                @Override
                public Object getBean() {
                    return AllDayView.this;
                }

                @Override
                public String getName() {
                    return "rowSpacing";
                }
            };
        }

        return rowSpacing;
    }

    /**
     * Returns the value of {@link #rowSpacingProperty()}.
     *
     * @return the row spacing in pixels
     */
    public final double getRowSpacing() {
        return rowSpacingProperty().get();
    }

    /**
     * Sets the value of {@link #rowSpacingProperty()}.
     *
     * @param space
     *            the space between rows in pixel
     */
    public final void setRowSpacing(double space) {
        if (space < 0) {
            throw new IllegalArgumentException(
                    "row spacing can not be smaller than zero");
        }
        rowSpacingProperty().set(space);
    }

    private StyleableDoubleProperty columnSpacing;

    /**
     * Stores the spacing between columns in the view.
     *
     * @return the spacing between columns in pixels
     */
    public final DoubleProperty columnSpacingProperty() {
        if (columnSpacing == null) {
            columnSpacing = new StyleableDoubleProperty(2) {

                @Override
                public CssMetaData getCssMetaData() {
                    return StyleableProperties.COLUMN_SPACING;
                }

                @Override
                public Object getBean() {
                    return AllDayView.this;
                }

                @Override
                public String getName() {
                    return "columnSpacing";
                }
            };
        }

        return columnSpacing;
    }

    /**
     * Returns the value of {@link #columnSpacingProperty()}.
     *
     * @return the row spacing in pixels
     */
    public final double getColumnSpacing() {
        return columnSpacingProperty().get();
    }

    /**
     * Sets the value of {@link #columnSpacingProperty()}.
     *
     * @param space
     *            the space between columns in pixel
     */
    public final void setColumnSpacing(double space) {
        columnSpacingProperty().set(space);
    }

    private final BooleanProperty adjustToFirstDayOfWeek = new SimpleBooleanProperty(
            this, "adjustToFirstDayOfWeek", true);

    /**
     * A flag used to indicate that the view should always show the first day of
     * the week (e.g. "Monday") at its beginning even if the
     * {@link #dateProperty()} is set to another day (e.g. "Thursday"). The
     * adjustment is normally needed if the view is used in combination with the
     * {@link DetailedWeekView}. It is not needed if the view is used together with the
     * {@link DayView}.
     *
     * @return true if the view always shows the first day of the week
     */
    public final BooleanProperty adjustToFirstDayOfWeekProperty() {
        return adjustToFirstDayOfWeek;
    }

    /**
     * Returns the value of {@link #adjustToFirstDayOfWeekProperty()}.
     *
     * @return true if the view always shows the first day of the week
     */
    public final boolean isAdjustToFirstDayOfWeek() {
        return adjustToFirstDayOfWeekProperty().get();
    }

    /**
     * Sets the value of {@link #adjustToFirstDayOfWeekProperty()}.
     *
     * @param adjust
     *            if true the view will always show the first day of the week
     */
    public final void setAdjustToFirstDayOfWeek(boolean adjust) {
        adjustToFirstDayOfWeekProperty().set(adjust);
    }

    private final IntegerProperty numberOfDays = new SimpleIntegerProperty(
            this, "numberOfDays");

    /**
     * Stores the number of days that will be shown by this view. This value
     * will be 1 if the view is used in combination with the {@link DayView} and
     * 7 if used together with the {@link DetailedWeekView}.
     *
     * @return the number of days shown by the view
     */
    public final IntegerProperty numberOfDaysProperty() {
        return numberOfDays;
    }

    /**
     * Returns the value of {@link #numberOfDaysProperty()}.
     *
     * @return the number of days shown by the view
     */
    public final int getNumberOfDays() {
        return numberOfDaysProperty().get();
    }

    /**
     * Sets the value of {@link #numberOfDaysProperty()}.
     *
     * @param number
     *            the new number of days shown by the view
     */
    public final void setNumberOfDays(int number) {
        if (number < 1) {
            throw new IllegalArgumentException(
                    "invalid number of days, must be larger than 0 but was "
                            + number);
        }

        numberOfDaysProperty().set(number);
    }

    private final ObjectProperty, AllDayEntryView>> entryViewFactory = new SimpleObjectProperty<>(
            this, "entryViewFactory", AllDayEntryView::new);

    /**
     * A callback used for producing views for entries. The views have to be of
     * type {@link AllDayEntryView}.
     *
     * @return the entry view factory
     */
    public final ObjectProperty, AllDayEntryView>> entryViewFactoryProperty() {
        return entryViewFactory;
    }

    /**
     * Returns the value of {@link #entryViewFactoryProperty()}.
     *
     * @return the entry view factory callback
     */
    public final Callback, AllDayEntryView> getEntryViewFactory() {
        return entryViewFactoryProperty().get();
    }

    /**
     * Sets the value of {@link #entryViewFactoryProperty()}.
     *
     * @param factory the new entry view factory
     */
    public final void setEntryViewFactory(
            Callback, AllDayEntryView> factory) {
        requireNonNull(factory);
        entryViewFactoryProperty().set(factory);
    }

    private static class StyleableProperties {

        private static final List> STYLEABLES;

        private static final CssMetaData ROW_HEIGHT = new CssMetaData(
                "-fx-row-height", StyleConverter.getSizeConverter(), 20d) {

            @Override
            public Double getInitialValue(AllDayView node) {
                return node.getRowHeight();
            }

            @Override
            public boolean isSettable(AllDayView n) {
                return n.rowHeight == null || !n.rowHeight.isBound();
            }

            @SuppressWarnings("unchecked")
            @Override
            public StyleableProperty getStyleableProperty(AllDayView n) {
                return (StyleableProperty) n.rowHeightProperty();
            }
        };

        private static final CssMetaData ROW_SPACING = new CssMetaData(
                "-fx-row-spacing", StyleConverter.getSizeConverter(), 2d) {

            @Override
            public Double getInitialValue(AllDayView node) {
                return node.getRowSpacing();
            }

            @Override
            public boolean isSettable(AllDayView n) {
                return n.rowSpacing == null || !n.rowSpacing.isBound();
            }

            @SuppressWarnings("unchecked")
            @Override
            public StyleableProperty getStyleableProperty(AllDayView n) {
                return (StyleableProperty) n.rowSpacingProperty();
            }
        };

        private static final CssMetaData COLUMN_SPACING = new CssMetaData(
                "-fx-column-spacing", StyleConverter.getSizeConverter(), 2d) {

            @Override
            public Double getInitialValue(AllDayView node) {
                return node.getColumnSpacing();
            }

            @Override
            public boolean isSettable(AllDayView n) {
                return n.columnSpacing == null || !n.columnSpacing.isBound();
            }

            @SuppressWarnings("unchecked")
            @Override
            public StyleableProperty getStyleableProperty(AllDayView n) {
                return (StyleableProperty) n.columnSpacingProperty();
            }
        };

        private static final CssMetaData EXTRA_PADDING = new CssMetaData(
                "-fx-extra-padding", StyleConverter.getInsetsConverter(),
                Insets.EMPTY) {

            @Override
            public Insets getInitialValue(AllDayView node) {
                return node.getExtraPadding();
            }

            @Override
            public boolean isSettable(AllDayView n) {
                return n.extraPadding == null || !n.extraPadding.isBound();
            }

            @SuppressWarnings("unchecked")
            @Override
            public StyleableProperty getStyleableProperty(AllDayView n) {
                return (StyleableProperty) n.extraPaddingProperty();
            }
        };

        static {
            final List> styleables = new ArrayList<>(Region.getClassCssMetaData());

            styleables.add(ROW_HEIGHT);
            styleables.add(ROW_SPACING);
            styleables.add(COLUMN_SPACING);
            styleables.add(EXTRA_PADDING);

            STYLEABLES = Collections.unmodifiableList(styleables);
        }
    }

    public static List> getClassCssMetaData() {
        return StyleableProperties.STYLEABLES;
    }

    @Override
    public final List> getControlCssMetaData() {
        return getClassCssMetaData();
    }

    private static final String ALL_DAY_VIEW_CATEGORY = "All Day View";

    @Override
    public ObservableList getPropertySheetItems() {
        ObservableList items = super.getPropertySheetItems();

        items.add(new Item() {

            @Override
            public Optional> getObservableValue() {
                return Optional.of(numberOfDaysProperty());
            }

            @Override
            public void setValue(Object value) {
                setNumberOfDays((Integer) value);
            }

            @Override
            public Object getValue() {
                return getNumberOfDays();
            }

            @Override
            public Class getType() {
                return Integer.class;
            }

            @Override
            public String getName() {
                return "Number Of Days";
            }

            @Override
            public String getDescription() {
                return "Determines how many days will be covered by this control";
            }

            @Override
            public String getCategory() {
                return ALL_DAY_VIEW_CATEGORY;
            }
        });

        // column spacing

        items.add(new Item() {

            @Override
            public Optional> getObservableValue() {
                return Optional.of(columnSpacingProperty());
            }

            @Override
            public void setValue(Object value) {
                setColumnSpacing((double) value);
            }

            @Override
            public Object getValue() {
                return getColumnSpacing();
            }

            @Override
            public Class getType() {
                return Double.class;
            }

            @Override
            public String getName() {
                return "Column Spacing";
            }

            @Override
            public String getDescription() {
                return "The gap between the days / columns";
            }

            @Override
            public String getCategory() {
                return ALL_DAY_VIEW_CATEGORY;
            }
        });

        // row height

        items.add(new Item() {

            @Override
            public Optional> getObservableValue() {
                return Optional.of(rowHeightProperty());
            }

            @Override
            public void setValue(Object value) {
                setRowHeight((double) value);
            }

            @Override
            public Object getValue() {
                return getRowHeight();
            }

            @Override
            public Class getType() {
                return Double.class;
            }

            @Override
            public String getName() {
                return "Row Height";
            }

            @Override
            public String getDescription() {
                return "The height of each row in the control";
            }

            @Override
            public String getCategory() {
                return ALL_DAY_VIEW_CATEGORY;
            }
        });

        // row spacing

        items.add(new Item() {

            @Override
            public Optional> getObservableValue() {
                return Optional.of(rowSpacingProperty());
            }

            @Override
            public void setValue(Object value) {
                setRowSpacing((double) value);
            }

            @Override
            public Object getValue() {
                return getRowSpacing();
            }

            @Override
            public Class getType() {
                return Double.class;
            }

            @Override
            public String getName() {
                return "Row Spacing";
            }

            @Override
            public String getDescription() {
                return "The gap between the rows";
            }

            @Override
            public String getCategory() {
                return ALL_DAY_VIEW_CATEGORY;
            }
        });

        // extra padding

        items.add(new Item() {

            @Override
            public Optional> getObservableValue() {
                return Optional.of(extraPaddingProperty());
            }

            @Override
            public void setValue(Object value) {
                setExtraPadding((Insets) value);
            }

            @Override
            public Object getValue() {
                return getExtraPadding();
            }

            @Override
            public Class getType() {
                return Insets.class;
            }

            @Override
            public String getName() {
                return "Extra Padding";
            }

            @Override
            public String getDescription() {
                return "Additional padding inside the control";
            }

            @Override
            public String getCategory() {
                return ALL_DAY_VIEW_CATEGORY;
            }
        });

        return items;
    }
}




© 2015 - 2025 Weber Informatics LLC | Privacy Policy