1
2
3
4
5
6
7
8
9
10
11 package de.funfried.netbeans.plugins.external.formatter.ui.options;
12
13 import java.awt.BorderLayout;
14 import java.awt.Component;
15 import java.awt.Container;
16 import java.awt.Cursor;
17 import java.awt.Font;
18 import java.awt.Frame;
19 import java.awt.event.ActionEvent;
20 import java.awt.event.ActionListener;
21 import java.awt.event.ItemEvent;
22 import java.awt.event.ItemListener;
23 import java.awt.event.MouseAdapter;
24 import java.awt.event.MouseEvent;
25 import java.net.MalformedURLException;
26 import java.net.URL;
27 import java.util.ArrayList;
28 import java.util.Collection;
29 import java.util.HashMap;
30 import java.util.List;
31 import java.util.Map;
32 import java.util.Objects;
33 import java.util.logging.Level;
34 import java.util.logging.Logger;
35 import java.util.prefs.BackingStoreException;
36 import java.util.prefs.Preferences;
37
38 import javax.swing.BorderFactory;
39 import javax.swing.DefaultListCellRenderer;
40 import javax.swing.GroupLayout;
41 import javax.swing.JCheckBox;
42 import javax.swing.JComboBox;
43 import javax.swing.JLabel;
44 import javax.swing.JList;
45 import javax.swing.JPanel;
46 import javax.swing.JSpinner;
47 import javax.swing.LayoutStyle;
48 import javax.swing.SpinnerNumberModel;
49 import javax.swing.SwingConstants;
50 import javax.swing.event.ChangeEvent;
51 import javax.swing.event.ChangeListener;
52
53 import org.apache.commons.lang3.StringUtils;
54 import org.netbeans.api.java.lexer.JavaTokenId;
55 import org.netbeans.api.project.Project;
56 import org.netbeans.spi.options.OptionsPanelController.Keywords;
57 import org.openide.awt.HtmlBrowser;
58 import org.openide.awt.Mnemonics;
59 import org.openide.util.ChangeSupport;
60 import org.openide.util.Exceptions;
61 import org.openide.util.Lookup;
62 import org.openide.util.NbBundle;
63 import org.openide.util.WeakListeners;
64
65 import de.funfried.netbeans.plugins.external.formatter.FormatterService;
66 import de.funfried.netbeans.plugins.external.formatter.MimeType;
67 import de.funfried.netbeans.plugins.external.formatter.ui.customizer.VerifiableConfigPanel;
68
69
70
71
72
73
74
75 @Keywords(location = "Editor", tabTitle = "External Formatter", keywords = { "eclipse", "google", "spring", "java", "external", "format", "formatter", "eclipse formatter", "google formatter",
76 "spring formatter", "external formatter", "sql" })
77 public class ExternalFormatterPanel extends JPanel implements VerifiableConfigPanel, ChangeListener {
78
79 private static final long serialVersionUID = 1L;
80
81
82 private static final Logger log = Logger.getLogger(ExternalFormatterPanel.class.getName());
83
84
85 private transient final Map<MimeType, Map<String, FormatterOptionsPanel>> formatterOptions = new HashMap<>();
86
87
88 private transient final Map<MimeType, List<FormatterService>> formatterIdsPerMimeType = new HashMap<>();
89
90
91 private transient final Map<MimeType, String> activeFormatterId = new HashMap<>();
92
93
94 private transient final ChangeSupport changeSupport;
95
96
97 private transient final Preferences preferences;
98
99
100 private transient volatile boolean switchingMimeType = false;
101
102
103 private transient final Project project;
104
105
106 private transient boolean formatterSelectionActive = true;
107
108
109
110
111
112
113
114
115
116 public ExternalFormatterPanel(Preferences preferences, Project project) {
117 this.preferences = preferences;
118 this.project = project;
119
120 this.changeSupport = new ChangeSupport(this);
121
122 Collection<? extends FormatterService> formatterServices = Lookup.getDefault().lookupAll(FormatterService.class);
123 for (FormatterService formatterService : formatterServices) {
124 List<MimeType> mimeTypes = formatterService.getSupportedMimeTypes();
125 for (MimeType mimeType : mimeTypes) {
126 List<FormatterService> formatterServicesOfMimeType = formatterIdsPerMimeType.get(mimeType);
127 if (formatterServicesOfMimeType == null) {
128 formatterServicesOfMimeType = new ArrayList<>();
129 }
130
131 formatterServicesOfMimeType.add(formatterService);
132
133 formatterIdsPerMimeType.put(mimeType, formatterServicesOfMimeType);
134 }
135 }
136
137 initComponents();
138 initMimeTypes();
139
140 updateEnabledState();
141 }
142
143
144
145
146
147
148
149 public void addChangeListener(ChangeListener listener) {
150 changeSupport.addChangeListener(listener);
151 }
152
153
154
155
156
157
158 public void removeChangeListener(ChangeListener listener) {
159 changeSupport.removeChangeListener(listener);
160 }
161
162
163
164
165 private void fireChangedListener() {
166 changeSupport.fireChange();
167 }
168
169
170
171
172
173 private void initMimeTypes() {
174 chooseMimeTypeCmbBox.removeAllItems();
175
176 for (MimeType mimeType : MimeType.values()) {
177 chooseMimeTypeCmbBox.addItem(new ExtValue(mimeType.toString(), mimeType.getDisplayName()));
178 }
179
180 chooseMimeTypeCmbBox.setSelectedIndex(0);
181 chooseMimeTypeCmbBox.setToolTipText(Objects.toString(chooseMimeTypeCmbBox.getSelectedItem(), null));
182 }
183
184
185
186
187
188
189
190
191 private void setActiveFormatter(MimeType mimeType, String formatterId, boolean fireChange) {
192 activeFormatterId.put(mimeType, formatterId);
193
194 if (fireChange) {
195 fireChangedListener();
196 }
197 }
198
199
200
201
202
203
204
205
206
207
208
209
210 private synchronized FormatterOptionsPanel getFormatterOptionsPanel(MimeType mimeType, String formatterId) {
211 Map<String, FormatterOptionsPanel> formatterOptionPanels = formatterOptions.get(mimeType);
212 if (formatterOptionPanels == null) {
213 formatterOptionPanels = new HashMap<>();
214
215 formatterOptions.put(mimeType, formatterOptionPanels);
216 }
217
218 FormatterOptionsPanel optionsPanel = formatterOptionPanels.get(formatterId);
219 if (optionsPanel == null) {
220 List<FormatterService> formatterServices = formatterIdsPerMimeType.get(mimeType);
221 if (formatterServices != null) {
222 for (FormatterService formatterService : formatterServices) {
223 if (formatterService != null && Objects.equals(formatterId, formatterService.getId())) {
224 optionsPanel = formatterService.createOptionsPanel(project);
225 optionsPanel.load(preferences);
226
227 formatterOptionPanels.put(formatterId, optionsPanel);
228
229 formatterOptions.put(mimeType, formatterOptionPanels);
230 }
231 }
232 }
233 }
234
235 return optionsPanel;
236 }
237
238
239
240
241
242
243 private void initComponents() {
244
245 txtProjectSpecificHint = new JLabel();
246 cbShowNotifications = new JCheckBox();
247 btnDonate = new JLabel();
248 btnVisitHomePage = new JLabel();
249 useIndentationSettingsChkBox = new JCheckBox();
250 overrideTabSizeSpn = new JSpinner();
251 overrideTabSizeChkBox = new JCheckBox();
252 formatterOptionsPanel = new JPanel();
253 chooseLanguageLbl = new JLabel();
254 chooseMimeTypeCmbBox = new JComboBox<>();
255 useFormatterLbl = new JLabel();
256 chooseFormatterCmbBox = new JComboBox<>();
257
258 Mnemonics.setLocalizedText(txtProjectSpecificHint, NbBundle.getMessage(ExternalFormatterPanel.class, "ExternalFormatterPanel.txtProjectSpecificHint.text"));
259
260 Mnemonics.setLocalizedText(cbShowNotifications, NbBundle.getMessage(ExternalFormatterPanel.class, "ExternalFormatterPanel.cbShowNotifications.text"));
261 cbShowNotifications.setToolTipText(NbBundle.getMessage(ExternalFormatterPanel.class, "ExternalFormatterPanel.cbShowNotifications.toolTipText"));
262 cbShowNotifications.addActionListener(new ActionListener() {
263 public void actionPerformed(ActionEvent evt) {
264 cbShowNotificationsActionPerformed(evt);
265 }
266 });
267
268 btnDonate.setHorizontalAlignment(SwingConstants.RIGHT);
269 Mnemonics.setLocalizedText(btnDonate, NbBundle.getMessage(ExternalFormatterPanel.class, "ExternalFormatterPanel.btnDonate.text"));
270 btnDonate.setToolTipText(NbBundle.getMessage(ExternalFormatterPanel.class, "ExternalFormatterPanel.btnDonate.toolTipText"));
271 btnDonate.setCursor(new Cursor(Cursor.HAND_CURSOR));
272 btnDonate.addMouseListener(new MouseAdapter() {
273 public void mouseClicked(MouseEvent evt) {
274 btnDonateMouseClicked(evt);
275 }
276 });
277
278 btnVisitHomePage.setHorizontalAlignment(SwingConstants.RIGHT);
279 Mnemonics.setLocalizedText(btnVisitHomePage, NbBundle.getMessage(ExternalFormatterPanel.class, "ExternalFormatterPanel.btnVisitHomePage.text"));
280 btnVisitHomePage.setToolTipText(NbBundle.getMessage(ExternalFormatterPanel.class, "ExternalFormatterPanel.btnVisitHomePage.toolTipText"));
281 btnVisitHomePage.setCursor(new Cursor(Cursor.HAND_CURSOR));
282 btnVisitHomePage.addMouseListener(new MouseAdapter() {
283 public void mouseClicked(MouseEvent evt) {
284 btnVisitHomePageMouseClicked(evt);
285 }
286 });
287
288 useIndentationSettingsChkBox.setSelected(true);
289 Mnemonics.setLocalizedText(useIndentationSettingsChkBox, NbBundle.getMessage(ExternalFormatterPanel.class, "ExternalFormatterPanel.useIndentationSettingsChkBox.text"));
290 useIndentationSettingsChkBox.setToolTipText(NbBundle.getMessage(ExternalFormatterPanel.class, "ExternalFormatterPanel.useIndentationSettingsChkBox.toolTipText"));
291 useIndentationSettingsChkBox.addActionListener(new ActionListener() {
292 public void actionPerformed(ActionEvent evt) {
293 useIndentationSettingsChkBoxActionPerformed(evt);
294 }
295 });
296
297 overrideTabSizeSpn.setModel(new SpinnerNumberModel(4, 1, 20, 1));
298 overrideTabSizeSpn.setToolTipText(NbBundle.getMessage(ExternalFormatterPanel.class, "ExternalFormatterPanel.overrideTabSizeSpn.toolTipText"));
299 overrideTabSizeSpn.setEnabled(false);
300 overrideTabSizeSpn.addChangeListener(new ChangeListener() {
301 public void stateChanged(ChangeEvent evt) {
302 overrideTabSizeSpnStateChanged(evt);
303 }
304 });
305
306 Mnemonics.setLocalizedText(overrideTabSizeChkBox, NbBundle.getMessage(ExternalFormatterPanel.class, "ExternalFormatterPanel.overrideTabSizeChkBox.text"));
307 overrideTabSizeChkBox.setToolTipText(NbBundle.getMessage(ExternalFormatterPanel.class, "ExternalFormatterPanel.overrideTabSizeChkBox.toolTipText"));
308 overrideTabSizeChkBox.addActionListener(new ActionListener() {
309 public void actionPerformed(ActionEvent evt) {
310 overrideTabSizeChkBoxActionPerformed(evt);
311 }
312 });
313
314 formatterOptionsPanel.setLayout(new BorderLayout());
315
316 Mnemonics.setLocalizedText(chooseLanguageLbl, NbBundle.getMessage(ExternalFormatterPanel.class, "ExternalFormatterPanel.chooseLanguageLbl.text"));
317
318 chooseMimeTypeCmbBox.setRenderer(new MimeTypesListCellRenderer());
319 chooseMimeTypeCmbBox.addItemListener(new ItemListener() {
320 public void itemStateChanged(ItemEvent evt) {
321 chooseMimeTypeCmbBoxItemStateChanged(evt);
322 }
323 });
324
325 Mnemonics.setLocalizedText(useFormatterLbl, NbBundle.getMessage(ExternalFormatterPanel.class, "ExternalFormatterPanel.useFormatterLbl.text"));
326
327 chooseFormatterCmbBox.addItemListener(new ItemListener() {
328 public void itemStateChanged(ItemEvent evt) {
329 chooseFormatterCmbBoxItemStateChanged(evt);
330 }
331 });
332
333 GroupLayout layout = new GroupLayout(this);
334 this.setLayout(layout);
335 layout.setHorizontalGroup(layout.createParallelGroup(GroupLayout.Alignment.LEADING)
336 .addGroup(layout.createSequentialGroup()
337 .addContainerGap()
338 .addGroup(layout.createParallelGroup(GroupLayout.Alignment.LEADING)
339 .addGroup(layout.createSequentialGroup()
340 .addGap(0, 0, Short.MAX_VALUE)
341 .addComponent(txtProjectSpecificHint))
342 .addGroup(layout.createSequentialGroup()
343 .addGroup(layout.createParallelGroup(GroupLayout.Alignment.LEADING)
344 .addComponent(formatterOptionsPanel, GroupLayout.DEFAULT_SIZE, GroupLayout.DEFAULT_SIZE, Short.MAX_VALUE)
345 .addGroup(layout.createSequentialGroup()
346 .addComponent(btnVisitHomePage, GroupLayout.PREFERRED_SIZE, GroupLayout.DEFAULT_SIZE, GroupLayout.PREFERRED_SIZE)
347 .addPreferredGap(LayoutStyle.ComponentPlacement.RELATED, GroupLayout.DEFAULT_SIZE, Short.MAX_VALUE)
348 .addComponent(btnDonate, GroupLayout.PREFERRED_SIZE, GroupLayout.DEFAULT_SIZE, GroupLayout.PREFERRED_SIZE))
349 .addGroup(layout.createSequentialGroup()
350 .addGroup(layout.createParallelGroup(GroupLayout.Alignment.LEADING)
351 .addComponent(cbShowNotifications)
352 .addGroup(layout.createSequentialGroup()
353 .addComponent(useIndentationSettingsChkBox)
354 .addGap(18, 18, 18)
355 .addComponent(overrideTabSizeChkBox)
356 .addPreferredGap(LayoutStyle.ComponentPlacement.RELATED)
357 .addComponent(overrideTabSizeSpn, GroupLayout.PREFERRED_SIZE, GroupLayout.DEFAULT_SIZE, GroupLayout.PREFERRED_SIZE))
358 .addGroup(layout.createSequentialGroup()
359 .addComponent(chooseLanguageLbl)
360 .addPreferredGap(LayoutStyle.ComponentPlacement.UNRELATED)
361 .addComponent(chooseMimeTypeCmbBox, GroupLayout.PREFERRED_SIZE, GroupLayout.DEFAULT_SIZE, GroupLayout.PREFERRED_SIZE)
362 .addGap(18, 18, 18)
363 .addComponent(useFormatterLbl)
364 .addPreferredGap(LayoutStyle.ComponentPlacement.UNRELATED)
365 .addComponent(chooseFormatterCmbBox, GroupLayout.PREFERRED_SIZE, GroupLayout.DEFAULT_SIZE, GroupLayout.PREFERRED_SIZE)))
366 .addGap(0, 0, Short.MAX_VALUE)))
367 .addContainerGap())))
368 );
369 layout.setVerticalGroup(layout.createParallelGroup(GroupLayout.Alignment.LEADING)
370 .addGroup(layout.createSequentialGroup()
371 .addComponent(txtProjectSpecificHint)
372 .addPreferredGap(LayoutStyle.ComponentPlacement.RELATED)
373 .addGroup(layout.createParallelGroup(GroupLayout.Alignment.BASELINE)
374 .addComponent(chooseLanguageLbl)
375 .addComponent(chooseMimeTypeCmbBox, GroupLayout.PREFERRED_SIZE, GroupLayout.DEFAULT_SIZE, GroupLayout.PREFERRED_SIZE)
376 .addComponent(useFormatterLbl)
377 .addComponent(chooseFormatterCmbBox, GroupLayout.PREFERRED_SIZE, GroupLayout.DEFAULT_SIZE, GroupLayout.PREFERRED_SIZE))
378 .addPreferredGap(LayoutStyle.ComponentPlacement.RELATED)
379 .addComponent(formatterOptionsPanel, GroupLayout.DEFAULT_SIZE, 31, Short.MAX_VALUE)
380 .addPreferredGap(LayoutStyle.ComponentPlacement.RELATED)
381 .addGroup(layout.createParallelGroup(GroupLayout.Alignment.BASELINE)
382 .addComponent(useIndentationSettingsChkBox)
383 .addComponent(overrideTabSizeSpn, GroupLayout.PREFERRED_SIZE, GroupLayout.DEFAULT_SIZE, GroupLayout.PREFERRED_SIZE)
384 .addComponent(overrideTabSizeChkBox))
385 .addPreferredGap(LayoutStyle.ComponentPlacement.RELATED)
386 .addComponent(cbShowNotifications)
387 .addGap(13, 13, 13)
388 .addGroup(layout.createParallelGroup(GroupLayout.Alignment.BASELINE)
389 .addComponent(btnDonate, GroupLayout.PREFERRED_SIZE, GroupLayout.DEFAULT_SIZE, GroupLayout.PREFERRED_SIZE)
390 .addComponent(btnVisitHomePage, GroupLayout.PREFERRED_SIZE, GroupLayout.DEFAULT_SIZE, GroupLayout.PREFERRED_SIZE))
391 .addContainerGap())
392 );
393 }
394
395 private void btnDonateMouseClicked(MouseEvent evt) {
396 Frame parentFrame = null;
397
398 Container parent = this.getParent();
399 while(parent != null) {
400 if(parent instanceof Frame) {
401 parentFrame = (Frame) parent;
402
403 break;
404 }
405
406 parent = parent.getParent();
407 }
408
409 ExternalFormatterSupportDialog dialog = new ExternalFormatterSupportDialog(parentFrame, parentFrame != null);
410 dialog.setTitle(NbBundle.getMessage(ExternalFormatterPanel.class, "ExternalFormatterSupportDialog.title.text"));
411 dialog.pack();
412 dialog.setLocationRelativeTo(this);
413 dialog.setVisible(true);
414 dialog.toFront();
415
416
417
418
419
420
421 }
422
423 private void btnVisitHomePageMouseClicked(MouseEvent evt) {
424 try {
425 HtmlBrowser.URLDisplayer.getDefault().showURLExternal(new URL("https://github.com/funfried/externalcodeformatter_for_netbeans/"));
426 } catch (MalformedURLException ex) {
427 Exceptions.printStackTrace(ex);
428 }
429 }
430
431 private void useIndentationSettingsChkBoxActionPerformed(ActionEvent evt) {
432 updateEnabledState();
433 fireChangedListener();
434 }
435
436 private void chooseMimeTypeCmbBoxItemStateChanged(ItemEvent evt) {
437 try {
438 switchingMimeType = true;
439
440 if (ItemEvent.SELECTED == evt.getStateChange()) {
441 chooseFormatterCmbBox.removeAllItems();
442
443 formatterSelectionActive = false;
444
445 MimeType selectedMimeType = MimeType.valueOf(getSelectedValue(chooseMimeTypeCmbBox));
446
447 List<FormatterService> formatterServices = formatterIdsPerMimeType.get(selectedMimeType);
448 if (formatterServices != null) {
449 ExtValue selected = new ExtValue(Settings.DEFAULT_FORMATTER, "Internal NetBeans formatter");
450 chooseFormatterCmbBox.addItem(selected);
451
452 for (FormatterService formatterService : formatterServices) {
453 String formatterId = formatterService.getId();
454 ExtValue value = new ExtValue(formatterId, formatterService.getDisplayName());
455
456 chooseFormatterCmbBox.addItem(value);
457
458 if (Objects.equals(activeFormatterId.get(selectedMimeType), formatterId)) {
459 selected = value;
460 }
461 }
462
463 formatterSelectionActive = true;
464
465 chooseFormatterCmbBox.setSelectedItem(selected);
466 chooseFormatterCmbBox.setToolTipText(Objects.toString(chooseFormatterCmbBox.getSelectedItem(), null));
467 } else {
468 formatterSelectionActive = true;
469 }
470 }
471
472 chooseMimeTypeCmbBox.setToolTipText(Objects.toString(chooseMimeTypeCmbBox.getSelectedItem(), null));
473 } finally {
474 switchingMimeType = false;
475 }
476 }
477
478 private void chooseFormatterCmbBoxItemStateChanged(ItemEvent evt) {
479 if (!formatterSelectionActive) {
480 return;
481 }
482
483 if (ItemEvent.DESELECTED == evt.getStateChange()) {
484 formatterOptionsPanel.setBorder(null);
485 formatterOptionsPanel.removeAll();
486 } else if (ItemEvent.SELECTED == evt.getStateChange()) {
487 MimeType selectedMimeType = MimeType.valueOf(getSelectedValue(chooseMimeTypeCmbBox));
488 String selectedFormatterId = getSelectedValue(chooseFormatterCmbBox);
489
490 FormatterOptionsPanel optionsPanel = getFormatterOptionsPanel(selectedMimeType, selectedFormatterId);
491 if (optionsPanel != null) {
492 formatterOptionsPanel.setBorder(BorderFactory.createEtchedBorder());
493 formatterOptionsPanel.add(optionsPanel.getComponent(), BorderLayout.CENTER);
494
495 optionsPanel.addChangeListener(WeakListeners.change(this, optionsPanel));
496 }
497
498 setActiveFormatter(selectedMimeType, selectedFormatterId, !switchingMimeType);
499 }
500
501 chooseFormatterCmbBox.setToolTipText(Objects.toString(chooseFormatterCmbBox.getSelectedItem(), null));
502 }
503
504 private void overrideTabSizeChkBoxActionPerformed(ActionEvent evt) {
505 updateEnabledState();
506 fireChangedListener();
507 }
508
509 private void overrideTabSizeSpnStateChanged(ChangeEvent evt) {
510 overrideTabSizeSpn.setToolTipText(Objects.toString(overrideTabSizeSpn.getValue(), null));
511
512 fireChangedListener();
513 }
514
515 private void cbShowNotificationsActionPerformed(ActionEvent evt) {
516 fireChangedListener();
517 }
518
519
520
521
522 @Override
523 @SuppressWarnings("deprecation")
524 public void load() {
525 MimeType selectedMimeType = MimeType.valueOf(getSelectedValue(chooseMimeTypeCmbBox));
526 String javaMimeType = JavaTokenId.language().mimeType();
527
528 for (MimeType mimeType : formatterIdsPerMimeType.keySet()) {
529 String activeFormatter = preferences.get(Settings.ENABLED_FORMATTER_PREFIX + mimeType.toString(), Settings.DEFAULT_FORMATTER);
530 if (Settings.DEFAULT_FORMATTER.equals(activeFormatter) && mimeType.canHandle(javaMimeType)) {
531 activeFormatter = preferences.get(Settings.ENABLED_FORMATTER, Settings.DEFAULT_FORMATTER);
532
533 preferences.remove(Settings.ENABLED_FORMATTER);
534 }
535
536 setActiveFormatter(mimeType, activeFormatter, false);
537
538 if (Objects.equals(selectedMimeType, mimeType)) {
539 chooseFormatterCmbBox.setSelectedItem(new ExtValue(activeFormatter, null));
540 chooseFormatterCmbBox.setToolTipText(Objects.toString(chooseFormatterCmbBox.getSelectedItem(), null));
541 }
542 }
543
544 boolean showNotifications = preferences.getBoolean(Settings.SHOW_NOTIFICATIONS, false);
545 boolean useIndentationSettings = preferences.getBoolean(Settings.ENABLE_USE_OF_INDENTATION_SETTINGS, true);
546 boolean overrideTabSize = preferences.getBoolean(Settings.OVERRIDE_TAB_SIZE, false);
547 int overrideTabSizeValue = preferences.getInt(Settings.OVERRIDE_TAB_SIZE_VALUE, 4);
548
549 useIndentationSettingsChkBox.setSelected(useIndentationSettings);
550 overrideTabSizeChkBox.setSelected(overrideTabSize);
551 overrideTabSizeSpn.setValue(overrideTabSizeValue);
552 overrideTabSizeSpn.setToolTipText(Objects.toString(overrideTabSizeSpn.getValue(), null));
553
554 cbShowNotifications.setSelected(showNotifications);
555
556 updateEnabledState();
557 }
558
559
560
561
562 @Override
563 public void store() {
564 for (MimeType mimeType : formatterIdsPerMimeType.keySet()) {
565 preferences.put(Settings.ENABLED_FORMATTER_PREFIX + mimeType.toString(), activeFormatterId.get(mimeType));
566
567 Map<String, FormatterOptionsPanel> options = formatterOptions.get(mimeType);
568 if (options != null) {
569 for (FormatterOptionsPanel option : options.values()) {
570 option.store(preferences);
571 }
572 }
573 }
574
575 preferences.putBoolean(Settings.ENABLE_USE_OF_INDENTATION_SETTINGS, useIndentationSettingsChkBox.isSelected());
576 preferences.putBoolean(Settings.OVERRIDE_TAB_SIZE, overrideTabSizeChkBox.isSelected());
577 preferences.putInt(Settings.OVERRIDE_TAB_SIZE_VALUE, Integer.parseInt(overrideTabSizeSpn.getValue().toString()));
578 preferences.putBoolean(Settings.SHOW_NOTIFICATIONS, cbShowNotifications.isSelected());
579
580 try {
581 preferences.flush();
582 } catch (BackingStoreException ex) {
583 log.log(Level.WARNING, "Could not flush formatter settings", ex);
584 }
585
586 ExternalFormatterPreferencesChangeSupport editorPreferencesChangeSupport = Lookup.getDefault().lookup(ExternalFormatterPreferencesChangeSupport.class);
587 if (editorPreferencesChangeSupport != null) {
588 editorPreferencesChangeSupport.fireChange();
589 } else {
590 log.warning("Could not find ExternalFormatterPreferencesChangeSupport in lookup!");
591 }
592 }
593
594
595
596
597 @Override
598 public boolean valid() {
599 for (MimeType mimeType : formatterOptions.keySet()) {
600 String activeId = activeFormatterId.get(mimeType);
601 if (StringUtils.isNotBlank(activeId) && !Objects.equals(Settings.DEFAULT_FORMATTER, activeId)) {
602 FormatterOptionsPanel optionsPanel = getFormatterOptionsPanel(mimeType, activeId);
603 if (optionsPanel != null && !optionsPanel.valid()) {
604 return false;
605 }
606 }
607 }
608
609 return true;
610 }
611
612
613 private JLabel btnDonate;
614 private JLabel btnVisitHomePage;
615 private JCheckBox cbShowNotifications;
616 private JComboBox<ExtValue> chooseFormatterCmbBox;
617 private JLabel chooseLanguageLbl;
618 private JComboBox<ExtValue> chooseMimeTypeCmbBox;
619 private JPanel formatterOptionsPanel;
620 private JCheckBox overrideTabSizeChkBox;
621 private JSpinner overrideTabSizeSpn;
622 private JLabel txtProjectSpecificHint;
623 private JLabel useFormatterLbl;
624 private JCheckBox useIndentationSettingsChkBox;
625
626
627
628
629
630 private void updateEnabledState() {
631 overrideTabSizeChkBox.setEnabled(useIndentationSettingsChkBox.isSelected());
632 overrideTabSizeSpn.setEnabled(overrideTabSizeChkBox.isEnabled() && overrideTabSizeChkBox.isSelected());
633
634 txtProjectSpecificHint.setVisible(project == null);
635 }
636
637
638
639
640
641
642
643
644 private String getSelectedValue(JComboBox comboBox) {
645 Object selectedItem = comboBox.getSelectedItem();
646 if (selectedItem != null) {
647 if (selectedItem instanceof ExtValue) {
648 return ((ExtValue) selectedItem).getValue();
649 } else {
650 return selectedItem.toString();
651 }
652 }
653
654 return null;
655 }
656
657
658
659
660 @Override
661 public void stateChanged(ChangeEvent e) {
662 fireChangedListener();
663 }
664
665
666
667
668 private class MimeTypesListCellRenderer extends DefaultListCellRenderer {
669
670
671
672
673 @Override
674 public Component getListCellRendererComponent(JList<?> list, Object value, int index, boolean isSelected, boolean cellHasFocus) {
675 Component comp = super.getListCellRendererComponent(list, value, index, isSelected, cellHasFocus);
676
677 if (value != null) {
678 String mimeType = value.toString();
679 if (value instanceof ExtValue) {
680 mimeType = ((ExtValue) value).getValue();
681 }
682
683 if (!Objects.equals(Settings.DEFAULT_FORMATTER, activeFormatterId.get(MimeType.valueOf(mimeType)))) {
684 Font standardFont = comp.getFont();
685
686 comp.setFont(new Font(standardFont.getName(), Font.BOLD, standardFont.getSize()));
687 }
688 }
689
690 return comp;
691 }
692 }
693
694
695
696
697 private static class ExtValue {
698
699
700
701
702 private final String value;
703
704
705
706
707 private final String visualValue;
708
709
710
711
712
713
714
715 public ExtValue(String value, String visualValue) {
716 this.value = value;
717 this.visualValue = visualValue;
718 }
719
720
721
722
723
724
725 public String getValue() {
726 return value;
727 }
728
729
730
731
732
733
734
735
736 public String getVisualValue() {
737 return visualValue;
738 }
739
740
741
742
743
744
745 @Override
746 public String toString() {
747 return StringUtils.isBlank(visualValue) ? value : visualValue;
748 }
749
750
751
752
753
754
755
756
757 @Override
758 public boolean equals(Object obj) {
759 if (obj == null) {
760 return false;
761 } else if (obj instanceof ExtValue) {
762 ExtValue other = (ExtValue) obj;
763
764 return Objects.equals(this.value, other.value);
765 } else {
766 return Objects.equals(this.value, obj);
767 }
768 }
769
770
771
772
773 @Override
774 public int hashCode() {
775 int hash = 7;
776 hash = 97 * hash + Objects.hashCode(this.value);
777 return hash;
778 }
779 }
780 }