001: /*
002: * FindBugs - Find Bugs in Java programs
003: * Copyright (C) 2006, University of Maryland
004: *
005: * This library is free software; you can redistribute it and/or
006: * modify it under the terms of the GNU Lesser General Public
007: * License as published by the Free Software Foundation; either
008: * version 2.1 of the License, or (at your option) any later version.
009: *
010: * This library is distributed in the hope that it will be useful,
011: * but WITHOUT ANY WARRANTY; without even the implied warranty of
012: * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
013: * Lesser General Public License for more details.
014: *
015: * You should have received a copy of the GNU Lesser General Public
016: * License along with this library; if not, write to the Free Software
017: * Foundation, Inc., 59 Temple Place, Suite 330, Boston MA 02111-1307, USA
018: */
019:
020: package edu.umd.cs.findbugs.gui2;
021:
022: import java.awt.BorderLayout;
023: import java.awt.Dimension;
024: import java.awt.GridBagConstraints;
025: import java.awt.GridBagLayout;
026: import java.awt.Insets;
027: import java.awt.event.ActionEvent;
028: import java.awt.event.ActionListener;
029: import java.awt.event.ItemEvent;
030: import java.awt.event.ItemListener;
031: import java.awt.event.WindowAdapter;
032: import java.awt.event.WindowEvent;
033: import java.util.ArrayList;
034: import java.util.Iterator;
035:
036: import javax.swing.AbstractAction;
037: import javax.swing.Box;
038: import javax.swing.BoxLayout;
039: import javax.swing.JButton;
040: import javax.swing.JCheckBox;
041: import javax.swing.JLabel;
042: import javax.swing.JOptionPane;
043: import javax.swing.JPanel;
044: import javax.swing.JScrollPane;
045: import javax.swing.JTabbedPane;
046: import javax.swing.JTextField;
047: import javax.swing.table.DefaultTableModel;
048: import javax.swing.tree.TreeModel;
049:
050: import edu.umd.cs.findbugs.filter.Filter;
051: import edu.umd.cs.findbugs.filter.Matcher;
052:
053: /**
054: * User Preferences
055: */
056:
057: /*
058: *
059: * Preferences, which should really be renamed Filters And Suppressions (fas, like fas file!)
060: * since thats all that's actually here now
061: *
062: */
063: @SuppressWarnings("serial")
064: public class PreferencesFrame extends FBDialog {
065:
066: private static int PROPERTIES_TAB = 0;
067: private static int FILTERS_TAB = 1;
068: private static int SUPPRESSIONS_TAB = 2;
069:
070: JTabbedPane mainTabPane;
071:
072: private static PreferencesFrame instance;
073: private CheckBoxList filterCheckBoxList = new CheckBoxList();
074: private JButton addButton;
075:
076: JButton removeButton;
077: JButton removeAllButton;
078: boolean frozen = false;
079:
080: //Variables for Properties tab.
081: private JTextField tabTextField;
082: private JTextField fontTextField;
083: private static int TAB_MIN = 1;
084: private static int TAB_MAX = 20;
085: private static int FONT_MIN = 10;
086: private static int FONT_MAX = 99;
087:
088: public static PreferencesFrame getInstance() {
089: // MainFrame.getInstance().getSorter().freezeOrder();
090: if (instance == null)
091: instance = new PreferencesFrame();
092:
093: return instance;
094: }
095:
096: private PreferencesFrame() {
097: setTitle(edu.umd.cs.findbugs.L10N.getLocalString(
098: "dlg.fil_sup_ttl", "Filters/Suppressions"));
099: setModal(true);
100:
101: mainTabPane = new JTabbedPane();
102:
103: mainTabPane.add("Properties", createPropertiesPane());
104:
105: mainTabPane.add(edu.umd.cs.findbugs.L10N.getLocalString(
106: "pref.filters", "Filters"), createFilterPane());
107:
108: MainFrame.getInstance().updateStatusBar();
109: getContentPane().setLayout(
110: new BoxLayout(getContentPane(), BoxLayout.Y_AXIS));
111:
112: JPanel top = new JPanel();
113: top.setLayout(new BoxLayout(top, BoxLayout.X_AXIS));
114: top.add(Box.createHorizontalStrut(5));
115: top.add(mainTabPane);
116: top.add(Box.createHorizontalStrut(5));
117:
118: JPanel bottom = new JPanel();
119: bottom.setLayout(new BoxLayout(bottom, BoxLayout.X_AXIS));
120: bottom.add(Box.createHorizontalGlue());
121: bottom.add(new JButton(new AbstractAction(
122: edu.umd.cs.findbugs.L10N.getLocalString("pref.close",
123: "Close")) {
124: public void actionPerformed(ActionEvent evt) {
125: // MainFrame.getInstance().getSorter().thawOrder();
126: PreferencesFrame.this .setVisible(false);
127: TreeModel bt = (MainFrame.getInstance().getTree()
128: .getModel());
129: if (bt instanceof BugTreeModel)
130: ((BugTreeModel) bt).checkSorter();
131:
132: resetPropertiesPane();
133: }
134: }));
135: bottom.add(Box.createHorizontalStrut(5));
136:
137: add(Box.createVerticalStrut(5));
138: add(top);
139: add(Box.createVerticalStrut(5));
140: add(bottom);
141: add(Box.createVerticalStrut(5));
142:
143: setDefaultCloseOperation(HIDE_ON_CLOSE);
144:
145: pack();
146: }
147:
148: // /**
149: // * Creates the general tab. This lets the user change the font
150: // * size and the total number of possible previous comments.
151: // * @return
152: // */
153: // private JPanel createGeneralPane() {
154: // JPanel generalPanel = new JPanel();
155: //
156: // generalPanel.add(new JLabel("Clear Recent Projects List"));
157: // JButton clearButton=new JButton("Clear");
158: // clearButton.addActionListener(new ActionListener()
159: // {
160: // public void actionPerformed(ActionEvent e)
161: // {
162: // GUISaveState.getInstance().clear();
163: // }
164: // });
165: // return generalPanel;
166: // }
167: //
168:
169: private JPanel createPropertiesPane() {
170: JPanel contentPanel = new JPanel(new BorderLayout());
171: JPanel mainPanel = new JPanel();
172:
173: float currFS = Driver.getFontSize();
174:
175: JPanel temp = new JPanel();
176: temp.add(new JLabel("Tab Size"));
177: tabTextField = new JTextField(Integer.toString(GUISaveState
178: .getInstance().getTabSize()));
179: tabTextField.setPreferredSize(new Dimension((int) (currFS * 2),
180: (int) (currFS * 1.3)));
181: temp.add(tabTextField);
182:
183: mainPanel.add(temp);
184: mainPanel.add(Box.createVerticalStrut(5));
185:
186: temp = new JPanel();
187: temp.add(new JLabel("Font Size"));
188: fontTextField = new JTextField(Float.toString(GUISaveState
189: .getInstance().getFontSize()));
190: fontTextField.setPreferredSize(new Dimension(
191: (int) (currFS * 3), (int) (currFS * 1.3)));
192: temp.add(fontTextField);
193:
194: mainPanel.add(temp);
195: mainPanel.add(Box.createVerticalGlue());
196:
197: contentPanel.add(mainPanel, BorderLayout.CENTER);
198:
199: JPanel bottomPanel = new JPanel();
200: bottomPanel.add(new JButton(new AbstractAction("Apply") {
201: public void actionPerformed(ActionEvent evt) {
202: changeTabSize();
203: changeFontSize();
204: }
205: }));
206:
207: bottomPanel.add(new JButton(new AbstractAction("Reset") {
208: public void actionPerformed(ActionEvent evt) {
209: resetPropertiesPane();
210: }
211: }));
212:
213: contentPanel.add(bottomPanel, BorderLayout.SOUTH);
214:
215: addWindowListener(new WindowAdapter() {
216: @Override
217: public void windowDeactivated(WindowEvent e) {
218: resetPropertiesPane();
219: }
220: });
221:
222: return contentPanel;
223: }
224:
225: private void changeTabSize() {
226: int tabSize = 0;
227:
228: try {
229: tabSize = Integer.decode(tabTextField.getText()).intValue();
230: } catch (NumberFormatException exc) {
231: JOptionPane.showMessageDialog(instance,
232: "Error in tab size field.", "Tab Size Error",
233: JOptionPane.INFORMATION_MESSAGE);
234: return;
235: }
236:
237: if (tabSize < TAB_MIN || tabSize > TAB_MAX) {
238: JOptionPane.showMessageDialog(instance,
239: "Tab size excedes range (" + TAB_MIN + " - "
240: + TAB_MAX + ").", "Tab Size Excedes Range",
241: JOptionPane.INFORMATION_MESSAGE);
242: return;
243: }
244:
245: if (tabSize != GUISaveState.getInstance().getTabSize()) {
246: GUISaveState.getInstance().setTabSize(tabSize);
247: MainFrame.getInstance().displayer.clearCache();
248: //This causes the GUI to redisplay the current code
249: MainFrame.getInstance().syncBugInformation();
250: }
251: }
252:
253: private void changeFontSize() {
254: float fontSize = 0;
255:
256: try {
257: fontSize = Float.parseFloat(fontTextField.getText());
258: } catch (NumberFormatException exc) {
259: JOptionPane.showMessageDialog(instance,
260: "Error in font size field.", "Font Size Error",
261: JOptionPane.INFORMATION_MESSAGE);
262: return;
263: }
264:
265: if (fontSize < FONT_MIN || fontSize > FONT_MAX) {
266: JOptionPane.showMessageDialog(instance,
267: "Font size excedes range (" + FONT_MIN + " - "
268: + FONT_MAX + ").",
269: "Font Size Excedes Range",
270: JOptionPane.INFORMATION_MESSAGE);
271: return;
272: }
273:
274: if (fontSize != GUISaveState.getInstance().getFontSize()) {
275: GUISaveState.getInstance().setFontSize(fontSize);
276: JOptionPane
277: .showMessageDialog(
278: instance,
279: "To implement the new font size please restart FindBugs.",
280: "Changing Font",
281: JOptionPane.INFORMATION_MESSAGE);
282: }
283: }
284:
285: private void resetPropertiesPane() {
286: tabTextField.setText(Integer.toString(GUISaveState
287: .getInstance().getTabSize()));
288: fontTextField.setText(Float.toString(GUISaveState.getInstance()
289: .getFontSize()));
290: }
291:
292: /**
293: * Create a JPanel to display the filtering controls.
294: */
295: private JPanel createFilterPane() {
296: addButton = new JButton(edu.umd.cs.findbugs.L10N
297: .getLocalString("dlg.add_dot_btn", "Add..."));
298: removeButton = new JButton(edu.umd.cs.findbugs.L10N
299: .getLocalString("dlg.remove_btn", "Remove"));
300: removeAllButton = new JButton(edu.umd.cs.findbugs.L10N
301: .getLocalString("dlg.remove_all_btn", "Remove All"));
302: JPanel filterPanel = new JPanel();
303: filterPanel.setLayout(new GridBagLayout());
304: GridBagConstraints gbc = new GridBagConstraints();
305:
306: gbc.gridheight = 4;
307: gbc.gridwidth = 1;
308: gbc.gridx = 0;
309: gbc.gridy = 0;
310: gbc.fill = GridBagConstraints.BOTH;
311: gbc.weightx = 1;
312: gbc.weighty = 1;
313: filterPanel.add(new JScrollPane(filterCheckBoxList), gbc);
314: updateFilterPanel();
315:
316: gbc.gridheight = 1;
317: gbc.gridx = 1;
318: gbc.gridy = 0;
319: gbc.fill = GridBagConstraints.HORIZONTAL;
320: gbc.weightx = 0;
321: gbc.weighty = 0;
322: filterPanel.add(addButton, gbc);
323: addButton.addActionListener(new ActionListener() {
324: public void actionPerformed(ActionEvent evt) {
325: NewFilterFrame.open();
326: }
327: });
328:
329: gbc.gridy = 1;
330: gbc.insets = new Insets(5, 0, 0, 0);
331: filterPanel.add(removeButton, gbc);
332: removeButton.addActionListener(new ActionListener() {
333: public void actionPerformed(ActionEvent evt) {
334: Object[] selected = filterCheckBoxList
335: .getSelectedValues();
336: boolean needsRebuild = false;
337: if (selected.length == 0)
338: return;
339: for (Object o : selected) {
340: MatchBox box = (MatchBox) o;
341: if (MainFrame.getInstance().getProject()
342: .getSuppressionFilter().isEnabled(
343: box.getMatcher()))
344: needsRebuild = true;
345: MainFrame.getInstance().getProject()
346: .getSuppressionFilter().removeChild(
347: box.getMatcher());
348: }
349: FilterActivity.notifyListeners(
350: FilterListener.Action.UNFILTERING, null);
351: MainFrame.getInstance().setProjectChanged(true);
352: updateFilterPanel();
353: }
354: });
355: gbc.gridy = 2;
356: gbc.weighty = 0;
357: gbc.insets = new Insets(5, 0, 0, 0);
358: filterPanel.add(removeAllButton, gbc);
359: removeAllButton.addActionListener(new ActionListener() {
360: public void actionPerformed(ActionEvent evt) {
361: boolean needsRebuild = false;
362: Filter suppressionFilter = MainFrame.getInstance()
363: .getProject().getSuppressionFilter();
364: if (!suppressionFilter.isEmpty())
365: needsRebuild = true;
366: suppressionFilter.clear();
367:
368: if (needsRebuild)//TODO This will rebuild even if all the filters being cleared were disabled
369: FilterActivity.notifyListeners(
370: FilterListener.Action.UNFILTERING, null);
371: MainFrame.getInstance().setProjectChanged(true);
372: updateFilterPanel();
373: }
374: });
375: gbc.gridy = 3;
376: gbc.weighty = 1;
377: gbc.insets = new Insets(0, 0, 0, 0);
378: filterPanel.add(Box.createGlue(), gbc);
379:
380: return filterPanel;
381: }
382:
383: private static class MatchBox extends JCheckBox {
384: Matcher m;
385:
386: MatchBox(String text, Matcher m) {
387: super (text);
388: this .m = m;
389: }
390:
391: Matcher getMatcher() {
392: return m;
393: }
394: }
395:
396: void updateFilterPanel() {
397: ArrayList<MatchBox> boxes = new ArrayList<MatchBox>();
398: final Filter f = MainFrame.getInstance().getProject()
399: .getSuppressionFilter();
400:
401: for (Iterator<Matcher> i = f.childIterator(); i.hasNext();) {
402: final Matcher m = i.next();
403: MatchBox box = new MatchBox(m.toString(), m);
404: box.addItemListener(new ItemListener() {
405: public void itemStateChanged(ItemEvent evt) {
406: boolean isSelected = ((JCheckBox) evt.getSource())
407: .isSelected();
408: boolean wasSelected = f.isEnabled(m);
409: if (isSelected == wasSelected)
410: return;
411: f.setEnabled(m, isSelected);
412: FilterActivity
413: .notifyListeners(
414: isSelected ? FilterListener.Action.FILTERING
415: : FilterListener.Action.UNFILTERING,
416: null);
417: MainFrame.getInstance().updateStatusBar();
418: MainFrame.getInstance().setProjectChanged(true);
419:
420: }
421: });
422: box.setSelected(f.isEnabled(m));
423: boxes.add(box);
424: }
425:
426: filterCheckBoxList.setListData(boxes.toArray(new MatchBox[boxes
427: .size()]));
428: }
429:
430: private static class UneditableTableModel extends DefaultTableModel {
431: public UneditableTableModel(Object[][] tableData,
432: String[] strings) {
433: super (tableData, strings);
434: }
435:
436: @Override
437: public boolean isCellEditable(int x, int y) {
438: return false;
439: }
440: }
441:
442: private static class FilterCheckBoxListener implements ItemListener {
443: FilterMatcher filter;
444:
445: FilterCheckBoxListener(FilterMatcher filter) {
446: this .filter = filter;
447: }
448:
449: public void itemStateChanged(ItemEvent evt) {
450: // RebuildThreadMonitor.waitForRebuild();
451: filter
452: .setActive(((JCheckBox) evt.getSource())
453: .isSelected());
454: MainFrame.getInstance().updateStatusBar();
455: MainFrame.getInstance().setProjectChanged(true);
456: }
457: }
458:
459: void freeze() {
460: frozen = true;
461: filterCheckBoxList.setEnabled(false);
462: addButton.setEnabled(false);
463: removeButton.setEnabled(false);
464: }
465:
466: void thaw() {
467: filterCheckBoxList.setEnabled(true);
468: addButton.setEnabled(true);
469: removeButton.setEnabled(true);
470: frozen = false;
471: }
472:
473: void setSelectedTab(int index) {
474: if (index > 0 && index <= mainTabPane.getTabCount())
475: mainTabPane.setSelectedIndex(index);
476: }
477: }
|