package com.chrisfolger.needsmoredojo.intellij.configurable; import com.chrisfolger.needsmoredojo.core.amd.autodetection.SourcesAutoDetector; import com.chrisfolger.needsmoredojo.core.amd.filesystem.SourcesLocator; import com.chrisfolger.needsmoredojo.core.settings.DojoSettings; import com.intellij.ide.DataManager; import com.intellij.openapi.actionSystem.DataContext; import com.intellij.openapi.actionSystem.PlatformDataKeys; import com.intellij.openapi.components.ServiceManager; import com.intellij.openapi.fileChooser.FileChooserDescriptor; import com.intellij.openapi.fileChooser.FileChooserDescriptorFactory; import com.intellij.openapi.options.Configurable; import com.intellij.openapi.project.Project; import com.intellij.openapi.ui.ComponentWithBrowseButton; import com.intellij.openapi.ui.Messages; import com.intellij.openapi.ui.TextComponentAccessor; import com.intellij.openapi.ui.TextFieldWithBrowseButton; import com.intellij.openapi.vfs.VirtualFile; import org.jetbrains.annotations.Nullable; import javax.swing.*; import javax.swing.event.ChangeEvent; import javax.swing.event.ChangeListener; import java.awt.*; import java.awt.event.ActionEvent; import java.awt.event.ActionListener; import java.awt.event.KeyEvent; import java.awt.event.KeyListener; import java.util.Collection; public class DojoSettingsConfigurable implements Configurable { private JComponent myComponent; private JButton autoDetectDojoSources; private JPanel myPanel; private TextFieldWithBrowseButton projectSourcesText; private TextFieldWithBrowseButton dojoSourcesText; private JTable moduleExceptionsTable; private JButton addMapping; private JTextField addModuleText; private JTextField addParameterText; private JButton removeMapping; private JCheckBox preferRelativePathsWhenCheckBox; private JButton autoDetectProjectSources; private JTable removeUnusedImportExceptionsTable; private JTextField addRUIExceptionModuleText; private JTextField addRUIExceptionParameterText; private JButton addRUIModule; private JButton removeRUIModule; private JCheckBox dojoSourcesIsTheSame; private JCheckBox pluginEnabled; private JCheckBox addModulesIfThereAreNoneDetected; private JCheckBox allowCaseInsensitiveSearch; private JTextField supportedFileTypes; private JCheckBox displayWarningIfSourcesCheckBox; private JCheckBox enableRefactoringSupportForCheckBox; private JRadioButton singleQuotesRadioButton; private JRadioButton doubleQuotesRadioButton; private ButtonGroup quotesButtonGroup; private Project project; private String dojoSourceString; private String projectSourceString; private DojoSettings settingsService; private boolean modified = false; private boolean initialized = false; public String getDisplayName() { return "Needs More Dojo"; } public boolean isModified() { return modified; } private class ProjectSourcesChosen extends ComponentWithBrowseButton.BrowseFolderActionListener<JTextField> { public ProjectSourcesChosen(@Nullable String title, @Nullable String description, FileChooserDescriptor fileChooserDescriptor) { super(title, description, projectSourcesText, null, fileChooserDescriptor, TextComponentAccessor.TEXT_FIELD_WHOLE_TEXT); } @Override public void actionPerformed(ActionEvent e) { super.actionPerformed(e); projectSourceString = projectSourcesText.getText().replace('\\', '/');; projectSourcesText.setText(projectSourceString); } } private class AutoDetectDojoSources implements ActionListener { @Override public void actionPerformed(ActionEvent e) { autoDetectDojoSources.setEnabled(false); VirtualFile directory = SourcesLocator.getDojoSourcesDirectory(project, false); if(directory == null) { Messages.showInfoMessage("Could not find any dojo sources via auto-detection", "Auto-detect Dojo Sources"); autoDetectDojoSources.setEnabled(true); return; } dojoSourcesText.setText(directory.getCanonicalPath()); dojoSourceString = directory.getCanonicalPath(); autoDetectDojoSources.setEnabled(true); updateModifiedState(); } } private class DojoSourcesChosen extends ComponentWithBrowseButton.BrowseFolderActionListener<JTextField> { public DojoSourcesChosen(@Nullable String title, @Nullable String description, FileChooserDescriptor fileChooserDescriptor) { super(title, description, dojoSourcesText, null, fileChooserDescriptor, TextComponentAccessor.TEXT_FIELD_WHOLE_TEXT); } @Override public void actionPerformed(ActionEvent e) { super.actionPerformed(e); dojoSourceString = dojoSourcesText.getText().replace('\\', '/'); dojoSourcesText.setText(dojoSourceString); } } private class TextChangedListener implements KeyListener { @Override public void keyTyped(KeyEvent e) { } @Override public void keyPressed(KeyEvent e) {} @Override public void keyReleased(KeyEvent e) { updateModifiedState(); } } private void updateModifiedState() { modified = !dojoSourcesText.getText().equals(settingsService.getDojoSourcesDirectory()) || !projectSourcesText.getText().equals(settingsService.getProjectSourcesDirectory()) || preferRelativePathsWhenCheckBox.isSelected() != settingsService.isPreferRelativeImports() || dojoSourcesIsTheSame.isSelected() != settingsService.isDojoSourcesShareProjectSourcesRoot() || pluginEnabled.isSelected() != settingsService.isNeedsMoreDojoEnabled() || addModulesIfThereAreNoneDetected.isSelected() != settingsService.isAddModuleIfThereAreNoneDefined() || allowCaseInsensitiveSearch.isSelected() != settingsService.isAllowCaseInsensitiveSearch() || !supportedFileTypes.getText().equals(settingsService.getSupportedFileTypes()) || enableRefactoringSupportForCheckBox.isSelected() != settingsService.isRefactoringEnabled() || singleQuotesRadioButton.isSelected() != settingsService.isSingleQuotedModuleIDs() || // this flag is true if it's unchecked displayWarningIfSourcesCheckBox.isSelected() == settingsService.isSetupWarningDisabled(); } public JComponent createComponent() { myComponent = (JComponent) myPanel; FileChooserDescriptor projectDescriptor = FileChooserDescriptorFactory.createSingleFolderDescriptor(); // have to use a custom one to allow jar file contents to be selected FileChooserDescriptor dojoDescriptor = new FileChooserDescriptor(true, true, true, false, true, false); projectSourcesText.addBrowseFolderListener(null, new ProjectSourcesChosen("Project Sources", "Select the root of your project's sources to support certain features of Needs More Dojo", projectDescriptor)); dojoSourcesText.addBrowseFolderListener(null, new DojoSourcesChosen("Dojo Sources", "Select the root of the dojo library sources to support certain features of Needs More Dojo", dojoDescriptor)); autoDetectDojoSources.addActionListener(new AutoDetectDojoSources()); // don't know how else to get the current project??? DataContext context = DataManager.getInstance().getDataContext(); final Project project = PlatformDataKeys.PROJECT.getData(context); this.project = project; settingsService = ServiceManager.getService(project, DojoSettings.class); dojoSourceString = settingsService.getDojoSourcesDirectory(); dojoSourcesText.setText(dojoSourceString); projectSourceString =settingsService.getProjectSourcesDirectory(); projectSourcesText.setText(projectSourceString); final ExceptionsListTableBuilder builder = new ExceptionsListTableBuilder(moduleExceptionsTable, project, settingsService.getAmdImportNamingExceptionsList()); final ExceptionsTableBuilder ruiBuilder = new ExceptionsTableBuilder(removeUnusedImportExceptionsTable, project, settingsService.getRuiImportExceptions()); addMapping.addActionListener(new ActionListener() { @Override public void actionPerformed(ActionEvent e) { builder.getTableModel().addRow(new String[] { addModuleText.getText(), addParameterText.getText()}); } }); addRUIModule.addActionListener(new ActionListener() { @Override public void actionPerformed(ActionEvent e) { ruiBuilder.getTableModel().addRow(new String[] { addRUIExceptionModuleText.getText(), addRUIExceptionParameterText.getText()}); } }); removeRUIModule.addActionListener(new ActionListener() { @Override public void actionPerformed(ActionEvent e) { ruiBuilder.getTableModel().removeRow(removeUnusedImportExceptionsTable.getSelectedRow()); } }); removeMapping.addActionListener(new ActionListener() { @Override public void actionPerformed(ActionEvent e) { builder.getTableModel().removeRow(moduleExceptionsTable.getSelectedRow()); } }); autoDetectProjectSources.addActionListener(new ActionListener() { @Override public void actionPerformed(ActionEvent e) { autoDetectProjectSources.setEnabled(false); addAutoDetectedSource(new SourcesAutoDetector().getPossibleSourceRoots(project)); autoDetectProjectSources.setEnabled(true); updateModifiedState(); } }); preferRelativePathsWhenCheckBox.setSelected(settingsService.isPreferRelativeImports()); dojoSourcesIsTheSame.setSelected(settingsService.isDojoSourcesShareProjectSourcesRoot()); addModulesIfThereAreNoneDetected.setSelected(settingsService.isAddModuleIfThereAreNoneDefined()); pluginEnabled.setSelected(settingsService.isNeedsMoreDojoEnabled()); updatePluginEnabledUI(); initialized = true; dojoSourcesText.getTextField().addKeyListener(new TextChangedListener()); projectSourcesText.getTextField().addKeyListener(new TextChangedListener()); addModulesIfThereAreNoneDetected.addChangeListener(new ChangeListener() { @Override public void stateChanged(ChangeEvent e) { updateModifiedState(); } }); allowCaseInsensitiveSearch.addChangeListener(new ChangeListener() { @Override public void stateChanged(ChangeEvent e) { updateModifiedState(); } }); enableRefactoringSupportForCheckBox.addChangeListener(new ChangeListener() { @Override public void stateChanged(ChangeEvent e) { updateModifiedState(); } }); displayWarningIfSourcesCheckBox.addChangeListener(new ChangeListener() { public void stateChanged(ChangeEvent e) { updateModifiedState(); } }); preferRelativePathsWhenCheckBox.addChangeListener(new ChangeListener() { @Override public void stateChanged(ChangeEvent e) { updateModifiedState(); } }); supportedFileTypes.addKeyListener(new TextChangedListener()); pluginEnabled.addChangeListener(new ChangeListener() { @Override public void stateChanged(ChangeEvent e) { updateModifiedState(); updatePluginEnabledUI(); } }); dojoSourcesIsTheSame.addChangeListener(new ChangeListener() { @Override public void stateChanged(ChangeEvent e) { updateSourcesEnabledState(); updateModifiedState(); } }); quotesButtonGroup = new ButtonGroup(); quotesButtonGroup.add(singleQuotesRadioButton); quotesButtonGroup.add(doubleQuotesRadioButton); singleQuotesRadioButton.addActionListener( new ActionListener() { @Override public void actionPerformed( ActionEvent e ) { updateModifiedState(); } } ); doubleQuotesRadioButton.addActionListener( new ActionListener() { @Override public void actionPerformed( ActionEvent e ) { updateModifiedState(); } } ); return myComponent; } public Icon getIcon() { return null; } private void updateSourcesEnabledState() { if(dojoSourcesIsTheSame.isSelected()) { dojoSourcesText.setEnabled(false); } else { dojoSourcesText.setEnabled(true); } } private void addAutoDetectedSource(Collection<String> possibleSourceRoots) { String[] choices = possibleSourceRoots.toArray(new String[0]); if(choices.length == 0) { Messages.showInfoMessage("Could not find any source roots via auto-detection", "Auto-detect Project Sources"); return; } String result = choices[0]; if(choices.length > 1) { result = Messages.showEditableChooseDialog("Found these possible source roots: ", "Auto-detect Project Sources", null, choices, choices[0], null); if(result == null || result.equals("")) { return; } if(result.contains("(") && result.contains(")")) { result = result.substring(result.indexOf('(') + 1, result.indexOf(')')); } } else if (choices.length == 1) { if(result.contains("(") && result.contains(")")) { result = result.substring(result.indexOf('(') + 1, result.indexOf(')')); } } projectSourceString = result; projectSourcesText.setText(result); } public void apply() { if(dojoSourcesText.getText() != null) { settingsService.setDojoSourcesDirectory(dojoSourcesText.getText()); } if(projectSourcesText.getText() != null) { settingsService.setProjectSourcesDirectory(projectSourcesText.getText()); } settingsService.setPreferRelativeImports(preferRelativePathsWhenCheckBox.isSelected()); settingsService.setDojoSourcesShareProjectSourcesRoot(dojoSourcesIsTheSame.isSelected()); settingsService.setNeedsMoreDojoEnabled(pluginEnabled.isSelected()); settingsService.setAddModuleIfThereAreNoneDefined(addModulesIfThereAreNoneDetected.isSelected()); settingsService.setAllowCaseInsensitiveSearch(allowCaseInsensitiveSearch.isSelected()); settingsService.setSupportedFileTypes(supportedFileTypes.getText()); settingsService.setSetupWarningDisabled(!displayWarningIfSourcesCheckBox.isSelected()); settingsService.setRefactoringEnabled(enableRefactoringSupportForCheckBox.isSelected()); settingsService.setSingleQuotedModuleIDs(singleQuotesRadioButton.isSelected()); modified = false; } public void disposeUIResources() { } public String getHelpTopic() { return ""; } public void reset() { dojoSourceString = settingsService.getDojoSourcesDirectory(); dojoSourcesText.setText(dojoSourceString); dojoSourcesText.setEnabled(!settingsService.isDojoSourcesShareProjectSourcesRoot()); dojoSourcesIsTheSame.setSelected(settingsService.isDojoSourcesShareProjectSourcesRoot()); projectSourceString =settingsService.getProjectSourcesDirectory(); projectSourcesText.setText(projectSourceString); pluginEnabled.setSelected(settingsService.isNeedsMoreDojoEnabled()); preferRelativePathsWhenCheckBox.setSelected(settingsService.isPreferRelativeImports()); addModulesIfThereAreNoneDetected.setSelected(settingsService.isAddModuleIfThereAreNoneDefined()); allowCaseInsensitiveSearch.setSelected(settingsService.isAllowCaseInsensitiveSearch()); supportedFileTypes.setText(settingsService.getSupportedFileTypes()); displayWarningIfSourcesCheckBox.setSelected(!settingsService.isSetupWarningDisabled()); enableRefactoringSupportForCheckBox.setSelected(settingsService.isRefactoringEnabled()); if (settingsService.isSingleQuotedModuleIDs()) { singleQuotesRadioButton.setSelected(true); } else { doubleQuotesRadioButton.setSelected(true); } modified = false; } private void updatePluginEnabledUI() { if(!pluginEnabled.isSelected()) { for(Component component : myPanel.getComponents()) { if(!component.equals(pluginEnabled)) { component.setEnabled(false); } } } else { for(Component component : myPanel.getComponents()) { if(!component.equals(pluginEnabled)) { component.setEnabled(true); } } // reset the dojo source textbox being enabled/disabled based on whether its checked as being // the same as project sources updateSourcesEnabledState(); } } }