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

jfxtras.internal.scene.control.skin.agenda.base24hour.AppointmentMenu Maven / Gradle / Ivy

The newest version!
/**
 * AppointmentMenu.java
 *
 * Copyright (c) 2011-2016, JFXtras
 * All rights reserved.
 * 
 * Redistribution and use in source and binary forms, with or without
 * modification, are permitted provided that the following conditions are met:
 *     * Redistributions of source code must retain the above copyright
 *       notice, this list of conditions and the following disclaimer.
 *     * Redistributions in binary form must reproduce the above copyright
 *       notice, this list of conditions and the following disclaimer in the
 *       documentation and/or other materials provided with the distribution.
 *     * Neither the name of the organization nor the
 *       names of its contributors may be used to endorse or promote products
 *       derived from this software without specific prior written permission.
 * 
 * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND
 * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
 * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
 * DISCLAIMED. IN NO EVENT SHALL  BE LIABLE FOR ANY
 * DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
 * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
 * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND
 * ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
 * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
 * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
 */

package jfxtras.internal.scene.control.skin.agenda.base24hour;

import java.time.LocalDateTime;

import javafx.scene.control.CheckBox;
import javafx.scene.control.TextField;
import javafx.scene.control.Tooltip;
import javafx.scene.input.MouseEvent;
import javafx.scene.layout.BorderPane;
import javafx.scene.layout.GridPane;
import javafx.scene.layout.HBox;
import javafx.scene.layout.Pane;
import javafx.scene.layout.VBox;
import javafx.scene.shape.Rectangle;
import javafx.scene.text.Text;
import javafx.stage.Popup;
import javafx.util.Callback;
import jfxtras.scene.control.ImageViewButton;
import jfxtras.scene.control.LocalDateTimeTextField;
import jfxtras.scene.control.agenda.Agenda.Appointment;
import jfxtras.scene.control.agenda.Agenda.AppointmentGroup;
import jfxtras.util.NodeUtil;

//TODO: internationalize the labels and tooltips
class AppointmentMenu extends Rectangle {

	/**
	 * 
	 * @param pane
	 * @param appointment
	 * @param layoutHelp
	 */
	AppointmentMenu(Pane pane, Appointment appointment, LayoutHelp layoutHelp) {
		this.pane = pane;
		this.appointment = appointment;
		this.layoutHelp = layoutHelp;
		
		// layout
		setX(NodeUtil.snapXY(layoutHelp.paddingProperty.get()));
		setY(NodeUtil.snapXY(layoutHelp.paddingProperty.get()));
		setWidth(6);
		setHeight(3);
		
		// style
		getStyleClass().add("MenuIcon");
		
		// mouse
		layoutHelp.setupMouseOverAsBusy(this);
		setupMouseClick();
	}
	final Pane pane;
	final Appointment appointment;
	final LayoutHelp layoutHelp;

	/**
	 * 
	 */
	private void setupMouseClick() {
		setOnMousePressed((mouseEvent) -> {
			mouseEvent.consume();
		});
		setOnMouseReleased((mouseEvent) -> {
			mouseEvent.consume();
		});
		setOnMouseClicked( (mouseEvent) -> {
			mouseEvent.consume();
			showMenu(mouseEvent);
		});
	}
	
