[i18n] idea-ui
[idea/community.git] / java / idea-ui / src / com / intellij / openapi / roots / ui / configuration / BuildElementsEditor.java
1 // Copyright 2000-2018 JetBrains s.r.o. Use of this source code is governed by the Apache 2.0 license that can be found in the LICENSE file.
2
3 package com.intellij.openapi.roots.ui.configuration;
4
5 import com.intellij.ide.JavaUiBundle;
6 import com.intellij.ide.util.BrowseFilesListener;
7 import com.intellij.openapi.actionSystem.LangDataKeys;
8 import com.intellij.openapi.fileChooser.FileChooserDescriptor;
9 import com.intellij.openapi.fileChooser.FileChooserDescriptorFactory;
10 import com.intellij.openapi.fileChooser.FileChooserFactory;
11 import com.intellij.openapi.roots.CompilerModuleExtension;
12 import com.intellij.openapi.util.NlsContexts;
13 import com.intellij.openapi.util.io.FileUtil;
14 import com.intellij.openapi.vfs.VfsUtilCore;
15 import com.intellij.openapi.vfs.VirtualFile;
16 import com.intellij.ui.DocumentAdapter;
17 import com.intellij.ui.FieldPanel;
18 import com.intellij.ui.IdeBorderFactory;
19 import com.intellij.ui.InsertPathAction;
20 import com.intellij.ui.components.fields.ExtendableTextField;
21 import com.intellij.util.ui.JBUI;
22 import com.intellij.util.ui.UIUtil;
23 import org.jetbrains.annotations.NonNls;
24 import org.jetbrains.annotations.NotNull;
25 import org.jetbrains.annotations.Nullable;
26
27 import javax.swing.*;
28 import javax.swing.event.DocumentEvent;
29 import java.awt.*;
30 import java.awt.event.ActionEvent;
31 import java.awt.event.ActionListener;
32 import java.io.IOException;
33
34 public class BuildElementsEditor extends ModuleElementsEditor {
35   private JRadioButton myInheritCompilerOutput;
36   private JRadioButton myPerModuleCompilerOutput;
37
38   private CommittableFieldPanel myOutputPathPanel;
39   private CommittableFieldPanel myTestsOutputPathPanel;
40   private JCheckBox myCbExcludeOutput;
41   private JLabel myOutputLabel;
42   private JLabel myTestOutputLabel;
43
44   protected BuildElementsEditor(final ModuleConfigurationState state) {
45     super(state);
46   }
47
48   @Override
49   public JComponent createComponentImpl() {
50     myInheritCompilerOutput = new JRadioButton(JavaUiBundle.message("project.inherit.compile.output.path"));
51     myPerModuleCompilerOutput = new JRadioButton(JavaUiBundle.message("project.module.compile.output.path"));
52     ButtonGroup group = new ButtonGroup();
53     group.add(myInheritCompilerOutput);
54     group.add(myPerModuleCompilerOutput);
55
56     myOutputPathPanel = createOutputPathPanel(JavaUiBundle.message("module.paths.output.title"), new CommitPathRunnable() {
57       @Override
58       public void saveUrl(String url) {
59         if (myInheritCompilerOutput.isSelected()) return;  //do not override settings if any
60         getCompilerExtension().setCompilerOutputPath(url);
61         fireModuleConfigurationChanged();
62       }
63     });
64     myTestsOutputPathPanel = createOutputPathPanel(JavaUiBundle.message("module.paths.test.output.title"), new CommitPathRunnable() {
65       @Override
66       public void saveUrl(String url) {
67         if (myInheritCompilerOutput.isSelected()) return; //do not override settings if any
68         getCompilerExtension().setCompilerOutputPathForTests(url);
69         fireModuleConfigurationChanged();
70       }
71     });
72
73     myCbExcludeOutput = new JCheckBox(JavaUiBundle.message("module.paths.exclude.output.checkbox"), getCompilerExtension().isExcludeOutput());
74     myCbExcludeOutput.addActionListener(new ActionListener() {
75       @Override
76       public void actionPerformed(final ActionEvent e) {
77         getCompilerExtension().setExcludeOutput(myCbExcludeOutput.isSelected());
78         fireModuleConfigurationChanged();
79       }
80     });
81
82     final JPanel outputPathsPanel = new JPanel(new GridBagLayout());
83
84
85     outputPathsPanel.add(myInheritCompilerOutput, new GridBagConstraints(0, GridBagConstraints.RELATIVE, 2, 1, 1.0, 0.0,
86                                                                          GridBagConstraints.WEST, GridBagConstraints.NONE,
87                                                                          JBUI.insets(6, 0, 0, 4), 0, 0));
88     outputPathsPanel.add(myPerModuleCompilerOutput, new GridBagConstraints(0, GridBagConstraints.RELATIVE, 2, 1, 1.0, 0.0,
89                                                                            GridBagConstraints.WEST, GridBagConstraints.NONE,
90                                                                            JBUI.insets(6, 0, 0, 4), 0, 0));
91
92     myOutputLabel = new JLabel(JavaUiBundle.message("module.paths.output.label"));
93     outputPathsPanel.add(myOutputLabel, new GridBagConstraints(0, GridBagConstraints.RELATIVE, 1, 1, 0.0, 0.0, GridBagConstraints.EAST,
94                                                                GridBagConstraints.NONE, JBUI.insets(6, 12, 0, 4), 0, 0));
95     myOutputLabel.setLabelFor(myOutputPathPanel.getTextField());
96     outputPathsPanel.add(myOutputPathPanel, new GridBagConstraints(1, GridBagConstraints.RELATIVE, 2, 1, 1.0, 0.0, GridBagConstraints.WEST,
97                                                                    GridBagConstraints.HORIZONTAL, JBUI.insets(6, 4, 0, 0), 0, 0));
98
99     myTestOutputLabel = new JLabel(JavaUiBundle.message("module.paths.test.output.label"));
100     outputPathsPanel.add(myTestOutputLabel, new GridBagConstraints(0, GridBagConstraints.RELATIVE, 1, 1, 0.0, 0.0, GridBagConstraints.EAST,
101                                                                    GridBagConstraints.NONE, JBUI.insets(6, 16, 0, 4), 0, 0));
102     myTestOutputLabel.setLabelFor(myTestsOutputPathPanel.getTextField());
103     outputPathsPanel.add(myTestsOutputPathPanel, new GridBagConstraints(1, GridBagConstraints.RELATIVE, 2, 1, 1.0, 0.0,
104                                                                         GridBagConstraints.WEST, GridBagConstraints.HORIZONTAL,
105                                                                         JBUI.insets(6, 4, 0, 0), 0, 0));
106
107     outputPathsPanel.add(myCbExcludeOutput, new GridBagConstraints(0, GridBagConstraints.RELATIVE, 2, 1, 1.0, 0.0, GridBagConstraints.WEST,
108                                                                    GridBagConstraints.NONE, JBUI.insets(6, 16, 0, 0), 0, 0));
109
110     final boolean outputPathInherited = getCompilerExtension().isCompilerOutputPathInherited();
111     myInheritCompilerOutput.setSelected(outputPathInherited);
112     myPerModuleCompilerOutput.setSelected(!outputPathInherited);
113
114     // fill with data
115     updateOutputPathPresentation();
116
117     //compiler settings
118     enableCompilerSettings(!outputPathInherited);
119
120     final ActionListener listener = new ActionListener() {
121       @Override
122       public void actionPerformed(ActionEvent e) {
123         enableCompilerSettings(!myInheritCompilerOutput.isSelected());
124       }
125     };
126
127     myInheritCompilerOutput.addActionListener(listener);
128     myPerModuleCompilerOutput.addActionListener(listener);
129
130     final JPanel panel = new JPanel(new BorderLayout());
131     panel.setBorder(IdeBorderFactory.createTitledBorder(JavaUiBundle.message("project.roots.output.compiler.title")));
132     panel.add(outputPathsPanel, BorderLayout.NORTH);
133     return panel;
134   }
135
136   private void fireModuleConfigurationChanged() {
137     fireConfigurationChanged();
138   }
139
140   private void updateOutputPathPresentation() {
141     if (getCompilerExtension().isCompilerOutputPathInherited()) {
142       ProjectConfigurable projectConfig = ProjectStructureConfigurable.getInstance(myProject).getProjectConfig();
143       if (projectConfig == null) {
144         return;
145       }
146       final String baseUrl = projectConfig.getCompilerOutputUrl();
147       moduleCompileOutputChanged(baseUrl, getModel().getModule().getName());
148     } else {
149       final VirtualFile compilerOutputPath = getCompilerExtension().getCompilerOutputPath();
150       if (compilerOutputPath != null) {
151         myOutputPathPanel.setText(FileUtil.toSystemDependentName(compilerOutputPath.getPath()));
152       }
153       else {
154         final String compilerOutputUrl = getCompilerExtension().getCompilerOutputUrl();
155         if (compilerOutputUrl != null) {
156           myOutputPathPanel.setText(FileUtil.toSystemDependentName(VfsUtilCore.urlToPath(compilerOutputUrl)));
157         }
158       }
159       final VirtualFile testsOutputPath = getCompilerExtension().getCompilerOutputPathForTests();
160       if (testsOutputPath != null) {
161         myTestsOutputPathPanel.setText(FileUtil.toSystemDependentName(testsOutputPath.getPath()));
162       }
163       else {
164         final String testsOutputUrl = getCompilerExtension().getCompilerOutputUrlForTests();
165         if (testsOutputUrl != null) {
166           myTestsOutputPathPanel.setText(FileUtil.toSystemDependentName(VfsUtilCore.urlToPath(testsOutputUrl)));
167         }
168       }
169     }
170   }
171
172   private void enableCompilerSettings(final boolean enabled) {
173     UIUtil.setEnabled(myOutputPathPanel, enabled, true);
174     UIUtil.setEnabled(myOutputLabel, enabled, true);
175     UIUtil.setEnabled(myTestsOutputPathPanel, enabled, true);
176     UIUtil.setEnabled(myTestOutputLabel, enabled, true);
177     myCbExcludeOutput.setEnabled(enabled);
178     getCompilerExtension().inheritCompilerOutputPath(!enabled);
179     updateOutputPathPresentation();
180     fireModuleConfigurationChanged();
181   }
182
183   private CommittableFieldPanel createOutputPathPanel(final @NlsContexts.DialogTitle String title, final CommitPathRunnable commitPathRunnable) {
184     final JTextField textField = new ExtendableTextField();
185     final FileChooserDescriptor outputPathsChooserDescriptor = FileChooserDescriptorFactory.createSingleFolderDescriptor();
186     outputPathsChooserDescriptor.putUserData(LangDataKeys.MODULE_CONTEXT, getModel().getModule());
187     outputPathsChooserDescriptor.setHideIgnored(false);
188     InsertPathAction.addTo(textField, outputPathsChooserDescriptor);
189     FileChooserFactory.getInstance().installFileCompletion(textField, outputPathsChooserDescriptor, true, null);
190     final Runnable commitRunnable = () -> {
191       if (!getModel().isWritable()) {
192         return;
193       }
194       final String path = textField.getText().trim();
195       if (path.length() == 0) {
196         commitPathRunnable.saveUrl(null);
197       }
198       else {
199         // should set only absolute paths
200         String canonicalPath;
201         try {
202           canonicalPath = FileUtil.resolveShortWindowsName(path);
203         }
204         catch (IOException e) {
205           canonicalPath = path;
206         }
207         commitPathRunnable.saveUrl(VfsUtilCore.pathToUrl(canonicalPath));
208       }
209     };
210
211     final ActionListener listener = new ActionListener() {
212       @Override
213       public void actionPerformed(ActionEvent e) {
214         commitRunnable.run();
215       }
216     };
217     myPerModuleCompilerOutput.addActionListener(listener);
218
219     textField.getDocument().addDocumentListener(new DocumentAdapter() {
220       @Override
221       protected void textChanged(@NotNull DocumentEvent e) {
222         commitRunnable.run();
223       }
224     });
225
226     return new CommittableFieldPanel(textField, null, null, new BrowseFilesListener(textField, title, "", outputPathsChooserDescriptor) {
227       @Override
228       public void actionPerformed(ActionEvent e) {
229         super.actionPerformed(e);
230         commitRunnable.run();
231       }
232     }, null, commitRunnable);
233   }
234
235   @Override
236   public void saveData() {
237     myOutputPathPanel.commit();
238     myTestsOutputPathPanel.commit();
239   }
240
241   @Override
242   public String getDisplayName() {
243     return JavaUiBundle.message("output.tab.title");
244   }
245
246   @Override
247   @Nullable
248   @NonNls
249   public String getHelpTopic() {
250     return "project.structureModulesPage.outputJavadoc";
251   }
252
253
254   @Override
255   public void moduleStateChanged() {
256     //if content entries tree was changed
257     myCbExcludeOutput.setSelected(getCompilerExtension().isExcludeOutput());
258   }
259
260   @Override
261   public void moduleCompileOutputChanged(final String baseUrl, final String moduleName) {
262     if (getCompilerExtension().isCompilerOutputPathInherited()) {
263       if (baseUrl != null) {
264         myOutputPathPanel.setText(FileUtil.toSystemDependentName(VfsUtilCore.urlToPath(baseUrl + "/" + CompilerModuleExtension
265           .PRODUCTION + "/" + moduleName)));
266         myTestsOutputPathPanel.setText(FileUtil.toSystemDependentName(VfsUtilCore.urlToPath(baseUrl + "/" + CompilerModuleExtension
267           .TEST + "/" + moduleName)));
268       }
269       else {
270         myOutputPathPanel.setText(null);
271         myTestsOutputPathPanel.setText(null);
272       }
273     }
274   }
275
276   public CompilerModuleExtension getCompilerExtension() {
277     return getModel().getModuleExtension(CompilerModuleExtension.class);
278   }
279
280   private interface CommitPathRunnable {
281     void saveUrl(String url);
282   }
283
284   private static class CommittableFieldPanel extends FieldPanel {
285     private final Runnable myCommitRunnable;
286
287     CommittableFieldPanel(final JTextField textField,
288                           String labelText,
289                           final String viewerDialogTitle,
290                           ActionListener browseButtonActionListener,
291                           final Runnable documentListener,
292                           final Runnable commitPathRunnable) {
293       super(textField, labelText, viewerDialogTitle, browseButtonActionListener, documentListener);
294       myCommitRunnable = commitPathRunnable;
295     }
296
297     public void commit() {
298       myCommitRunnable.run();
299     }
300   }
301 }