Focus control for Boot wizards

This commit is contained in:
aboyko
2023-01-09 18:17:11 -05:00
parent 5f25dedcc2
commit b16c7894a8
10 changed files with 106 additions and 75 deletions

View File

@@ -1,5 +1,5 @@
/*******************************************************************************
* Copyright (c) 2017 Pivotal, Inc.
* Copyright (c) 2017, 2023 Pivotal, Inc.
* All rights reserved. This program and the accompanying materials
* are made available under the terms of the Eclipse Public License v1.0
* which accompanies this distribution, and is available at
@@ -40,6 +40,8 @@ public class DynamicSection extends ReflowableSection {
private Integer widthHint = DEFAULT_MIN_SIZE.y;
private Integer heightHint = DEFAULT_MIN_SIZE.x;
private boolean isFocused;
public DynamicSection(IPageWithSections owner, LiveExpression<IPageSection> content) {
super(owner);
this.content = content;
@@ -90,6 +92,9 @@ public class DynamicSection extends ReflowableSection {
} else {
validator.setDelegate(null);
}
if (isFocused) {
newContents.setFocus();
}
}
@Override
@@ -104,4 +109,12 @@ public class DynamicSection extends ReflowableSection {
super.dispose();
}
@Override
public void setFocus() {
isFocused = true;
if (content.getValue() != null) {
content.getValue().setFocus();
}
}
}

View File

@@ -15,7 +15,6 @@ import java.util.List;
import org.eclipse.swt.SWT;
import org.eclipse.swt.graphics.Point;
import org.eclipse.ui.PlatformUI;
import org.springframework.ide.eclipse.boot.core.initializr.InitializrServiceSpec.Dependency;
import org.springframework.ide.eclipse.boot.livexp.ui.DynamicSection;
import org.springframework.ide.eclipse.boot.wizard.CheckBoxesSection.CheckBoxModel;
@@ -74,12 +73,12 @@ public class MultipleViewsDependencyPage extends WizardPageWithSections {
sections.add(createFrequentlyUsedSection(model));
sections.add(createTwoColumnSection(model));
return new GroupSection(this, null, sections.toArray(new WizardPageSection[0])).grabVertical(true);
return new GroupSection(this, null, 2, sections.toArray(new WizardPageSection[0])).grabVertical(true);
}
public WizardPageSection createTwoColumnSection(final NewSpringBootWizardModel model) {
return new GroupSection(this,null,
new GroupSection(this, null,
return new GroupSection(this, null, 0,
new GroupSection(this, null, 1,
new CommentSection(this, "Available:"),
getSearchSection(model),
new GroupSection(this, "",
@@ -113,14 +112,12 @@ public class MultipleViewsDependencyPage extends WizardPageWithSections {
}
protected WizardPageSection getSearchSection(final NewSpringBootWizardModel model) {
final SearchBoxSection searchBoxSection = new SearchBoxSection(this, model.getDependencyFilterBoxText()) {
return new SearchBoxSection(this, model.getDependencyFilterBoxText()) {
@Override
protected String getSearchHint() {
return "Type to search dependencies";
}
};
PlatformUI.getWorkbench().getDisplay().asyncExec(() -> getControl().addListener(SWT.Show, event -> searchBoxSection.focusControl()));
return new GroupSection(this, null, searchBoxSection.grabFocus(true));
}
protected WizardPageSection createFrequentlyUsedSection(NewSpringBootWizardModel model) {
@@ -134,4 +131,12 @@ public class MultipleViewsDependencyPage extends WizardPageWithSections {
return frequentlyUsedSection;
}
@Override
public void setVisible(boolean visible) {
super.setVisible(visible);
if (visible) {
getSections().get(0).setFocus();
}
}
}

View File

@@ -101,6 +101,7 @@ public class NewSpringBootWizard extends Wizard implements INewWizard, IImportWi
super(owner, null);
this.model = model;
addSections(createSections().toArray(new WizardPageSection[0]));
focusSectionIndex = 0;
}
protected List<WizardPageSection> createSections() {
@@ -174,10 +175,19 @@ public class NewSpringBootWizard extends Wizard implements INewWizard, IImportWi
return new ProjectDetailsSection(this, dynamicModel);
}
return new CommentSection(this, NO_CONTENT_AVAILABLE);
} ));
}));
return ImmutableList.of(comboSection, dynamicSection);
}
@Override
public void setVisible(boolean visible) {
super.setVisible(visible);
if (visible) {
getSections().get(1).setFocus();
}
}
}

View File

@@ -1,5 +1,5 @@
/*******************************************************************************
* Copyright (c) 2015, 2020 Pivotal Software, Inc.
* Copyright (c) 2015, 2023 Pivotal Software, Inc.
* All rights reserved. This program and the accompanying materials
* are made available under the terms of the Eclipse Public License v1.0
* which accompanies this distribution, and is available at
@@ -14,8 +14,6 @@ import org.eclipse.jface.layout.GridDataFactory;
import org.eclipse.swt.SWT;
import org.eclipse.swt.events.ModifyEvent;
import org.eclipse.swt.events.ModifyListener;
import org.eclipse.swt.events.PaintEvent;
import org.eclipse.swt.events.PaintListener;
import org.eclipse.swt.widgets.Composite;
import org.eclipse.swt.widgets.Control;
import org.eclipse.swt.widgets.Text;
@@ -39,7 +37,6 @@ public class SearchBoxSection extends WizardPageSection implements Disposable {
private Text searchBox;
private LiveVariable<String> model;
private ValueListener<String> modelListener;
private boolean grabFocus;
public SearchBoxSection(IPageWithSections owner, LiveVariable<String> model) {
super(owner);
@@ -76,9 +73,6 @@ public class SearchBoxSection extends WizardPageSection implements Disposable {
}
}
});
if (grabFocus) {
focusControl();
}
// IContentProposalProvider proposalProvider = new TagContentProposalProvider(viewModel);
// ContentProposalAdapter caAdapter = new ContentProposalAdapter(searchBox, new TextContentAdapter(), proposalProvider, UIUtils.CTRL_SPACE, null);
// caAdapter.setProposalAcceptanceStyle(ContentProposalAdapter.PROPOSAL_REPLACE);
@@ -97,31 +91,15 @@ public class SearchBoxSection extends WizardPageSection implements Disposable {
searchBox.dispose();
}
/**
* When the control for this section is created, it will attempt to immediately grab
* keyboard focus.
*/
public SearchBoxSection grabFocus(boolean grab) {
this.grabFocus = grab;
return this;
}
public void focusControl() {
if (searchBox != null) {
if (!searchBox.setFocus()) {
searchBox.addPaintListener(new PaintListener() {
@Override
public void paintControl(PaintEvent e) {
if (searchBox.setFocus()) {
searchBox.removePaintListener(this);
}
}
});
}
}
}
protected Control getControl() {
return searchBox;
}
@Override
public void setFocus() {
if (searchBox != null && !searchBox.isDisposed()) {
searchBox.setFocus();
}
}
}

