diff --git a/Jenkinsfile b/Jenkinsfile new file mode 100644 index 0000000..3bae475 --- /dev/null +++ b/Jenkinsfile @@ -0,0 +1,37 @@ +pipeline { + environment { + JAVA_TOOL_OPTIONS = '-Duser.home=/var/jenkins_home' + } + agent { + docker { + image 'maven:3.6.1-jdk-8-alpine' + args '-e MAVEN_CONFIG=/var/jenkins_home/.m2' + } + } + stages { + stage('Preparation') { + steps { + git url: 'https://github.com/rlsutton1/GridStack.git', credentialsId: 'bitbucket' + } + } + stage('Build') { + steps { + sh 'mvn -B -Dmaven.test.skip=true -DskipTests -f gridstack-addon/pom.xml clean package' + } + } + stage('Deliver') { + steps { + sh 'mvn jar:jar install:install help:evaluate -Dexpression=project.name -f gridstack-addon/pom.xml' + } + } + } + post { + always { + emailext attachLog: true, + to: '$DEFAULT_RECIPIENTS', + subject: '$DEFAULT_SUBJECT', + body: '$DEFAULT_CONTENT' + } + } +} + diff --git a/gridstack-addon/pom.xml b/gridstack-addon/pom.xml index 4e68e70..a37ceb3 100644 --- a/gridstack-addon/pom.xml +++ b/gridstack-addon/pom.xml @@ -5,7 +5,7 @@ org.vaadin.alump.gridstack gridstack-addon bundle - 0.3.1-SNAPSHOT + 0.3.1-nj GridStack Add-on diff --git a/gridstack-addon/src/main/java/org/vaadin/alump/gridstack/GridStackLayout.java b/gridstack-addon/src/main/java/org/vaadin/alump/gridstack/GridStackLayout.java index 843d7e6..87d4f1e 100644 --- a/gridstack-addon/src/main/java/org/vaadin/alump/gridstack/GridStackLayout.java +++ b/gridstack-addon/src/main/java/org/vaadin/alump/gridstack/GridStackLayout.java @@ -18,18 +18,6 @@ package org.vaadin.alump.gridstack; import com.vaadin.annotations.JavaScript; -import com.vaadin.event.LayoutEvents; -import com.vaadin.shared.Connector; -import com.vaadin.shared.EventId; -import com.vaadin.shared.MouseEventDetails; -import com.vaadin.ui.AbstractLayout; -import com.vaadin.ui.Component; -import org.vaadin.alump.gridstack.client.shared.*; - -import java.util.ArrayList; -import java.util.Collection; -import java.util.Iterator; -import java.util.List; /** * Vaadin layout using gridstack.js library to layout components @@ -37,623 +25,18 @@ * gridstack.js by Pavel Reznikov: http://troolee.github.io/gridstack.js/ */ @JavaScript({"jquery-1.11.3.min.js", "jquery-ui.min.js", "lodash.min.js", "gridstack.js"}) -public class GridStackLayout extends AbstractLayout implements LayoutEvents.LayoutClickNotifier { - - protected final List components = new ArrayList(); - - private boolean initialClientResponseSent = false; - - private final List moveListeners = new ArrayList(); - - /** - * Use this as x or y coordinate if you want to leave slot selection of component to client side - */ - public final static int CLIENT_SIDE_SELECTS = -1; - - private GridStackServerRpc serverRpc = new GridStackServerRpc() { - - @Override - public void layoutClick(MouseEventDetails mouseEventDetails, Connector connector) { - fireEvent(LayoutEvents.LayoutClickEvent.createEvent(GridStackLayout.this, - mouseEventDetails, connector)); - } - - @Override - public void onChildrenMoved(List moves) { - Collection events = new ArrayList(); - for(GridStackMoveData move : moves) { - Component childComponent = (Component)move.child; - GridStackCoordinates oldCoordinates = getCoordinates(childComponent); - - GridStackChildOptions info = getState(false).childOptions.get(move.child); - info.x = move.x; - info.y = move.y; - info.width = move.width; - info.height = move.height; - - if(!oldCoordinates.equals(getCoordinates(childComponent))) { - events.add(createMoveEvent(childComponent, oldCoordinates)); - } - } - fireMoveEvents(events); - } - }; - - /** - * Creates GridStackLayout with default 3 columns - */ - public GridStackLayout() { - super(); - registerRpc(serverRpc, GridStackServerRpc.class); - } - - /** - * Create GridStackLayout with defined column count. - * @param columns Number of columns, if more than 8 see documentation (extra SCSS including required) - */ - public GridStackLayout(int columns) { - this(); - if(columns <= 0) { - throw new IllegalArgumentException("Amount of columns can not be 0 or negative"); - } - addStyleName("with-" + columns + "-columns"); - getState().gridStackOptions.width = columns; - } - - /** - * Create GridStackLayout with defined column and row count. - * @param columns Number of columns, if more than 8 see documentation (extra SCSS including required) - * @param rows Maxium amount of rows allowed - */ - public GridStackLayout(int columns, int rows) { - this(columns); - if(rows <= 0) { - throw new IllegalArgumentException("Amount of rows can not be 0 or negative"); - } - getState().gridStackOptions.height = rows; - } - - @Override - public void beforeClientResponse(boolean initial) { - super.beforeClientResponse(initial); - initialClientResponseSent = true; - } - - - @Override - protected GridStackLayoutState getState() { - return (GridStackLayoutState)super.getState(); - } - - @Override - protected GridStackLayoutState getState(boolean markDirty) { - return (GridStackLayoutState)super.getState(markDirty); - } - - /** - * {@inheritDoc} - */ - @Override - public void addComponent(Component component) { - addComponent(component, CLIENT_SIDE_SELECTS, CLIENT_SIDE_SELECTS); - } - - /** - * Add component to layout - * @param component Component added - * @param useDragHandle true to add component with a separate drag handle, or false to make whole content act as a - * drag handle. Notice that using a separate drag handle is recommended if you component - * is or contains any active components (buttons etc..) - */ - public void addComponent(Component component, boolean useDragHandle) { - addComponent(component, CLIENT_SIDE_SELECTS, CLIENT_SIDE_SELECTS, useDragHandle); - } - - /** - * Add component to given slot - * @param component Component added - * @param x Slot's X coordinate - * @param y Slot's Y coordinate - */ - public void addComponent(Component component, int x, int y) { - addComponent(component, x, y, 1, 1); - } - - /** - * Add component to given slot - * @param component Component added - * @param x Slot's X coordinate - * @param y Slot's Y coordinate - * @param useDragHandle true to add component with a separate drag handle, or false to make whole content act as a - * drag handle. Notice that using a separate drag handle is recommended if you component - * is or contains any active components (buttons etc..) - */ - public void addComponent(Component component, int x, int y, boolean useDragHandle) { - addComponent(component, x, y, 1, 1, useDragHandle); - } - - /** - * Add component to given slot, and define it's size - * @param component Component added - * @param x Slot's X coordinate (use negative values if position can be defined on client side) - * @param y Slot's Y coordinate (use negative values if position can be defined on client side) - * @param width Width of space reserved (in slots) - * @param height Height of space reserved (in slots) - */ - public void addComponent(Component component, int x, int y, int width, int height) { - addComponent(component, x, y, width, height, true); - } - - /** - * Add component to given slot, and define it's size - * @param component Component added - * @param x Slot's X coordinate (use negative values if position can be defined on client side) - * @param y Slot's Y coordinate (use negative values if position can be defined on client side) - * @param width Width of space reserved (in slots) - * @param height Height of space reserved (in slots) - * @param useDragHandle true to add component with a separate drag handle, or false to make whole content act as a - * drag handle. Notice that using a separate drag handle is recommended if you component - * is or contains any active components (buttons etc..) - */ - public void addComponent(Component component, int x, int y, int width, int height, boolean useDragHandle) { - super.addComponent(component); - components.add(component); - - GridStackChildOptions info = new GridStackChildOptions(); - info.x = x; - info.y = y; - info.width = width; - info.height = height; - info.useDragHandle = useDragHandle; - getState().childOptions.put(component, info); - } - - /** - * Reset component's position and allow child side define new position for it. - * @param component Child component which position is reset - */ - public void resetComponentPosition(Component component) { - moveComponent(component, CLIENT_SIDE_SELECTS, CLIENT_SIDE_SELECTS); - } - - /** - * Move given child component - * @param component Child component moved and/or resized - * @param x When defined component's X value is updated, if null old value is kept - * @param y When defined component's Y value is updated, if null old value is kept - * @throws IllegalArgumentException If given value are invalid (eg. component is not child of this layout) - */ - public void moveComponent(Component component, Integer x, Integer y) throws IllegalArgumentException { - moveAndResizeComponent(component, x, y, null, null); - } - - /** - * Move given child component - * @param component Child component moved and/or resized - * @param width When defined component's width is updated, if null old value is kept - * @param height When defined component's height is updated, if null old value is kept - * @throws IllegalArgumentException If given value are invalid (eg. component is not child of this layout) - */ - public void resizeComponent(Component component, Integer width, Integer height) throws IllegalArgumentException { - moveAndResizeComponent(component, null, null, width, height); - } - - /** - * Move and/or resize given child component - * @param component Child component moved and/or resized - * @param x When defined component's X value is updated, if null old value is kept - * @param y When defined component's Y value is updated, if null old value is kept - * @param width When defined component's width is updated, if null old value is kept - * @param height When defined component's height is updated, if null old value is kept - * @throws IllegalArgumentException If given value are invalid (eg. component is not child of this layout, or - * coordinates are invalid). - */ - public void moveAndResizeComponent(Component component, Integer x, Integer y, Integer width, Integer height) - throws IllegalArgumentException { - - if(x != null & width != null && x >= 0 && x + width > getState(false).gridStackOptions.width) { - throw new IllegalArgumentException("Component would go outside the right edge of layout"); - } - - GridStackChildOptions info = getState().childOptions.get(component); - if(info == null) { - throw new IllegalArgumentException("Given component is not child of GridStackLayout"); - } - if(x != null) { - info.x = x; - } - if(y != null) { - info.y = y; - } - if(width != null) { - info.width = width; - } - if(height != null) { - info.height = height; - } - } - - /** - * Get component with given slot coordinate - * @param x Slot's X coordinate - * @param y Slot's Y coordinate - * @return Component at slot, or null if component not found - */ - public Component getComponent(int x, int y) { - return getComponent(x, y, false); - } - - /** - * Get component with given slot coordinate - * @param x Slot's X coordinate - * @param y Slot's Y coordinate - * @param acceptInsideHit If true also other slots reserved by component are accepted - * @return Component at slot, or null if component not found - */ - public Component getComponent(int x, int y, boolean acceptInsideHit) { - for(Connector connector : getState().childOptions.keySet()) { - GridStackChildOptions info = getState().childOptions.get(connector); - if(acceptInsideHit) { - if(x >= info.x && x < (info.x + info.width) && y >= info.y && y < (info.y + info.width)) { - return (Component) connector; - } - } else { - if (info.x == x && info.y == y) { - return (Component) connector; - } - } - } - return null; - } - - /** - * {@inheritDoc} - */ - @Override - public void removeComponent(Component component) { - getState().childOptions.remove(component); - components.remove(component); - super.removeComponent(component); - } - - @Override - public void replaceComponent(Component oldComponent, Component newComponent) { - if(oldComponent == newComponent) { - return; - } - if(oldComponent.getParent() != this) { - throw new IllegalArgumentException("Replacable component not child of this layout"); - } - GridStackChildOptions oldOptions = getState(false).childOptions.get(oldComponent); - removeComponent(oldComponent); - - if(newComponent.getParent() == this) { - removeComponent(newComponent); - } - addComponent(newComponent, oldOptions.x, oldOptions.y, oldOptions.width, oldOptions.height); - } - - /** - * {@inheritDoc} - */ - @Override - public int getComponentCount() { - return components.size(); - } - - /** - * {@inheritDoc} - */ - @Override - public Iterator iterator() { - return components.iterator(); - } - - /** - * {@inheritDoc} - */ - @Override - public void addLayoutClickListener(LayoutEvents.LayoutClickListener listener) { - addListener(EventId.LAYOUT_CLICK_EVENT_IDENTIFIER, - LayoutEvents.LayoutClickEvent.class, listener, - LayoutEvents.LayoutClickListener.clickMethod); - } - - @Override - @Deprecated - public void addListener(LayoutEvents.LayoutClickListener layoutClickListener) { - addLayoutClickListener(layoutClickListener); - } - - /** - * {@inheritDoc} - */ - @Override - public void removeLayoutClickListener(LayoutEvents.LayoutClickListener listener) { - removeListener(EventId.LAYOUT_CLICK_EVENT_IDENTIFIER, - LayoutEvents.LayoutClickEvent.class, listener); - } - - @Override - @Deprecated - public void removeListener(LayoutEvents.LayoutClickListener layoutClickListener) { - removeLayoutClickListener(layoutClickListener); - } - - /** - * Add listener for component move events - * @param listener Listener added - */ - public void addGridStackMoveListener(GridStackMoveEvent.GridStackMoveListener listener) { - moveListeners.add(listener); - } - - /** - * Remove listener of component move events - * @param listener Listener removed - */ - public void removeGridStackMoveListener(GridStackMoveEvent.GridStackMoveListener listener) { - moveListeners.remove(listener); - } - - /** - * Get coordinates (X,Y,width,height) of component - * @param child Child component of layout - * @return Coordinates (X,Y,width,height) of component - * @throws IllegalArgumentException If child not found - */ - public GridStackCoordinates getCoordinates(Component child) { - GridStackChildOptions opts = getComponentOptions(child, false); - return new GridStackCoordinates(opts.x, opts.y, opts.width, opts.height); - } - - protected GridStackMoveEvent createMoveEvent(Component component, GridStackCoordinates oldCoordinates) { - return new GridStackMoveEvent(this, component, oldCoordinates, - getCoordinates(component)); - } - - protected void fireMoveEvents(Collection events) { - if(events.isEmpty()) { - return; - } - - for(GridStackMoveEvent.GridStackMoveListener listener : moveListeners) { - listener.onGridStackMove(events); - } - } - - /** - * Define size limitations to child component. For now some values must be defined before child has been rendered - * on client side. - * @param child Child of this layout - * @param minWidth Mininum width in slots (null is undefined) - * @param maxWidth Maxium width in slots (null is undefined) - * @param minHeight Mininum height in slots (null is undefined) - * @param maxHeight Maximum height in slots (null is undefined) - */ - public void setComponentSizeLimits(Component child, Integer minWidth, Integer maxWidth, Integer minHeight, Integer maxHeight) { - GridStackChildOptions childOpts = getComponentOptions(child); - childOpts.minWidth = minWidth; - childOpts.maxWidth = maxWidth; - childOpts.minHeight = minHeight; - childOpts.maxHeight = maxHeight; - } - - /** - * Check if given child is locked (not allowed to move because of other dragged children) - * @param child Child component of layout - * @return true if locked, false if not - * @throws IllegalArgumentException If child not found - */ - public boolean isComponentLocked(Component child) { - return getComponentOptions(child, false).locked; - } - - /** - * Change locked state of child. Locked children will not be moved away from other dragged children. - * @param child Child component of layout - * @param locked true if locked, false if not - * @throws IllegalArgumentException If child not found - */ - public void setComponentLocked(Component child, boolean locked) { - getComponentOptions(child).locked = locked; - } - - protected GridStackChildOptions getComponentOptions(Component child) { - return getComponentOptions(child, true, true); - } - - protected GridStackChildOptions getComponentOptions(Component child, boolean modify) { - return getComponentOptions(child, modify, true); - } - - protected GridStackChildOptions getComponentOptions(Component child, boolean modify, boolean throwIfMissing) { - if(child == null || child.getParent() != this) { - throw new IllegalArgumentException("Given component is not child of this layout"); - } - GridStackChildOptions opt = getState(modify).childOptions.get(child); - if(opt == null) { - throw new IllegalStateException("Missing child options"); - } - return opt; - } - - /** - * Define if layout is animated when child components are moved - * @param animate true to animate, false to not animate - * @return This GridStackLayout for command chaining - */ - public GridStackLayout setAnimate(boolean animate) { - getState().gridStackOptions.animate = animate; - return this; - } - - /** - * Check if layout is animated - * @return true if animated, false if not - */ - public boolean isAnimate() { - return getState(false).gridStackOptions.animate; - } - - /** - * Set layout static (no dragging of resizing) or dynamic (dragging and resizing allowed) - * @param staticGrid true to set static (no dragging of resizing), false to set dynamic (dragging and resizing - * allowed) - * @return This GridStackLayout for command chaining - */ - public GridStackLayout setStaticGrid(boolean staticGrid) { - getState().gridStackOptions.staticGrid = staticGrid; - return this; - } - - /** - * Check if layout is in static mode - * @return true if in static mode, false if not, null if not defined by server side - */ - public Boolean isStaticGrid() { - return getState(false).gridStackOptions.staticGrid; - } - - - /** - * Check if component has specific dragging handle - * @param child Child component of layout - * @return true if component has separate dragging handle, false if whole content acts as dragging handle - */ - public boolean isComponentWithDragHandle(Component child) { - return getComponentOptions(child, false).useDragHandle; - } - - /** - * Define vertical margin between components on GridStack layout. Value is only read when rendered on client side - * first time, so changing value after that will not have any effect (unless client side is detached). - * @param marginPx Vertical margin in pixels - * @return This GridStackLayout for command chaining - */ - public GridStackLayout setVerticalMargin(int marginPx) { - getState(true).gridStackOptions.verticalMargin = marginPx; - return this; - } - - /** - * Get vertical margin between components. Value might be mismatch to actual value used, if changed after client - * side was last attached. - * @return Vertical margin in pixels, if null the gridstack.js default is used. - */ - public Integer getVerticalMargin() { - return getState(false).gridStackOptions.verticalMargin; - } - - /** - * Define height of cell in pixels. - * @param heightPx Cell height in pixels - * @return This GridStackLayout for command chaining - */ - public GridStackLayout setCellHeight(int heightPx) { - getState(true).gridStackOptions.cellHeight = heightPx; - return this; - } - - /** - * Get height of cell in pixels. - * @return Cell height in pixels, if null the gridstack.js default is used. - */ - public Integer getCellHeight() { - return getState(false).gridStackOptions.cellHeight; - } - - /** - * Set minimal width. If window width is less, grid will be shown in one-column mode. Changing value after - * it has been attached on client side will not apply until client side is detached and attached. - * @param minWidthPx Minimal width in pixels - * @return This GridStackLayout for command chaining - */ - public GridStackLayout setMinWidth(int minWidthPx) { - getState(true).gridStackOptions.minWidth = minWidthPx; - return this; - } - - /** - * Get minimal width. If window width is less, grid will be shown in one-column mode. Value might be mismatch to - * actual value used, if changed after client side was last attached. - * @return Minimal width in pixels, if null the gridstack.js default is used. - */ - public Integer getMinWidth() { - return getState(false).gridStackOptions.minWidth; - } - - /** - * Define if wrapper around child should allow vertical scrolling or not - * @param child Child of layout - * @param scrolling true to enable vertical scrolling, false to disable it - * @throws IllegalArgumentException If child not found - */ - public void setWrapperScrolling(Component child, boolean scrolling) { - getComponentOptions(child, true).disableScrolling = !scrolling; - } - - /** - * Check if wrapper around child allows vertical scrolling or not - * @param child Child of layout - * @return true if wrapper allows vertical scrolling, false if wrapper hides vertical overflow - * @throws IllegalArgumentException If child not found - */ - public boolean isWrapperScrolling(Component child) { - return getComponentOptions(child, false).disableScrolling; - } - - /** - * Check if given area is empty. Remember that any client side defined positioning not yet reported back to - * server side will be unknown and so can result work results. - * @param x Left edge coordinate of area - * @param x Top edge coordinate of area - * @param width Width of area in slots - * @param height Height of area in slots - * @return true if area is available and valid for use - * @throws IllegalArgumentException If invalid values given - */ - public boolean isAreaEmpty(int x, int y, int width, int height) throws IllegalArgumentException { - return isAreaEmpty(new GridStackCoordinates(x, y, width, height)); - } - - /** - * Check if given area is empty. Remember that any client side defined positioning not yet reported back to - * server side will be unknown and so can result work results. Will also return false if area would go outside the - * right edge. - * @param coordinates Coordinate area checked (x, y, width, height) - * @return true if area is available and valid for use - * @throws IllegalArgumentException If invalid values given - */ - public boolean isAreaEmpty(GridStackCoordinates coordinates) throws IllegalArgumentException { - if(coordinates.getX() < 0) { - throw new IllegalArgumentException("X can not be negative"); - } - if(coordinates.getY() < 0) { - throw new IllegalArgumentException("Y can not be negative"); - } - if(coordinates.getWidth() <= 0) { - throw new IllegalArgumentException("Width most be larger than zero"); - } - if(coordinates.getHeight() <= 0) { - throw new IllegalArgumentException("Height most be larger than zero"); - } - - // If item would drop out of left side, return false - if(coordinates.getX() + coordinates.getWidth() > getState(false).gridStackOptions.width) { - return false; - } - - for(int dx = 0; dx < coordinates.getWidth(); ++dx) { - for(int dy = 0; dy < coordinates.getHeight(); ++dy) { - Component occupant = getComponent(coordinates.getX() + dx, coordinates.getY() + dy, true); - if(occupant != null) { - return false; - } - } - } - - return true; - } - +public class GridStackLayout extends GridStackLayoutNoJQuery{ + + private static final long serialVersionUID = 6467470894116980564L; + + public GridStackLayout(int i) + { + super(i); + } + + public GridStackLayout(int columns, int rows) + { + super(columns,rows); + } + } diff --git a/gridstack-addon/src/main/java/org/vaadin/alump/gridstack/GridStackLayoutNoJQuery.java b/gridstack-addon/src/main/java/org/vaadin/alump/gridstack/GridStackLayoutNoJQuery.java new file mode 100644 index 0000000..aed586b --- /dev/null +++ b/gridstack-addon/src/main/java/org/vaadin/alump/gridstack/GridStackLayoutNoJQuery.java @@ -0,0 +1,674 @@ +/** + * GridStackLayout.java (GridStackLayout) + * + * Copyright 2015 Vaadin Ltd, Sami Viitanen + * + * 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.vaadin.alump.gridstack; + +import java.util.ArrayList; +import java.util.Collection; +import java.util.Iterator; +import java.util.List; + +import org.vaadin.alump.gridstack.client.shared.GridStackChildOptions; +import org.vaadin.alump.gridstack.client.shared.GridStackLayoutState; +import org.vaadin.alump.gridstack.client.shared.GridStackMoveData; +import org.vaadin.alump.gridstack.client.shared.GridStackServerRpc; + +import com.vaadin.annotations.JavaScript; +import com.vaadin.event.LayoutEvents; +import com.vaadin.shared.Connector; +import com.vaadin.shared.EventId; +import com.vaadin.shared.MouseEventDetails; +import com.vaadin.ui.AbstractLayout; +import com.vaadin.ui.Component; + +/** + * Vaadin layout using gridstack.js library to layout components + * + * gridstack.js by Pavel Reznikov: http://troolee.github.io/gridstack.js/ + */ +@JavaScript({ "lodash.min.js", "gridstack.js"}) +public class GridStackLayoutNoJQuery extends AbstractLayout implements LayoutEvents.LayoutClickNotifier { + + /** + * + */ + private static final long serialVersionUID = 7108377304337805340L; + + protected final List components = new ArrayList(); + + private boolean initialClientResponseSent; + + private final List moveListeners = new ArrayList(); + + /** + * Use this as x or y coordinate if you want to leave slot selection of component to client side + */ + public final static int CLIENT_SIDE_SELECTS = -1; + + private GridStackServerRpc serverRpc = new GridStackServerRpc() { + + /** + * + */ + private static final long serialVersionUID = 5534784708887723233L; + + @Override + public void layoutClick(MouseEventDetails mouseEventDetails, Connector connector) { + fireEvent(LayoutEvents.LayoutClickEvent.createEvent(GridStackLayoutNoJQuery.this, + mouseEventDetails, connector)); + } + + @Override + public void onChildrenMoved(List moves) { + Collection events = new ArrayList(); + for(GridStackMoveData move : moves) { + Component childComponent = (Component)move.child; + GridStackCoordinates oldCoordinates = getCoordinates(childComponent); + + GridStackChildOptions info = getState(false).childOptions.get(move.child); + info.x = move.x; + info.y = move.y; + info.width = move.width; + info.height = move.height; + + if(!oldCoordinates.equals(getCoordinates(childComponent))) { + events.add(createMoveEvent(childComponent, oldCoordinates)); + } + } + fireMoveEvents(events); + } + }; + + + /** + * Creates GridStackLayout with default 3 columns + */ + public GridStackLayoutNoJQuery() { + super(); + registerRpc(serverRpc, GridStackServerRpc.class); + } + + /** + * Create GridStackLayout with defined column count. + * @param columns Number of columns, if more than 8 see documentation (extra SCSS including required) + */ + public GridStackLayoutNoJQuery(int columns) { + this(); + if(columns <= 0) { + throw new IllegalArgumentException("Amount of columns can not be 0 or negative"); + } + addStyleName("with-" + columns + "-columns"); + getState().gridStackOptions.width = columns; + } + + /** + * Create GridStackLayout with defined column and row count. + * @param columns Number of columns, if more than 8 see documentation (extra SCSS including required) + * @param rows Maxium amount of rows allowed + */ + public GridStackLayoutNoJQuery(int columns, int rows) { + this(columns); + if(rows <= 0) { + throw new IllegalArgumentException("Amount of rows can not be 0 or negative"); + } + getState().gridStackOptions.height = rows; + } + + @Override + public void beforeClientResponse(boolean initial) { + super.beforeClientResponse(initial); + initialClientResponseSent = true; + } + + + @Override + protected GridStackLayoutState getState() { + return (GridStackLayoutState)super.getState(); + } + + @Override + protected GridStackLayoutState getState(boolean markDirty) { + return (GridStackLayoutState)super.getState(markDirty); + } + + /** + * {@inheritDoc} + */ + @Override + public void addComponent(Component component) { + addComponent(component, CLIENT_SIDE_SELECTS, CLIENT_SIDE_SELECTS); + } + + /** + * Add component to layout + * @param component Component added + * @param useDragHandle true to add component with a separate drag handle, or false to make whole content act as a + * drag handle. Notice that using a separate drag handle is recommended if you component + * is or contains any active components (buttons etc..) + */ + public void addComponent(Component component, boolean useDragHandle) { + addComponent(component, CLIENT_SIDE_SELECTS, CLIENT_SIDE_SELECTS, useDragHandle); + } + + /** + * Add component to given slot + * @param component Component added + * @param x Slot's X coordinate + * @param y Slot's Y coordinate + */ + public void addComponent(Component component, int x, int y) { + addComponent(component, x, y, 1, 1); + } + + /** + * Add component to given slot + * @param component Component added + * @param x Slot's X coordinate + * @param y Slot's Y coordinate + * @param useDragHandle true to add component with a separate drag handle, or false to make whole content act as a + * drag handle. Notice that using a separate drag handle is recommended if you component + * is or contains any active components (buttons etc..) + */ + public void addComponent(Component component, int x, int y, boolean useDragHandle) { + addComponent(component, x, y, 1, 1, useDragHandle); + } + + /** + * Add component to given slot, and define it's size + * @param component Component added + * @param x Slot's X coordinate (use negative values if position can be defined on client side) + * @param y Slot's Y coordinate (use negative values if position can be defined on client side) + * @param width Width of space reserved (in slots) + * @param height Height of space reserved (in slots) + */ + public void addComponent(Component component, int x, int y, int width, int height) { + addComponent(component, x, y, width, height, true); + } + + /** + * Add component to given slot, and define it's size + * @param component Component added + * @param x Slot's X coordinate (use negative values if position can be defined on client side) + * @param y Slot's Y coordinate (use negative values if position can be defined on client side) + * @param width Width of space reserved (in slots) + * @param height Height of space reserved (in slots) + * @param useDragHandle true to add component with a separate drag handle, or false to make whole content act as a + * drag handle. Notice that using a separate drag handle is recommended if you component + * is or contains any active components (buttons etc..) + */ + public void addComponent(Component component, int x, int y, int width, int height, boolean useDragHandle) { + super.addComponent(component); + components.add(component); + + GridStackChildOptions info = new GridStackChildOptions(); + info.x = x; + info.y = y; + info.width = width; + info.height = height; + info.useDragHandle = useDragHandle; + getState().childOptions.put(component, info); + } + + /** + * Reset component's position and allow child side define new position for it. + * @param component Child component which position is reset + */ + public void resetComponentPosition(Component component) { + moveComponent(component, CLIENT_SIDE_SELECTS, CLIENT_SIDE_SELECTS); + } + + /** + * Move given child component + * @param component Child component moved and/or resized + * @param x When defined component's X value is updated, if null old value is kept + * @param y When defined component's Y value is updated, if null old value is kept + * @throws IllegalArgumentException If given value are invalid (eg. component is not child of this layout) + */ + public void moveComponent(Component component, Integer x, Integer y) throws IllegalArgumentException { + moveAndResizeComponent(component, x, y, null, null); + } + + /** + * Move given child component + * @param component Child component moved and/or resized + * @param width When defined component's width is updated, if null old value is kept + * @param height When defined component's height is updated, if null old value is kept + * @throws IllegalArgumentException If given value are invalid (eg. component is not child of this layout) + */ + public void resizeComponent(Component component, Integer width, Integer height) throws IllegalArgumentException { + moveAndResizeComponent(component, null, null, width, height); + } + + /** + * Move and/or resize given child component + * @param component Child component moved and/or resized + * @param x When defined component's X value is updated, if null old value is kept + * @param y When defined component's Y value is updated, if null old value is kept + * @param width When defined component's width is updated, if null old value is kept + * @param height When defined component's height is updated, if null old value is kept + * @throws IllegalArgumentException If given value are invalid (eg. component is not child of this layout, or + * coordinates are invalid). + */ + public void moveAndResizeComponent(Component component, Integer x, Integer y, Integer width, Integer height) + throws IllegalArgumentException { + + if(x != null & width != null && x >= 0 && x + width > getState(false).gridStackOptions.width) { + throw new IllegalArgumentException("Component would go outside the right edge of layout"); + } + + GridStackChildOptions info = getState().childOptions.get(component); + if(info == null) { + throw new IllegalArgumentException("Given component is not child of GridStackLayout"); + } + if(x != null) { + info.x = x; + } + if(y != null) { + info.y = y; + } + if(width != null) { + info.width = width; + } + if(height != null) { + info.height = height; + } + } + + /** + * Get component with given slot coordinate + * @param x Slot's X coordinate + * @param y Slot's Y coordinate + * @return Component at slot, or null if component not found + */ + public Component getComponent(int x, int y) { + return getComponent(x, y, false); + } + + /** + * Get component with given slot coordinate + * @param x Slot's X coordinate + * @param y Slot's Y coordinate + * @param acceptInsideHit If true also other slots reserved by component are accepted + * @return Component at slot, or null if component not found + */ + public Component getComponent(int x, int y, boolean acceptInsideHit) { + for(Connector connector : getState().childOptions.keySet()) { + GridStackChildOptions info = getState().childOptions.get(connector); + if(acceptInsideHit) { + if(x >= info.x && x < (info.x + info.width) && y >= info.y && y < (info.y + info.width)) { + return (Component) connector; + } + } else { + if (info.x == x && info.y == y) { + return (Component) connector; + } + } + } + return null; + } + + /** + * {@inheritDoc} + */ + @Override + public void removeComponent(Component component) { + getState().childOptions.remove(component); + components.remove(component); + super.removeComponent(component); + } + + @Override + public void replaceComponent(Component oldComponent, Component newComponent) { + if(oldComponent == newComponent) { + return; + } + if(oldComponent.getParent() != this) { + throw new IllegalArgumentException("Replacable component not child of this layout"); + } + GridStackChildOptions oldOptions = getState(false).childOptions.get(oldComponent); + removeComponent(oldComponent); + + if(newComponent.getParent() == this) { + removeComponent(newComponent); + } + addComponent(newComponent, oldOptions.x, oldOptions.y, oldOptions.width, oldOptions.height); + } + + /** + * {@inheritDoc} + */ + @Override + public int getComponentCount() { + return components.size(); + } + + /** + * {@inheritDoc} + */ + @Override + public Iterator iterator() { + return components.iterator(); + } + + /** + * {@inheritDoc} + */ + @Override + public void addLayoutClickListener(LayoutEvents.LayoutClickListener listener) { + addListener(EventId.LAYOUT_CLICK_EVENT_IDENTIFIER, + LayoutEvents.LayoutClickEvent.class, listener, + LayoutEvents.LayoutClickListener.clickMethod); + } + + @Override + @Deprecated + public void addListener(LayoutEvents.LayoutClickListener layoutClickListener) { + addLayoutClickListener(layoutClickListener); + } + + /** + * {@inheritDoc} + */ + @Override + public void removeLayoutClickListener(LayoutEvents.LayoutClickListener listener) { + removeListener(EventId.LAYOUT_CLICK_EVENT_IDENTIFIER, + LayoutEvents.LayoutClickEvent.class, listener); + } + + @Override + @Deprecated + public void removeListener(LayoutEvents.LayoutClickListener layoutClickListener) { + removeLayoutClickListener(layoutClickListener); + } + + /** + * Add listener for component move events + * @param listener Listener added + */ + public void addGridStackMoveListener(GridStackMoveEvent.GridStackMoveListener listener) { + moveListeners.add(listener); + } + + /** + * Remove listener of component move events + * @param listener Listener removed + */ + public void removeGridStackMoveListener(GridStackMoveEvent.GridStackMoveListener listener) { + moveListeners.remove(listener); + } + + /** + * Get coordinates (X,Y,width,height) of component + * @param child Child component of layout + * @return Coordinates (X,Y,width,height) of component + * @throws IllegalArgumentException If child not found + */ + public GridStackCoordinates getCoordinates(Component child) { + GridStackChildOptions opts = getComponentOptions(child, false); + return new GridStackCoordinates(opts.x, opts.y, opts.width, opts.height); + } + + protected GridStackMoveEvent createMoveEvent(Component component, GridStackCoordinates oldCoordinates) { + return new GridStackMoveEvent(this, component, oldCoordinates, + getCoordinates(component)); + } + + protected void fireMoveEvents(Collection events) { + if(events.isEmpty()) { + return; + } + + for(GridStackMoveEvent.GridStackMoveListener listener : moveListeners) { + listener.onGridStackMove(events); + } + } + + /** + * Define size limitations to child component. For now some values must be defined before child has been rendered + * on client side. + * @param child Child of this layout + * @param minWidth Mininum width in slots (null is undefined) + * @param maxWidth Maxium width in slots (null is undefined) + * @param minHeight Mininum height in slots (null is undefined) + * @param maxHeight Maximum height in slots (null is undefined) + */ + public void setComponentSizeLimits(Component child, Integer minWidth, Integer maxWidth, Integer minHeight, Integer maxHeight) { + GridStackChildOptions childOpts = getComponentOptions(child); + childOpts.minWidth = minWidth; + childOpts.maxWidth = maxWidth; + childOpts.minHeight = minHeight; + childOpts.maxHeight = maxHeight; + } + + /** + * Check if given child is locked (not allowed to move because of other dragged children) + * @param child Child component of layout + * @return true if locked, false if not + * @throws IllegalArgumentException If child not found + */ + public boolean isComponentLocked(Component child) { + return getComponentOptions(child, false).locked; + } + + /** + * Change locked state of child. Locked children will not be moved away from other dragged children. + * @param child Child component of layout + * @param locked true if locked, false if not + * @throws IllegalArgumentException If child not found + */ + public void setComponentLocked(Component child, boolean locked) { + getComponentOptions(child).locked = locked; + } + + protected GridStackChildOptions getComponentOptions(Component child) { + return getComponentOptions(child, true, true); + } + + protected GridStackChildOptions getComponentOptions(Component child, boolean modify) { + return getComponentOptions(child, modify, true); + } + + protected GridStackChildOptions getComponentOptions(Component child, boolean modify, boolean throwIfMissing) { + if(child == null || child.getParent() != this) { + throw new IllegalArgumentException("Given component is not child of this layout"); + } + GridStackChildOptions opt = getState(modify).childOptions.get(child); + if(opt == null) { + throw new IllegalStateException("Missing child options"); + } + return opt; + } + + /** + * Define if layout is animated when child components are moved + * @param animate true to animate, false to not animate + * @return This GridStackLayout for command chaining + */ + public GridStackLayoutNoJQuery setAnimate(boolean animate) { + getState().gridStackOptions.animate = animate; + return this; + } + + /** + * Check if layout is animated + * @return true if animated, false if not + */ + public boolean isAnimate() { + return getState(false).gridStackOptions.animate; + } + + /** + * Set layout static (no dragging of resizing) or dynamic (dragging and resizing allowed) + * @param staticGrid true to set static (no dragging of resizing), false to set dynamic (dragging and resizing + * allowed) + * @return This GridStackLayout for command chaining + */ + public GridStackLayoutNoJQuery setStaticGrid(boolean staticGrid) { + getState().gridStackOptions.staticGrid = staticGrid; + return this; + } + + /** + * Check if layout is in static mode + * @return true if in static mode, false if not, null if not defined by server side + */ + public Boolean isStaticGrid() { + return getState(false).gridStackOptions.staticGrid; + } + + + /** + * Check if component has specific dragging handle + * @param child Child component of layout + * @return true if component has separate dragging handle, false if whole content acts as dragging handle + */ + public boolean isComponentWithDragHandle(Component child) { + return getComponentOptions(child, false).useDragHandle; + } + + /** + * Define vertical margin between components on GridStack layout. Value is only read when rendered on client side + * first time, so changing value after that will not have any effect (unless client side is detached). + * @param marginPx Vertical margin in pixels + * @return This GridStackLayout for command chaining + */ + public GridStackLayoutNoJQuery setVerticalMargin(int marginPx) { + getState(true).gridStackOptions.verticalMargin = marginPx; + return this; + } + + /** + * Get vertical margin between components. Value might be mismatch to actual value used, if changed after client + * side was last attached. + * @return Vertical margin in pixels, if null the gridstack.js default is used. + */ + public Integer getVerticalMargin() { + return getState(false).gridStackOptions.verticalMargin; + } + + /** + * Define height of cell in pixels. + * @param heightPx Cell height in pixels + * @return This GridStackLayout for command chaining + */ + public GridStackLayoutNoJQuery setCellHeight(int heightPx) { + getState(true).gridStackOptions.cellHeight = heightPx; + return this; + } + + /** + * Get height of cell in pixels. + * @return Cell height in pixels, if null the gridstack.js default is used. + */ + public Integer getCellHeight() { + return getState(false).gridStackOptions.cellHeight; + } + + /** + * Set minimal width. If window width is less, grid will be shown in one-column mode. Changing value after + * it has been attached on client side will not apply until client side is detached and attached. + * @param minWidthPx Minimal width in pixels + * @return This GridStackLayout for command chaining + */ + public GridStackLayoutNoJQuery setMinWidth(int minWidthPx) { + getState(true).gridStackOptions.minWidth = minWidthPx; + return this; + } + + /** + * Get minimal width. If window width is less, grid will be shown in one-column mode. Value might be mismatch to + * actual value used, if changed after client side was last attached. + * @return Minimal width in pixels, if null the gridstack.js default is used. + */ + public Integer getMinWidth() { + return getState(false).gridStackOptions.minWidth; + } + + /** + * Define if wrapper around child should allow vertical scrolling or not + * @param child Child of layout + * @param scrolling true to enable vertical scrolling, false to disable it + * @throws IllegalArgumentException If child not found + */ + public void setWrapperScrolling(Component child, boolean scrolling) { + getComponentOptions(child, true).disableScrolling = !scrolling; + } + + /** + * Check if wrapper around child allows vertical scrolling or not + * @param child Child of layout + * @return true if wrapper allows vertical scrolling, false if wrapper hides vertical overflow + * @throws IllegalArgumentException If child not found + */ + public boolean isWrapperScrolling(Component child) { + return getComponentOptions(child, false).disableScrolling; + } + + /** + * Check if given area is empty. Remember that any client side defined positioning not yet reported back to + * server side will be unknown and so can result work results. + * @param x Left edge coordinate of area + * @param x Top edge coordinate of area + * @param width Width of area in slots + * @param height Height of area in slots + * @return true if area is available and valid for use + * @throws IllegalArgumentException If invalid values given + */ + public boolean isAreaEmpty(int x, int y, int width, int height) throws IllegalArgumentException { + return isAreaEmpty(new GridStackCoordinates(x, y, width, height)); + } + + /** + * Check if given area is empty. Remember that any client side defined positioning not yet reported back to + * server side will be unknown and so can result work results. Will also return false if area would go outside the + * right edge. + * @param coordinates Coordinate area checked (x, y, width, height) + * @return true if area is available and valid for use + * @throws IllegalArgumentException If invalid values given + */ + public boolean isAreaEmpty(GridStackCoordinates coordinates) throws IllegalArgumentException { + if(coordinates.getX() < 0) { + throw new IllegalArgumentException("X can not be negative"); + } + if(coordinates.getY() < 0) { + throw new IllegalArgumentException("Y can not be negative"); + } + if(coordinates.getWidth() <= 0) { + throw new IllegalArgumentException("Width most be larger than zero"); + } + if(coordinates.getHeight() <= 0) { + throw new IllegalArgumentException("Height most be larger than zero"); + } + + // If item would drop out of left side, return false + if(coordinates.getX() + coordinates.getWidth() > getState(false).gridStackOptions.width) { + return false; + } + + for(int dx = 0; dx < coordinates.getWidth(); ++dx) { + for(int dy = 0; dy < coordinates.getHeight(); ++dy) { + Component occupant = getComponent(coordinates.getX() + dx, coordinates.getY() + dy, true); + if(occupant != null) { + return false; + } + } + } + + return true; + } + +} diff --git a/gridstack-addon/src/main/java/org/vaadin/alump/gridstack/GridStackMoveEvent.java b/gridstack-addon/src/main/java/org/vaadin/alump/gridstack/GridStackMoveEvent.java index 25e9e94..db7d0be 100644 --- a/gridstack-addon/src/main/java/org/vaadin/alump/gridstack/GridStackMoveEvent.java +++ b/gridstack-addon/src/main/java/org/vaadin/alump/gridstack/GridStackMoveEvent.java @@ -27,7 +27,7 @@ */ public class GridStackMoveEvent { - private final GridStackLayout layout; + private final GridStackLayoutNoJQuery layout; private final Component movedChild; private final GridStackCoordinates oldCoordinates; private final GridStackCoordinates newCoordinates; @@ -41,7 +41,7 @@ public interface GridStackMoveListener { void onGridStackMove(Collection events); } - public GridStackMoveEvent(GridStackLayout layout, Component movedChild, GridStackCoordinates oldCoordinates, + public GridStackMoveEvent(GridStackLayoutNoJQuery layout, Component movedChild, GridStackCoordinates oldCoordinates, GridStackCoordinates newCoordinates) { this.layout = layout; this.movedChild = movedChild; @@ -49,7 +49,7 @@ public GridStackMoveEvent(GridStackLayout layout, Component movedChild, GridStac this.oldCoordinates = oldCoordinates; } - public GridStackLayout getLayout() { + public GridStackLayoutNoJQuery getLayout() { return layout; } diff --git a/gridstack-addon/src/main/java/org/vaadin/alump/gridstack/client/GridStackLayoutConnector.java b/gridstack-addon/src/main/java/org/vaadin/alump/gridstack/client/GridStackLayoutConnector.java index 9880e4c..cfb672d 100644 --- a/gridstack-addon/src/main/java/org/vaadin/alump/gridstack/client/GridStackLayoutConnector.java +++ b/gridstack-addon/src/main/java/org/vaadin/alump/gridstack/client/GridStackLayoutConnector.java @@ -41,7 +41,7 @@ import java.util.List; import java.util.logging.Logger; -@Connect(org.vaadin.alump.gridstack.GridStackLayout.class) +@Connect(org.vaadin.alump.gridstack.GridStackLayoutNoJQuery.class) public class GridStackLayoutConnector extends AbstractLayoutConnector { private transient final static Logger LOGGER = Logger.getLogger(GridStackLayoutConnector.class.getName());