blob: e0d4a03a4e1437ddd5d7fa623da102163b310e9e [file] [log] [blame]
/*
* Copyright 2000-2013 JetBrains s.r.o.
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
package com.intellij.openapi.options.newEditor;
import com.intellij.CommonBundle;
import com.intellij.ide.ui.search.SearchUtil;
import com.intellij.ide.util.PropertiesComponent;
import com.intellij.openapi.actionSystem.DataProvider;
import com.intellij.openapi.application.ApplicationManager;
import com.intellij.openapi.help.HelpManager;
import com.intellij.openapi.options.Configurable;
import com.intellij.openapi.options.ConfigurableGroup;
import com.intellij.openapi.options.ConfigurationException;
import com.intellij.openapi.options.SearchableConfigurable;
import com.intellij.openapi.project.Project;
import com.intellij.openapi.ui.DialogWrapper;
import com.intellij.openapi.util.ActionCallback;
import com.intellij.openapi.util.Disposer;
import org.jetbrains.annotations.NonNls;
import org.jetbrains.annotations.NotNull;
import org.jetbrains.annotations.Nullable;
import javax.swing.*;
import java.awt.*;
import java.awt.event.ActionEvent;
import java.awt.event.KeyEvent;
import java.util.Collection;
import java.util.List;
import java.util.Map;
public class OptionsEditorDialog extends DialogWrapper implements DataProvider{
private Project myProject;
private ConfigurableGroup[] myGroups;
private Configurable myPreselected;
private OptionsEditor myEditor;
private ApplyAction myApplyAction;
public static final String DIMENSION_KEY = "OptionsEditor";
@NonNls static final String LAST_SELECTED_CONFIGURABLE = "options.lastSelected";
/** This constructor should be eliminated after the new modality approach
* will have been checked. See a {@code Registry} key ide.perProjectModality
* @deprecated
*/
public OptionsEditorDialog(Project project, ConfigurableGroup[] groups,
@Nullable Configurable preselectedConfigurable, boolean applicationModalIfPossible) {
super(project, true, applicationModalIfPossible);
init(project, groups, preselectedConfigurable != null ? preselectedConfigurable : findLastSavedConfigurable(groups, project));
}
/** This constructor should be eliminated after the new modality approach
* will have been checked. See a {@code Registry} key ide.perProjectModality
* @deprecated
*/
public OptionsEditorDialog(Project project, ConfigurableGroup[] groups,
@NotNull String preselectedConfigurableDisplayName, boolean applicationModalIfPossible) {
super(project, true, applicationModalIfPossible);
init(project, groups, getPreselectedByDisplayName(groups, preselectedConfigurableDisplayName, project));
}
public OptionsEditorDialog(Project project, ConfigurableGroup[] groups, @Nullable Configurable preselectedConfigurable) {
super(project, true);
init(project, groups, preselectedConfigurable != null ? preselectedConfigurable : findLastSavedConfigurable(groups, project));
}
public OptionsEditorDialog(Project project, ConfigurableGroup[] groups, @NotNull String preselectedConfigurableDisplayName) {
super(project, true);
init(project, groups, getPreselectedByDisplayName(groups, preselectedConfigurableDisplayName, project));
}
private void init(final Project project, final ConfigurableGroup[] groups, @Nullable final Configurable preselected) {
myProject = project;
myGroups = groups;
myPreselected = preselected;
setTitle(CommonBundle.settingsTitle());
init();
}
@Nullable
private static Configurable getPreselectedByDisplayName(final ConfigurableGroup[] groups, final String preselectedConfigurableDisplayName,
final Project project) {
Configurable result = findPreselectedByDisplayName(preselectedConfigurableDisplayName, groups);
return result == null ? findLastSavedConfigurable(groups, project) : result;
}
@Override
public boolean isTypeAheadEnabled() {
return true;
}
protected JComponent createCenterPanel() {
myEditor = new OptionsEditor(myProject, myGroups, myPreselected);
myEditor.getContext().addColleague(new OptionsEditorColleague.Adapter() {
@Override
public ActionCallback onModifiedAdded(final Configurable configurable) {
updateStatus();
return new ActionCallback.Done();
}
@Override
public ActionCallback onModifiedRemoved(final Configurable configurable) {
updateStatus();
return new ActionCallback.Done();
}
@Override
public ActionCallback onErrorsChanged() {
updateStatus();
return new ActionCallback.Done();
}
});
Disposer.register(myDisposable, myEditor);
return myEditor;
}
public boolean updateStatus() {
myApplyAction.setEnabled(myEditor.canApply());
final Map<Configurable,ConfigurationException> errors = myEditor.getContext().getErrors();
if (errors.size() == 0) {
setErrorText(null);
} else {
String text = "Changes were not applied because of an error";
final String errorMessage = getErrorMessage(errors);
if (errorMessage != null) {
text += "<br>" + errorMessage;
}
setErrorText(text);
}
return errors.size() == 0;
}
@Nullable
private static String getErrorMessage(final Map<Configurable, ConfigurationException> errors) {
final Collection<ConfigurationException> values = errors.values();
final ConfigurationException[] exceptions = values.toArray(new ConfigurationException[values.size()]);
if (exceptions.length > 0) {
return exceptions[0].getMessage();
}
return null;
}
@Override
protected String getDimensionServiceKey() {
return DIMENSION_KEY;
}
@Override
protected void doOKAction() {
myEditor.flushModifications();
if (myEditor.canApply()) {
myEditor.apply();
if (!updateStatus()) return;
}
saveCurrentConfigurable();
ApplicationManager.getApplication().saveAll();
super.doOKAction();
}
private void saveCurrentConfigurable() {
final Configurable current = myEditor.getContext().getCurrentConfigurable();
if (current == null) return;
final PropertiesComponent props = PropertiesComponent.getInstance(myProject);
if (current instanceof SearchableConfigurable) {
props.setValue(LAST_SELECTED_CONFIGURABLE, ((SearchableConfigurable)current).getId());
} else {
props.setValue(LAST_SELECTED_CONFIGURABLE, current.getClass().getName());
}
}
@Nullable
private static Configurable findLastSavedConfigurable(ConfigurableGroup[] groups, final Project project) {
final String id = PropertiesComponent.getInstance(project).getValue(LAST_SELECTED_CONFIGURABLE);
if (id == null) return null;
return findConfigurableInGroups(id, groups);
}
@Nullable
private static Configurable findConfigurableInGroups(String id, Configurable.Composite... groups) {
// avoid unnecessary group expand: check top-level configurables in all groups before looking at children
for (Configurable.Composite group : groups) {
final Configurable[] configurables = group.getConfigurables();
for (Configurable c : configurables) {
if (c instanceof SearchableConfigurable && id.equals(((SearchableConfigurable)c).getId())) {
return c;
} else if (id.equals(c.getClass().getName())) {
return c;
}
}
}
for (Configurable.Composite group : groups) {
final Configurable[] configurables = group.getConfigurables();
for (Configurable c : configurables) {
if (c instanceof Configurable.Composite) {
Configurable result = findConfigurableInGroups(id, (Configurable.Composite)c);
if (result != null) {
return result;
}
}
}
}
return null;
}
@Nullable
private static Configurable findPreselectedByDisplayName(final String preselectedConfigurableDisplayName, ConfigurableGroup[] groups) {
final List<Configurable> all = SearchUtil.expand(groups);
for (Configurable each : all) {
if (preselectedConfigurableDisplayName.equals(each.getDisplayName())) return each;
}
return null;
}
@Override
public void doCancelAction(final AWTEvent source) {
if (source instanceof KeyEvent || source instanceof ActionEvent) {
if (myEditor.getContext().isHoldingFilter()) {
myEditor.clearFilter();
return;
}
}
super.doCancelAction(source);
}
@Override
public void doCancelAction() {
saveCurrentConfigurable();
super.doCancelAction();
}
@NotNull
@Override
protected Action[] createActions() {
myApplyAction = new ApplyAction();
return new Action[] {getOKAction(), getCancelAction(), myApplyAction, getHelpAction()};
}
@Override
protected void doHelpAction() {
final String topic = myEditor.getHelpTopic();
if (topic != null) {
HelpManager.getInstance().invokeHelp(topic);
}
}
@Override
public JComponent getPreferredFocusedComponent() {
return myEditor.getPreferredFocusedComponent();
}
public Object getData(@NonNls String dataId) {
if (OptionsEditor.KEY.is(dataId)) {
return myEditor;
}
return null;
}
private class ApplyAction extends AbstractAction {
public ApplyAction() {
super(CommonBundle.getApplyButtonText());
setEnabled(false);
}
public void actionPerformed(final ActionEvent e) {
myEditor.apply();
myEditor.revalidate();
myEditor.repaint();
}
}
}