-
Notifications
You must be signed in to change notification settings - Fork 10
Refactor: Update ComboBoxWithBrowseButton usage #267
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
base: main
Are you sure you want to change the base?
Changes from all commits
File filter
Filter by extension
Conversations
Jump to
Diff view
Diff view
There are no files selected for viewing
| Original file line number | Diff line number | Diff line change |
|---|---|---|
|
|
@@ -5,6 +5,9 @@ | |
| import com.intellij.ide.util.PropertiesComponent; | ||
| import com.intellij.ide.util.projectWizard.SettingsStep; | ||
| import com.intellij.openapi.application.ApplicationManager; | ||
| import com.intellij.openapi.fileChooser.FileChooser; | ||
| import com.intellij.openapi.fileChooser.FileChooserDescriptor; | ||
| import com.intellij.openapi.fileChooser.FileChooserDescriptorFactory; | ||
| import com.intellij.openapi.ui.ComboBox; | ||
| import com.intellij.openapi.ui.TextFieldWithBrowseButton; | ||
| import com.intellij.openapi.ui.ValidationInfo; | ||
|
|
@@ -13,15 +16,17 @@ | |
| import com.intellij.openapi.util.text.HtmlBuilder; | ||
| import com.intellij.openapi.util.text.HtmlChunk; | ||
| import com.intellij.openapi.util.text.StringUtil; | ||
| import com.intellij.openapi.vfs.VirtualFile; | ||
| import com.intellij.platform.ProjectGeneratorPeer; | ||
| import com.intellij.platform.WebProjectGenerator; | ||
| import com.intellij.ui.ColorUtil; | ||
| import com.intellij.ui.ComboboxWithBrowseButton; | ||
| import com.intellij.ui.DocumentAdapter; | ||
| import com.intellij.ui.JBColor; | ||
| import com.intellij.ui.components.JBCheckBox; | ||
| import com.intellij.ui.components.JBLabel; | ||
| import com.intellij.ui.components.JBList; | ||
| import com.intellij.ui.components.fields.ExtendableTextComponent; | ||
| import com.intellij.ui.components.fields.ExtendableTextField; | ||
| import com.intellij.uiDesigner.core.GridConstraints; | ||
| import com.intellij.util.ui.AsyncProcessIcon; | ||
| import com.jetbrains.lang.dart.DartBundle; | ||
|
|
@@ -31,6 +36,7 @@ | |
|
|
||
| import javax.swing.*; | ||
| import javax.swing.event.DocumentEvent; | ||
| import javax.swing.plaf.basic.BasicComboBoxEditor; | ||
| import javax.swing.text.JTextComponent; | ||
| import java.awt.*; | ||
| import java.util.List; | ||
|
|
@@ -41,7 +47,7 @@ public class DartGeneratorPeer implements ProjectGeneratorPeer<DartProjectWizard | |
| private static final String CREATE_SAMPLE_UNCHECKED = "CREATE_SAMPLE_UNCHECKED"; | ||
|
|
||
| private JPanel myMainPanel; | ||
| private ComboboxWithBrowseButton mySdkPathComboWithBrowse; | ||
| private ComboBox<String> mySdkPathComboWithBrowse; | ||
| private JBLabel myVersionLabel; | ||
|
|
||
| private JPanel myTemplatesPanel; | ||
|
|
@@ -59,12 +65,8 @@ public class DartGeneratorPeer implements ProjectGeneratorPeer<DartProjectWizard | |
| private String myDartCreateTemplatesSdkPath; //used to expire the above cache if the sdk is changed an alternative would be to use the same cache method as com.jetbrains.lang.dart.sdk.DartSdkUtil.getSdkVersion | ||
|
|
||
| public DartGeneratorPeer() { | ||
| // set initial values before initDartSdkControls() because listeners should not be triggered on initialization | ||
| mySdkPathComboWithBrowse.getComboBox().setEditable(true); | ||
| //mySdkPathComboWithBrowse.getComboBox().getEditor().setItem(...); initial sdk path will be correctly taken from known paths history | ||
|
|
||
| // now setup controls | ||
| DartSdkUtil.initDartSdkControls(null, mySdkPathComboWithBrowse, myVersionLabel); | ||
| mySdkPathComboWithBrowse.setEditable(true); | ||
| DartSdkUtil.addKnownSDKPathsToCombo(mySdkPathComboWithBrowse); | ||
|
|
||
| myCreateSampleProjectCheckBox.addActionListener(e -> myTemplatesList.setEnabled(myCreateSampleProjectCheckBox.isSelected())); | ||
| String selectedTemplateName = PropertiesComponent.getInstance().getValue(DART_PROJECT_TEMPLATE); | ||
|
|
@@ -92,11 +94,14 @@ public Component getListCellRendererComponent(JList list, Object value, int inde | |
| myCreateSampleProjectCheckBox.setEnabled(false); | ||
| myTemplatesList.setEnabled(false); | ||
|
|
||
| final JTextComponent editorComponent = (JTextComponent)mySdkPathComboWithBrowse.getComboBox().getEditor().getEditorComponent(); | ||
| final JTextComponent editorComponent = (JTextComponent)mySdkPathComboWithBrowse.getEditor().getEditorComponent(); | ||
| editorComponent.getDocument().addDocumentListener(new DocumentAdapter() { | ||
| @Override | ||
| protected void textChanged(final @NotNull DocumentEvent e) { | ||
| if(e.getType() == DocumentEvent.EventType.INSERT){ | ||
| final String sdkHomePath = getSdkPathText(); | ||
| final String sdkVersion = DartSdkUtil.getSdkVersion(sdkHomePath); | ||
| myVersionLabel.setText(sdkVersion == null ? "" : sdkVersion); | ||
| onSdkPathChanged(); | ||
| } | ||
|
Comment on lines
101
to
106
Contributor
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. The DocumentListener here only reacts to INSERT events. This means if a user deletes characters from the SDK path (e.g., to correct a typo), the version label and the project templates list will not update. This leads to an inconsistent UI state. The check should be removed to handle all text changes, including deletions. final String sdkHomePath = getSdkPathText();
final String sdkVersion = DartSdkUtil.getSdkVersion(sdkHomePath);
myVersionLabel.setText(sdkVersion == null ? "" : sdkVersion);
onSdkPathChanged(); |
||
| } | ||
|
|
@@ -105,8 +110,12 @@ protected void textChanged(final @NotNull DocumentEvent e) { | |
| onSdkPathChanged(); | ||
| } | ||
|
|
||
| private String getSdkPathText() { | ||
| return mySdkPathComboWithBrowse.getEditor().getItem().toString().trim(); | ||
| } | ||
|
|
||
| private void onSdkPathChanged() { | ||
| String sdkPath = mySdkPathComboWithBrowse.getComboBox().getEditor().getItem().toString().trim(); | ||
| String sdkPath = getSdkPathText(); | ||
| // If the sdk path has changed, recalculate the create template options | ||
| if (myDartCreateTemplatesSdkPath != null && !myDartCreateTemplatesSdkPath.equals(sdkPath)) { | ||
| clearTemplates(); | ||
|
|
@@ -159,7 +168,7 @@ private void startLoadingTemplates() { | |
| asyncProcessIcon.resume(); | ||
|
|
||
| ApplicationManager.getApplication().executeOnPooledThread(() -> { | ||
| final String comboSdkPath = mySdkPathComboWithBrowse.getComboBox().getEditor().getItem().toString().trim(); | ||
| final String comboSdkPath = getSdkPathText(); | ||
| final String sdkPath = | ||
| FileUtil.toSystemIndependentName(comboSdkPath); | ||
| DartProjectTemplate.loadTemplatesAsync(sdkPath, templates -> { | ||
|
|
@@ -236,7 +245,7 @@ public void buildUI(final @NotNull SettingsStep settingsStep) { | |
|
|
||
| @Override | ||
| public @NotNull DartProjectWizardData getSettings() { | ||
| final String sdkPath = FileUtil.toSystemIndependentName(mySdkPathComboWithBrowse.getComboBox().getEditor().getItem().toString().trim()); | ||
| final String sdkPath = FileUtil.toSystemIndependentName(getSdkPathText()); | ||
| final DartProjectTemplate template = myCreateSampleProjectCheckBox.isSelected() ? myTemplatesList.getSelectedValue() : null; | ||
| PropertiesComponent.getInstance().setValue(DART_PROJECT_TEMPLATE, template == null ? CREATE_SAMPLE_UNCHECKED : template.getName()); | ||
|
|
||
|
|
@@ -245,7 +254,7 @@ public void buildUI(final @NotNull SettingsStep settingsStep) { | |
|
|
||
| @Override | ||
| public @Nullable ValidationInfo validate() { | ||
| final String sdkPath = mySdkPathComboWithBrowse.getComboBox().getEditor().getItem().toString().trim(); | ||
| final String sdkPath = getSdkPathText(); | ||
| final String message = DartSdkUtil.getErrorMessageIfWrongSdkRootPath(sdkPath); | ||
| if (message != null) { | ||
| return new ValidationInfo(message, mySdkPathComboWithBrowse); | ||
|
|
@@ -284,7 +293,7 @@ public boolean validateInIntelliJ() { | |
| } | ||
|
|
||
| private void enableIntellijLiveValidation() { | ||
| final JTextComponent editorComponent = (JTextComponent)mySdkPathComboWithBrowse.getComboBox().getEditor().getEditorComponent(); | ||
| final JTextComponent editorComponent = (JTextComponent)mySdkPathComboWithBrowse.getEditor().getEditorComponent(); | ||
| editorComponent.getDocument().addDocumentListener(new DocumentAdapter() { | ||
| @Override | ||
| protected void textChanged(final @NotNull DocumentEvent e) { | ||
|
|
@@ -304,7 +313,7 @@ public boolean isBackgroundJobRunning() { | |
|
|
||
| @Override | ||
| public void addSettingsStateListener(final @NotNull WebProjectGenerator.SettingsStateListener stateListener) { | ||
| final JTextComponent editorComponent = (JTextComponent)mySdkPathComboWithBrowse.getComboBox().getEditor().getEditorComponent(); | ||
| final JTextComponent editorComponent = (JTextComponent)mySdkPathComboWithBrowse.getEditor().getEditorComponent(); | ||
| editorComponent.getDocument().addDocumentListener(new DocumentAdapter() { | ||
| @Override | ||
| protected void textChanged(final @NotNull DocumentEvent e) { | ||
|
|
@@ -318,6 +327,29 @@ protected void textChanged(final @NotNull DocumentEvent e) { | |
| } | ||
|
|
||
| private void createUIComponents() { | ||
| mySdkPathComboWithBrowse = new ComboboxWithBrowseButton(new ComboBox<>()); | ||
| ExtendableTextComponent.Extension browseExtension = | ||
| ExtendableTextComponent.Extension.create(AllIcons.General.OpenDisk, AllIcons.General.OpenDiskHover, | ||
| DartBundle.message("dart.sdk.path.label"), | ||
| () -> { | ||
| final FileChooserDescriptor descriptor = | ||
| FileChooserDescriptorFactory.createSingleFolderDescriptor(); | ||
| final VirtualFile file = | ||
| FileChooser.chooseFile(descriptor, mySdkPathComboWithBrowse, null, null); | ||
| if (file != null) { | ||
| mySdkPathComboWithBrowse.getEditor().setItem(file.getPath()); | ||
|
Contributor
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. When a folder is selected via the browse button, file.getPath() returns a system-independent path (using forward slashes). For better consistency with the IntelliJ UI, especially on Windows, it is recommended to convert this to a system-dependent path before setting it in the editor. mySdkPathComboWithBrowse.getEditor().setItem(FileUtil.toSystemDependentName(file.getPath()));References
|
||
| } | ||
| }); | ||
|
|
||
| mySdkPathComboWithBrowse = new ComboBox<>(); | ||
| mySdkPathComboWithBrowse.setEditable(true); | ||
| mySdkPathComboWithBrowse.setEditor(new BasicComboBoxEditor() { | ||
| @Override | ||
| protected JTextField createEditorComponent() { | ||
| final ExtendableTextField ecbEditor = new ExtendableTextField(); | ||
| ecbEditor.addExtension(browseExtension); | ||
| ecbEditor.setBorder(null); | ||
| return ecbEditor; | ||
| } | ||
| }); | ||
| } | ||
|
Comment on lines
329
to
354
Contributor
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. The logic for creating a ComboBox with a browse extension is duplicated here and in DartConfigurable.java. To improve maintainability and reduce duplication, this logic should be extracted into a reusable utility method, for example in DartSdkUtil. References
|
||
| } | ||
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
The replacement of ComboBoxWithBrowseButton with TextFieldWithBrowseButton has resulted in the removal of the project discovery logic and the dropdown list of projects. This is a regression in functionality, as users can no longer easily select from detected Dart projects within the workspace. Consider using a ComboBox with an ExtendableTextField and a browse extension (similar to the implementation in DartGeneratorPeer) to maintain the original behavior while adhering to the new API.
References