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