/*
This file belongs to the Servoy development and deployment environment, Copyright (C) 1997-2011 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.server.headlessclient.dataui;
import java.awt.Color;
import java.awt.Cursor;
import java.awt.Dimension;
import java.awt.Font;
import java.awt.Insets;
import java.awt.Point;
import java.awt.Rectangle;
import java.util.ArrayList;
import java.util.List;
import javax.swing.border.Border;
import javax.swing.border.TitledBorder;
import javax.swing.event.ListSelectionEvent;
import javax.swing.event.ListSelectionListener;
import org.apache.wicket.Component;
import org.apache.wicket.MarkupContainer;
import org.apache.wicket.Page;
import org.apache.wicket.ajax.AjaxRequestTarget;
import org.apache.wicket.behavior.SimpleAttributeModifier;
import org.apache.wicket.markup.ComponentTag;
import org.apache.wicket.markup.MarkupStream;
import org.apache.wicket.markup.html.IHeaderResponse;
import org.apache.wicket.markup.html.WebMarkupContainer;
import org.apache.wicket.markup.html.basic.Label;
import org.apache.wicket.markup.html.list.Loop;
import org.apache.wicket.model.AbstractReadOnlyModel;
import org.apache.wicket.model.IModel;
import org.apache.wicket.model.Model;
import org.apache.wicket.version.undo.Change;
import org.odlabs.wiquery.core.javascript.JsStatement;
import org.odlabs.wiquery.ui.accordion.Accordion;
import org.odlabs.wiquery.ui.accordion.AccordionAnimated;
import com.servoy.base.util.ITagResolver;
import com.servoy.j2db.FormController;
import com.servoy.j2db.IApplication;
import com.servoy.j2db.IForm;
import com.servoy.j2db.IScriptExecuter;
import com.servoy.j2db.component.ComponentFactory;
import com.servoy.j2db.dataprocessing.IDisplayRelatedData;
import com.servoy.j2db.dataprocessing.IFoundSetInternal;
import com.servoy.j2db.dataprocessing.IRecordInternal;
import com.servoy.j2db.dataprocessing.ISaveConstants;
import com.servoy.j2db.dataprocessing.ISwingFoundSet;
import com.servoy.j2db.dataprocessing.RelatedFoundSet;
import com.servoy.j2db.dataprocessing.SortColumn;
import com.servoy.j2db.dataprocessing.TagResolver;
import com.servoy.j2db.persistence.StaticContentSpecLoader;
import com.servoy.j2db.persistence.TabPanel;
import com.servoy.j2db.server.headlessclient.MainPage;
import com.servoy.j2db.server.headlessclient.TabIndexHelper;
import com.servoy.j2db.server.headlessclient.WebForm;
import com.servoy.j2db.server.headlessclient.dataui.WebTabPanel.ServoyTabIcon;
import com.servoy.j2db.ui.IComponent;
import com.servoy.j2db.ui.IDataRenderer;
import com.servoy.j2db.ui.IFormLookupPanel;
import com.servoy.j2db.ui.IFormUI;
import com.servoy.j2db.ui.IProviderStylePropertyChanges;
import com.servoy.j2db.ui.IStylePropertyChanges;
import com.servoy.j2db.ui.ISupportSecuritySettings;
import com.servoy.j2db.ui.ISupportSimulateBounds;
import com.servoy.j2db.ui.ISupportSimulateBoundsProvider;
import com.servoy.j2db.ui.ISupportWebBounds;
import com.servoy.j2db.ui.ITabPanel;
import com.servoy.j2db.ui.scripting.RuntimeAccordionPanel;
import com.servoy.j2db.util.HtmlUtils;
import com.servoy.j2db.util.Pair;
import com.servoy.j2db.util.PersistHelper;
import com.servoy.j2db.util.Utils;
/**
* Represents an accordion panel in the webbrowser.
*
* @author lvostinar
* @since 6.1
*
*/
public class WebAccordionPanel extends WebMarkupContainer implements ITabPanel, IDisplayRelatedData, IProviderStylePropertyChanges, ISupportSecuritySettings,
ISupportWebBounds, ISupportWebTabSeq, ListSelectionListener, IWebFormContainer, ISupportSimulateBoundsProvider
{
private static final long serialVersionUID = 1L;
private final IApplication application;
private WebTabFormLookup currentForm;
private Accordion accordion;
protected IRecordInternal parentData;
private final List<String> allRelationNames = new ArrayList<String>(5);
protected final List<WebTabHolder> allTabs = new ArrayList<WebTabHolder>(5);
private final List<ISwingFoundSet> related = new ArrayList<ISwingFoundSet>();
private IScriptExecuter scriptExecutor;
private String onTabChangeMethodCmd;
private Object[] onTabChangeArgs;
private int tabSequenceIndex = ISupportWebTabSeq.DEFAULT;
private final RuntimeAccordionPanel scriptable;
public WebAccordionPanel(IApplication application, final RuntimeAccordionPanel scriptable, String name)
{
super(name);
this.application = application;
setOutputMarkupPlaceholderTag(true);
accordion = new Accordion("accordion_" + name)
{
@Override
public JsStatement statement()
{
JsStatement statement = super.statement();
int index = getTabIndex();
if (index > 0) // 0 is opened by default
{
statement = statement.chain("accordion", "'activate'", String.valueOf(index));
}
return statement;
}
};
add(accordion);
// disable animation, see http://forum.jquery.com/topic/jquery-accordion-not-work-on-ie-7
accordion.setAnimated(new AccordionAnimated(Boolean.FALSE));
accordion.setFillSpace(true);
IModel<Integer> tabsModel = new AbstractReadOnlyModel<Integer>()
{
private static final long serialVersionUID = 1L;
@Override
public Integer getObject()
{
return Integer.valueOf(allTabs.size());
}
};
final boolean useAJAX = Utils.getAsBoolean(application.getRuntimeProperties().get("useAJAX")); //$NON-NLS-1$
accordion.add(new Loop("tabs", tabsModel) //$NON-NLS-1$
{
private static final long serialVersionUID = 1L;
@Override
protected void populateItem(final LoopItem item)
{
item.setRenderBodyOnly(true);
final WebTabHolder holder = allTabs.get(item.getIteration());
ServoySubmitLink link = new ServoySubmitLink("tablink", useAJAX)//$NON-NLS-1$
{
@Override
public void onClick(AjaxRequestTarget target)
{
Page page = findPage();
if (page != null)
{
boolean needsRelayout = false;
if (currentForm != null && currentForm != holder.getPanel() && currentForm.getFormName().equals(holder.getPanel().getFormName()))
{
needsRelayout = true;
}
setActiveTabPanel(holder.getPanel());
if (target != null)
{
if (needsRelayout && page instanceof MainPage && ((MainPage)page).getController() != null)
{
if (Utils.getAsBoolean(((MainPage)page).getController().getApplication().getRuntimeProperties().get("enableAnchors"))) //$NON-NLS-1$
{
target.appendJavascript("layoutEntirePage();"); //$NON-NLS-1$
}
}
relinkFormIfNeeded();
accordion.activate(target, item.getIteration());
WebEventExecutor.generateResponse(target, page);
}
}
}
@Override
protected void disableLink(ComponentTag tag)
{
// do nothing here
}
};
link.setEnabled(holder.isEnabled() && WebAccordionPanel.this.isEnabled());
if (holder.getIcon() != null)
{
accordion.hideIcons();
}
if (holder.getTooltip() != null)
{
link.setMetaData(TooltipAttributeModifier.TOOLTIP_METADATA, holder.getTooltip());
}
TabIndexHelper.setUpTabIndexAttributeModifier(link, tabSequenceIndex);
link.add(TooltipAttributeModifier.INSTANCE);
String text = holder.getText();
if (holder.getDisplayedMnemonic() > 0)
{
final String mnemonic = Character.toString((char)holder.getDisplayedMnemonic());
link.add(new SimpleAttributeModifier("accesskey", mnemonic)); //$NON-NLS-1$
if (text != null && text.contains(mnemonic) && !HtmlUtils.hasUsefulHtmlContent(text))
{
StringBuffer sbBodyText = new StringBuffer(text);
int mnemonicIdx = sbBodyText.indexOf(mnemonic);
if (mnemonicIdx != -1)
{
sbBodyText.insert(mnemonicIdx + 1, "</u>"); //$NON-NLS-1$
sbBodyText.insert(mnemonicIdx, "<u>"); //$NON-NLS-1$
text = sbBodyText.toString();
}
}
}
Label label = new Label("linktext", new Model<String>(text)); //$NON-NLS-1$
label.setEscapeModelStrings(false);
if (holder.getIcon() != null)
{
label.add(new SimpleAttributeModifier("class", "accordionlinkmargin"));
}
link.add(label);
ServoyTabIcon icon = new ServoyTabIcon("icon", holder, scriptable); //$NON-NLS-1$
if (holder.getIcon() != null)
{
icon.add(new StyleAppendingModifier(new Model<String>()
{
@Override
public String getObject()
{
return "float: left;"; //$NON-NLS-1$
}
}));
}
holder.getPanel().getWebForm().add(new StyleAppendingModifier(new Model<String>()
{
private int getAllPartsHeight()
{
int height = 0;
if (getCurrentForm().getController().getDataRenderers() != null)
{
IDataRenderer[] renderers = getCurrentForm().getController().getDataRenderers();
for (IDataRenderer renderer : renderers)
{
if (renderer != null)
{
height += renderer.getSize().height;
}
}
}
return height;
}
@Override
public String getObject()
{
String formStyle = "padding: 0px;"; //$NON-NLS-1$
if (getBorder() instanceof TitledBorder)
{
int fsize = 0;
int height = getAllPartsHeight();
TitledBorder td = (TitledBorder)getBorder();
if (td.getTitleFont() != null) fsize = td.getTitleFont().getSize();
if (fsize > 11) height = getAllPartsHeight() - (fsize - 11);
formStyle += "height: " + height + "px;"; //$NON-NLS-1$ //$NON-NLS-2$
}
return formStyle;
}
}));
link.add(icon);
item.add(link);
item.add(new Label("webform", new Model<String>(""))); // temporary add //$NON-NLS-1$//$NON-NLS-2$
label.add(new StyleAppendingModifier(new Model<String>()
{
private static final long serialVersionUID = 1L;
@Override
public String getObject()
{
String style = "white-space: nowrap;"; //$NON-NLS-1$
if (font != null)
{
Pair<String, String>[] fontPropetiesPair = PersistHelper.createFontCSSProperties(PersistHelper.createFontString(font));
if (fontPropetiesPair != null)
{
for (Pair<String, String> element : fontPropetiesPair)
{
if (element == null) continue;
style += element.getLeft() + ": " + element.getRight() + ";"; //$NON-NLS-1$ //$NON-NLS-2$
}
}
}
if (holder.getForeground() != null)
{
style += " color:" + PersistHelper.createColorString(holder.getForeground()); //$NON-NLS-1$
}
else if (foreground != null)
{
style += " color:" + PersistHelper.createColorString(foreground); //$NON-NLS-1$
}
return style;
}
}));
}
});
add(new AbstractServoyDefaultAjaxBehavior()
{
@Override
protected void respond(AjaxRequestTarget target)
{
}
@Override
public void renderHead(IHeaderResponse response)
{
super.renderHead(response);
// avoid flickering, see also tabpanel
response.renderOnDomReadyJavascript("var accordion = document.getElementById('" + WebAccordionPanel.this.getMarkupId() +
"');if (accordion){accordion.style.visibility = 'inherit';}");
}
});
accordion.add(new StyleAppendingModifier(new Model<String>()
{
@Override
public String getObject()
{
if (getBorder() instanceof TitledBorder)
{
return "margin-top: -0.4em;"; //"padding: 6px 0px 0px 0px; margin-top: -8px;"; //$NON-NLS-1$
}
return ""; //$NON-NLS-1$
}
}));
add(new StyleAppendingModifier(new Model<String>()
{
private static final long serialVersionUID = 1L;
@Override
public String getObject()
{
return "visibility: hidden;"; //$NON-NLS-1$
}
}));
add(StyleAttributeModifierModel.INSTANCE);
this.scriptable = scriptable;
((ChangesRecorder)scriptable.getChangesRecorder()).setDefaultBorderAndPadding(null, TemplateGenerator.DEFAULT_LABEL_PADDING);
}
public final RuntimeAccordionPanel getScriptObject()
{
return scriptable;
}
public IStylePropertyChanges getStylePropertyChanges()
{
return scriptable.getChangesRecorder();
}
private void setActiveTabPanel(WebTabFormLookup fl)
{
if (fl != currentForm)
{
WebTabFormLookup previous = currentForm;
if (previous != null)
{
int stopped = application.getFoundSetManager().getEditRecordList().stopEditing(false);
boolean cantStop = stopped != ISaveConstants.STOPPED && stopped != ISaveConstants.AUTO_SAVE_BLOCKED;
List<Runnable> invokeLaterRunnables = new ArrayList<Runnable>();
boolean ok = previous.notifyVisible(false, invokeLaterRunnables);
Utils.invokeLater(application, invokeLaterRunnables);
if (cantStop || !ok)
{
return;
}
}
int previousIndex = -1;
for (int i = 0; i < allTabs.size(); i++)
{
WebTabHolder holder = allTabs.get(i);
if (holder.getPanel() == previous)
{
previousIndex = i;
break;
}
}
if (previousIndex != -1)
{
final int changedIndex = previousIndex;
addStateChange(new Change()
{
@Override
public void undo()
{
if (allTabs.size() > changedIndex)
{
WebTabHolder holder = allTabs.get(changedIndex);
setActiveTabPanel(holder.getPanel());
}
}
});
}
List<Runnable> invokeLaterRunnables2 = new ArrayList<Runnable>();
setCurrentForm(fl, previousIndex, invokeLaterRunnables2);
Utils.invokeLater(application, invokeLaterRunnables2);
}
}
private void setCurrentForm(WebTabFormLookup fl, int previousIndex, List<Runnable> invokeLaterRunnables)
{
if (fl != null && !fl.isFormReady()) return;
getStylePropertyChanges().setChanged();
currentForm = fl;
if (parentData != null)
{
showFoundSet(currentForm, parentData, getDefaultSort());
}
// Test if current one is there
if (currentForm.isReady())
{
addCurrentFormComponent();
recomputeTabSequence();
boolean visible = true;
WebForm webform = findParent(WebForm.class);
if (webform != null)
{
visible = webform.getController().isFormVisible();
}
currentForm.notifyVisible(visible, invokeLaterRunnables);
if (onTabChangeMethodCmd != null && previousIndex != -1)
{
scriptExecutor.executeFunction(onTabChangeMethodCmd, Utils.arrayMerge((new Object[] { Integer.valueOf(previousIndex + 1) }), onTabChangeArgs),
true, this, false, StaticContentSpecLoader.PROPERTY_ONCHANGEMETHODID.getPropertyName(), false);
}
}
}
private void addCurrentFormComponent()
{
if (currentForm.isReady())
{
int index = getTabIndex();
if (index >= 0)
{
MarkupContainer parent = (MarkupContainer)((MarkupContainer)accordion.get(0)).get(index);
if (parent != null)
{
if (parent.get(currentForm.getWebForm().getId()) != null)
{
// replace it
parent.replace(currentForm.getWebForm());
}
else
{
// else add it
parent.add(currentForm.getWebForm());
}
}
}
}
}
public WebForm getCurrentForm()
{
return currentForm != null ? currentForm.getWebForm() : null;
}
public IFormUI[] getChildForms()
{
WebForm form = getCurrentForm();
if (form != null && form.getParent() == null)
{
form = null;
}
return form != null ? new IFormUI[] { form } : null;
}
/**
* @see org.apache.wicket.MarkupContainer#remove(org.apache.wicket.Component)
*/
@Override
public void remove(Component component)
{
if (currentForm != null && currentForm.isReady() && component == currentForm.getWebForm())
{
currentForm.setWebForm(null);
//replace(new Label("webform", new Model<String>("")));
}
else super.remove(component);
}
public void recomputeTabSequence()
{
FormController fc = currentForm.getWebForm().getController();
fc.recomputeTabSequence(tabSequenceIndex);
}
public boolean isCurrentForm(IFormUI formUI)
{
return getCurrentForm() == formUI;
}
/**
* @see wicket.MarkupContainer#onRender(wicket.markup.MarkupStream)
*/
@Override
protected void onRender(MarkupStream markupStream)
{
super.onRender(markupStream);
getStylePropertyChanges().setRendered();
}
@Override
protected void onBeforeRender()
{
//tab has to be initialized now.. see also MainPage.listview.onBeforRender..
initalizeFirstTab();
super.onBeforeRender();
relinkFormIfNeeded();
}
public void initalizeFirstTab()
{
if (currentForm == null && allTabs.size() > 0)
{
WebTabHolder holder = allTabs.get(0);
List<Runnable> invokeLaterRunnables = new ArrayList<Runnable>();
setCurrentForm(holder.getPanel(), -1, invokeLaterRunnables);
Utils.invokeLater(application, invokeLaterRunnables);
}
else if (currentForm != null && currentForm.getWebForm() == null)
{
// webForm was removed from this tabpanel of the current Form (reuse or destroyed)
List<Runnable> invokeLaterRunnables = new ArrayList<Runnable>();
setCurrentForm(currentForm, -1, invokeLaterRunnables);
Utils.invokeLater(application, invokeLaterRunnables);
}
return;
}
private void relinkFormIfNeeded()
{
if (currentForm != null && isVisibleInHierarchy() && currentForm.getWebForm().findParent(ITabPanel.class) != this)
{
addCurrentFormComponent();
}
}
public void setTabLayoutPolicy(int scroll_tab_layout)
{
//TODO ignore???
}
public IFormLookupPanel createFormLookupPanel(String tabname, String relationName, String formName)
{
return new WebTabFormLookup(tabname, relationName, formName, this, application);
}
public void setCursor(Cursor cursor)
{
}
public void setValidationEnabled(boolean b)
{
}
public void notifyVisible(boolean visible, List<Runnable> invokeLaterRunnables)
{
if (currentForm == null && allTabs.size() > 0)
{
WebTabHolder holder = allTabs.get(0);
setCurrentForm(holder.getPanel(), -1, invokeLaterRunnables);
}
if (currentForm != null)
{
FormController controller = currentForm.getWebForm().getController();
//this is not needed when closing
if (visible && parentData != null)
{
showFoundSet(currentForm, parentData, controller.getDefaultSortColumns());
// Test if current one is there
if (currentForm.isReady())
{
addCurrentFormComponent();
recomputeTabSequence();
}
}
controller.notifyVisible(visible, invokeLaterRunnables);
}
}
public void notifyResized()
{
if (currentForm != null && currentForm.isReady())
{
WebForm webForm = currentForm.getWebForm();
FormController controller = webForm.getController();
if (controller != null && webForm.isFormWidthHeightChanged())
{
controller.notifyResized();
webForm.clearFormWidthHeightChangedFlag();
if (Utils.getAsBoolean(application.getRuntimeProperties().get("enableAnchors"))) //$NON-NLS-1$
{
scriptable.getChangesRecorder().setChanged();
}
}
}
}
public void setRecord(IRecordInternal parentState, boolean stopEditing)
{
parentData = parentState;
if (currentForm != null)
{
showFoundSet(currentForm, parentState, getDefaultSort());
}
else if (allTabs.size() > 0)
{
showFoundSet(allTabs.get(0).getPanel(), parentState, getDefaultSort());
}
ITagResolver resolver = getTagResolver(parentState);
for (int i = 0; i < allTabs.size(); i++)
{
WebTabHolder element = allTabs.get(i);
if (element.refreshTagStrings(resolver))
{
getStylePropertyChanges().setChanged();
}
}
}
private ITagResolver getTagResolver(IRecordInternal parentState)
{
ITagResolver resolver;
WebForm webForm = findParent(WebForm.class);
if (webForm != null)
{
resolver = webForm.getController().getTagResolver();
}
else
{
resolver = TagResolver.createResolver(parentState);
}
return resolver;
}
protected void showFoundSet(WebTabFormLookup flp, IRecordInternal parentState, List<SortColumn> sort)
{
deregisterSelectionListeners();
if (!flp.isReady()) return;
FormController fp = flp.getWebForm().getController();
if (fp != null && flp.getRelationName() != null)
{
IFoundSetInternal relatedFoundset = parentState == null ? null : parentState.getRelatedFoundSet(flp.getRelationName(), sort);
registerSelectionListeners(parentState, flp.getRelationName());
fp.loadData(relatedFoundset, null);
}
ITagResolver resolver = getTagResolver(parentState);
//refresh tab text
for (int i = 0; i < allTabs.size(); i++)
{
WebTabHolder element = allTabs.get(i);
if (element.getPanel() == flp)
{
element.refreshTagStrings(resolver);
break;
}
}
}
private void registerSelectionListeners(IRecordInternal parentState, String relationName)
{
String[] parts = relationName.split("\\."); //$NON-NLS-1$
IRecordInternal currentRecord = parentState;
for (int i = 0; currentRecord != null && i < parts.length - 1; i++)
{
IFoundSetInternal fs = currentRecord.getRelatedFoundSet(parts[i]);
if (fs instanceof ISwingFoundSet)
{
related.add((ISwingFoundSet)fs);
((ISwingFoundSet)fs).getSelectionModel().addListSelectionListener(this);
}
currentRecord = (fs == null) ? null : fs.getRecord(fs.getSelectedIndex());
}
}
private void deregisterSelectionListeners()
{
for (ISwingFoundSet fs : related)
{
fs.getSelectionModel().removeListSelectionListener(this);
}
related.clear();
}
public String getSelectedRelationName()
{
if (currentForm != null)
{
return currentForm.getRelationName();
}
return null;
}
public String[] getAllRelationNames()
{
String[] retval = new String[allRelationNames.size()];
for (int i = 0; i < retval.length; i++)
{
Object relationName = allRelationNames.get(i);
if (relationName != null)
{
retval[i] = relationName.toString();
}
}
return retval;
}
public List<SortColumn> getDefaultSort()
{
if (currentForm != null)
{
// extra test, if the current record is null and the form is not ready just return an empty list.
// record can be null in the destroy, then creating the form doesn't make any sense.
return currentForm.getDefaultSort(parentData != null || currentForm.isReady());
}
else if (allTabs.size() > 0)
{
WebTabHolder holder = allTabs.get(0);
return holder.getPanel().getDefaultSort(parentData != null || holder.getPanel().isReady());
}
return null;
}
public boolean stopUIEditing(boolean looseFocus)
{
if (currentForm != null && currentForm.isReady())
{
return currentForm.getWebForm().getController().stopUIEditing(true);
}
return true;
}
public void destroy()
{
deregisterSelectionListeners();
//TODO should deregister related foundsets??
}
public void addTab(String text, int iconMediaId, IFormLookupPanel flp, String tip)
{
byte[] iconData = ComponentFactory.loadIcon(application.getFlattenedSolution(), new Integer(iconMediaId));
insertTab(text, iconData, flp, tip, allTabs.size());
}
public void addTab(String text, byte[] iconData, IFormLookupPanel flp, String tip)
{
insertTab(text, iconData, flp, tip, allTabs.size());
}
public void insertTab(String text, byte[] iconData, IFormLookupPanel flp, String tip, int index)
{
allTabs.add(index, new WebTabHolder(text, flp, iconData, tip));
allRelationNames.add(index, flp.getRelationName());
getStylePropertyChanges().setChanged();
if (allTabs.size() == 1)
{
setActiveTabPanel((WebTabFormLookup)flp);
}
}
public void setTabForegroundAt(int index, Color fg)
{
if (index >= 0 && index < allTabs.size())
{
WebTabHolder holder = allTabs.get(index);
holder.setForeground(fg);
}
}
public void setTabBackgroundAt(int index, Color bg)
{
}
public boolean addTab(IForm formController, String formName, String tabname, String tabText, String tabtooltip, String iconURL, String fg, String bg,
String relationName, RelatedFoundSet relatedFs, int idx)
{
if (formController != null)
{
//to make sure we don't have recursion on adding a tab, to a tabpanel, that is based
//on the form that the tabpanel is placed on
WebForm webForm = findParent(WebForm.class);
if (webForm != null)
{
FormController parentFormController = webForm.getController();
if (parentFormController != null && parentFormController.equals(formController))
{
return false;
}
}
}
WebTabFormLookup flp = (WebTabFormLookup)createFormLookupPanel(tabname, relationName, formName);
if (formController != null) flp.setReadOnly(formController.isReadOnly());
byte[] iconData = null;
//TODO handle icon
int count = allTabs.size();
int tabIndex = idx;
if (tabIndex == -1 || tabIndex >= count)
{
tabIndex = count;
addTab(application.getI18NMessageIfPrefixed(tabText), iconData, flp, application.getI18NMessageIfPrefixed(tabtooltip));
}
else
{
insertTab(application.getI18NMessageIfPrefixed(tabText), iconData, flp, application.getI18NMessageIfPrefixed(tabtooltip), tabIndex);
}
if (fg != null) setTabForegroundAt(tabIndex, PersistHelper.createColor(fg));
if (bg != null) setTabBackgroundAt(tabIndex, PersistHelper.createColor(bg));
if (relatedFs != null && currentForm == flp)
{
FormController fp = flp.getWebForm().getController();
if (fp != null && flp.getRelationName() != null && flp.getRelationName().equals(relationName))
{
fp.loadData(relatedFs, null);
}
}
return true;
}
public int getMaxTabIndex()
{
return allTabs.size() - 1;
}
public String getTabFormNameAt(int i)
{
WebTabHolder holder = allTabs.get(i);
return holder.getPanel().getFormName();
}
public int getTabIndex()
{
for (int i = 0; i < allTabs.size(); i++)
{
if (currentForm == null)
{
// no current form set yet, default to first tab
return 0;
}
if (allTabs.get(i).getPanel() == currentForm)
{
return i;
}
}
return -1;
}
public String getTabNameAt(int i)
{
WebTabHolder holder = allTabs.get(i);
return holder.getPanel().getName();
}
public String getTabTextAt(int i)
{
WebTabHolder holder = allTabs.get(i);
return holder.getText();
}
public void setMnemonicAt(int i, int mnemonic)
{
WebTabHolder holder = allTabs.get(i);
holder.setDisplayedMnemonic(mnemonic);
}
public int getMnemonicAt(int i)
{
WebTabHolder holder = allTabs.get(i);
return holder.getDisplayedMnemonic();
}
public boolean isTabEnabledAt(int index)
{
WebTabHolder holder = allTabs.get(index);
return holder.isEnabled();
}
public boolean removeTabAt(int index)
{
WebTabHolder holder = allTabs.get(index);
List<Runnable> invokeLaterRunnables = new ArrayList<Runnable>();
boolean ok = holder.getPanel().notifyVisible(false, invokeLaterRunnables);
Utils.invokeLater(application, invokeLaterRunnables);
if (!ok)
{
return false;
}
allTabs.remove(index);
if (holder.getPanel() == currentForm)
{
if (allTabs.size() > 0)
{
setActiveTabPanel(allTabs.get(0).getPanel());
}
else
{
//safety
currentForm = null;
}
}
return true;
}
public boolean removeAllTabs()
{
for (int i = 0; i < allTabs.size(); i++)
{
WebTabHolder comp = allTabs.get(i);
List<Runnable> invokeLaterRunnables = new ArrayList<Runnable>();
boolean ok = comp.getPanel().notifyVisible(false, invokeLaterRunnables);
Utils.invokeLater(application, invokeLaterRunnables);
if (!ok)
{
return false;
}
}
allTabs.clear();
allRelationNames.clear();
//safety
currentForm = null;
return true;
}
public void setTabEnabledAt(int i, boolean b)
{
WebTabHolder holder = allTabs.get(i);
holder.setEnabled(b);
}
public void setTabIndex(int index)
{
setActiveTabPanel(allTabs.get(index).getPanel());
}
public void setTabIndex(String name)
{
for (int i = 0; i < allTabs.size(); i++)
{
WebTabHolder holder = allTabs.get(i);
if (Utils.stringSafeEquals(holder.getPanel().getName(), name))
{
setActiveTabPanel(holder.getPanel());
break;
}
}
}
public void setTabTextAt(int i, String s)
{
WebTabHolder holder = allTabs.get(i);
holder.setText(TemplateGenerator.getSafeText(s));
}
/*
* readonly---------------------------------------------------
*/
public boolean isReadOnly()
{
if (currentForm != null)
{
return currentForm.isReadOnly();
}
return false;
}
public void setReadOnly(boolean b)
{
for (int i = 0; i < allTabs.size(); i++)
{
WebTabHolder holder = allTabs.get(i);
holder.getPanel().setReadOnly(b);
}
}
public void setName(String n)
{
name = n;
}
private String name;
public String getName()
{
return name;
}
/*
* border---------------------------------------------------
*/
private Border border;
public void setBorder(Border border)
{
this.border = border;
}
public Border getBorder()
{
return border;
}
/*
* opaque---------------------------------------------------
*/
public void setOpaque(boolean opaque)
{
this.opaque = opaque;
}
private boolean opaque;
public boolean isOpaque()
{
return opaque;
}
private String tooltip;
public void setToolTipText(String tooltip)
{
this.tooltip = Utils.stringIsEmpty(tooltip) ? null : tooltip;
}
/**
* @see com.servoy.j2db.ui.IComponent#getToolTipText()
*/
public String getToolTipText()
{
return tooltip;
}
/*
* font---------------------------------------------------
*/
public void setFont(Font font)
{
this.font = font;
}
private Font font;
public Font getFont()
{
return font;
}
private Color background;
public void setBackground(Color cbg)
{
this.background = cbg;
}
public Color getBackground()
{
return background;
}
private Color foreground;
public void setForeground(Color cfg)
{
this.foreground = cfg;
}
public Color getForeground()
{
return foreground;
}
/*
* visible---------------------------------------------------
*/
public void setComponentVisible(boolean visible)
{
if (viewable)
{
setVisible(visible);
}
}
public void setComponentEnabled(final boolean b)
{
if (accessible)
{
super.setEnabled(b);
accordion.setDisabled(!b);
visitChildren(IComponent.class, new IVisitor<Component>()
{
public Object component(Component component)
{
if (component instanceof IComponent)
{
((IComponent)component).setComponentEnabled(b);
}
else
{
component.setEnabled(b);
}
return CONTINUE_TRAVERSAL;
}
});
getStylePropertyChanges().setChanged();
}
}
private boolean accessible = true;
public void setAccessible(boolean b)
{
if (!b) setComponentEnabled(b);
accessible = b;
}
private boolean viewable = true;
public void setViewable(boolean b)
{
if (!b) setComponentVisible(b);
this.viewable = b;
}
public boolean isViewable()
{
return viewable;
}
/*
* location---------------------------------------------------
*/
private Point location = new Point(0, 0);
public int getAbsoluteFormLocationY()
{
WebDataRenderer parent = findParent(WebDataRenderer.class);
if (parent != null)
{
return parent.getYOffset() + getLocation().y;
}
return getLocation().y;
}
public void setLocation(Point location)
{
this.location = location;
}
public Point getLocation()
{
return location;
}
/*
* size---------------------------------------------------
*/
private Dimension size = new Dimension(0, 0);
public Dimension getSize()
{
return size;
}
public Rectangle getWebBounds()
{
Dimension d = ((ChangesRecorder)getStylePropertyChanges()).calculateWebSize(size.width, size.height, border, new Insets(0, 0, 0, 0), 0, null);
return new Rectangle(location, d);
}
/**
* @see com.servoy.j2db.ui.ISupportWebBounds#getPaddingAndBorder()
*/
public Insets getPaddingAndBorder()
{
return ((ChangesRecorder)getStylePropertyChanges()).getPaddingAndBorder(size.height, border, new Insets(0, 0, 0, 0), 0, null);
}
public void setSize(Dimension size)
{
if (this.size != null && currentForm != null && currentForm.isReady())
{
currentForm.getWebForm().setFormWidth(0);
}
this.size = size;
}
/**
* @see com.servoy.j2db.ui.ITabPanel#addScriptExecuter(com.servoy.j2db.IScriptExecuter)
*/
public void addScriptExecuter(IScriptExecuter executor)
{
this.scriptExecutor = executor;
}
/**
* @see com.servoy.j2db.ui.ITabPanel#setOnTabChangeMethodCmd(java.lang.String, TabPanel)
*/
public void setOnTabChangeMethodCmd(String onTabChangeMethodCmd, Object[] onTabChangeArgs)
{
this.onTabChangeMethodCmd = onTabChangeMethodCmd;
this.onTabChangeArgs = onTabChangeArgs;
}
public void setTabSequenceIndex(int tabIndex)
{
this.tabSequenceIndex = tabIndex;
}
public int getTabSequenceIndex()
{
return tabSequenceIndex;
}
public int getTabIndex(WebForm current)
{
if (currentForm != null && currentForm.getWebForm() == current)
{
Object o = scriptable.js_getTabIndex();
if (o instanceof Integer)
{
if (((Integer)o).intValue() == -1) return -1;
return ((Integer)o).intValue() - 1;
}
}
for (int i = 0; i < allTabs.size(); i++)
{
WebTabHolder holder = allTabs.get(i);
if (holder.getPanel().getFormName() == current.getController().getName())
{
return i;
}
}
return -1;
}
public void valueChanged(ListSelectionEvent e)
{
if (parentData != null)
{
showFoundSet(currentForm, parentData, getDefaultSort());
}
}
public void setHorizontalAlignment(int alignment)
{
}
public ISupportSimulateBounds getBoundsProvider()
{
return findParent(ISupportSimulateBounds.class);
}
@Override
protected void onComponentTagBody(MarkupStream markupStream, ComponentTag openTag)
{
if (getBorder() instanceof TitledBorder)
{
getResponse().write(WebBaseButton.getTitledBorderOpenMarkup((TitledBorder)getBorder()));
}
super.onComponentTagBody(markupStream, openTag);
if (getBorder() instanceof TitledBorder)
{
getResponse().write(WebBaseButton.getTitledBorderCloseMarkup());
}
}
@Override
public void uiRecreated()
{// the Accordion must be rerendered to let it set the correct jqueryui accordion "ui-.." clases on the div (forms)
getStylePropertyChanges().setChanged();
recomputeTabSequence();
}
}