View File

@@ -288,8 +288,6 @@ public class ChooseTypedContentSection extends WizardPageSection {
}
};
// PT 164654725 - IMPORTANT: set grab focus BEFORE creating content
searchBox.grabFocus(true);
searchBox.createContents(field);
Label fieldNameLabel = null;
@@ -431,6 +429,14 @@ public class ChooseTypedContentSection extends WizardPageSection {
}
@Override
public void setFocus() {
if (searchBox != null) {
searchBox.setFocus();
}
}
// private String[] getLabels() {
// String[] labels = new String[options.length];
// for (int i = 0; i < labels.length; i++) {
@@ -439,4 +445,6 @@ public class ChooseTypedContentSection extends WizardPageSection {
// return labels;
// }
}

View File

@@ -127,6 +127,7 @@ public class GSImportWizard extends Wizard implements IImportWizard, INewWizard
// }
// }
@Override
public void init(IWorkbench workbench, IStructuredSelection selection) {
// this.workbench = workbench;
// super.init(workbench, selection);

View File

@@ -97,9 +97,10 @@ public class DependencyPage extends WizardPageWithSections {
createDynamicSections(model, sections);
}
GroupSection groupSection = new GroupSection(DependencyPage.this, null,
GroupSection groupSection = new GroupSection(DependencyPage.this, null, 1,
sections.toArray(new WizardPageSection[0]));
groupSection.grabVertical(true);
groupSection.setFocus();
return groupSection;
}
};
@@ -193,6 +194,12 @@ public class DependencyPage extends WizardPageWithSections {
String message = ExceptionUtil.getMessage(e);
setErrorMessage(message);
Log.log(e);
} finally {
// After loading of starters data is completed set the focus to the search box.
// It is highly unlikely that use had the time to switch focus to anything else.
if (dynamicControlCreation.getValue() != null) {
dynamicControlCreation.getValue().setFocus();
}
}
});
}
@@ -204,8 +211,8 @@ public class DependencyPage extends WizardPageWithSections {
@SuppressWarnings("resource")
public WizardPageSection createTwoColumnSection(final InitializrModel model) {
return new GroupSection(this,null,
new GroupSection(this, null,
return new GroupSection(this, null, 0,
new GroupSection(this, null, 1,
new CommentSection(this, "Available:"),
getSearchSection(model),
new GroupSection(this, "",
@@ -239,39 +246,13 @@ public class DependencyPage extends WizardPageWithSections {
}
protected WizardPageSection getSearchSection(final InitializrModel model) {
final SearchBoxSection searchBoxSection = new SearchBoxSection(this, model.searchBox.getText()) {
return new SearchBoxSection(this, model.searchBox.getText()) {
@Override
protected String getSearchHint() {
return "Type to search dependencies";
}
@Override
public void focusControl() {
Control searchControl = getControl();
if (searchControl != null && !searchControl.isDisposed()) {
searchControl.setFocus();
}
}
}.grabFocus(true);
// PT 174313406 - Async focus on search box. Dynamic creation seems to interfere with grabbing focus on the search box upon control creation
// therefore set it asynchronously
asyncSetFocus(searchBoxSection);
return searchBoxSection;
}
private void asyncSetFocus(SearchBoxSection searchBoxSection) {
UIJob showJob = new UIJob("Focus search box") {
@Override
public IStatus runInUIThread(IProgressMonitor monitor) {
searchBoxSection.focusControl();
return Status.OK_STATUS;
}
};
showJob.setSystem(true);
showJob.schedule(1000);
}
@SuppressWarnings("resource")
@@ -326,6 +307,17 @@ public class DependencyPage extends WizardPageWithSections {
}
}
@Override
public void setVisible(boolean visible) {
super.setVisible(visible);
if (visible) {
// Restore focus to search box when going back a page. There is no control that has the focus going back hence set it.
if (dynamicControlCreation.getValue() != null) {
dynamicControlCreation.getValue().setFocus();
}
}
}
private static class ErrorGroupSection {
private static final String NO_CONTENT = "No content available";