/* * *************************************************************************** * * @(#) Copyright (C) Siemens AG 2010-2014 All Rights Reserved Confidential * * *************************************************************************** */ package com.siemens.opal.ui.cep.ctl.orders; import com.siemens.opal.ui.cep.ctl.data.OrdersDS; import com.siemens.opal.ui.i18n.CommonConstants; import com.siemens.opal.ui.i18n.CtlConstants; import com.siemens.opal.ui.i18n.I18NHelper; import com.smartgwt.client.data.DSCallback; import com.smartgwt.client.data.DSRequest; import com.smartgwt.client.data.DSResponse; import com.smartgwt.client.data.DataSource; import com.smartgwt.client.data.Record; import com.smartgwt.client.data.RecordList; import com.smartgwt.client.types.TimeDisplayFormat; import com.smartgwt.client.types.TimeUnit; import com.smartgwt.client.util.BooleanCallback; import com.smartgwt.client.util.DateUtil; import com.smartgwt.client.util.SC; import com.smartgwt.client.widgets.Button; import com.smartgwt.client.widgets.calendar.CalendarEvent; import com.smartgwt.client.widgets.calendar.CalendarView; import com.smartgwt.client.widgets.calendar.CellHoverCustomizer; import com.smartgwt.client.widgets.calendar.EventHoverHTMLCustomizer; import com.smartgwt.client.widgets.calendar.EventWindow; import com.smartgwt.client.widgets.calendar.HeaderLevel; import com.smartgwt.client.widgets.calendar.Lane; import com.smartgwt.client.widgets.calendar.Timeline; import com.smartgwt.client.widgets.calendar.events.EventRepositionStop; import com.smartgwt.client.widgets.calendar.events.EventRepositionStopHandler; import com.smartgwt.client.widgets.calendar.events.EventResizeStop; import com.smartgwt.client.widgets.calendar.events.EventResizeStopHandler; import com.smartgwt.client.widgets.events.ClickEvent; import com.smartgwt.client.widgets.events.ClickHandler; import com.smartgwt.client.widgets.grid.ListGridField; import com.smartgwt.client.widgets.grid.ListGridRecord; import com.smartgwt.client.widgets.layout.HLayout; import com.smartgwt.client.widgets.layout.VLayout; import java.util.ArrayList; import java.util.Date; import java.util.HashMap; import java.util.Iterator; import java.util.List; import java.util.Map; /** * This class hold the timeline component presenting the orders execution. * * @author z0033z0j */ public class OrderSchedulePane extends VLayout { /** * The start date of the timeline. */ private Date minDate = null; /** * The end date of the timeline. */ private Date maxDate = null; /** * The datasource with orders. */ private final DataSource dataSource; /** * The timeline itself. */ private final Timeline timeline; /** * The lanes of the timeline. */ private final Map lanes = new HashMap<>(); /** * the width of the lane titles

* use fixed width of the timeline lane title column, to accommodate fully the * title text */ private static final int TIMELINE_TITLE_WIDTH = 160; /** * The number of columns in the timeline. *

* Each column represents an hour. */ private int columnCount; /** * Well, now. */ private final Date now = new Date(); /** * The number of columns which will be added/removed from the timeline when * zooming in/out.

* Best if this is divisible by 2. */ private static final int ZOOM_RANGE = 6; /** * the language constants. */ private final CtlConstants constants = I18NHelper.getCtlConstants(); private final CommonConstants commonConstants = I18NHelper.getCommonConstants(); /** * Creates an instance of the scheduler pane. Setting up the time line and * fill it with data. * * @param dataSource data source with orders */ public OrderSchedulePane(DataSource dataSource) { this.dataSource = dataSource; columnCount = 24; //HLayout zoomLayout = createZoomLayout(); timeline = createTimeline(); timeline.setDataSource(dataSource); updateData(); addMembers(timeline); //addMembers(zoomLayout, timeline); } /** * Triggers the scheduler pane update its displayed data. */ public final void updateData() { /** * Get all orders first, and create all lanes. */ OrdersDS.getInstance().fetchData(null, new DSCallback() { @Override public void execute(DSResponse dsResponse, Object data, DSRequest dsRequest) { createLanes(dsResponse.getDataAsRecordList()); timeline.invalidateCache(); //Simply fetching the data does not work timeline.fetchData(); //Providing a callback shows that no records are recieved, while there actually are returned by the datasource. // timeline.fetchData(null, new DSCallback() { // // @Override // public void execute(DSResponse dsResponse, Object data, DSRequest dsRequest) { // determineMinMaxDate(); // createIndicator(); // updateResolution(); // // Record[] records = dsResponse.getData(); // SC.logWarn("records.length == " + records.length); // } // }); // This works, but does not provide paging // dataSource.fetchData(null, new DSCallback() { // // @Override // public void execute(DSResponse dsResponse, Object data, DSRequest dsRequest) { // determineMinMaxDate(); // createIndicator(); // updateResolution(); // // timeline.setData(dsResponse.getData()); // } // // }); } }); } /** * Creates and initializes the timeline component. * * @return */ private Timeline createTimeline() { Timeline t = new Timeline(); t.setCanReorderLanes(false); ListGridField laneField = new ListGridField("title", "HiddenTitle"); laneField.setShowTitle(false); laneField.setWidth(TIMELINE_TITLE_WIDTH); t.setLaneFields(laneField); t.setTimeFormatter(TimeDisplayFormat.TO24HOURTIME); t.setShowSnapGrid(false); t.setChildrenSnapToGrid(false); t.setChildrenSnapResizeToGrid(false); t.setWidth100(); t.setHeight100(); t.setAutoFetchData(false); t.setShowControlsBar(true); t.setHideUnusedLanes(false); t.setAllowDurationEvents(false); t.setUseSublanes(true); t.setCanEditLane(false); t.setCanEditSublane(false); t.setCanCreateEvents(false); /** * Editing must be enabled for dragging and resizing to work. */ t.setCanEditEvents(true); t.setCanRemoveEvents(false); t.setDisableWeekends(false); t.setShowEventDescriptions(false); t.setColumnsPerPage(2); t.setLaneEventPadding(0); t.setShowZones(false); t.setShowIndicators(true); t.setEventAutoArrange(false); t.setEventHoverHTMLCustomizer(new EventHoverHTMLCustomizer() { @Override public String getEventHoverHTML(CalendarEvent calendarEvent, EventWindow eventWindow) { return ""; //return buildEventDescription(calendarEvent); //calendarEvent.getDescription(); } }); t.setShowViewHovers(true); t.setShowLaneFieldHovers(true); /** * Show hovers above lane titles. */ t.setCellHoverCustomizer(new CellHoverCustomizer() { @Override public String getHoverHTML(ListGridRecord record, int rowNum, int colNum, Date date, String defaultValue, CalendarView view) { /** * According to the javadoc of Timeline.setShowLaneFieldHovers(), the * date will be null when hovering above the lane titles. */ if (date != null) { return null; } return ""; //return buildLaneDescription(record); } }); t.addEventResizeStopHandler(new EventResizeStopHandler() { @Override public void onEventResizeStop(EventResizeStop event) { //updateOrder(event.getNewEvent()); //cancel the event - update logic will be handled server-side event.cancel(); } }); t.addEventRepositionStopHandler(new EventRepositionStopHandler() { @Override public void onEventRepositionStop(EventRepositionStop event) { //updateOrder(event.getNewEvent()); //cancel the event - update logic will be handled server-side event.cancel(); } }); // set initial resolution HeaderLevel[] headers = new HeaderLevel[]{ new HeaderLevel(TimeUnit.DAY), new HeaderLevel(TimeUnit.HOUR) }; int headerWidth = 60; headers[1].setHeaderWidth(headerWidth); t.setEventSnapGap(2); t.setResolution(headers, TimeUnit.HOUR, columnCount); return t; } /** * This method re-creates the lanes on an update of the data. * * @param recordList order records which make up the lanes. */ private void createLanes(RecordList recordList) { minDate = null; maxDate = null; // clear old content first removeAllLanes(); Lane[] laneArray = new Lane[recordList.getLength()]; // create lanes for (int i = 0; i < recordList.getLength(); i++) { Record record = recordList.get(i); Lane lane = getOrCreateLane(record.getAttributeAsInt("id"), record.getAttribute("name"), record.getAttribute("state")); laneArray[i] = lane; // we also do an update on min and max date here to avoid looping a second time. updateMinAndMaxDate(record.getAttributeAsDate("plannedStart")); updateMinAndMaxDate(record.getAttributeAsDate("plannedEnd")); updateMinAndMaxDate(record.getAttributeAsDate("actualStart")); updateMinAndMaxDate(record.getAttributeAsDate("actualEnd")); } timeline.setLanes(laneArray); } /** * Set the indicator for the current point in time. */ private void createIndicator() { CalendarEvent indicator = new CalendarEvent(-1, DateUtil.TOSHORT24HOURTIME.format(now), "", now, null); indicator.setStyleName("indicatorRed"); //The canDrag is enabled just because otherwise the gripper is not shown. indicator.setCanDrag(true); timeline.setIndicators(indicator); } /** * Updates the resoultion of the timeline. */ private void updateResolution() { columnCount = (int) ((maxDate.getTime() - minDate.getTime()) / 1000 / 60 / 60); int fourDays = 4 * 24; if (columnCount > fourDays) { //Do not make the timeline bigger than 4 days columnCount = fourDays; } timeline.setResolution(timeline.getHeaderLevels(), TimeUnit.HOUR, columnCount); } /** * Set the timeline zoom level. * * @param offset zooming offset. */ private void timelineZoom(int offset) { int tmpColCount = columnCount + offset; if (tmpColCount > 24 * 4 || tmpColCount < 24 / 2) { return; } this.columnCount = tmpColCount; timeline.setResolution(timeline.getHeaderLevels(), TimeUnit.HOUR, columnCount); long halfRange = (offset / 2) * 60L * 60L * 1000L; Date lastChosenDate = timeline.getChosenDate(); Date chosenDate = new Date(lastChosenDate.getTime() - halfRange); timeline.setChosenDate(chosenDate); timeline.redraw(); } /** * determine min and max date. */ private void determineMinMaxDate() { minDate = minDate == null ? new Date() : minDate; long fourteenDays = 14 * 24 * 60 * 60 * 1000L; maxDate = maxDate == null ? new Date(minDate.getTime() + fourteenDays) : maxDate; //TODO: Cannot change configuration property 'startDate' to Mon Sep 15 07:00:00 GMT+200 2014 now that component isc_Timeline_0 has been created. timeline.setStartDate(minDate); timeline.setEndDate(maxDate); timeline.setChosenDate(minDate); } /** * Updates (or not) the min and max date by comparing it to provided date. * * @param date date to compare with. */ private void updateMinAndMaxDate(Date date) { // Don't update on a null date if (date == null) { return; } if (minDate == null) { minDate = date; } else { minDate = (date.before(minDate)) ? date : minDate; } if (maxDate == null) { maxDate = date; } else { maxDate = (date.after(maxDate)) ? date : maxDate; } } private Lane getOrCreateLane(int orderID, String orderName, String orderState) { String laneName = orderID + " - " + orderName + " - " + orderState; Lane lane = lanes.get(laneName); if (lane == null) { lane = createLane(orderName, laneName, 50); lanes.put(laneName, lane); } return lane; } private Lane createLane(String name, String title, Integer height) { ArrayList sublanes = new ArrayList<>(); sublanes.add(createSubLane("1", 6)); sublanes.add(createSubLane("planned", 16)); sublanes.add(createSubLane("2", 6)); sublanes.add(createSubLane("actual", 16)); sublanes.add(createSubLane("3", 6)); Lane lane = new Lane(name, title); lane.setHeight(height); lane.setSublanes(sublanes.toArray(new Lane[sublanes.size()])); return lane; } private Lane createSubLane(String name, int height) { final Lane lane = new Lane(name, name); lane.setHeight(height); return lane; } private void removeAllLanes() { // for (Lane lane : timeline.getLanes()) { // timeline.removeLane(lane.getName()); // } lanes.clear(); } }