1
2
3
4
5
6
7
8
9
10
11 package de.funfried.netbeans.plugins.external.formatter.java.eclipse.ui;
12
13 import java.awt.Color;
14 import java.awt.event.ActionEvent;
15 import java.awt.event.ActionListener;
16 import java.awt.event.FocusAdapter;
17 import java.awt.event.FocusEvent;
18 import java.awt.event.ItemEvent;
19 import java.awt.event.ItemListener;
20 import java.io.File;
21 import java.io.IOException;
22 import java.net.URL;
23 import java.nio.file.Path;
24 import java.nio.file.Paths;
25 import java.util.List;
26 import java.util.Objects;
27 import java.util.logging.Level;
28 import java.util.logging.Logger;
29 import java.util.prefs.Preferences;
30
31 import javax.swing.DefaultComboBoxModel;
32 import javax.swing.GroupLayout;
33 import javax.swing.JButton;
34 import javax.swing.JCheckBox;
35 import javax.swing.JComboBox;
36 import javax.swing.JLabel;
37 import javax.swing.JTextField;
38 import javax.swing.LayoutStyle;
39 import javax.swing.SwingConstants;
40 import javax.swing.event.DocumentEvent;
41 import javax.swing.event.DocumentListener;
42 import javax.swing.filechooser.FileFilter;
43 import javax.swing.filechooser.FileNameExtensionFilter;
44
45 import org.apache.commons.lang3.StringUtils;
46 import org.netbeans.api.project.Project;
47 import org.openide.awt.Mnemonics;
48 import org.openide.filesystems.FileChooserBuilder;
49 import org.openide.util.NbBundle;
50 import org.xml.sax.SAXException;
51
52 import de.funfried.netbeans.plugins.external.formatter.eclipse.xml.ConfigReader;
53 import de.funfried.netbeans.plugins.external.formatter.exceptions.ConfigReadException;
54 import de.funfried.netbeans.plugins.external.formatter.java.eclipse.EclipseJavaFormatterSettings;
55 import de.funfried.netbeans.plugins.external.formatter.ui.options.AbstractFormatterOptionsPanel;
56
57
58
59
60
61 public class EclipseJavaFormatterOptionsPanel extends AbstractFormatterOptionsPanel {
62
63 private static final Logger log = Logger.getLogger(EclipseJavaFormatterOptionsPanel.class.getName());
64
65
66
67
68
69
70
71 public EclipseJavaFormatterOptionsPanel(Project project) {
72 super(project);
73
74 initComponents();
75
76 if (project != null) {
77 lblFormatterFile.setToolTipText(NbBundle.getMessage(EclipseJavaFormatterOptionsPanel.class, "EclipseJavaFormatterOptionsPanel.lblFormatterFile.toolTipText.projectSpecific"));
78 browseButton.setToolTipText(NbBundle.getMessage(EclipseJavaFormatterOptionsPanel.class, "EclipseJavaFormatterOptionsPanel.browseButton.toolTipText.projectSpecific"));
79 }
80 }
81
82
83
84
85
86
87
88 @SuppressWarnings("unchecked")
89
90 private void initComponents() {
91
92 lblFormatterFile = new JLabel();
93 formatterLocField = new JTextField();
94 browseButton = new JButton();
95 errorLabel = new JLabel();
96 jLabel2 = new JLabel();
97 cbProfile = new JComboBox<>();
98 lblProfile = new JLabel();
99 cbUseProjectPref = new JCheckBox();
100 lblLinefeed = new JLabel();
101 cbLinefeed = new JComboBox<>();
102 lblSourceLevel = new JLabel();
103 cbSourceLevel = new JComboBox<>();
104
105 lblFormatterFile.setHorizontalAlignment(SwingConstants.RIGHT);
106 Mnemonics.setLocalizedText(lblFormatterFile, NbBundle.getMessage(EclipseJavaFormatterOptionsPanel.class, "EclipseJavaFormatterOptionsPanel.lblFormatterFile.text"));
107 lblFormatterFile.setToolTipText(NbBundle.getMessage(EclipseJavaFormatterOptionsPanel.class, "EclipseJavaFormatterOptionsPanel.lblFormatterFile.toolTipText"));
108
109 formatterLocField.setText(NbBundle.getMessage(EclipseJavaFormatterOptionsPanel.class, "EclipseJavaFormatterOptionsPanel.formatterLocField.text"));
110 formatterLocField.setPreferredSize(formatterLocField.getMinimumSize());
111 formatterLocField.addFocusListener(new FocusAdapter() {
112 public void focusLost(FocusEvent evt) {
113 formatterLocFieldFocusLost(evt);
114 }
115 });
116 formatterLocField.addActionListener(new ActionListener() {
117 public void actionPerformed(ActionEvent evt) {
118 formatterLocFieldActionPerformed(evt);
119 }
120 });
121
122 Mnemonics.setLocalizedText(browseButton, NbBundle.getMessage(EclipseJavaFormatterOptionsPanel.class, "EclipseJavaFormatterOptionsPanel.browseButton.text"));
123 browseButton.setToolTipText(NbBundle.getMessage(EclipseJavaFormatterOptionsPanel.class, "EclipseJavaFormatterOptionsPanel.browseButton.toolTipText"));
124 browseButton.addActionListener(new ActionListener() {
125 public void actionPerformed(ActionEvent evt) {
126 browseButtonActionPerformed(evt);
127 }
128 });
129
130 errorLabel.setForeground(new Color(255, 51, 51));
131 Mnemonics.setLocalizedText(errorLabel, NbBundle.getMessage(EclipseJavaFormatterOptionsPanel.class, "EclipseJavaFormatterOptionsPanel.errorLabel.text"));
132
133 Mnemonics.setLocalizedText(jLabel2, NbBundle.getMessage(EclipseJavaFormatterOptionsPanel.class, "EclipseJavaFormatterOptionsPanel.jLabel2.text"));
134 jLabel2.setEnabled(false);
135
136 cbProfile.setEnabled(false);
137 cbProfile.addItemListener(new ItemListener() {
138 public void itemStateChanged(ItemEvent evt) {
139 cbProfileItemStateChanged(evt);
140 }
141 });
142
143 lblProfile.setHorizontalAlignment(SwingConstants.RIGHT);
144 Mnemonics.setLocalizedText(lblProfile, NbBundle.getMessage(EclipseJavaFormatterOptionsPanel.class, "EclipseJavaFormatterOptionsPanel.lblProfile.text"));
145 lblProfile.setToolTipText(NbBundle.getMessage(EclipseJavaFormatterOptionsPanel.class, "EclipseJavaFormatterOptionsPanel.lblProfile.toolTipText"));
146
147 cbUseProjectPref.setSelected(true);
148 Mnemonics.setLocalizedText(cbUseProjectPref, NbBundle.getMessage(EclipseJavaFormatterOptionsPanel.class, "EclipseJavaFormatterOptionsPanel.cbUseProjectPref.text"));
149 cbUseProjectPref.setToolTipText(NbBundle.getMessage(EclipseJavaFormatterOptionsPanel.class, "EclipseJavaFormatterOptionsPanel.cbUseProjectPref.toolTipText"));
150
151 lblLinefeed.setHorizontalAlignment(SwingConstants.RIGHT);
152 Mnemonics.setLocalizedText(lblLinefeed, NbBundle.getMessage(EclipseJavaFormatterOptionsPanel.class, "EclipseJavaFormatterOptionsPanel.lblLinefeed.text"));
153 lblLinefeed.setToolTipText(NbBundle.getMessage(EclipseJavaFormatterOptionsPanel.class, "EclipseJavaFormatterOptionsPanel.lblLinefeed.toolTipText"));
154
155 cbLinefeed.setModel(new DefaultComboBoxModel<>(new String[] { "System", "\\n", "\\r\\n", "\\r" }));
156 cbLinefeed.addItemListener(new ItemListener() {
157 public void itemStateChanged(ItemEvent evt) {
158 cbLinefeedItemStateChanged(evt);
159 }
160 });
161
162 Mnemonics.setLocalizedText(lblSourceLevel, NbBundle.getMessage(EclipseJavaFormatterOptionsPanel.class, "EclipseJavaFormatterOptionsPanel.lblSourceLevel.text"));
163 lblSourceLevel.setToolTipText(NbBundle.getMessage(EclipseJavaFormatterOptionsPanel.class, "EclipseJavaFormatterOptionsPanel.lblSourceLevel.toolTipText"));
164
165 cbSourceLevel.setModel(new DefaultComboBoxModel<>(new String[] { "No override", "1.9", "1.8", "1.7", "1.6", "1.5", "1.4" }));
166 cbSourceLevel.addItemListener(new ItemListener() {
167 public void itemStateChanged(ItemEvent evt) {
168 cbSourceLevelItemStateChanged(evt);
169 }
170 });
171
172 GroupLayout layout = new GroupLayout(this);
173 this.setLayout(layout);
174 layout.setHorizontalGroup(layout.createParallelGroup(GroupLayout.Alignment.LEADING)
175 .addGroup(layout.createSequentialGroup()
176 .addContainerGap()
177 .addGroup(layout.createParallelGroup(GroupLayout.Alignment.TRAILING)
178 .addComponent(lblFormatterFile)
179 .addComponent(lblProfile, GroupLayout.PREFERRED_SIZE, 110, GroupLayout.PREFERRED_SIZE)
180 .addComponent(lblLinefeed, GroupLayout.PREFERRED_SIZE, 110, GroupLayout.PREFERRED_SIZE))
181 .addPreferredGap(LayoutStyle.ComponentPlacement.UNRELATED)
182 .addGroup(layout.createParallelGroup(GroupLayout.Alignment.LEADING)
183 .addGroup(layout.createSequentialGroup()
184 .addComponent(jLabel2, GroupLayout.PREFERRED_SIZE, GroupLayout.DEFAULT_SIZE, GroupLayout.PREFERRED_SIZE)
185 .addPreferredGap(LayoutStyle.ComponentPlacement.UNRELATED)
186 .addComponent(errorLabel, GroupLayout.DEFAULT_SIZE, GroupLayout.DEFAULT_SIZE, Short.MAX_VALUE))
187 .addGroup(layout.createSequentialGroup()
188 .addComponent(formatterLocField, GroupLayout.DEFAULT_SIZE, GroupLayout.DEFAULT_SIZE, Short.MAX_VALUE)
189 .addPreferredGap(LayoutStyle.ComponentPlacement.RELATED)
190 .addComponent(browseButton))
191 .addGroup(layout.createSequentialGroup()
192 .addComponent(cbLinefeed, GroupLayout.PREFERRED_SIZE, 121, GroupLayout.PREFERRED_SIZE)
193 .addGap(18, 18, 18)
194 .addComponent(lblSourceLevel)
195 .addPreferredGap(LayoutStyle.ComponentPlacement.RELATED)
196 .addComponent(cbSourceLevel, GroupLayout.PREFERRED_SIZE, 121, GroupLayout.PREFERRED_SIZE))
197 .addComponent(cbUseProjectPref)
198 .addComponent(cbProfile, GroupLayout.PREFERRED_SIZE, 200, GroupLayout.PREFERRED_SIZE))
199 .addContainerGap())
200 );
201 layout.setVerticalGroup(layout.createParallelGroup(GroupLayout.Alignment.LEADING)
202 .addGroup(layout.createSequentialGroup()
203 .addContainerGap()
204 .addGroup(layout.createParallelGroup(GroupLayout.Alignment.BASELINE)
205 .addComponent(lblFormatterFile)
206 .addComponent(formatterLocField, GroupLayout.PREFERRED_SIZE, GroupLayout.DEFAULT_SIZE, GroupLayout.PREFERRED_SIZE)
207 .addComponent(browseButton))
208 .addGap(7, 7, 7)
209 .addGroup(layout.createParallelGroup(GroupLayout.Alignment.LEADING)
210 .addComponent(errorLabel, GroupLayout.PREFERRED_SIZE, 26, GroupLayout.PREFERRED_SIZE)
211 .addComponent(jLabel2, GroupLayout.PREFERRED_SIZE, GroupLayout.DEFAULT_SIZE, GroupLayout.PREFERRED_SIZE))
212 .addPreferredGap(LayoutStyle.ComponentPlacement.RELATED)
213 .addGroup(layout.createParallelGroup(GroupLayout.Alignment.BASELINE)
214 .addComponent(cbProfile, GroupLayout.PREFERRED_SIZE, GroupLayout.DEFAULT_SIZE, GroupLayout.PREFERRED_SIZE)
215 .addComponent(lblProfile))
216 .addPreferredGap(LayoutStyle.ComponentPlacement.UNRELATED)
217 .addComponent(cbUseProjectPref)
218 .addPreferredGap(LayoutStyle.ComponentPlacement.UNRELATED)
219 .addGroup(layout.createParallelGroup(GroupLayout.Alignment.BASELINE)
220 .addComponent(cbLinefeed, GroupLayout.PREFERRED_SIZE, GroupLayout.DEFAULT_SIZE, GroupLayout.PREFERRED_SIZE)
221 .addComponent(lblLinefeed)
222 .addComponent(lblSourceLevel)
223 .addComponent(cbSourceLevel, GroupLayout.PREFERRED_SIZE, GroupLayout.DEFAULT_SIZE, GroupLayout.PREFERRED_SIZE))
224 .addContainerGap(GroupLayout.DEFAULT_SIZE, Short.MAX_VALUE))
225 );
226
227 formatterLocField.getDocument().addDocumentListener(new DocumentListener() {
228
229
230
231 @Override
232 public void insertUpdate(DocumentEvent e) {
233 fireChangedListener();
234 }
235
236
237
238
239 @Override
240 public void removeUpdate(DocumentEvent e) {
241 fireChangedListener();
242 }
243
244
245
246
247 @Override
248 public void changedUpdate(DocumentEvent e) {
249 fireChangedListener();
250 }
251 });
252 }
253
254 private void formatterLocFieldActionPerformed(ActionEvent evt) {
255 loadEclipseFormatterFileForPreview(formatterLocField.getText(), getSelectedProfile());
256 fireChangedListener();
257 }
258
259 private void browseButtonActionPerformed(ActionEvent evt) {
260
261 File home = new File(System.getProperty("user.home"));
262 final FileNameExtensionFilter fileNameExtensionFilterXML = new FileNameExtensionFilter("Eclipse formatter (*.xml)", "xml");
263 final FileNameExtensionFilter fileNameExtensionFilterEPF = new FileNameExtensionFilter("Workspace mechanic (*.epf)", "epf");
264 final FileFilter fileNameExtensionFilterProjectSetting = new FileFilter() {
265
266
267
268 @Override
269 public boolean accept(File f) {
270 if (f.isDirectory()) {
271 return true;
272 }
273 return EclipseJavaFormatterSettings.PROJECT_PREF_FILE.equals(f.getName());
274 }
275
276
277
278
279 @Override
280 public String getDescription() {
281 return "Eclipse project settings (" + EclipseJavaFormatterSettings.PROJECT_PREF_FILE + ")";
282 }
283 };
284
285
286 File toAdd = new FileChooserBuilder("user-dir").setFileHiding(false).setFilesOnly(true).setTitle("Choose configuration ...").setDefaultWorkingDirectory(home).setApproveText("Choose")
287 .addFileFilter(fileNameExtensionFilterProjectSetting).addFileFilter(fileNameExtensionFilterXML).addFileFilter(fileNameExtensionFilterEPF).setFileFilter(fileNameExtensionFilterXML)
288 .showOpenDialog();
289
290 if (toAdd != null) {
291 loadEclipseFormatterFileForPreview(toAdd.getAbsolutePath(), getSelectedProfile());
292 fireChangedListener();
293 }
294 }
295
296 private void cbProfileItemStateChanged(ItemEvent evt) {
297 if (ItemEvent.SELECTED == evt.getStateChange()) {
298 cbProfile.setToolTipText(Objects.toString(cbProfile.getSelectedItem(), null));
299
300 fireChangedListener();
301 }
302 }
303
304 private void cbLinefeedItemStateChanged(ItemEvent evt) {
305 if (ItemEvent.SELECTED == evt.getStateChange()) {
306 cbLinefeed.setToolTipText(Objects.toString(cbLinefeed.getSelectedItem(), null));
307
308 fireChangedListener();
309 }
310 }
311
312 private void cbSourceLevelItemStateChanged(ItemEvent evt) {
313 if (ItemEvent.SELECTED == evt.getStateChange()) {
314 cbSourceLevel.setToolTipText(Objects.toString(cbSourceLevel.getSelectedItem(), null));
315
316 fireChangedListener();
317 }
318 }
319
320 private void formatterLocFieldFocusLost(FocusEvent evt) {
321 loadEclipseFormatterFileForPreview(formatterLocField.getText(), getSelectedProfile());
322
323 fireChangedListener();
324 }
325
326
327 private JButton browseButton;
328 private JComboBox<String> cbLinefeed;
329 private JComboBox<String> cbProfile;
330 private JComboBox<String> cbSourceLevel;
331 private JCheckBox cbUseProjectPref;
332 private JLabel errorLabel;
333 private JTextField formatterLocField;
334 private JLabel jLabel2;
335 private JLabel lblFormatterFile;
336 private JLabel lblLinefeed;
337 private JLabel lblProfile;
338 private JLabel lblSourceLevel;
339
340
341 private String getLinefeed() {
342 if (0 == cbLinefeed.getSelectedIndex()) {
343 return "";
344 }
345 return cbLinefeed.getSelectedItem().toString();
346 }
347
348
349
350
351
352
353 private String getSelectedProfile() {
354 if (null != cbProfile.getSelectedItem()) {
355 return cbProfile.getSelectedItem().toString();
356 } else {
357 return "";
358 }
359 }
360
361 private String getSourceLevel() {
362 if (cbSourceLevel.getSelectedIndex() >= 1) {
363 return "" + cbSourceLevel.getSelectedItem();
364 } else {
365 return "";
366 }
367 }
368
369
370
371
372 @Override
373 public void load(Preferences preferences) {
374 String eclipseFormatterLocation = preferences.get(EclipseJavaFormatterSettings.CONFIG_FILE_LOCATION, "");
375 String eclipseFormatterProfile = preferences.get(EclipseJavaFormatterSettings.ACTIVE_PROFILE, "");
376 boolean useProjectPrefs = preferences.getBoolean(EclipseJavaFormatterSettings.USE_PROJECT_PREFS, true);
377 String eclipseLineFeed = preferences.get(EclipseJavaFormatterSettings.LINEFEED, "");
378 String sourceLevel = preferences.get(EclipseJavaFormatterSettings.SOURCELEVEL, "");
379
380 loadEclipseFormatterFileForPreview(eclipseFormatterLocation, eclipseFormatterProfile);
381
382 cbUseProjectPref.setSelected(useProjectPrefs);
383
384 if (StringUtils.isBlank(eclipseLineFeed)) {
385
386 cbLinefeed.setSelectedIndex(0);
387 } else {
388 cbLinefeed.setSelectedItem(eclipseLineFeed);
389 }
390
391 cbLinefeed.setToolTipText(Objects.toString(cbLinefeed.getSelectedItem(), null));
392
393 if (StringUtils.isBlank(sourceLevel)) {
394
395 cbSourceLevel.setSelectedIndex(0);
396 } else {
397 cbSourceLevel.setSelectedItem(sourceLevel);
398 }
399
400 cbSourceLevel.setToolTipText(Objects.toString(cbSourceLevel.getSelectedItem(), null));
401 }
402
403 private void loadEclipseFormatterFileForPreview(String formatterFile, String activeProfile) {
404 String filePath;
405
406 try {
407 URL url = new URL(formatterFile);
408
409 filePath = url.toString();
410 } catch (IOException ex) {
411 Path formatterFilePath = Paths.get(formatterFile);
412 if (!formatterFilePath.isAbsolute() && project != null) {
413 formatterFilePath = Paths.get(project.getProjectDirectory().getPath()).resolve(formatterFilePath);
414 }
415
416 filePath = formatterFilePath.toAbsolutePath().toString();
417 }
418
419 formatterLocField.setText(formatterFile);
420
421 cbProfile.setEnabled(false);
422
423 cbProfile.removeAllItems();
424 cbProfile.setToolTipText(null);
425
426 try {
427
428 if (EclipseJavaFormatterSettings.isXMLConfigurationFile(filePath)) {
429 List<String> profileNames = ConfigReader.getProfileNames(ConfigReader.readContentFromFilePath(filePath));
430 cbProfile.addItem(NbBundle.getMessage(EclipseJavaFormatterOptionsPanel.class, "EclipseJavaFormatterOptionsPanel.chooseProfile"));
431
432 String entryToSelect = null;
433 for (String profileName : profileNames) {
434 cbProfile.addItem(profileName);
435 if (activeProfile != null && activeProfile.equals(profileName)) {
436 entryToSelect = profileName;
437 }
438 }
439 selectProfileOrFallback(entryToSelect, profileNames);
440 cbProfile.setEnabled(true);
441 }
442
443 formatterLocField.setToolTipText(filePath);
444 } catch (IOException | SAXException | ConfigReadException ex) {
445 log.log(Level.INFO, "Could not parse formatter config", ex);
446 }
447 }
448
449 private void selectProfileOrFallback(String entryToSelect, List<String> profiles) {
450 if (null != entryToSelect) {
451 cbProfile.setSelectedItem(entryToSelect);
452 } else if (profiles.size() == 1) {
453
454 cbProfile.setSelectedIndex(1);
455 } else {
456
457 cbProfile.setSelectedIndex(0);
458 }
459
460 cbProfile.setToolTipText(Objects.toString(cbProfile.getSelectedItem(), null));
461 }
462
463
464
465
466 @Override
467 public void store(Preferences preferences) {
468 preferences.put(EclipseJavaFormatterSettings.CONFIG_FILE_LOCATION, formatterLocField.getText());
469 preferences.put(EclipseJavaFormatterSettings.ACTIVE_PROFILE, getSelectedProfile());
470 preferences.putBoolean(EclipseJavaFormatterSettings.USE_PROJECT_PREFS, cbUseProjectPref.isSelected());
471 preferences.put(EclipseJavaFormatterSettings.LINEFEED, getLinefeed());
472 preferences.put(EclipseJavaFormatterSettings.SOURCELEVEL, getSourceLevel());
473 }
474
475
476
477
478 @Override
479 public boolean valid() {
480 errorLabel.setText("");
481
482 String fileName = formatterLocField.getText();
483 if (StringUtils.isBlank(fileName) && cbUseProjectPref.isSelected()) {
484
485 return true;
486 } else if (StringUtils.isNotBlank(fileName) && project != null) {
487 Path formatterFilePath = Paths.get(fileName);
488 if (!formatterFilePath.isAbsolute()) {
489 fileName = Paths.get(project.getProjectDirectory().getPath()).resolve(formatterFilePath).toString();
490 }
491 }
492
493 boolean fileExists;
494 try {
495 new URL(formatterLocField.getText());
496
497 fileName = formatterLocField.getText();
498 fileExists = true;
499 } catch (IOException ex) {
500 fileExists = new File(fileName).exists();
501 }
502
503 boolean isXML = EclipseJavaFormatterSettings.isXMLConfigurationFile(fileName);
504 boolean isEPF = EclipseJavaFormatterSettings.isWorkspaceMechanicFile(fileName);
505 boolean isProjectSetting = EclipseJavaFormatterSettings.isProjectSetting(fileName);
506
507 if (!fileExists || (!isXML && !isEPF && !isProjectSetting) || (isXML && cbProfile.getSelectedIndex() < 0)) {
508 errorLabel.setText("Invalid file. Please enter a valid configuration file.");
509 return false;
510 } else {
511 return !isXML || cbProfile.getSelectedIndex() != 0;
512 }
513 }
514 }