	/**
	 * 
	 * @param mouseEvent
	 */
	void showMenu(MouseEvent mouseEvent) {
		// has the client done his own popup?
		Callback lEditCallback = layoutHelp.skinnable.getEditAppointmentCallback();
		if (lEditCallback != null) {
			lEditCallback.call(appointment);
			return;
		}

		// only if not already showing
		if (popup != null && popup.isShowing()) {
			return;
		}
		
		// create popup
		popup = new Popup();
		popup.setAutoFix(true);
		popup.setAutoHide(true);
		popup.setHideOnEscape(true);
		popup.setOnHidden( (windowEvent) -> {
			layoutHelp.skin.setupAppointments();
		});

		// popup contents
		BorderPane lBorderPane = new BorderPane() {
			// As of 1.8.0_40 CSS files are added in the scope of a control, the popup does not fall under the control, so the stylesheet must be reapplied 
			// When JFxtras is based on 1.8.0_40+: @Override 
			public String getUserAgentStylesheet() {
				return layoutHelp.skinnable.getUserAgentStylesheet();
			}
		};
		lBorderPane.getStyleClass().add(layoutHelp.skinnable.getClass().getSimpleName() + "Popup");
		popup.getContent().add(lBorderPane);

		// close icon
		lBorderPane.setRight(createCloseIcon());
		
		// initial layout
		VBox lVBox = new VBox(layoutHelp.paddingProperty.get());
		lBorderPane.setCenter(lVBox);

		// start and end
		lVBox.getChildren().add(new Text("Time:"));
		lVBox.getChildren().add(createStartTextField());
		lVBox.getChildren().add(createEndTextField());

		// wholeday
		if ((appointment.isWholeDay() != null && appointment.isWholeDay() == true) || appointment.getEndLocalDateTime() != null) {
			lVBox.getChildren().add(createWholedayCheckbox());
		}
		
		// summary
		lVBox.getChildren().add(new Text("Summary:"));
		lVBox.getChildren().add(createSummaryTextField());

		// location
		lVBox.getChildren().add(new Text("Location:"));
		lVBox.getChildren().add(createLocationTextField());

		// actions
		lVBox.getChildren().add(new Text("Actions:"));  
		lVBox.getChildren().add(createActions());

		// appointment groups
		lVBox.getChildren().add(new Text("Group:"));
		lVBox.getChildren().add(createAppointmentGroups());
		
		// show it just below the menu icon
		popup.show(pane, NodeUtil.screenX(pane), NodeUtil.screenY(pane));
	}
	private Popup popup;
	
	/**
	 * @return
	 */
	private ImageViewButton createCloseIcon() {
		closeIconImageView = new ImageViewButton();
		closeIconImageView.getStyleClass().add("close-icon");
		closeIconImageView.setPickOnBounds(true);
		closeIconImageView.setOnMouseClicked( (mouseEvent2) -> {
			popup.hide();
		});
		return closeIconImageView;
	}
	private ImageViewButton closeIconImageView = null;

	/**
	 * 
	 * @return
	 */
	private LocalDateTimeTextField createStartTextField() {
		startTextField = new LocalDateTimeTextField();
		startTextField.setLocale(layoutHelp.skinnable.getLocale());
		startTextField.setLocalDateTime(appointment.getStartLocalDateTime());
		
		// event handling
		startTextField.localDateTimeProperty().addListener( (observable, oldValue, newValue) ->  {
			
			// remember
			LocalDateTime lOldStart = appointment.getStartLocalDateTime();

			// set
			appointment.setStartLocalDateTime(newValue);

			// update end date
			if (appointment.getEndLocalDateTime() != null) {
				
				// enddate = start + duration
				long lDurationInNano = appointment.getEndLocalDateTime().getNano() - lOldStart.getNano();
				LocalDateTime lEndLocalDateTime = appointment.getStartLocalDateTime().plusNanos(lDurationInNano);
				appointment.setEndLocalDateTime(lEndLocalDateTime);

				// update field
				endTextField.setLocalDateTime(appointment.getEndLocalDateTime());
			}

			// refresh is done upon popup close
			layoutHelp.callAppointmentChangedCallback(appointment);
		});

		return startTextField;
	}
	private LocalDateTimeTextField startTextField = null;

	/**
	 * 
	 * @return
	 */
	private LocalDateTimeTextField createEndTextField() {
		endTextField = new LocalDateTimeTextField();
		endTextField.setLocale(layoutHelp.skinnable.getLocale());
		endTextField.setLocalDateTime(appointment.getEndLocalDateTime());
		endTextField.setVisible(appointment.getEndLocalDateTime() != null);

		endTextField.localDateTimeProperty().addListener( (observable, oldValue, newValue) ->  {
			appointment.setEndLocalDateTime(newValue);
			// refresh is done upon popup close
			layoutHelp.callAppointmentChangedCallback(appointment);
		});

		return endTextField;
	}
	private LocalDateTimeTextField endTextField = null;

	/**
	 * 
	 * @return
	 */
	private CheckBox createWholedayCheckbox() {
		wholedayCheckBox = new CheckBox("Wholeday");
		wholedayCheckBox.setId("wholeday-checkbox");
		wholedayCheckBox.selectedProperty().set(appointment.isWholeDay());

		wholedayCheckBox.selectedProperty().addListener( (observable, oldValue, newValue) ->  {
			appointment.setWholeDay(newValue);
			if (newValue == true) {
				appointment.setEndLocalDateTime(null);
			}
			else {
				LocalDateTime lEndTime = appointment.getStartLocalDateTime().plusMinutes(30);
				appointment.setEndLocalDateTime(lEndTime);
				endTextField.setLocalDateTime(appointment.getEndLocalDateTime());
			}
			endTextField.setVisible(appointment.getEndLocalDateTime() != null);
			// refresh is done upon popup close
			layoutHelp.callAppointmentChangedCallback(appointment);
		});
		
		return wholedayCheckBox;
	}
	private CheckBox wholedayCheckBox = null;

