/* This file belongs to the Servoy development and deployment environment, Copyright (C) 1997-2010 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.smart.dataui; import java.awt.BorderLayout; import java.awt.Color; import java.awt.Component; import java.awt.Container; import java.awt.Graphics; import java.beans.PropertyChangeEvent; import java.beans.PropertyChangeListener; import java.util.ArrayList; import java.util.List; import javax.swing.JSplitPane; import javax.swing.SwingUtilities; import javax.swing.UIManager; import javax.swing.border.Border; import javax.swing.event.ListSelectionEvent; import javax.swing.event.ListSelectionListener; import com.servoy.j2db.FormController; import com.servoy.j2db.IApplication; import com.servoy.j2db.IForm; import com.servoy.j2db.IScriptExecuter; import com.servoy.j2db.dataprocessing.IDisplayRelatedData; import com.servoy.j2db.dataprocessing.IFoundSetInternal; import com.servoy.j2db.dataprocessing.IRecordInternal; import com.servoy.j2db.dataprocessing.ISwingFoundSet; import com.servoy.j2db.dataprocessing.RelatedFoundSet; import com.servoy.j2db.dataprocessing.SortColumn; import com.servoy.j2db.persistence.StaticContentSpecLoader; import com.servoy.j2db.scripting.FormScope; import com.servoy.j2db.ui.IDataRenderer; import com.servoy.j2db.ui.IFormLookupPanel; import com.servoy.j2db.ui.ISplitPane; import com.servoy.j2db.ui.ISupportSecuritySettings; import com.servoy.j2db.ui.scripting.RuntimeSplitPane; import com.servoy.j2db.util.EnablePanel; import com.servoy.j2db.util.IFocusCycleRoot; import com.servoy.j2db.util.ISupportFocusTransfer; import com.servoy.j2db.util.Utils; import com.servoy.j2db.util.gui.AutoTransferFocusListener; public class SpecialSplitPane extends EnablePanel implements ISplitPane, IDisplayRelatedData, ISupportSecuritySettings, IFocusCycleRoot<Component>, ISupportFocusTransfer, ListSelectionListener { private final IApplication application; private final SplitPane splitPane; private final List<String> allRelationNames = new ArrayList<String>(2); private final List<ISwingFoundSet> related = new ArrayList<ISwingFoundSet>(); private IRecordInternal parentData; private boolean accessible = true; private final List<Component> tabSeqComponentList = new ArrayList<Component>(); private boolean transferFocusBackwards = false; private String onDividerChangeMethodCmd; private IScriptExecuter scriptExecutor; private final RuntimeSplitPane scriptable; public SpecialSplitPane(IApplication app, RuntimeSplitPane scriptable, int orient, boolean design) { super(); application = app; setLayout(new BorderLayout()); splitPane = new SplitPane(orient, design); splitPane.addPropertyChangeListener(JSplitPane.DIVIDER_LOCATION_PROPERTY, new PropertyChangeListener() { public void propertyChange(PropertyChangeEvent evt) { if (onDividerChangeMethodCmd != null && scriptExecutor != null) { scriptExecutor.executeFunction(onDividerChangeMethodCmd, new Object[] { new Integer(-1) }, false, SpecialSplitPane.this, false, StaticContentSpecLoader.PROPERTY_ONCHANGEMETHODID.getPropertyName(), true); } } }); add(splitPane, BorderLayout.CENTER); setFocusTraversalPolicy(ServoyFocusTraversalPolicy.defaultPolicy); tabSeqComponentList.add(splitPane); addFocusListener(new AutoTransferFocusListener(this, this)); this.scriptable = scriptable; if (scriptable != null /* design mode */) scriptable.setEnclosingComponent(splitPane); } public final RuntimeSplitPane getScriptObject() { return scriptable; } /** * @return the splitPane */ public SplitPane getSplitPane() { return splitPane; } public String getId() { return (String)getClientProperty("Id"); //$NON-NLS-1$ } public void setComponentEnabled(boolean enabled) { if (accessible) { super.setEnabled(enabled); } } public void setComponentVisible(boolean visible) { if (viewable) { setVisible(visible); } } 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() { return null; } public String getSelectedRelationName() { return null; } public void notifyVisible(boolean visible, List<Runnable> invokeLaterRunnables) { Component[] components = splitPane.getSplitComponents(); for (Component c : components) { if (c instanceof FormLookupPanel) { notifyVisibleForm(visible, (FormLookupPanel)c, invokeLaterRunnables); } } } private boolean notifyVisibleForm(boolean visible, FormLookupPanel flp, List<Runnable> invokeLaterRunnables) { if (visible)//this is not needed when closing { FormController fp = flp.getFormPanel();//makes sure is visible if (fp != null) { if (parentData != null) { showFoundSet(flp, parentData, flp.getDefaultSort()); } } } return flp.notifyVisible(visible, invokeLaterRunnables); } public void setRecord(IRecordInternal parentState, boolean stopEditing) { parentData = parentState; Component[] components = splitPane.getSplitComponents(); FormLookupPanel flp; for (Component c : components) { if (c instanceof FormLookupPanel) { flp = (FormLookupPanel)c; showFoundSet(flp, parentState, flp.getDefaultSort()); } } } public boolean isReadOnly() { return !isEnabled(); } public void setValidationEnabled(boolean validationEnabled) { } public boolean stopUIEditing(boolean looseFocus) { Component[] components = splitPane.getSplitComponents(); FormLookupPanel flp; boolean stopUIEditing = true; for (Component c : components) { if (c instanceof FormLookupPanel) { flp = (FormLookupPanel)c; if (flp.isReady()) { stopUIEditing = stopUIEditing && flp.stopUIEditing(looseFocus); } } } return stopUIEditing; } public void destroy() { deregisterSelectionListeners(); } 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; } public void valueChanged(ListSelectionEvent e) { if (parentData != null) { Component[] components = splitPane.getSplitComponents(); FormLookupPanel flp; for (Component c : components) { if (c instanceof FormLookupPanel) { flp = (FormLookupPanel)c; flp.getFormPanel();//make sure the flp is ready showFoundSet(flp, parentData, flp.getDefaultSort()); } } } } @Override public void setOpaque(boolean isOpaque) { if (splitPane != null) splitPane.setOpaque(isOpaque); super.setOpaque(isOpaque); } public int getAbsoluteFormLocationY() { Container parent = getParent(); while ((parent != null) && !(parent instanceof IDataRenderer)) { parent = parent.getParent(); } if (parent != null) { return ((IDataRenderer)parent).getYOffset() + getLocation().y; } return getLocation().y; } @Override public void setBackground(Color bgcolor) { if (splitPane != null && bgcolor != null && !bgcolor.equals(UIManager.getColor("Panel.background"))) //$NON-NLS-1$ { splitPane.setBackground(bgcolor); } } @Override public Color getBackground() { if (splitPane != null) return splitPane.getBackground(); else return super.getBackground(); } @Override public void setBorder(Border b) { if (splitPane != null) splitPane.setBorder(b); } @Override public Border getBorder() { if (splitPane != null) return splitPane.getBorder(); else return super.getBorder(); } private void showFoundSet(FormLookupPanel flp, IRecordInternal parentState, List<SortColumn> sort) { deregisterSelectionListeners(); if (!flp.isReady()) return; try { FormController fp = flp.getFormPanel(); if (fp != null && flp.getRelationName() != null) { IFoundSetInternal relatedFoundSet = parentState == null ? null : parentState.getRelatedFoundSet(flp.getRelationName(), sort); registerSelectionListeners(parentState, flp.getRelationName()); fp.loadData(relatedFoundSet, null); } } catch (RuntimeException re) { application.handleException("Error setting the foundset of the relation " + flp.getRelationName() + " on the tab with form " + flp.getFormName(), re); throw re; } } 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 void setLeftForm(IFormLookupPanel flp) { allRelationNames.add(0, flp == null ? null : flp.getRelationName()); splitPane.setLeftForm((FormLookupPanel)flp); } public IFormLookupPanel getLeftForm() { Component leftComponent = splitPane.getLeftComponent(); return (leftComponent instanceof IFormLookupPanel) ? (IFormLookupPanel)leftComponent : null; } public void setRightForm(IFormLookupPanel flp) { allRelationNames.add(allRelationNames.size() > 0 ? 1 : 0, flp == null ? null : flp.getRelationName()); splitPane.setRightForm((FormLookupPanel)flp); } public IFormLookupPanel getRightForm() { Component rightComponent = splitPane.getRightComponent(); return (rightComponent instanceof IFormLookupPanel) ? (IFormLookupPanel)rightComponent : null; } public FormLookupPanel createFormLookupPanel(String tabname, String relationName, String formName) { return new FormLookupPanel(application, tabname, relationName, formName); } public FormScope getForm(boolean bLeftForm) { Component component = bLeftForm ? splitPane.getLeftComponent() : splitPane.getRightComponent(); if (component instanceof FormLookupPanel) return ((FormLookupPanel)component).getFormPanel().getFormScope(); return null; } public void setDividerLocation(final double location) { setRuntimeDividerLocation(location); } public void setRuntimeDividerLocation(final double location) { if (location < 1) { splitPane.setDividerLocation(location); if (!isValid()) { SwingUtilities.invokeLater(new Runnable() { public void run() { // if not valid, sizes may be incorrect; hopefully now we have correct values // first call is for getter to work immediately splitPane.setDividerLocation(location); } }); } } else splitPane.setDividerLocation((int)location); } public double getDividerLocation() { return splitPane.getDividerLocation(); } public void setDividerSize(int size) { splitPane.setDividerSize(size < 1 ? -1 : size); } public int getDividerSize() { return splitPane.getDividerSize(); } public double getResizeWeight() { return splitPane.getResizeWeight(); } public void setResizeWeight(double resizeWeight) { splitPane.setResizeWeight(resizeWeight); } public boolean getContinuousLayout() { return splitPane.isContinuousLayout(); } public void setContinuousLayout(boolean b) { splitPane.setContinuousLayout(b); } public int getFormMinSize(boolean bLeftForm) { return bLeftForm ? splitPane.getLeftFormMinSize() : splitPane.getRightFormMinSize(); } public void setFormMinSize(boolean bLeftForm, int minSize) { if (bLeftForm) { splitPane.setLeftFormMinSize(minSize); } else { splitPane.setRightFormMinSize(minSize); } } public boolean setForm(boolean bLeftForm, Object form, Object relation) { FormController f = null; String fName = null; boolean readOnly = false; if (form instanceof FormController) { f = (FormController)form; readOnly = f.isReadOnly(); } if (form instanceof FormController.JSForm) { f = (FormController)((FormController.JSForm)form).getFormPanel(); readOnly = f.isReadOnly(); } if (f != null) fName = f.getName(); if (form instanceof String) fName = (String)form; if (fName != null) { String name = fName; RelatedFoundSet relatedFs = null; String relationName = null; if (relation instanceof RelatedFoundSet) { relatedFs = (RelatedFoundSet)relation; } else if (relation instanceof String) { relationName = (String)relation; } if (relatedFs != null) { relationName = relatedFs.getRelationName(); if (f != null && !relatedFs.getDataSource().equals(f.getDataSource())) { return false; } // TODO do this check to check if the parent table has this relation? How to get the parent table // Table parentTable = null; // application.getSolution().getRelations(Solution.SOLUTION+Solution.MODULES, parentTable, true, false); } IFormLookupPanel replacedForm = bLeftForm ? getLeftForm() : getRightForm(); if (replacedForm != null) { List<Runnable> invokeLaterRunnables = new ArrayList<Runnable>(0); boolean bNotifyVisibleForm = notifyVisibleForm(false, (FormLookupPanel)replacedForm, invokeLaterRunnables); Utils.invokeLater(application, invokeLaterRunnables); if (!bNotifyVisibleForm) return false; } FormLookupPanel flp = createFormLookupPanel(name, relationName, fName); if (f != null) flp.setReadOnly(readOnly); if (bLeftForm) setLeftForm(flp); else setRightForm(flp); if (relatedFs != null) { FormController fp = flp.getFormPanel(); if (fp != null && flp.getRelationName() != null && flp.getRelationName().equals(relationName)) { fp.loadData(relatedFs, null); } } List<Runnable> invokeLaterRunnables = new ArrayList<Runnable>(0); boolean bNotifyVisibleForm = notifyVisibleForm(true, flp, invokeLaterRunnables); Utils.invokeLater(application, invokeLaterRunnables); return bNotifyVisibleForm; } else if (form == null) { IFormLookupPanel replacedForm = bLeftForm ? getLeftForm() : getRightForm(); if (replacedForm != null) { List<Runnable> invokeLaterRunnables = new ArrayList<Runnable>(0); boolean bNotifyVisibleForm = notifyVisibleForm(false, (FormLookupPanel)replacedForm, invokeLaterRunnables); Utils.invokeLater(application, invokeLaterRunnables); if (!bNotifyVisibleForm) return false; } if (bLeftForm) setLeftForm(null); else setRightForm(null); return true; } return false; } public Component getFirstFocusableField() { return splitPane; } public Component getLastFocusableField() { return splitPane; } public List<Component> getTabSeqComponents() { return tabSeqComponentList; } public boolean isTraversalPolicyEnabled() { return true; } public void setTabSeqComponents(List<Component> tabSequence) { // ignore } public boolean isTransferFocusBackwards() { return transferFocusBackwards; } public void setTransferFocusBackwards(boolean transferBackwards) { this.transferFocusBackwards = transferBackwards; } @Override protected void paintBorder(Graphics g) { Border border = splitPane.getBorder(); if (border != null) { border.paintBorder(splitPane, g, 0, 0, getWidth(), getHeight()); } } @Override public String toString() { return "SpecialSplitPane, name='" + getName() + "', hash " + hashCode(); //$NON-NLS-1$ //$NON-NLS-2$ } /* * (non-Javadoc) * * @see com.servoy.j2db.ui.ISplitPane#setOnDividerChangeMethodCmd(java.lang.String) */ public void setOnDividerChangeMethodCmd(String onDividerChangeMethodCmd) { this.onDividerChangeMethodCmd = onDividerChangeMethodCmd; } /* * (non-Javadoc) * * @see com.servoy.j2db.ui.ISplitPane#addScriptExecuter(com.servoy.j2db.IScriptExecuter) */ public void addScriptExecuter(IScriptExecuter el) { this.scriptExecutor = el; } /* * (non-Javadoc) * * @see com.servoy.j2db.ui.ITabPanel#setTabLayoutPolicy(int) */ public void setTabLayoutPolicy(int scroll_tab_layout) { // IGNORE } /* * (non-Javadoc) * * @see com.servoy.j2db.ui.ITabPanel#addTab(java.lang.String, int, com.servoy.j2db.ui.IFormLookupPanel, java.lang.String) */ public void addTab(String text, int iconMediaId, IFormLookupPanel flp, String tooltip) { // IGNORE } /* * (non-Javadoc) * * @see com.servoy.j2db.ui.ITabPanel#setTabForegroundAt(int, java.awt.Color) */ public void setTabForegroundAt(int index, Color fg) { // IGNORE } /* * (non-Javadoc) * * @see com.servoy.j2db.ui.ITabPanel#setTabBackgroundAt(int, java.awt.Color) */ public void setTabBackgroundAt(int index, Color bg) { // IGNORE } /* * (non-Javadoc) * * @see com.servoy.j2db.ui.ITabPanel#setTabEnabledAt(int, boolean) */ public void setTabEnabledAt(int index, boolean enabled) { IFormLookupPanel form = index == 0 ? getLeftForm() : index == 1 ? getRightForm() : null; if (form instanceof FormLookupPanel) ((FormLookupPanel)form).setEnabled(enabled); } /* * (non-Javadoc) * * @see com.servoy.j2db.ui.ITabPanel#setOnTabChangeMethodCmd(java.lang.String, java.lang.Object[]) */ public void setOnTabChangeMethodCmd(String onTabChangeMethodCmd, Object[] onTabChangeArgs) { // IGNORE } /* * (non-Javadoc) * * @see com.servoy.j2db.ui.ITabPanel#removeTabAt(int) */ public boolean removeTabAt(int index) { return false; } /* * (non-Javadoc) * * @see com.servoy.j2db.ui.ITabPanel#removeAllTabs() */ public boolean removeAllTabs() { return false; } /* * (non-Javadoc) * * @see com.servoy.j2db.ui.ITabPanel#addTab(com.servoy.j2db.IForm, java.lang.String, java.lang.String, java.lang.String, java.lang.String, java.lang.String, * java.lang.String, java.lang.String, java.lang.String, com.servoy.j2db.dataprocessing.RelatedFoundSet, int) */ public boolean addTab(IForm formController, String formName, String tabname, String tabText, String tooltip, String iconURL, String fg, String bg, String relationName, RelatedFoundSet relatedFs, int tabIndex) { return false; } /* * (non-Javadoc) * * @see com.servoy.j2db.ui.ITabPanel#setTabTextAt(int, java.lang.String) */ public void setTabTextAt(int i, String text) { // IGNORE } /* * (non-Javadoc) * * @see com.servoy.j2db.ui.ITabPanel#getTabTextAt(int) */ public String getTabTextAt(int i) { return null; } /* * (non-Javadoc) * * @see com.servoy.j2db.ui.ITabPanel#setMnemonicAt(int, int) */ public void setMnemonicAt(int i, int mnemonic) { // IGNORE } /* * (non-Javadoc) * * @see com.servoy.j2db.ui.ITabPanel#getMnemonicAt(int) */ public int getMnemonicAt(int i) { return 0; } /* * (non-Javadoc) * * @see com.servoy.j2db.ui.ITabPanel#getTabNameAt(int) */ public String getTabNameAt(int i) { IFormLookupPanel form = i == 0 ? getLeftForm() : i == 1 ? getRightForm() : null; return form != null ? form.getName() : null; } /* * (non-Javadoc) * * @see com.servoy.j2db.ui.ITabPanel#getTabFormNameAt(int) */ public String getTabFormNameAt(int i) { IFormLookupPanel form = i == 0 ? getLeftForm() : i == 1 ? getRightForm() : null; return form != null ? form.getFormName() : null; } /* * (non-Javadoc) * * @see com.servoy.j2db.ui.ITabPanel#setTabIndex(int) */ public void setTabIndex(int index) { // IGNORE } /* * (non-Javadoc) * * @see com.servoy.j2db.ui.ITabPanel#setTabIndex(java.lang.String) */ public void setTabIndex(String name) { // IGNORE } /* * (non-Javadoc) * * @see com.servoy.j2db.ui.ITabPanel#isTabEnabledAt(int) */ public boolean isTabEnabledAt(int index) { IFormLookupPanel form = index == 0 ? getLeftForm() : index == 1 ? getRightForm() : null; if (form instanceof FormLookupPanel) return ((FormLookupPanel)form).isEnabled(); return false; } /* * (non-Javadoc) * * @see com.servoy.j2db.ui.ITabPanel#getTabIndex() */ public int getTabIndex() { // TODO Auto-generated method stub return 0; } /* * (non-Javadoc) * * @see com.servoy.j2db.ui.ITabPanel#getMaxTabIndex() */ public int getMaxTabIndex() { return 1; } /* * (non-Javadoc) * * @see com.servoy.j2db.ui.ITabPanel#setHorizontalAlignment(int) */ public void setHorizontalAlignment(int alignment) { // IGNORE } }