IDEA-63980 Make idea.cycle.buffer.size configurable in IDEA GUI / IDEA settings
[idea/community.git] / platform / lang-impl / src / com / intellij / execution / console / ConsoleConfigurable.java
1 package com.intellij.execution.console;
2
3 import com.intellij.execution.impl.ConsoleBuffer;
4 import com.intellij.ide.ui.UISettings;
5 import com.intellij.openapi.application.ApplicationBundle;
6 import com.intellij.openapi.editor.ex.EditorSettingsExternalizable;
7 import com.intellij.openapi.editor.impl.softwrap.SoftWrapAppliancePlaces;
8 import com.intellij.openapi.options.Configurable;
9 import com.intellij.openapi.options.ConfigurationException;
10 import com.intellij.openapi.options.SearchableConfigurable;
11 import com.intellij.openapi.ui.InputValidatorEx;
12 import com.intellij.openapi.ui.Messages;
13 import com.intellij.openapi.ui.Splitter;
14 import com.intellij.openapi.util.text.StringUtil;
15 import com.intellij.ui.AddEditDeleteListPanel;
16 import com.intellij.util.ui.GridBag;
17 import org.jetbrains.annotations.Nls;
18 import org.jetbrains.annotations.NotNull;
19 import org.jetbrains.annotations.Nullable;
20
21 import javax.swing.*;
22 import javax.swing.event.ChangeEvent;
23 import javax.swing.event.ChangeListener;
24 import java.awt.*;
25 import java.util.ArrayList;
26 import java.util.Arrays;
27 import java.util.List;
28
29 /**
30  * @author peter
31  */
32 public class ConsoleConfigurable implements SearchableConfigurable, Configurable.NoScroll {
33   private JPanel myMainComponent;
34   private JCheckBox myCbUseSoftWrapsAtConsole;
35   private JTextField myCommandsHistoryLimitField;
36   private JCheckBox myCbOverrideConsoleCycleBufferSize;
37   private JTextField myConsoleCycleBufferSizeField;
38
39
40   private MyAddDeleteListPanel myPositivePanel;
41   private MyAddDeleteListPanel myNegativePanel;
42   private final ConsoleFoldingSettings mySettings = ConsoleFoldingSettings.getSettings();
43
44   @Override
45   public JComponent createComponent() {
46     if (myMainComponent == null) {
47       myMainComponent = new JPanel(new BorderLayout());
48       myCbUseSoftWrapsAtConsole = new JCheckBox(ApplicationBundle.message("checkbox.use.soft.wraps.at.console"), false);
49       myCommandsHistoryLimitField = new JTextField(3);
50       myCbOverrideConsoleCycleBufferSize = new JCheckBox(ApplicationBundle.message("checkbox.override.console.cycle.buffer.size", String.valueOf(ConsoleBuffer.getLegacyCycleBufferSize() / 1024)), false);
51       myCbOverrideConsoleCycleBufferSize.addChangeListener(new ChangeListener(){
52         @Override
53         public void stateChanged(ChangeEvent e) {
54           myConsoleCycleBufferSizeField.setEnabled(myCbOverrideConsoleCycleBufferSize.isSelected());
55         }
56       });
57       myConsoleCycleBufferSizeField = new JTextField(3);
58
59       JPanel northPanel = new JPanel(new GridBagLayout());
60       GridBag gridBag = new GridBag();
61       gridBag.anchor(GridBagConstraints.WEST).setDefaultAnchor(GridBagConstraints.WEST);
62       northPanel
63         .add(myCbUseSoftWrapsAtConsole,
64              gridBag.nextLine().next());
65       northPanel.add(Box.createHorizontalGlue(), gridBag.next().coverLine());
66       northPanel.add(new JLabel(ApplicationBundle.message("editbox.console.history.limit")), gridBag.nextLine().next());
67       northPanel.add(myCommandsHistoryLimitField, gridBag.next());
68       if (ConsoleBuffer.useCycleBuffer()) {
69         northPanel.add(myCbOverrideConsoleCycleBufferSize, gridBag.nextLine().next());
70         northPanel.add(myConsoleCycleBufferSizeField, gridBag.next());
71       }
72       if (!editFoldingsOnly()) {
73         JPanel wrapper = new JPanel(new BorderLayout());
74         wrapper.add(northPanel, BorderLayout.WEST);
75         myMainComponent.add(wrapper, BorderLayout.NORTH);
76       }
77       Splitter splitter = new Splitter(true);
78       myMainComponent.add(splitter, BorderLayout.CENTER);
79       myPositivePanel =
80         new MyAddDeleteListPanel("Fold console lines that contain", "Enter a substring of a console line you'd like to see folded:");
81       myNegativePanel = new MyAddDeleteListPanel("Exceptions", "Enter a substring of a console line you don't want to fold:");
82       splitter.setFirstComponent(myPositivePanel);
83       splitter.setSecondComponent(myNegativePanel);
84
85       myPositivePanel.getEmptyText().setText("Fold nothing");
86       myNegativePanel.getEmptyText().setText("No exceptions");
87     }
88     return myMainComponent;
89   }
90
91   protected boolean editFoldingsOnly() {
92     return false;
93   }
94
95   public void addRule(@NotNull String rule) {
96     myPositivePanel.addRule(rule);
97   }
98
99   @Override
100   public boolean isModified() {
101     EditorSettingsExternalizable editorSettings = EditorSettingsExternalizable.getInstance();
102     boolean isModified = !Arrays.asList(myNegativePanel.getListItems()).equals(mySettings.getNegativePatterns());
103     isModified |= !Arrays.asList(myPositivePanel.getListItems()).equals(mySettings.getPositivePatterns());
104     isModified |= isModified(myCbUseSoftWrapsAtConsole, editorSettings.isUseSoftWraps(SoftWrapAppliancePlaces.CONSOLE));
105     isModified |= isModified(myCommandsHistoryLimitField, UISettings.getInstance().CONSOLE_COMMAND_HISTORY_LIMIT);
106     if (ConsoleBuffer.useCycleBuffer()) {
107       isModified |= isModified(myCbOverrideConsoleCycleBufferSize, UISettings.getInstance().OVERRIDE_CONSOLE_CYCLE_BUFFER_SIZE);
108       isModified |= isModified(myConsoleCycleBufferSizeField, UISettings.getInstance().CONSOLE_CYCLE_BUFFER_SIZE_KB);
109     }
110
111     return isModified;
112   }
113
114   private static boolean isModified(JToggleButton checkBox, boolean value) {
115     return checkBox.isSelected() != value;
116   }
117
118   private static boolean isModified(JTextField textField, int value) {
119     try {
120       int fieldValue = Integer.parseInt(textField.getText().trim());
121       return fieldValue != value;
122     }
123     catch (NumberFormatException e) {
124       return false;
125     }
126   }
127
128   @Override
129   public void apply() throws ConfigurationException {
130     EditorSettingsExternalizable editorSettings = EditorSettingsExternalizable.getInstance();
131     UISettings uiSettings = UISettings.getInstance();
132
133     editorSettings.setUseSoftWraps(myCbUseSoftWrapsAtConsole.isSelected(), SoftWrapAppliancePlaces.CONSOLE);
134     boolean uiSettingsChanged = false;
135     if (isModified(myCommandsHistoryLimitField, uiSettings.CONSOLE_COMMAND_HISTORY_LIMIT)) {
136       uiSettings.CONSOLE_COMMAND_HISTORY_LIMIT = Math.max(0, Math.min(1000, Integer.parseInt(myCommandsHistoryLimitField.getText().trim())));
137       uiSettingsChanged = true;
138     }
139     if (ConsoleBuffer.useCycleBuffer()) {
140       if (isModified(myCbOverrideConsoleCycleBufferSize, uiSettings.OVERRIDE_CONSOLE_CYCLE_BUFFER_SIZE)) {
141         uiSettings.OVERRIDE_CONSOLE_CYCLE_BUFFER_SIZE = myCbOverrideConsoleCycleBufferSize.isSelected();
142         uiSettingsChanged = true;
143       }
144       if (isModified(myConsoleCycleBufferSizeField, uiSettings.CONSOLE_CYCLE_BUFFER_SIZE_KB)) {
145         uiSettings.CONSOLE_CYCLE_BUFFER_SIZE_KB = Math.max(0, Math.min(1024*100, Integer.parseInt(myConsoleCycleBufferSizeField.getText().trim())));
146         uiSettingsChanged = true;
147       }
148     }
149     if (uiSettingsChanged) {
150       uiSettings.fireUISettingsChanged();
151     }
152
153
154     myNegativePanel.applyTo(mySettings.getNegativePatterns());
155     myPositivePanel.applyTo(mySettings.getPositivePatterns());
156   }
157
158   @Override
159   public void reset() {
160     EditorSettingsExternalizable editorSettings = EditorSettingsExternalizable.getInstance();
161     UISettings uiSettings = UISettings.getInstance();
162
163     myCbUseSoftWrapsAtConsole.setSelected(editorSettings.isUseSoftWraps(SoftWrapAppliancePlaces.CONSOLE));
164     myCommandsHistoryLimitField.setText(Integer.toString(uiSettings.CONSOLE_COMMAND_HISTORY_LIMIT));
165
166     myCbOverrideConsoleCycleBufferSize.setEnabled(ConsoleBuffer.useCycleBuffer());
167     myCbOverrideConsoleCycleBufferSize.setSelected(uiSettings.OVERRIDE_CONSOLE_CYCLE_BUFFER_SIZE);
168     myConsoleCycleBufferSizeField.setEnabled(ConsoleBuffer.useCycleBuffer() && uiSettings.OVERRIDE_CONSOLE_CYCLE_BUFFER_SIZE);
169     myConsoleCycleBufferSizeField.setText(Integer.toString(uiSettings.CONSOLE_CYCLE_BUFFER_SIZE_KB));
170
171
172     myNegativePanel.resetFrom(mySettings.getNegativePatterns());
173     myPositivePanel.resetFrom(mySettings.getPositivePatterns());
174   }
175
176   @Override
177   public void disposeUIResources() {
178     myMainComponent = null;
179     myNegativePanel = null;
180     myPositivePanel = null;
181   }
182
183   @Override
184   @NotNull
185   public String getId() {
186     return getDisplayName();
187   }
188
189   @Override
190   public Runnable enableSearch(String option) {
191     return null;
192   }
193
194   @Override
195   @Nls
196   public String getDisplayName() {
197     return "Console Folding";
198   }
199
200   @Override
201   public String getHelpTopic() {
202     return "reference.idesettings.console.folding";
203   }
204
205   private static class MyAddDeleteListPanel extends AddEditDeleteListPanel<String> {
206     private final String myQuery;
207
208     public MyAddDeleteListPanel(String title, String query) {
209       super(title, new ArrayList<String>());
210       myQuery = query;
211     }
212
213     @Override
214     @Nullable
215     protected String findItemToAdd() {
216       return showEditDialog("");
217     }
218
219     @Nullable
220     private String showEditDialog(final String initialValue) {
221       return Messages.showInputDialog(this, myQuery, "Folding Pattern", Messages.getQuestionIcon(), initialValue, new InputValidatorEx() {
222         @Override
223         public boolean checkInput(String inputString) {
224           return !StringUtil.isEmpty(inputString);
225         }
226
227         @Override
228         public boolean canClose(String inputString) {
229           return !StringUtil.isEmpty(inputString);
230         }
231
232         @Nullable
233         @Override
234         public String getErrorText(String inputString) {
235           if (!checkInput(inputString)) {
236             return "Console folding rule string cannot be empty";
237           }
238           return null;
239         }
240       });
241     }
242
243     void resetFrom(List<String> patterns) {
244       myListModel.clear();
245       for (String pattern : patterns) {
246         myListModel.addElement(pattern);
247       }
248     }
249
250     void applyTo(List<String> patterns) {
251       patterns.clear();
252       for (Object o : getListItems()) {
253         patterns.add((String)o);
254       }
255     }
256
257     public void addRule(String rule) {
258       addElement(rule);
259     }
260
261     @Override
262     public void setBounds(int x, int y, int width, int height) {
263       super.setBounds(x, y, width, height);
264     }
265
266     @Override
267     protected String editSelectedItem(String item) {
268       return showEditDialog(item);
269     }
270   }
271 }