/* 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(); } }