summaryrefslogtreecommitdiffstats
path: root/server/src/com/vaadin/ui/CustomLayout.java
diff options
context:
space:
mode:
authorArtur Signell <artur@vaadin.com>2012-08-13 18:34:33 +0300
committerArtur Signell <artur@vaadin.com>2012-08-13 19:18:33 +0300
commite85d933b25cc3c5cc85eb7eb4b13b950fd8e1569 (patch)
tree9ab6f13f7188cab44bbd979b1cf620f15328a03f /server/src/com/vaadin/ui/CustomLayout.java
parent14dd4d0b28c76eb994b181a4570f3adec53342e6 (diff)
downloadvaadin-framework-e85d933b25cc3c5cc85eb7eb4b13b950fd8e1569.tar.gz
vaadin-framework-e85d933b25cc3c5cc85eb7eb4b13b950fd8e1569.zip
Moved server files to a server src folder (#9299)
Diffstat (limited to 'server/src/com/vaadin/ui/CustomLayout.java')
-rw-r--r--server/src/com/vaadin/ui/CustomLayout.java329
1 files changed, 329 insertions, 0 deletions
diff --git a/server/src/com/vaadin/ui/CustomLayout.java b/server/src/com/vaadin/ui/CustomLayout.java
new file mode 100644
index 0000000000..d7830603f0
--- /dev/null
+++ b/server/src/com/vaadin/ui/CustomLayout.java
@@ -0,0 +1,329 @@
+/*
+@VaadinApache2LicenseForJavaFiles@
+ */
+
+package com.vaadin.ui;
+
+import java.io.IOException;
+import java.io.InputStream;
+import java.io.InputStreamReader;
+import java.util.HashMap;
+import java.util.Iterator;
+import java.util.Map;
+import java.util.Set;
+
+import com.vaadin.shared.ui.customlayout.CustomLayoutState;
+import com.vaadin.terminal.PaintException;
+import com.vaadin.terminal.PaintTarget;
+import com.vaadin.terminal.Vaadin6Component;
+import com.vaadin.terminal.gwt.server.JsonPaintTarget;
+
+/**
+ * <p>
+ * A container component with freely designed layout and style. The layout
+ * consists of items with textually represented locations. Each item contains
+ * one sub-component, which can be any Vaadin component, such as a layout. The
+ * adapter and theme are responsible for rendering the layout with a given style
+ * by placing the items in the defined locations.
+ * </p>
+ *
+ * <p>
+ * The placement of the locations is not fixed - different themes can define the
+ * locations in a way that is suitable for them. One typical example would be to
+ * create visual design for a web site as a custom layout: the visual design
+ * would define locations for "menu", "body", and "title", for example. The
+ * layout would then be implemented as an XHTML template for each theme.
+ * </p>
+ *
+ * <p>
+ * The default theme handles the styles that are not defined by drawing the
+ * subcomponents just as in OrderedLayout.
+ * </p>
+ *
+ * @author Vaadin Ltd.
+ * @author Duy B. Vo (<a
+ * href="mailto:devduy@gmail.com?subject=Vaadin">devduy@gmail.com</a>)
+ * @version
+ * @VERSION@
+ * @since 3.0
+ */
+@SuppressWarnings("serial")
+public class CustomLayout extends AbstractLayout implements Vaadin6Component {
+
+ private static final int BUFFER_SIZE = 10000;
+
+ /**
+ * Custom layout slots containing the components.
+ */
+ private final HashMap<String, Component> slots = new HashMap<String, Component>();
+
+ /**
+ * Default constructor only used by subclasses. Subclasses are responsible
+ * for setting the appropriate fields. Either
+ * {@link #setTemplateName(String)}, that makes layout fetch the template
+ * from theme, or {@link #setTemplateContents(String)}.
+ */
+ protected CustomLayout() {
+ setWidth(100, UNITS_PERCENTAGE);
+ }
+
+ /**
+ * Constructs a custom layout with the template given in the stream.
+ *
+ * @param templateStream
+ * Stream containing template data. Must be using UTF-8 encoding.
+ * To use a String as a template use for instance new
+ * ByteArrayInputStream("<template>".getBytes()).
+ * @param streamLength
+ * Length of the templateStream
+ * @throws IOException
+ */
+ public CustomLayout(InputStream templateStream) throws IOException {
+ this();
+ initTemplateContentsFromInputStream(templateStream);
+ }
+
+ /**
+ * Constructor for custom layout with given template name. Template file is
+ * fetched from "<theme>/layout/<templateName>".
+ */
+ public CustomLayout(String template) {
+ this();
+ setTemplateName(template);
+ }
+
+ protected void initTemplateContentsFromInputStream(
+ InputStream templateStream) throws IOException {
+ InputStreamReader reader = new InputStreamReader(templateStream,
+ "UTF-8");
+ StringBuilder b = new StringBuilder(BUFFER_SIZE);
+
+ char[] cbuf = new char[BUFFER_SIZE];
+ int offset = 0;
+
+ while (true) {
+ int nrRead = reader.read(cbuf, offset, BUFFER_SIZE);
+ b.append(cbuf, 0, nrRead);
+ if (nrRead < BUFFER_SIZE) {
+ break;
+ }
+ }
+
+ setTemplateContents(b.toString());
+ }
+
+ @Override
+ public CustomLayoutState getState() {
+ return (CustomLayoutState) super.getState();
+ }
+
+ /**
+ * Adds the component into this container to given location. If the location
+ * is already populated, the old component is removed.
+ *
+ * @param c
+ * the component to be added.
+ * @param location
+ * the location of the component.
+ */
+ public void addComponent(Component c, String location) {
+ final Component old = slots.get(location);
+ if (old != null) {
+ removeComponent(old);
+ }
+ slots.put(location, c);
+ getState().getChildLocations().put(c, location);
+ c.setParent(this);
+ fireComponentAttachEvent(c);
+ requestRepaint();
+ }
+
+ /**
+ * Adds the component into this container. The component is added without
+ * specifying the location (empty string is then used as location). Only one
+ * component can be added to the default "" location and adding more
+ * components into that location overwrites the old components.
+ *
+ * @param c
+ * the component to be added.
+ */
+ @Override
+ public void addComponent(Component c) {
+ this.addComponent(c, "");
+ }
+
+ /**
+ * Removes the component from this container.
+ *
+ * @param c
+ * the component to be removed.
+ */
+ @Override
+ public void removeComponent(Component c) {
+ if (c == null) {
+ return;
+ }
+ slots.values().remove(c);
+ getState().getChildLocations().remove(c);
+ super.removeComponent(c);
+ requestRepaint();
+ }
+
+ /**
+ * Removes the component from this container from given location.
+ *
+ * @param location
+ * the Location identifier of the component.
+ */
+ public void removeComponent(String location) {
+ this.removeComponent(slots.get(location));
+ }
+
+ /**
+ * Gets the component container iterator for going trough all the components
+ * in the container.
+ *
+ * @return the Iterator of the components inside the container.
+ */
+ @Override
+ public Iterator<Component> getComponentIterator() {
+ return slots.values().iterator();
+ }
+
+ /**
+ * Gets the number of contained components. Consistent with the iterator
+ * returned by {@link #getComponentIterator()}.
+ *
+ * @return the number of contained components
+ */
+ @Override
+ public int getComponentCount() {
+ return slots.values().size();
+ }
+
+ /**
+ * Gets the child-component by its location.
+ *
+ * @param location
+ * the name of the location where the requested component
+ * resides.
+ * @return the Component in the given location or null if not found.
+ */
+ public Component getComponent(String location) {
+ return slots.get(location);
+ }
+
+ /* Documented in superclass */
+ @Override
+ public void replaceComponent(Component oldComponent, Component newComponent) {
+
+ // Gets the locations
+ String oldLocation = null;
+ String newLocation = null;
+ for (final Iterator<String> i = slots.keySet().iterator(); i.hasNext();) {
+ final String location = i.next();
+ final Component component = slots.get(location);
+ if (component == oldComponent) {
+ oldLocation = location;
+ }
+ if (component == newComponent) {
+ newLocation = location;
+ }
+ }
+
+ if (oldLocation == null) {
+ addComponent(newComponent);
+ } else if (newLocation == null) {
+ removeComponent(oldLocation);
+ addComponent(newComponent, oldLocation);
+ } else {
+ slots.put(newLocation, oldComponent);
+ slots.put(oldLocation, newComponent);
+ getState().getChildLocations().put(newComponent, oldLocation);
+ getState().getChildLocations().put(oldComponent, newLocation);
+ requestRepaint();
+ }
+ }
+
+ /** Get the name of the template */
+ public String getTemplateName() {
+ return getState().getTemplateName();
+ }
+
+ /** Get the contents of the template */
+ public String getTemplateContents() {
+ return getState().getTemplateContents();
+ }
+
+ /**
+ * Set the name of the template used to draw custom layout.
+ *
+ * With GWT-adapter, the template with name 'templatename' is loaded from
+ * VAADIN/themes/themename/layouts/templatename.html. If the theme has not
+ * been set (with Application.setTheme()), themename is 'default'.
+ *
+ * @param templateName
+ */
+ public void setTemplateName(String templateName) {
+ getState().setTemplateName(templateName);
+ getState().setTemplateContents(null);
+ requestRepaint();
+ }
+
+ /**
+ * Set the contents of the template used to draw the custom layout.
+ *
+ * @param templateContents
+ */
+ public void setTemplateContents(String templateContents) {
+ getState().setTemplateContents(templateContents);
+ getState().setTemplateName(null);
+ requestRepaint();
+ }
+
+ /**
+ * Although most layouts support margins, CustomLayout does not. The
+ * behaviour of this layout is determined almost completely by the actual
+ * template.
+ *
+ * @throws UnsupportedOperationException
+ */
+ @Override
+ public void setMargin(boolean enabled) {
+ throw new UnsupportedOperationException(
+ "CustomLayout does not support margins.");
+ }
+
+ /**
+ * Although most layouts support margins, CustomLayout does not. The
+ * behaviour of this layout is determined almost completely by the actual
+ * template.
+ *
+ * @throws UnsupportedOperationException
+ */
+ @Override
+ public void setMargin(boolean topEnabled, boolean rightEnabled,
+ boolean bottomEnabled, boolean leftEnabled) {
+ throw new UnsupportedOperationException(
+ "CustomLayout does not support margins.");
+ }
+
+ @Override
+ public void changeVariables(Object source, Map<String, Object> variables) {
+ // Nothing to see here
+ }
+
+ @Override
+ public void paintContent(PaintTarget target) throws PaintException {
+ // Workaround to make the CommunicationManager read the template file
+ // and send it to the client
+ String templateName = getState().getTemplateName();
+ if (templateName != null && templateName.length() != 0) {
+ Set<Object> usedResources = ((JsonPaintTarget) target)
+ .getUsedResources();
+ String resourceName = "layouts/" + templateName + ".html";
+ usedResources.add(resourceName);
+ }
+ }
+
+}