/* * Copyright 2000-2018 Vaadin Ltd. * * 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.vaadin.ui; import java.util.Collections; import java.util.Iterator; import java.util.LinkedList; import org.jsoup.nodes.Element; import com.vaadin.event.LayoutEvents.LayoutClickEvent; import com.vaadin.event.LayoutEvents.LayoutClickListener; import com.vaadin.event.LayoutEvents.LayoutClickNotifier; import com.vaadin.shared.Connector; import com.vaadin.shared.EventId; import com.vaadin.shared.MouseEventDetails; import com.vaadin.shared.Registration; import com.vaadin.shared.ui.csslayout.CssLayoutServerRpc; import com.vaadin.shared.ui.csslayout.CssLayoutState; import com.vaadin.ui.declarative.DesignContext; /** * CssLayout is a layout component that can be used in browser environment only. * It simply renders components and their captions into a same div element. * Component layout can then be adjusted with css. *
* In comparison to {@link HorizontalLayout} and {@link VerticalLayout} *
* With {@link CustomLayout} one can often achieve similar results (good looking * layouts with web technologies), but with CustomLayout developer needs to work * with fixed templates. *
* By extending CssLayout one can also inject some css rules straight to child * components using {@link #getCss(Component)}. * *
* (*) Relative sizes (set from server side) are treated bit differently than in * other layouts in Vaadin. In cssLayout the size is calculated relatively to * CSS layouts content area which is pretty much as in html and css. In other * layouts the size of component is calculated relatively to the "slot" given by * layout. *
* Also note that client side framework in Vaadin modifies inline style
* properties width and height. This happens on each update to component. If one
* wants to set component sizes with CSS, component must have undefined size on
* server side (which is not the default for all components) and the size must
* be defined with class styles - not by directly injecting width and height.
*
* @since 6.1 brought in from "FastLayouts" incubator project
*
*/
public class CssLayout extends AbstractLayout implements LayoutClickNotifier {
private CssLayoutServerRpc rpc = (MouseEventDetails mouseDetails,
Connector clickedConnector) -> fireEvent(
LayoutClickEvent.createEvent(CssLayout.this, mouseDetails,
clickedConnector));
/**
* Custom layout slots containing the components.
*/
protected LinkedList
* Note that styles are injected over previous styles before actual child
* rendering. Previous styles are not cleared, but overridden.
*
*
* Note that one most often achieves better code style, by separating
* styling to theme (with custom theme and {@link #addStyleName(String)}.
* With own custom styles it is also very easy to break browser
* compatibility.
*
* @param c
* the component
* @return css rules to be applied to component
*/
protected String getCss(Component c) {
return null;
}
/* Documented in superclass */
@Override
public void replaceComponent(Component oldComponent,
Component newComponent) {
// Gets the locations
int oldLocation = -1;
int newLocation = -1;
int location = 0;
for (final Component component : components) {
if (component == oldComponent) {
oldLocation = location;
}
if (component == newComponent) {
newLocation = location;
}
location++;
}
if (oldLocation == -1) {
addComponent(newComponent);
} else if (newLocation == -1) {
removeComponent(oldComponent);
addComponent(newComponent, oldLocation);
} else {
if (oldLocation > newLocation) {
components.remove(oldComponent);
components.add(newLocation, oldComponent);
components.remove(newComponent);
components.add(oldLocation, newComponent);
} else {
components.remove(newComponent);
components.add(oldLocation, newComponent);
components.remove(oldComponent);
components.add(newLocation, oldComponent);
}
markAsDirty();
}
}
@Override
public Registration addLayoutClickListener(LayoutClickListener listener) {
return addListener(EventId.LAYOUT_CLICK_EVENT_IDENTIFIER,
LayoutClickEvent.class, listener,
LayoutClickListener.clickMethod);
}
@Override
@Deprecated
public void removeLayoutClickListener(LayoutClickListener listener) {
removeListener(EventId.LAYOUT_CLICK_EVENT_IDENTIFIER,
LayoutClickEvent.class, listener);
}
/**
* Returns the index of the given component.
*
* @param component
* The component to look up.
* @return The index of the component or -1 if the component is not a child.
*/
public int getComponentIndex(Component component) {
return components.indexOf(component);
}
/**
* Returns the component at the given position.
*
* @param index
* The position of the component.
* @return The component at the given index.
* @throws IndexOutOfBoundsException
* If the index is out of range.
*/
public Component getComponent(int index) throws IndexOutOfBoundsException {
return components.get(index);
}
/*
* (non-Javadoc)
*
* @see com.vaadin.ui.AbstractComponent#readDesign(org.jsoup.nodes .Element,
* com.vaadin.ui.declarative.DesignContext)
*/
@Override
public void readDesign(Element design, DesignContext designContext) {
// process default attributes
super.readDesign(design, designContext);
// handle children
for (Element childComponent : design.children()) {
Component newChild = designContext.readDesign(childComponent);
addComponent(newChild);
}
}
/*
* (non-Javadoc)
*
* @see com.vaadin.ui.AbstractComponent#writeDesign(org.jsoup.nodes.Element
* , com.vaadin.ui.declarative.DesignContext)
*/
@Override
public void writeDesign(Element design, DesignContext designContext) {
// write default attributes
super.writeDesign(design, designContext);
CssLayout def = designContext.getDefaultInstance(this);
// handle children
if (!designContext.shouldWriteChildren(this, def)) {
return;
}
Element designElement = design;
for (Component child : this) {
Element childNode = designContext.createElement(child);
designElement.appendChild(childNode);
}
}
}