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

org.icefaces.ace.component.dashboard.DashboardRenderer Maven / Gradle / Ivy

The newest version!
/*
 * Copyright 2004-2014 ICEsoft Technologies Canada Corp.
 *
 * 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 org.icefaces.ace.component.dashboard;

import java.io.IOException;

import javax.faces.component.UIComponent;
import javax.faces.context.FacesContext;
import javax.faces.context.ResponseWriter;
import javax.faces.FacesException;

import org.icefaces.ace.json.*;
import org.icefaces.ace.renderkit.CoreRenderer;
import org.icefaces.ace.util.JSONBuilder;
import org.icefaces.render.MandatoryResourceComponent;
import org.icefaces.ace.util.ComponentUtils;
import org.icefaces.impl.util.CoreUtils;

import java.util.ArrayList;
import java.util.Iterator;
import java.util.List;
import java.util.Map;

import java.util.Locale;
import java.util.ResourceBundle;

@MandatoryResourceComponent(tagName="dashboard", value="org.icefaces.ace.component.dashboard.Dashboard")
public class DashboardRenderer extends CoreRenderer {

    @Override
    public void decode(FacesContext context, UIComponent component) {
		Map requestParameterMap = context.getExternalContext().getRequestParameterMap();
		Dashboard dashboard = (Dashboard) component;
		String clientId = component.getClientId();

		// update all sizes and positions of all child dashboard panes
		if (requestParameterMap.containsKey(clientId + "_state")) {
			String raw = requestParameterMap.get(clientId + "_state");
			dashboard.submittedState = raw; // save state for comparison during the render phase
			try {
				JSONArray array = new JSONArray(raw);
				int length = array.length();
				for (int i = 0; i < length; i++) {
					JSONObject pane = array.getJSONObject(i);
					String paneClientId = pane.getString("paneId");
					UIComponent c = CoreUtils.findComponentByClientId(context.getViewRoot(), paneClientId);
					if (c instanceof DashboardPane) {
						DashboardPane dashboardPane = (DashboardPane) c;
						dashboardPane.setOldSizeX(dashboardPane.getSizeX());
						dashboardPane.setSizeX(pane.getInt("sizeX"));
						dashboardPane.setOldSizeY(dashboardPane.getSizeY());
						dashboardPane.setSizeY(pane.getInt("sizeY"));
						dashboardPane.setOldRow(dashboardPane.getRow());
						dashboardPane.setRow(pane.getInt("row"));
						dashboardPane.setOldColumn(dashboardPane.getColumn());
						dashboardPane.setColumn(pane.getInt("column"));
					}
				}
			} catch (JSONException e) {

			}
		}
    }

    @Override
    public void encodeBegin(FacesContext context, UIComponent component) throws IOException {
        ResponseWriter writer = context.getResponseWriter();
        Dashboard dashboard = (Dashboard) component;
        String clientId = dashboard.getClientId(context);

        writer.startElement("div", component);
        writer.writeAttribute("id", clientId, null);
        ComponentUtils.enableOnElementUpdateNotify(writer, clientId);

		String baseClass = "ice-ace-dashboard";
		String styleClass = dashboard.getStyleClass();
        if (styleClass != null) {
            baseClass += " " + styleClass;
        }
        writer.writeAttribute("class", baseClass, null);
	}

    @Override
    public void encodeEnd(FacesContext context, UIComponent component) throws IOException {
        ResponseWriter writer = context.getResponseWriter();
        Dashboard dashboard = (Dashboard) component;

		// we use a separate script for the size and position data to avoid reinitializing the component
		// every time the state is updated in the server
		encodeSizeAndPositionData(context, dashboard);

		encodeScript(context, dashboard);

        writer.endElement("div");
    }

    protected void encodeSizeAndPositionData(FacesContext context, Dashboard dashboard) throws IOException {
        ResponseWriter writer = context.getResponseWriter();
        String clientId = dashboard.getClientId(context);

        writer.startElement("span", null);
        writer.writeAttribute("id", clientId + "_sizeAndPositionData", null);

		writer.startElement("script", null);
		writer.writeAttribute("type", "text/javascript", null);

		JSONBuilder jb = JSONBuilder.create();

		List positions = createPositionsList(dashboard);

		jb.beginArray();

		int maxColumns = dashboard.getMaxColumns();
		maxColumns = maxColumns < 1 || maxColumns > 100 ? 100 : maxColumns;
		List children = dashboard.getChildren();
		// render panes' settings in the order they appear
		for (int i = 0; i < children.size(); i++) {
			UIComponent child = children.get(i);
			if (child instanceof DashboardPane) {
				DashboardPane pane = (DashboardPane) child;
				if (!pane.isRendered() || pane.isClosed()) continue;
				int row = pane.getRow();
				int column = pane.getColumn();
				int sizeX = pane.getSizeX();

				// if not explicitly set, assign row and column position to pane
				if (!(row > 0 && column > 0 && column + sizeX - 1 <= maxColumns)) {
					assignPosition(pane, positions, maxColumns);
				}

				// render pane's size and position settings
				jb.beginMap();
				jb.entry("paneId", pane.getClientId(context));
				jb.entry("sizeX", "" + pane.getSizeX());
				jb.entry("sizeY", "" + pane.getSizeY());
				jb.entry("row", "" + pane.getRow());
				jb.entry("column", "" + pane.getColumn());
				jb.endMap();
			}
		}

		jb.endArray();

		String state = jb.toString();
		state = state.replace('\'','\"');

		writer.write("ice.ace.Dashboard.data['"+clientId+"'] = " + state + ";");

        writer.endElement("script");

        writer.startElement("input", null);
        writer.writeAttribute("type", "hidden", null);
        writer.writeAttribute("id", clientId + "_state", null);
        writer.writeAttribute("name", clientId + "_state", null);
        writer.writeAttribute("value", state, null);
        writer.endElement("input");

        writer.endElement("span");

		dashboard.generatedState = state;
	}

    protected List createPositionsList(Dashboard dashboard) {
		List positions = new ArrayList();

		int maxColumns = dashboard.getMaxColumns();
		maxColumns = maxColumns < 1 || maxColumns > 100 ? 100 : maxColumns;
		List children = dashboard.getChildren();
		for (int i = 0; i < children.size(); i++) {
			UIComponent child = children.get(i);
			if (child instanceof DashboardPane) {
				DashboardPane pane = (DashboardPane) child;
				if (!pane.isRendered() || pane.isClosed()) continue;
				int row = pane.getRow();
				int column = pane.getColumn();
				int sizeY = pane.getSizeY();
				int sizeX = pane.getSizeX();
				if (sizeY < 1) sizeY = 1;
				if (sizeX < 1) sizeX = 1;
				if (row > 0 && column > 0 && column + sizeX - 1 <= maxColumns) {
					int size = positions.size();
					if (row + sizeY - 1 > size) {
						for (int j = 0; j < (row + sizeY - 1 - size); j++) {
							positions.add(new boolean[maxColumns]);
						}
					}
					int rowIndex = row - 1;
					for (int j = 0; j < sizeY; j++) {
						boolean[] rowArray = positions.get(rowIndex);
						int columnIndex = column - 1;
						for (int k = 0; k < sizeX; k++) {
							rowArray[columnIndex] = true;
							columnIndex++;
						}
						rowIndex++;
					}
				}
			}
		}

		return positions;
	}

	protected void assignPosition(DashboardPane pane, List positions, int maxColumns) {

		int sizeY = pane.getSizeY();
		int sizeX = pane.getSizeX();
		if (sizeY < 1) sizeY = 1;
		if (sizeX < 1) sizeX = 1;

		// make sure no pane takes more columns than the maximum allowed
		sizeX = sizeX > maxColumns ? maxColumns : sizeX;

		// if no rows yet, add one
		if (positions.size() == 0) {
			positions.add(new boolean[maxColumns]);
		}

		boolean assigned = false;
		for (int i = 0; i < positions.size(); i++) {

			// make sure there are enough rows in the position list to fit this pane
			// add enough rows to fit the size of this pane
			// add +1 more in case it doesn't fit at this row, so we can try the next row at the next iteration
			while (positions.size() < i + sizeY + 1) {
				positions.add(new boolean[maxColumns]);
			}

			boolean[] row = positions.get(i);
			for (int j = 0; j < maxColumns; j++) {
				// won't fit in this row due to horizontal size
				if (j + sizeX > maxColumns) {
					break;
				}

				// check if there's enough space for this pane starting at (i,j)
				if (row[j] == false) {

					boolean fits = true;
					for (int k = 0; k < sizeY; k++) {
						boolean[] sizeRow = positions.get(i + k);
						for (int l = 0; l < sizeX; l++) {
							if (sizeRow[j + l] == true) {
								fits = false;
								break;
							}
						}
						if (!fits) break;
					}

					if (fits) {
						// mark occupied spaces in the positions list
						for (int k = 0; k < sizeY; k++) {
							boolean[] sizeRow = positions.get(i + k);
							for (int l = 0; l < sizeX; l++) {
								sizeRow[j + l] = true;
							}
						}

						// assign row and column positions to pane
						pane.setRow(i+1);
						pane.setColumn(j+1);

						// signal that we've assigned a suitable position and exit algorithm
						assigned = true;
						break;
					}
				}
			}
			if (assigned) break;
		}
	}

    protected void encodeScript(FacesContext context, Dashboard dashboard) throws IOException {
        ResponseWriter writer = context.getResponseWriter();
        String clientId = dashboard.getClientId(context);

		Locale locale = context.getViewRoot().getLocale();
		String bundleName = context.getApplication().getMessageBundle();
		ClassLoader classLoader = Thread.currentThread().getContextClassLoader();
		if (bundleName == null) bundleName = "org.icefaces.ace.resources.messages";
		if (classLoader == null) classLoader = bundleName.getClass().getClassLoader();
		ResourceBundle bundle = ResourceBundle.getBundle(bundleName, locale, classLoader);
		final String MESSAGES_PREFIX = "org.icefaces.ace.component.dashboard.";

        writer.startElement("span", null);
        writer.writeAttribute("id", clientId + "_script", null);

        writer.startElement("script", null);
        writer.writeAttribute("type", "text/javascript", null);

        JSONBuilder jb = JSONBuilder.create();
        jb.beginFunction("ice.ace.create")
			.item("Dashboard")
			.beginArray()
			.item(clientId)
			.beginMap();

				jb.entry("resizable", dashboard.isResizable())
				.entry("paneWidth", dashboard.getPaneWidth())
				.entry("paneHeight", dashboard.getPaneHeight())
				.entry("marginX", dashboard.getMarginX())
				.entry("marginY", dashboard.getMarginY())
				.entry("maxColumns", dashboard.getMaxColumns())
				.entry("closeTitle", bundle.getString(MESSAGES_PREFIX + "closeTitle"));

/*
			String style = dashboard.getStyle();
			if (style != null) {
				jb.entry("style", style);
			}
*/

			// --- encode panes' settings ---
			jb.beginMap("panes");
			for (UIComponent child : dashboard.getChildren()) {
				if (child.isRendered() && child instanceof DashboardPane) {
					DashboardPane pane = (DashboardPane) child;
					if (pane.isClosed()) continue;

					jb.beginMap(pane.getClientId(context));

						encodeClientBehaviors(context, pane, jb);

					jb.endMap();
				}
			}
			jb.endMap();

        jb.endMap().endArray();
		jb.endFunction();

		writer.write(jb.toString());

		// compare the generated state to the submitted state, if available
		// if there are changes (made porgrammatically), re-initialize the component
		if (dashboard.submittedState != null) {
			if (!dashboard.submittedState.equals(dashboard.generatedState)) {
				dashboard.setLastRefresh(System.currentTimeMillis());
			}
		}
		writer.write(" // " + dashboard.getLastRefresh());

        writer.endElement("script");
        writer.endElement("span");

		// draggable script
        writer.startElement("span", null);
        writer.writeAttribute("id", clientId + "_draggableScript", null);
        writer.startElement("script", null);
        writer.writeAttribute("type", "text/javascript", null);
		if (dashboard.isDraggable())
			writer.write("(function(){ ice.ace.instance('"+clientId+"').enableDragging(); })();");
		else
			writer.write("(function(){ ice.ace.instance('"+clientId+"').disableDragging(); })();");
        writer.endElement("script");
        writer.endElement("span");
    }
}




© 2015 - 2024 Weber Informatics LLC | Privacy Policy