	/**
	 * 
	 * @return
	 */
	private TextField createSummaryTextField() {
		summaryTextField = new TextField();
		summaryTextField.setText(appointment.getSummary());
		summaryTextField.textProperty().addListener( (observable, oldValue, newValue) ->  {
			appointment.setSummary(newValue);
			// refresh is done upon popup close
			layoutHelp.callAppointmentChangedCallback(appointment);
		});
		return summaryTextField;
	}
	private TextField summaryTextField = null;

	/**
	 * 
	 * @return
	 */
	private TextField createLocationTextField() {
		locationTextField = new TextField();
		locationTextField.setText( appointment.getLocation() == null ? "" : appointment.getLocation());
		locationTextField.textProperty().addListener( (observable, oldValue, newValue) ->  {
			appointment.setLocation(newValue);
			// refresh is done upon popup close
			layoutHelp.callAppointmentChangedCallback(appointment);
		});
		return locationTextField;
	}
	private TextField locationTextField = null;

	/**
	 * 
	 * @return
	 */
	private HBox createActions() {
		HBox lHBox = new HBox();
		
		// delete
		{
			deleteImageViewButton = createActionButton("delete-icon", "Delete");
			deleteImageViewButton.setOnMouseClicked( (mouseEvent) -> {
				popup.hide();
				layoutHelp.skinnable.appointments().remove(appointment);
				// refresh is done via the collection events
			});
			lHBox.getChildren().add(deleteImageViewButton);
		}
		
		// action
		if (layoutHelp.skinnable.getActionCallback() != null)
		{
			actionImageViewButton = createActionButton("action-icon", "Action");
			actionImageViewButton.setOnMouseClicked( (mouseEvent) -> {
				popup.hide();
				layoutHelp.skinnable.getActionCallback().call(appointment);
				// any refresh is done via the collection events
			});
			lHBox.getChildren().add(actionImageViewButton);
		}
		
		return lHBox;
	}
	private ImageViewButton deleteImageViewButton = null;
	private ImageViewButton actionImageViewButton = null;

	private ImageViewButton createActionButton(String styleClass, String tooltipText) {
		ImageViewButton lImageViewButton = new ImageViewButton();
		lImageViewButton.getStyleClass().add(styleClass);
		lImageViewButton.setPickOnBounds(true);
		Tooltip.install(lImageViewButton, new Tooltip(tooltipText)); 
		return lImageViewButton;
	}

	/**
	 * 
	 * @return
	 */
	private GridPane createAppointmentGroups() {
		
		// construct a area of appointment groups
		GridPane lAppointmentGroupGridPane = new GridPane();
		lAppointmentGroupGridPane.getStyleClass().add("AppointmentGroups");
		lAppointmentGroupGridPane.setHgap(2);
		lAppointmentGroupGridPane.setVgap(2);
		
		int lCnt = 0;
		for (AppointmentGroup lAppointmentGroup : layoutHelp.skinnable.appointmentGroups())
		{
			// create the appointment group
			final Pane lPane = new Pane();
			lPane.setPrefSize(15, 15);
			lPane.getStyleClass().addAll("AppointmentGroup", lAppointmentGroup.getStyleClass());
			lAppointmentGroupGridPane.add(lPane, lCnt % 10, lCnt / 10 );
			lCnt++;

			// tooltip
			if (lAppointmentGroup.getDescription() != null) {
				Tooltip.install(lPane, new Tooltip(lAppointmentGroup.getDescription()));
			}

			// mouse 
			layoutHelp.setupMouseOverAsBusy(lPane);
			lPane.setOnMouseClicked( (mouseEvent) -> {
				mouseEvent.consume(); // consume before anything else, in case there is a problem in the handling

				// assign appointment group
				appointment.setAppointmentGroup(lAppointmentGroup);

				// refresh is done upon popup close
				layoutHelp.callAppointmentChangedCallback(appointment);
				popup.hide();
			});
		}
		return lAppointmentGroupGridPane;
	}
}




© 2015 - 2024 Weber Informatics LLC | Privacy Policy