From 4394174bfff2f41db4bf03f7e5b2b22798d72a13 Mon Sep 17 00:00:00 2001 From: Lars Vogel Date: Sat, 11 Apr 2026 01:30:02 +0200 Subject: [PATCH] Replace Forms API with plain SWT in workspace dialogs MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Remove dependency on FormToolkit, ExpandableComposite, and ScrolledForm in ChooseWorkspaceDialog and ChooseWorkspaceWithSettingsDialog. Replace with plain SWT composites and Labels with Unicode triangle characters (U+25B8 ▸ / U+25BE ▾) for the expand/collapse toggle. This improves dialog startup performance by eliminating the Forms overhead: extra decorated composites, global paint/focus listeners, color management, and recursive ScrolledForm reflow on each toggle. The Unicode triangles are from the Geometric Shapes block (Unicode 1.0) and render reliably on Windows, macOS, and Linux system fonts. Also fix layout data mismatch where the path Combo used GridData inside a BorderLayout container (now uses BorderData). --- .../internal/ide/ChooseWorkspaceDialog.java | 83 ++++++++----- .../ChooseWorkspaceWithSettingsDialog.java | 114 ++++++++++-------- 2 files changed, 118 insertions(+), 79 deletions(-) diff --git a/bundles/org.eclipse.ui.ide/src/org/eclipse/ui/internal/ide/ChooseWorkspaceDialog.java b/bundles/org.eclipse.ui.ide/src/org/eclipse/ui/internal/ide/ChooseWorkspaceDialog.java index 78701c3ece16..7ecc039f6b35 100644 --- a/bundles/org.eclipse.ui.ide/src/org/eclipse/ui/internal/ide/ChooseWorkspaceDialog.java +++ b/bundles/org.eclipse.ui.ide/src/org/eclipse/ui/internal/ide/ChooseWorkspaceDialog.java @@ -39,6 +39,7 @@ import org.eclipse.jface.dialogs.IDialogConstants; import org.eclipse.jface.dialogs.IDialogSettings; import org.eclipse.jface.dialogs.TitleAreaDialog; +import org.eclipse.jface.resource.JFaceResources; import org.eclipse.jface.util.Geometry; import org.eclipse.jface.window.Window; import org.eclipse.osgi.util.NLS; @@ -70,11 +71,6 @@ import org.eclipse.swt.widgets.Monitor; import org.eclipse.swt.widgets.Shell; import org.eclipse.ui.PlatformUI; -import org.eclipse.ui.forms.events.ExpansionAdapter; -import org.eclipse.ui.forms.events.ExpansionEvent; -import org.eclipse.ui.forms.widgets.ExpandableComposite; -import org.eclipse.ui.forms.widgets.Form; -import org.eclipse.ui.forms.widgets.FormToolkit; import org.osgi.framework.FrameworkUtil; /** @@ -99,7 +95,7 @@ public class ChooseWorkspaceDialog extends TitleAreaDialog { private Map recentWorkspacesLinks; - private Form recentWorkspacesForm; + private Composite recentWorkspacesForm; private Button defaultButton; @@ -312,34 +308,61 @@ protected void cancelPressed() { * Workspace */ private void createRecentWorkspacesComposite(final Composite composite) { - FormToolkit toolkit = new FormToolkit(composite.getDisplay()); - composite.addDisposeListener(c -> toolkit.dispose()); - recentWorkspacesForm = toolkit.createForm(composite); + recentWorkspacesForm = new Composite(composite, SWT.NONE); recentWorkspacesForm.setBackground(composite.getBackground()); - recentWorkspacesForm.getBody().setLayout(new GridLayout()); - ExpandableComposite recentWorkspacesExpandable = toolkit.createExpandableComposite(recentWorkspacesForm.getBody(), - ExpandableComposite.TWISTIE); + recentWorkspacesForm.setLayout(new GridLayout()); recentWorkspacesForm.setLayoutData(new GridData(SWT.FILL, SWT.FILL, true, false)); - recentWorkspacesExpandable.setBackground(composite.getBackground()); - recentWorkspacesExpandable.setText(IDEWorkbenchMessages.ChooseWorkspaceDialog_recentWorkspaces); - recentWorkspacesExpandable.setExpanded(launchData.isShowRecentWorkspaces()); - recentWorkspacesExpandable.addExpansionListener(new ExpansionAdapter() { - @Override - public void expansionStateChanged(ExpansionEvent e) { - launchData.setShowRecentWorkspaces(((ExpandableComposite) e.getSource()).isExpanded()); - Point size = getInitialSize(); - Shell shell = getShell(); - shell.setBounds(getConstrainedShellBounds( - new Rectangle(shell.getLocation().x, shell.getLocation().y, size.x, size.y))); - } - }); - Composite panel = new Composite(recentWorkspacesExpandable, SWT.NONE); - recentWorkspacesExpandable.setClient(panel); + Composite header = new Composite(recentWorkspacesForm, SWT.NONE); + header.setLayoutData(new GridData(SWT.FILL, SWT.FILL, true, false)); + GridLayout headerLayout = new GridLayout(2, false); + headerLayout.marginWidth = 0; + headerLayout.marginHeight = 0; + header.setLayout(headerLayout); + header.setBackground(composite.getBackground()); + + Label toggle = new Label(header, SWT.NONE); + toggle.setBackground(composite.getBackground()); + toggle.setCursor(composite.getDisplay().getSystemCursor(SWT.CURSOR_HAND)); + + Label label = new Label(header, SWT.NONE); + label.setText(IDEWorkbenchMessages.ChooseWorkspaceDialog_recentWorkspaces); + label.setBackground(composite.getBackground()); + label.setFont(JFaceResources.getFontRegistry().getBold(JFaceResources.DIALOG_FONT)); + label.setCursor(composite.getDisplay().getSystemCursor(SWT.CURSOR_HAND)); + + Composite panel = new Composite(recentWorkspacesForm, SWT.NONE); + panel.setBackground(composite.getBackground()); + GridData panelData = new GridData(SWT.FILL, SWT.FILL, true, false); + panel.setLayoutData(panelData); + RowLayout layout = new RowLayout(SWT.VERTICAL); layout.marginLeft = 14; layout.spacing = 6; panel.setLayout(layout); + + boolean expanded = launchData.isShowRecentWorkspaces(); + panel.setVisible(expanded); + panelData.exclude = !expanded; + toggle.setText(expanded ? "\u25BE" : "\u25B8"); //$NON-NLS-1$ //$NON-NLS-2$ + + Listener toggleListener = e -> { + boolean newState = !panel.getVisible(); + panel.setVisible(newState); + ((GridData) panel.getLayoutData()).exclude = !newState; + toggle.setText(newState ? "\u25BE" : "\u25B8"); //$NON-NLS-1$ //$NON-NLS-2$ + launchData.setShowRecentWorkspaces(newState); + recentWorkspacesForm.requestLayout(); + + Point size = getInitialSize(); + Shell shell = getShell(); + shell.setBounds(getConstrainedShellBounds( + new Rectangle(shell.getLocation().x, shell.getLocation().y, size.x, size.y))); + }; + + toggle.addListener(SWT.MouseDown, toggleListener); + label.addListener(SWT.MouseDown, toggleListener); + List recentWorkspaces = getRecentWorkspaces(); recentWorkspacesLinks = new HashMap<>(recentWorkspaces.size()); Map uniqueWorkspaceNames = createUniqueWorkspaceNameMap(); @@ -526,7 +549,7 @@ protected Combo createPathCombo(Composite panel) { new DirectoryProposalContentAssist().apply(combo); combo.setTextDirection(SWT.AUTO_TEXT_DIRECTION); combo.setFocus(); - combo.setLayoutData(new GridData(400, SWT.DEFAULT)); + combo.setLayoutData(new BorderData(SWT.CENTER)); combo.addModifyListener(e -> { Button okButton = getButton(Window.OK); if(okButton != null && !okButton.isDisposed()) { @@ -705,9 +728,9 @@ public Combo getCombo() { /** * Get the "Recent Workspaces" form or null if not initialized. * - * @return Form + * @return Composite */ - public Form getRecentWorkspacesForm() { + public Composite getRecentWorkspacesForm() { return recentWorkspacesForm; } diff --git a/bundles/org.eclipse.ui.ide/src/org/eclipse/ui/internal/ide/ChooseWorkspaceWithSettingsDialog.java b/bundles/org.eclipse.ui.ide/src/org/eclipse/ui/internal/ide/ChooseWorkspaceWithSettingsDialog.java index 0955fae4425e..2dd0ecdb7a42 100644 --- a/bundles/org.eclipse.ui.ide/src/org/eclipse/ui/internal/ide/ChooseWorkspaceWithSettingsDialog.java +++ b/bundles/org.eclipse.ui.ide/src/org/eclipse/ui/internal/ide/ChooseWorkspaceWithSettingsDialog.java @@ -33,8 +33,10 @@ import org.eclipse.jface.dialogs.IDialogSettings; import org.eclipse.jface.fieldassist.ControlDecoration; import org.eclipse.jface.fieldassist.FieldDecorationRegistry; +import org.eclipse.jface.resource.JFaceResources; import org.eclipse.osgi.util.NLS; import org.eclipse.swt.SWT; +import org.eclipse.swt.custom.ScrolledComposite; import org.eclipse.swt.events.SelectionAdapter; import org.eclipse.swt.events.SelectionEvent; import org.eclipse.swt.graphics.Image; @@ -46,13 +48,10 @@ import org.eclipse.swt.widgets.Button; import org.eclipse.swt.widgets.Composite; import org.eclipse.swt.widgets.Control; +import org.eclipse.swt.widgets.Label; +import org.eclipse.swt.widgets.Listener; import org.eclipse.swt.widgets.Shell; import org.eclipse.ui.PlatformUI; -import org.eclipse.ui.forms.events.ExpansionEvent; -import org.eclipse.ui.forms.events.IExpansionListener; -import org.eclipse.ui.forms.widgets.ExpandableComposite; -import org.eclipse.ui.forms.widgets.FormToolkit; -import org.eclipse.ui.forms.widgets.ScrolledForm; import org.eclipse.ui.internal.WorkbenchPlugin; import org.eclipse.ui.preferences.SettingsTransfer; import org.osgi.framework.FrameworkUtil; @@ -116,47 +115,64 @@ protected Control createDialogArea(Composite parent) { * Create the controls for selecting the controls we are going to export. */ private void createSettingsControls(Composite workArea) { - final FormToolkit toolkit = new FormToolkit(workArea.getDisplay()); - workArea.addDisposeListener(e -> toolkit.dispose()); - final ScrolledForm form = toolkit.createScrolledForm(workArea); - form.getBody().setBackground(workArea.getBackground()); - form.getBody().setLayout(new GridLayout()); - form.setLayoutData(new GridData(SWT.FILL, SWT.FILL, true, true)); - - final ExpandableComposite copySettingsExpandable = - toolkit.createExpandableComposite(form.getBody(), ExpandableComposite.TWISTIE); - - copySettingsExpandable.setText(IDEWorkbenchMessages.ChooseWorkspaceWithSettingsDialog_SettingsGroupName); - copySettingsExpandable.setBackground(workArea.getBackground()); - copySettingsExpandable.setLayout(new GridLayout()); - copySettingsExpandable.setLayoutData(new GridData(SWT.FILL, SWT.FILL, true, false)); - copySettingsExpandable.addExpansionListener(new IExpansionListener() { - - @Override - public void expansionStateChanged(ExpansionEvent e) { - form.reflow(true); - Point size = getInitialSize(); - Shell shell = getShell(); - shell.setBounds(getConstrainedShellBounds( - new Rectangle(shell.getLocation().x, shell.getLocation().y, size.x, size.y))); - } - - @Override - public void expansionStateChanging(ExpansionEvent e) { - // Nothing to do here - - } - }); - - Composite sectionClient = toolkit.createComposite(copySettingsExpandable); + final ScrolledComposite sc = new ScrolledComposite(workArea, SWT.V_SCROLL | SWT.H_SCROLL); + sc.setExpandHorizontal(true); + sc.setExpandVertical(true); + sc.setLayoutData(new GridData(SWT.FILL, SWT.FILL, true, true)); + + Composite body = new Composite(sc, SWT.NONE); + body.setBackground(workArea.getBackground()); + body.setLayout(new GridLayout()); + sc.setContent(body); + + Composite header = new Composite(body, SWT.NONE); + header.setLayoutData(new GridData(SWT.FILL, SWT.FILL, true, false)); + GridLayout headerLayout = new GridLayout(2, false); + headerLayout.marginWidth = 0; + headerLayout.marginHeight = 0; + header.setLayout(headerLayout); + header.setBackground(workArea.getBackground()); + + Label toggle = new Label(header, SWT.NONE); + toggle.setBackground(workArea.getBackground()); + toggle.setCursor(workArea.getDisplay().getSystemCursor(SWT.CURSOR_HAND)); + + Label label = new Label(header, SWT.NONE); + label.setText(IDEWorkbenchMessages.ChooseWorkspaceWithSettingsDialog_SettingsGroupName); + label.setBackground(workArea.getBackground()); + label.setFont(JFaceResources.getFontRegistry().getBold(JFaceResources.DIALOG_FONT)); + label.setCursor(workArea.getDisplay().getSystemCursor(SWT.CURSOR_HAND)); + + Composite sectionClient = new Composite(body, SWT.NONE); sectionClient.setBackground(workArea.getBackground()); - - if (createButtons(toolkit, sectionClient)) { - copySettingsExpandable.setExpanded(true); - } - - copySettingsExpandable.setClient(sectionClient); - + GridData clientData = new GridData(SWT.FILL, SWT.FILL, true, false); + sectionClient.setLayoutData(clientData); + + boolean expanded = createButtons(sectionClient); + sectionClient.setVisible(expanded); + clientData.exclude = !expanded; + toggle.setText(expanded ? "\u25BE" : "\u25B8"); //$NON-NLS-1$ //$NON-NLS-2$ + + Listener toggleListener = e -> { + boolean newState = !sectionClient.getVisible(); + sectionClient.setVisible(newState); + ((GridData) sectionClient.getLayoutData()).exclude = !newState; + toggle.setText(newState ? "\u25BE" : "\u25B8"); //$NON-NLS-1$ //$NON-NLS-2$ + + body.layout(true); + sc.setMinSize(body.computeSize(SWT.DEFAULT, SWT.DEFAULT)); + + Point size = getInitialSize(); + Shell shell = getShell(); + shell.setBounds(getConstrainedShellBounds( + new Rectangle(shell.getLocation().x, shell.getLocation().y, size.x, size.y))); + }; + + toggle.addListener(SWT.MouseDown, toggleListener); + label.addListener(SWT.MouseDown, toggleListener); + + body.layout(true); + sc.setMinSize(body.computeSize(SWT.DEFAULT, SWT.DEFAULT)); } /** @@ -164,7 +180,7 @@ public void expansionStateChanging(ExpansionEvent e) { * * @return boolean true if any were selected */ - private boolean createButtons(FormToolkit toolkit, Composite sectionClient) { + private boolean createButtons(Composite sectionClient) { String[] enabledSettings = getEnabledSettings( PlatformUI.getDialogSettingsProvider(FrameworkUtil.getBundle(ChooseWorkspaceWithSettingsDialog.class)) .getDialogSettings() @@ -176,8 +192,9 @@ private boolean createButtons(FormToolkit toolkit, Composite sectionClient) { sectionClient.setLayout(layout); for (final IConfigurationElement settingsTransfer : SettingsTransfer.getSettingsTransfers()) { - final Button button = toolkit.createButton(sectionClient, - settingsTransfer.getAttribute(ATT_NAME), SWT.CHECK); + final Button button = new Button(sectionClient, SWT.CHECK); + button.setText(settingsTransfer.getAttribute(ATT_NAME)); + button.setBackground(sectionClient.getBackground()); ControlDecoration deco = new ControlDecoration(button, SWT.TOP | SWT.RIGHT); Image image = FieldDecorationRegistry.getDefault().getFieldDecoration(FieldDecorationRegistry.DEC_WARNING) @@ -206,7 +223,6 @@ private boolean createButtons(FormToolkit toolkit, Composite sectionClient) { } } - button.setBackground(sectionClient.getBackground()); button.addSelectionListener(new SelectionAdapter() { @Override