package org.eclipse.dltk.ui.preferences; import java.util.HashSet; import java.util.Iterator; import java.util.Set; import org.eclipse.core.runtime.Assert; import org.eclipse.dltk.internal.ui.preferences.ScrolledPageContent; import org.eclipse.jface.preference.IPreferenceStore; import org.eclipse.jface.resource.JFaceResources; import org.eclipse.swt.SWT; import org.eclipse.swt.layout.GridData; import org.eclipse.swt.layout.GridLayout; import org.eclipse.swt.widgets.Composite; import org.eclipse.swt.widgets.Control; import org.eclipse.ui.forms.events.ExpansionAdapter; import org.eclipse.ui.forms.events.ExpansionEvent; import org.eclipse.ui.forms.widgets.ExpandableComposite; /** * Use as follows: * * <pre> * SectionManager manager= new SectionManager(); * Composite composite= manager.createSectionComposite(parent); * * Composite xSection= manager.createSection("section X")); * xSection.setLayout(new FillLayout()); * new Button(xSection, SWT.PUSH); // add controls to section.. * * [...] * * return composite; // return main composite * </pre> */ public class SectionManager { /** The preference setting for keeping no section open. */ private static final String __NONE = "__none"; //$NON-NLS-1$ private Set fSections = new HashSet(); private boolean fIsBeingManaged = false; private ExpansionAdapter fListener = new ExpansionAdapter() { @Override public void expansionStateChanged(ExpansionEvent e) { ExpandableComposite source = (ExpandableComposite) e .getSource(); updateSectionStyle(source); if (fIsBeingManaged) return; if (e.getState()) { try { fIsBeingManaged = true; for (Iterator iter = fSections.iterator(); iter .hasNext();) { ExpandableComposite composite = (ExpandableComposite) iter .next(); if (composite != source) composite.setExpanded(false); } } finally { fIsBeingManaged = false; } if (fLastOpenKey != null && fDialogSettingsStore != null) fDialogSettingsStore.setValue(fLastOpenKey, source .getText()); } else { if (!fIsBeingManaged && fLastOpenKey != null && fDialogSettingsStore != null) fDialogSettingsStore.setValue(fLastOpenKey, __NONE); } ExpandableComposite exComp = getParentExpandableComposite(source); if (exComp != null) exComp.layout(true, true); ScrolledPageContent parentScrolledComposite = getParentScrolledComposite(source); if (parentScrolledComposite != null) { parentScrolledComposite.reflow(true); } } }; private final ExpandableComposite getParentExpandableComposite( Control control) { Control parent = control.getParent(); while (!(parent instanceof ExpandableComposite) && parent != null) { parent = parent.getParent(); } if (parent instanceof ExpandableComposite) { return (ExpandableComposite) parent; } return null; } protected final ScrolledPageContent getParentScrolledComposite( Control control) { Control parent = control.getParent(); while (!(parent instanceof ScrolledPageContent) && parent != null) { parent = parent.getParent(); } if (parent instanceof ScrolledPageContent) { return (ScrolledPageContent) parent; } return null; } private boolean isNestedInScrolledComposite(Composite parent) { return getParentScrolledComposite(parent) != null; } private Composite fBody; private final String fLastOpenKey; private final IPreferenceStore fDialogSettingsStore; private ExpandableComposite fFirstChild = null; /** * Creates a new section manager. */ public SectionManager() { this(null, null); } /** * Creates a new section manager. */ public SectionManager(IPreferenceStore dialogSettingsStore, String lastOpenKey) { fDialogSettingsStore = dialogSettingsStore; fLastOpenKey = lastOpenKey; } private void manage(ExpandableComposite section) { if (section == null) throw new NullPointerException(); if (fSections.add(section)) section.addExpansionListener(fListener); makeScrollableCompositeAware(section); } /** * Creates a new composite that can contain a set of expandable * sections. A <code>ScrolledPageComposite</code> is created and a new * composite within that, to ensure that expanding the sections will * always have enough space, unless there already is a * <code>ScrolledComposite</code> along the parent chain of * <code>parent</code>, in which case a normal <code>Composite</code> * is created. * <p> * The receiver keeps a reference to the inner body composite, so that * new sections can be added via <code>createSection</code>. * </p> * * @param parent * the parent composite * @return the newly created composite */ public Composite createSectionComposite(Composite parent) { Assert.isTrue(fBody == null); boolean isNested = isNestedInScrolledComposite(parent); Composite composite; if (isNested) { composite = new Composite(parent, SWT.NONE); fBody = composite; } else { composite = new ScrolledPageContent(parent); fBody = ((ScrolledPageContent) composite).getBody(); } fBody.setLayout(new GridLayout()); return composite; } private void makeScrollableCompositeAware(Control control) { ScrolledPageContent parentScrolledComposite = getParentScrolledComposite(control); if (parentScrolledComposite != null) { parentScrolledComposite.adaptChild(control); } } protected void updateSectionStyle(ExpandableComposite excomposite) { excomposite.setFont(JFaceResources.getFontRegistry().getBold( JFaceResources.DIALOG_FONT)); } /** * Creates an expandable section within the parent created previously by * calling <code>createSectionComposite</code>. Controls can be added * directly to the returned composite, which has no layout initially. * * @param label * the display name of the section * @return a composite within the expandable section */ public Composite createSection(String label) { Assert.isNotNull(fBody); final ExpandableComposite excomposite = new ExpandableComposite( fBody, SWT.NONE, ExpandableComposite.TWISTIE | ExpandableComposite.CLIENT_INDENT | ExpandableComposite.COMPACT); if (fFirstChild == null) fFirstChild = excomposite; excomposite.setText(label); String last = null; if (fLastOpenKey != null && fDialogSettingsStore != null) last = fDialogSettingsStore.getString(fLastOpenKey); if (fFirstChild == excomposite && !__NONE.equals(last) || label.equals(last)) { excomposite.setExpanded(true); if (fFirstChild != excomposite) fFirstChild.setExpanded(false); } else { excomposite.setExpanded(false); } excomposite.setLayoutData(new GridData(GridData.FILL, GridData.BEGINNING, true, false)); updateSectionStyle(excomposite); manage(excomposite); Composite contents = new Composite(excomposite, SWT.NONE); excomposite.setClient(contents); return contents; } }