/* This file belongs to the Servoy development and deployment environment, Copyright (C) 1997-2013 Servoy BV This program is free software; you can redistribute it and/or modify it under the terms of the GNU Affero General Public License as published by the Free Software Foundation; either version 3 of the License, or (at your option) any later version. This program is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU Affero General Public License for more details. You should have received a copy of the GNU Affero General Public License along with this program; if not, see http://www.gnu.org/licenses or write to the Free Software Foundation,Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 */ package com.servoy.j2db.debug.layout; import java.util.ArrayList; import java.util.Collections; import java.util.Comparator; import java.util.HashSet; import java.util.List; import java.util.Set; import com.servoy.base.persistence.IMobileProperties; import com.servoy.j2db.FlattenedSolution; import com.servoy.j2db.component.ComponentFactory; import com.servoy.j2db.debug.layout.ILayoutWrapper.MobileFormSection; import com.servoy.j2db.persistence.AbstractBase; import com.servoy.j2db.persistence.Field; import com.servoy.j2db.persistence.FlattenedForm; import com.servoy.j2db.persistence.Form; import com.servoy.j2db.persistence.FormElementGroup; import com.servoy.j2db.persistence.GraphicalComponent; import com.servoy.j2db.persistence.IFlattenedPersistWrapper; import com.servoy.j2db.persistence.IFormElement; import com.servoy.j2db.persistence.IPersist; import com.servoy.j2db.persistence.IRepository; import com.servoy.j2db.persistence.ISupportBounds; import com.servoy.j2db.persistence.ISupportExtendsID; import com.servoy.j2db.persistence.Portal; import com.servoy.j2db.persistence.PositionComparator; import com.servoy.j2db.scripting.solutionmodel.JSButton; import com.servoy.j2db.scripting.solutionmodel.JSField; import com.servoy.j2db.scripting.solutionmodel.JSForm; import com.servoy.j2db.scripting.solutionmodel.JSLabel; import com.servoy.j2db.scripting.solutionmodel.JSPortal; import com.servoy.j2db.util.CompositeComparator; import com.servoy.j2db.util.PersistHelper; import com.servoy.j2db.util.Utils; /** * Static methods for layouting elements in mobile form editor. * Can be called from DebugWebclient for layouting forms created using solution model. * * @author rgansevles * */ public class MobileFormLayout { public static final int MOBILE_FORM_WIDTH = 350; // fixed width, future: make configurable private static final int MIN_FORM_HEIGHT = 250; public static void layoutForm(List< ? extends ILayoutWrapper> elements) { // children are based on model order as created in editPart.getModelChildren() int y = 0; int height = 0; for (ILayoutWrapper element : elements) { int x; if (element.getElementType() == MobileFormSection.ContentElement) { x = 10; y++; } else { x = 0; } int width = MOBILE_FORM_WIDTH - (2 * x); y += height; int childHeight = element.getPreferredHeight(); height = childHeight <= 0 ? 55 : childHeight; if (y + height < MIN_FORM_HEIGHT && element.getElementType() == MobileFormSection.Footer) { y = MIN_FORM_HEIGHT - height; } element.setBounds(x, y, width, height); } } public static void layoutHeader(List< ? extends ILayoutWrapper> elements, int containerX, int containerY, int containerWidth) { int y = containerY + 8; int height = 28; for (ILayoutWrapper element : elements) { int width = 50; int x; if (element.getMobileProperty(IMobileProperties.HEADER_LEFT_BUTTON) != null) { x = containerX + 20; } else if (element.getMobileProperty(IMobileProperties.HEADER_TEXT) != null) { width = containerWidth - 150; x = containerX + (containerWidth - width) / 2; } else if (element.getMobileProperty(IMobileProperties.HEADER_RIGHT_BUTTON) != null) { x = containerX + containerWidth - width - 20; } else continue; element.setBounds(x, y, width, height); } } public static void layoutFooter(List< ? extends ILayoutWrapper> elements, int containerX, int containerY, int containerWidth) { int x = containerX + 1; int y = containerY + 1; int width = 49; int height = 38; for (ILayoutWrapper element : elements) { element.setBounds(x, y, width, height); x += width + 1; if (x + width > containerWidth) { // next line x = containerX + 2; y += height + 2; } } } public static void layoutGroup(int containerX, int containerY, int containerWidth, int containerHeight, List< ? extends ILayoutWrapper> elements) { int x = containerX + 2; int y = containerY + 2; int width = containerWidth - 4; for (ILayoutWrapper element : elements) { int childPrefHeight = element.getPreferredHeight(); int height = (childPrefHeight > 0 ? childPrefHeight : 38); element.setBounds(x, y, width, height); y += height + 2; } } public static int calculateGroupHeight(List<ILayoutWrapper> elements) { int height = 0; for (ILayoutWrapper element : elements) { int childPrefHeight = element.getPreferredHeight(); height += (childPrefHeight > 0 ? childPrefHeight : 38) + 2; } return height; } public static List<ISupportBounds> getBodyElementsForRecordView(FlattenedSolution editingFlattenedSolution, Form flattenedForm) { List<ISupportBounds> elements = new ArrayList<ISupportBounds>(); Set<String> groups = new HashSet<String>(); for (IPersist persist : flattenedForm.getAllObjectsAsList()) { if (persist instanceof ISupportExtendsID && PersistHelper.isOverrideOrphanElement((ISupportExtendsID)persist)) { // skip orphaned overrides continue; } if (persist instanceof IFormElement && persist instanceof AbstractBase) { String groupID = ((IFormElement)persist).getGroupID(); if (groupID == null) { if (persist instanceof Portal && ((Portal)persist).isMobileInsetList()) { // inset list elements.add(((Portal)persist)); } // tabpanel: list elements or navtab else if (((AbstractBase)persist).getCustomMobileProperty(IMobileProperties.HEADER_ITEM.propertyName) == null && ((AbstractBase)persist).getCustomMobileProperty(IMobileProperties.FOOTER_ITEM.propertyName) == null) { // regular item elements.add((ISupportBounds)(persist instanceof IFlattenedPersistWrapper ? ((IFlattenedPersistWrapper< ? >)persist).getWrappedPersist() : persist)); } } else if (groups.add(groupID)) { elements.add(new FormElementGroup(groupID, editingFlattenedSolution, FlattenedForm.getWrappedForm(flattenedForm))); } } } // sort by y-position Collections.sort(elements, PositionComparator.YX_BOUNDS_COMPARATOR); return elements; } @SuppressWarnings("unchecked") public static List<IFormElement> getGroupElements(FormElementGroup group) { List<IFormElement> returnList = Utils.asList(group.getElements()); Collections.sort(returnList, new CompositeComparator<IFormElement>(new Comparator<IFormElement>() { // sort so that label comes first public int compare(IFormElement element1, IFormElement element2) { if (element1.getTypeID() == IRepository.GRAPHICALCOMPONENTS) { return element2.getTypeID() == IRepository.GRAPHICALCOMPONENTS ? 0 : -1; } return element2.getTypeID() == IRepository.GRAPHICALCOMPONENTS ? 1 : 0; } }, PositionComparator.XY_PERSIST_COMPARATOR)); return returnList; } public static ILayoutWrapper createLayoutWrapper(ISupportBounds element, JSForm jsform) { if (element instanceof Portal) { // inset list return new ComponentLayoutWrapper(new JSPortal(jsform, (Portal)element, jsform.getApplication(), false)); } if (element instanceof Field) { return new ComponentLayoutWrapper(new JSField(jsform, (Field)element, jsform.getApplication(), false)); } if (element instanceof GraphicalComponent) { return new ComponentLayoutWrapper(ComponentFactory.isButton((GraphicalComponent)element) ? new JSButton(jsform, (GraphicalComponent)element, jsform.getApplication(), false) : new JSLabel(jsform, (GraphicalComponent)element, jsform.getApplication(), false)); } if (element instanceof FormElementGroup) { // group return new GroupLayoutWrapper((FormElementGroup)element, jsform); } return null; } }