blob: a995ea372d9978fba6d898f1c4722bbbdb0e802a [file] [log] [blame]
/*
* Copyright 2000-2014 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.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.options.ex.ConfigurableVisitor;
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 com.intellij.ui.Gray;
import com.intellij.ui.IdeBorderFactory;
import com.intellij.ui.JBColor;
import com.intellij.ui.border.CustomLineBorder;
import org.jetbrains.annotations.NonNls;
import org.jetbrains.annotations.NotNull;
import org.jetbrains.annotations.Nullable;
import javax.swing.*;
import javax.swing.border.Border;
import javax.swing.border.CompoundBorder;
import javax.swing.border.EmptyBorder;
import java.awt.*;
import java.awt.event.ActionEvent;
import java.awt.event.KeyEvent;
import java.util.Collection;
import java.util.Map;
/**
* @author Konstantin Bulenkov
*/
public class IdeSettingsDialog 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 IdeSettingsDialog(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 IdeSettingsDialog(Project project, ConfigurableGroup[] groups,
@NotNull String preselectedConfigurableDisplayName, boolean applicationModalIfPossible) {
super(project, true, applicationModalIfPossible);
init(project, groups, getPreselectedByDisplayName(groups, preselectedConfigurableDisplayName, project));
}
public IdeSettingsDialog(Project project, ConfigurableGroup[] groups, @Nullable Configurable preselectedConfigurable) {
super(project, true);
init(project, groups, preselectedConfigurable != null ? preselectedConfigurable : findLastSavedConfigurable(groups, project));
}
public IdeSettingsDialog(Project project, ConfigurableGroup[] groups, @NotNull String preselectedConfigurableDisplayName) {
super(project, true);
init(project, groups, getPreselectedByDisplayName(groups, preselectedConfigurableDisplayName, project));
}
@Nullable
@Override
protected Border createContentPaneBorder() {
return IdeBorderFactory.createEmptyBorder(0);
}
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 = new ConfigurableVisitor.ByName(preselectedConfigurableDisplayName).find(groups);
return result == null ? findLastSavedConfigurable(groups, project) : result;
}
@Override
public boolean isTypeAheadEnabled() {
return true;
}
@Nullable
@Override
protected JComponent createSouthPanel() {
final JComponent panel = super.createSouthPanel();
CustomLineBorder line = new CustomLineBorder(new JBColor(Gray._153.withAlpha(128), Gray._100.withAlpha(128)), 1, 0, 0, 0);
panel.setBorder(new CompoundBorder(line, new EmptyBorder(8, 12, 8, 12)));
return panel;
}
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 new ConfigurableVisitor.ByID(id).find(groups);
}
@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();
}
}
}