PageRenderTime 82ms CodeModel.GetById 18ms RepoModel.GetById 0ms app.codeStats 0ms

/projects/netbeans-7.3/java.hints.ui/src/org/netbeans/modules/java/hints/spiimpl/options/HintsPanel.java

https://gitlab.com/essere.lab.public/qualitas.class-corpus
Java | 1058 lines | 849 code | 127 blank | 82 comment | 76 complexity | e6dc48edab9cd7e353e3f68011d697f7 MD5 | raw file
  1. /*
  2. * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS HEADER.
  3. *
  4. * Copyright 1997-2011 Oracle and/or its affiliates. All rights reserved.
  5. *
  6. * Oracle and Java are registered trademarks of Oracle and/or its affiliates.
  7. * Other names may be trademarks of their respective owners.
  8. *
  9. * The contents of this file are subject to the terms of either the GNU
  10. * General Public License Version 2 only ("GPL") or the Common
  11. * Development and Distribution License("CDDL") (collectively, the
  12. * "License"). You may not use this file except in compliance with the
  13. * License. You can obtain a copy of the License at
  14. * http://www.netbeans.org/cddl-gplv2.html
  15. * or nbbuild/licenses/CDDL-GPL-2-CP. See the License for the
  16. * specific language governing permissions and limitations under the
  17. * License. When distributing the software, include this License Header
  18. * Notice in each file and include the License file at
  19. * nbbuild/licenses/CDDL-GPL-2-CP. Oracle designates this
  20. * particular file as subject to the "Classpath" exception as provided
  21. * by Oracle in the GPL Version 2 section of the License file that
  22. * accompanied this code. If applicable, add the following below the
  23. * License Header, with the fields enclosed by brackets [] replaced by
  24. * your own identifying information:
  25. * "Portions Copyrighted [year] [name of copyright owner]"
  26. *
  27. * Contributor(s):
  28. *
  29. * The Original Software is NetBeans. The Initial Developer of the Original
  30. * Software is Sun Microsystems, Inc. Portions Copyright 1997-2011 Sun
  31. * Microsystems, Inc. All Rights Reserved.
  32. *
  33. * If you wish your version of this file to be governed by only the CDDL
  34. * or only the GPL Version 2, indicate your decision by adding
  35. * "[Contributor] elects to include this software in this distribution
  36. * under the [CDDL or GPL Version 2] license." If you do not indicate a
  37. * single choice of license, a recipient has the option to distribute
  38. * your version of this file under either the CDDL, the GPL Version 2 or
  39. * to extend the choice of license to its licensees as provided above.
  40. * However, if you add GPL Version 2 code and therefore, elected the GPL
  41. * Version 2 license, then the option applies only if the new code is
  42. * made subject to such option by the copyright holder.
  43. */
  44. package org.netbeans.modules.java.hints.spiimpl.options;
  45. import java.awt.Component;
  46. import java.awt.Font;
  47. import java.awt.GridBagConstraints;
  48. import java.awt.GridBagLayout;
  49. import java.awt.Point;
  50. import java.awt.event.ActionEvent;
  51. import java.awt.event.ActionListener;
  52. import java.awt.event.ItemListener;
  53. import java.awt.event.KeyEvent;
  54. import java.awt.event.MouseAdapter;
  55. import java.awt.event.MouseEvent;
  56. import java.awt.event.MouseListener;
  57. import java.io.IOException;
  58. import java.util.ArrayList;
  59. import java.util.Collection;
  60. import java.util.Comparator;
  61. import java.util.HashMap;
  62. import java.util.Iterator;
  63. import java.util.Map;
  64. import java.util.Map.Entry;
  65. import java.util.MissingResourceException;
  66. import java.util.ResourceBundle;
  67. import java.util.Set;
  68. import java.util.TreeMap;
  69. import java.util.TreeSet;
  70. import java.util.concurrent.atomic.AtomicBoolean;
  71. import java.util.prefs.Preferences;
  72. import javax.swing.AbstractAction;
  73. import javax.swing.ButtonGroup;
  74. import javax.swing.ButtonModel;
  75. import javax.swing.JCheckBox;
  76. import javax.swing.JLabel;
  77. import javax.swing.JMenuItem;
  78. import javax.swing.JOptionPane;
  79. import javax.swing.JPopupMenu;
  80. import javax.swing.JTree;
  81. import javax.swing.KeyStroke;
  82. import javax.swing.SwingUtilities;
  83. import javax.swing.event.ChangeListener;
  84. import javax.swing.event.TreeSelectionEvent;
  85. import javax.swing.event.TreeSelectionListener;
  86. import javax.swing.text.BadLocationException;
  87. import javax.swing.text.StyledDocument;
  88. import javax.swing.tree.DefaultMutableTreeNode;
  89. import javax.swing.tree.DefaultTreeCellRenderer;
  90. import javax.swing.tree.DefaultTreeModel;
  91. import javax.swing.tree.MutableTreeNode;
  92. import javax.swing.tree.TreeCellRenderer;
  93. import javax.swing.tree.TreeNode;
  94. import javax.swing.tree.TreePath;
  95. import javax.swing.tree.TreeSelectionModel;
  96. import org.netbeans.api.annotations.common.NullAllowed;
  97. import org.netbeans.modules.analysis.spi.Analyzer.CustomizerContext;
  98. import org.netbeans.modules.java.hints.analysis.AnalyzerImpl;
  99. import org.netbeans.modules.java.hints.spiimpl.RulesManager;
  100. import org.netbeans.modules.java.hints.spiimpl.refactoring.Configuration;
  101. import org.netbeans.modules.java.hints.spiimpl.refactoring.ConfigurationRenderer;
  102. import org.netbeans.modules.java.hints.spiimpl.refactoring.ConfigurationsComboModel;
  103. import org.netbeans.modules.java.hints.spiimpl.refactoring.Utilities;
  104. import org.openide.filesystems.FileObject;
  105. import org.openide.loaders.DataObjectNotFoundException;
  106. import org.openide.util.Exceptions;
  107. import org.openide.util.NbBundle;
  108. import org.netbeans.modules.java.hints.providers.spi.HintMetadata;
  109. import org.netbeans.modules.java.hints.providers.spi.HintMetadata.Options;
  110. import org.netbeans.modules.java.hints.spiimpl.options.HintsPanelLogic.HintCategory;
  111. import org.netbeans.modules.java.hints.spiimpl.refactoring.Utilities.ClassPathBasedHintWrapper;
  112. import org.netbeans.modules.options.editor.spi.OptionsFilter;
  113. import org.netbeans.modules.options.editor.spi.OptionsFilter.Acceptor;
  114. import org.openide.cookies.EditorCookie;
  115. import org.openide.filesystems.FileUtil;
  116. import org.openide.loaders.DataFolder;
  117. import org.openide.loaders.DataObject;
  118. import org.openide.text.CloneableEditorSupport;
  119. import org.openide.text.NbDocument;
  120. import org.openide.util.NbBundle.Messages;
  121. import org.openide.util.RequestProcessor;
  122. public final class HintsPanel extends javax.swing.JPanel {
  123. private static final String DELETE = "delete";
  124. private static final String DECLARATIVE_HINT_TEMPLATE_LOCATION = "org-netbeans-modules-java-hints/templates/Inspection.hint";
  125. private final static RequestProcessor WORKER = new RequestProcessor(HintsPanel.class.getName(), 1, false, false);
  126. private HintsPanelLogic logic;
  127. private DefaultTreeModel errorTreeModel;
  128. private final AtomicBoolean initialized = new AtomicBoolean(false);
  129. private final ClassPathBasedHintWrapper cpBased;
  130. private final QueryStatus queryStatus;
  131. //AWT only:
  132. private HintMetadata toSelect = null;
  133. DefaultMutableTreeNode extraNode = new DefaultMutableTreeNode(NbBundle.getMessage(HintsPanel.class, "CTL_DepScanning")); //NOI18N
  134. private boolean hasNewHints;
  135. private boolean confirmed;
  136. @Messages("LBL_Loading=Loading...")
  137. HintsPanel(@NullAllowed final OptionsFilter filter) {
  138. this.cpBased = null;
  139. this.queryStatus = QueryStatus.SHOW_QUERIES;
  140. WORKER.post(new Runnable() {
  141. @Override
  142. public void run() {
  143. RulesManager.getInstance();
  144. SwingUtilities.invokeLater(new Runnable() {
  145. @Override
  146. public void run() {
  147. HintsPanel.this.removeAll();
  148. HintsPanel.this.init(filter, true, false, false, true);
  149. buttonsPanel.setVisible(false);
  150. searchPanel.setVisible(false);
  151. configurationsPanel.setVisible(false);
  152. }
  153. });
  154. }
  155. });
  156. setLayout(new GridBagLayout());
  157. add(new JLabel(Bundle.LBL_Loading()), new GridBagConstraints());
  158. }
  159. public HintsPanel(Configuration preselected, ClassPathBasedHintWrapper cpBased) {
  160. this.cpBased = cpBased;
  161. this.queryStatus = QueryStatus.ONLY_ENABLED;
  162. init(null, false, true, true, true);
  163. configCombo.setSelectedItem(preselected);
  164. }
  165. public HintsPanel(HintMetadata preselected, @NullAllowed final CustomizerContext<?, ?> cc, ClassPathBasedHintWrapper cpBased) {
  166. this.cpBased = cpBased;
  167. this.queryStatus = cc == null ? QueryStatus.NEVER : QueryStatus.SHOW_QUERIES;
  168. init(null, false, false, cc == null, false);
  169. select(preselected);
  170. configurationsPanel.setVisible(false);
  171. if (cc != null) {
  172. errorTree.getSelectionModel().addTreeSelectionListener(new TreeSelectionListener() {
  173. @Override public void valueChanged(TreeSelectionEvent e) {
  174. HintMetadata hm = getSelectedHint();
  175. if (hm != null) {
  176. cc.setSelectedId(AnalyzerImpl.ID_JAVA_HINTS_PREFIX + hm.id);
  177. }
  178. }
  179. });
  180. }
  181. }
  182. public HintsPanel(Preferences configurations, ClassPathBasedHintWrapper cpBased) {
  183. this.cpBased = cpBased;
  184. this.queryStatus = QueryStatus.SHOW_QUERIES;
  185. init(null, false, false, false, true);
  186. setOverlayPreferences(configurations);
  187. configurationsPanel.setVisible(false);
  188. }
  189. public void setOverlayPreferences(Preferences configurations) {
  190. logic.setOverlayPreferences(configurations);
  191. }
  192. public boolean hasNewHints() {
  193. return hasNewHints;
  194. }
  195. private org.netbeans.modules.java.hints.spiimpl.refactoring.OptionsFilter optionsFilter;
  196. private void setModel(DefaultTreeModel errorTreeModel) {
  197. if (optionsFilter!=null) {
  198. optionsFilter.installFilteringModel(errorTree, errorTreeModel, new AcceptorImpl());
  199. } else {
  200. errorTree.setModel(errorTreeModel);
  201. }
  202. }
  203. private void init(@NullAllowed OptionsFilter filter, boolean inOptionsDialog, boolean useConfigCombo, boolean showOkCancel, boolean showCheckBoxes) {
  204. initComponents();
  205. scriptScrollPane.setVisible(false);
  206. optionsFilter = null;
  207. if (!inOptionsDialog && filter==null) {
  208. optionsFilter = new org.netbeans.modules.java.hints.spiimpl.refactoring.OptionsFilter(
  209. searchTextField.getDocument(), new Runnable() {
  210. @Override
  211. public void run() {
  212. }
  213. }
  214. );
  215. }
  216. configCombo.setModel(new ConfigurationsComboModel(true));
  217. configCombo.setRenderer(new ConfigurationRenderer());
  218. if (useConfigCombo || inOptionsDialog) {
  219. configCombo.setSelectedItem(null);
  220. }
  221. descriptionTextArea.setContentType("text/html"); // NOI18N
  222. scriptTextArea.setEditorKit(CloneableEditorSupport.getEditorKit("text/x-javahints"));
  223. scriptTextArea.setEditable(true);
  224. // if( "Windows".equals(UIManager.getLookAndFeel().getID()) ) //NOI18N
  225. // setOpaque( false );
  226. errorTree.setCellRenderer(showCheckBoxes? new CheckBoxRenderer() : new JLabelRenderer());
  227. errorTree.setRootVisible( false );
  228. errorTree.setShowsRootHandles( true );
  229. errorTree.getSelectionModel().setSelectionMode( TreeSelectionModel.SINGLE_TREE_SELECTION );
  230. errorTree.addMouseListener(new MouseAdapter() {
  231. @Override
  232. public void mousePressed(MouseEvent e) {
  233. handleClick(e);
  234. }
  235. @Override
  236. public void mouseReleased(MouseEvent e) {
  237. handleClick(e);
  238. }
  239. private void handleClick(MouseEvent e) {
  240. if (e.isPopupTrigger()) {
  241. Point p = e.getPoint();
  242. TreePath path = errorTree.getPathForLocation(e.getPoint().x, e.getPoint().y);
  243. if (path != null) {
  244. DefaultMutableTreeNode o = (DefaultMutableTreeNode) path.getLastPathComponent();
  245. if (o.getUserObject() instanceof HintMetadata) {
  246. HintMetadata hint = (HintMetadata) o.getUserObject();
  247. if (hint.category.equals(HintCategory.CUSTOM_CATEGORY)) {
  248. JPopupMenu popup = new JPopupMenu();
  249. popup.add(new JMenuItem(new RenameHint(o, hint, path)));
  250. popup.add(new JMenuItem(new RemoveHint(o, hint)));
  251. popup.show(errorTree, e.getX(), e.getY());
  252. }
  253. }
  254. }
  255. }
  256. }
  257. });
  258. errorTree.getInputMap().put(KeyStroke.getKeyStroke(KeyEvent.VK_DELETE, 0), DELETE);
  259. errorTree.getActionMap().put(DELETE, new RemoveHint(null, null));
  260. toProblemCheckBox.setVisible(false);
  261. Collection<? extends HintMetadata> hints = inOptionsDialog?filterCustom(RulesManager.getInstance().readHints(null, null, null).keySet()):Utilities.getBatchSupportedHints(cpBased).keySet();
  262. errorTreeModel = constructTM(hints, inOptionsDialog);
  263. if (filter != null) {
  264. ((OptionsFilter) filter).installFilteringModel(errorTree, errorTreeModel, new AcceptorImpl());
  265. } else {
  266. setModel(errorTreeModel);
  267. }
  268. initialized.set(true);
  269. update(inOptionsDialog);
  270. if (toSelect != null) {
  271. select(toSelect, true);
  272. toSelect = null;
  273. }
  274. boolean editEnabled = showOkCancel && FileUtil.getConfigFile(DECLARATIVE_HINT_TEMPLATE_LOCATION)!=null;
  275. newButton.setVisible(editEnabled);
  276. importButton.setVisible(false);
  277. exportButton.setVisible(false);
  278. editScriptButton.setVisible(editEnabled);
  279. editingButtons.setVisible(false);
  280. severityComboBox.setVisible(useConfigCombo || inOptionsDialog);
  281. severityLabel.setVisible(useConfigCombo || inOptionsDialog);
  282. okButton.setVisible(showOkCancel);
  283. cancelButton.setVisible(showOkCancel);
  284. validate();
  285. }
  286. /** This method is called from within the constructor to
  287. * initialize the form.
  288. * WARNING: Do NOT modify this code. The content of this method is
  289. * always regenerated by the Form Editor.
  290. */
  291. // <editor-fold defaultstate="collapsed" desc="Generated Code">//GEN-BEGIN:initComponents
  292. private void initComponents() {
  293. java.awt.GridBagConstraints gridBagConstraints;
  294. jSplitPane1 = new javax.swing.JSplitPane();
  295. treePanel = new javax.swing.JPanel();
  296. jScrollPane1 = new javax.swing.JScrollPane();
  297. errorTree = new EditableJTree();
  298. detailsPanel = new javax.swing.JPanel();
  299. optionsPanel = new javax.swing.JPanel();
  300. severityLabel = new javax.swing.JLabel();
  301. severityComboBox = new javax.swing.JComboBox();
  302. toProblemCheckBox = new javax.swing.JCheckBox();
  303. customizerPanel = new javax.swing.JPanel();
  304. descriptionPanel = new javax.swing.JPanel();
  305. descriptionScrollPane = new javax.swing.JScrollPane();
  306. descriptionTextArea = new javax.swing.JEditorPane();
  307. descriptionLabel = new javax.swing.JLabel();
  308. editingButtons = new javax.swing.JPanel();
  309. saveButton = new javax.swing.JButton();
  310. cancelEdit = new javax.swing.JButton();
  311. openInEditor = new javax.swing.JButton();
  312. scriptScrollPane = new javax.swing.JScrollPane();
  313. scriptTextArea = new javax.swing.JEditorPane();
  314. buttonsPanel = new javax.swing.JPanel();
  315. newButton = new javax.swing.JButton();
  316. importButton = new javax.swing.JButton();
  317. exportButton = new javax.swing.JButton();
  318. okButton = new javax.swing.JButton();
  319. editScriptButton = new javax.swing.JButton();
  320. cancelButton = new javax.swing.JButton();
  321. configurationsPanel = new javax.swing.JPanel();
  322. configLabel = new javax.swing.JLabel();
  323. configCombo = new javax.swing.JComboBox();
  324. searchPanel = new javax.swing.JPanel();
  325. refactoringsLabel = new javax.swing.JLabel();
  326. searchLabel = new javax.swing.JLabel();
  327. searchTextField = new javax.swing.JTextField();
  328. setBorder(javax.swing.BorderFactory.createEmptyBorder(8, 8, 8, 8));
  329. setLayout(new java.awt.GridBagLayout());
  330. jSplitPane1.setBorder(null);
  331. jSplitPane1.setDividerLocation(320);
  332. treePanel.setOpaque(false);
  333. treePanel.setLayout(new java.awt.BorderLayout());
  334. errorTree.setEditable(true);
  335. jScrollPane1.setViewportView(errorTree);
  336. errorTree.getAccessibleContext().setAccessibleName(org.openide.util.NbBundle.getMessage(HintsPanel.class, "HintsPanel.errorTree.AccessibleContext.accessibleName")); // NOI18N
  337. errorTree.getAccessibleContext().setAccessibleDescription(org.openide.util.NbBundle.getMessage(HintsPanel.class, "HintsPanel.errorTree.AccessibleContext.accessibleDescription")); // NOI18N
  338. treePanel.add(jScrollPane1, java.awt.BorderLayout.CENTER);
  339. jSplitPane1.setLeftComponent(treePanel);
  340. detailsPanel.setBorder(javax.swing.BorderFactory.createEmptyBorder(0, 6, 0, 0));
  341. detailsPanel.setOpaque(false);
  342. optionsPanel.setOpaque(false);
  343. optionsPanel.setLayout(new java.awt.GridBagLayout());
  344. severityLabel.setLabelFor(severityComboBox);
  345. org.openide.awt.Mnemonics.setLocalizedText(severityLabel, org.openide.util.NbBundle.getMessage(HintsPanel.class, "CTL_ShowAs_Label")); // NOI18N
  346. gridBagConstraints = new java.awt.GridBagConstraints();
  347. gridBagConstraints.gridx = 0;
  348. gridBagConstraints.gridy = 0;
  349. gridBagConstraints.anchor = java.awt.GridBagConstraints.WEST;
  350. gridBagConstraints.insets = new java.awt.Insets(0, 0, 0, 4);
  351. optionsPanel.add(severityLabel, gridBagConstraints);
  352. severityLabel.getAccessibleContext().setAccessibleDescription(org.openide.util.NbBundle.getMessage(HintsPanel.class, "HintsPanel.severityLabel.AccessibleContext.accessibleDescription")); // NOI18N
  353. severityComboBox.setModel(new javax.swing.DefaultComboBoxModel(new String[] { "Item 1", "Item 2", "Item 3", "Item 4" }));
  354. optionsPanel.add(severityComboBox, new java.awt.GridBagConstraints());
  355. severityComboBox.getAccessibleContext().setAccessibleName(org.openide.util.NbBundle.getMessage(HintsPanel.class, "AN_Show_As_Combo")); // NOI18N
  356. severityComboBox.getAccessibleContext().setAccessibleDescription(org.openide.util.NbBundle.getMessage(HintsPanel.class, "AD_Show_As_Combo")); // NOI18N
  357. org.openide.awt.Mnemonics.setLocalizedText(toProblemCheckBox, org.openide.util.NbBundle.getMessage(HintsPanel.class, "CTL_InTasklist_CheckBox")); // NOI18N
  358. toProblemCheckBox.setBorder(javax.swing.BorderFactory.createEmptyBorder(0, 0, 0, 0));
  359. gridBagConstraints = new java.awt.GridBagConstraints();
  360. gridBagConstraints.gridx = 0;
  361. gridBagConstraints.gridy = 2;
  362. gridBagConstraints.gridwidth = 3;
  363. gridBagConstraints.anchor = java.awt.GridBagConstraints.NORTHWEST;
  364. gridBagConstraints.insets = new java.awt.Insets(8, 0, 0, 0);
  365. optionsPanel.add(toProblemCheckBox, gridBagConstraints);
  366. customizerPanel.setOpaque(false);
  367. customizerPanel.setLayout(new java.awt.BorderLayout());
  368. gridBagConstraints = new java.awt.GridBagConstraints();
  369. gridBagConstraints.gridx = 0;
  370. gridBagConstraints.gridy = 3;
  371. gridBagConstraints.gridwidth = 3;
  372. gridBagConstraints.fill = java.awt.GridBagConstraints.BOTH;
  373. gridBagConstraints.anchor = java.awt.GridBagConstraints.NORTHWEST;
  374. gridBagConstraints.weightx = 1.0;
  375. gridBagConstraints.weighty = 1.0;
  376. gridBagConstraints.insets = new java.awt.Insets(8, 0, 0, 0);
  377. optionsPanel.add(customizerPanel, gridBagConstraints);
  378. descriptionPanel.setOpaque(false);
  379. descriptionPanel.setLayout(new java.awt.GridBagLayout());
  380. descriptionTextArea.setEditable(false);
  381. descriptionTextArea.setPreferredSize(new java.awt.Dimension(100, 50));
  382. descriptionScrollPane.setViewportView(descriptionTextArea);
  383. gridBagConstraints = new java.awt.GridBagConstraints();
  384. gridBagConstraints.gridx = 0;
  385. gridBagConstraints.gridy = 1;
  386. gridBagConstraints.gridwidth = 4;
  387. gridBagConstraints.fill = java.awt.GridBagConstraints.BOTH;
  388. gridBagConstraints.anchor = java.awt.GridBagConstraints.NORTHWEST;
  389. gridBagConstraints.weightx = 1.0;
  390. gridBagConstraints.weighty = 1.0;
  391. descriptionPanel.add(descriptionScrollPane, gridBagConstraints);
  392. descriptionLabel.setLabelFor(descriptionTextArea);
  393. org.openide.awt.Mnemonics.setLocalizedText(descriptionLabel, org.openide.util.NbBundle.getMessage(HintsPanel.class, "CTL_Description_Border")); // NOI18N
  394. gridBagConstraints = new java.awt.GridBagConstraints();
  395. gridBagConstraints.gridx = 0;
  396. gridBagConstraints.gridy = 0;
  397. gridBagConstraints.anchor = java.awt.GridBagConstraints.NORTHWEST;
  398. descriptionPanel.add(descriptionLabel, gridBagConstraints);
  399. org.openide.awt.Mnemonics.setLocalizedText(saveButton, org.openide.util.NbBundle.getMessage(HintsPanel.class, "HintsPanel.saveButton.text")); // NOI18N
  400. saveButton.addActionListener(new java.awt.event.ActionListener() {
  401. public void actionPerformed(java.awt.event.ActionEvent evt) {
  402. saveButtonActionPerformed(evt);
  403. }
  404. });
  405. org.openide.awt.Mnemonics.setLocalizedText(cancelEdit, org.openide.util.NbBundle.getMessage(HintsPanel.class, "HintsPanel.cancelEdit.text")); // NOI18N
  406. cancelEdit.addActionListener(new java.awt.event.ActionListener() {
  407. public void actionPerformed(java.awt.event.ActionEvent evt) {
  408. cancelEditActionPerformed(evt);
  409. }
  410. });
  411. org.openide.awt.Mnemonics.setLocalizedText(openInEditor, org.openide.util.NbBundle.getMessage(HintsPanel.class, "HintsPanel.openInEditor.text")); // NOI18N
  412. openInEditor.addActionListener(new java.awt.event.ActionListener() {
  413. public void actionPerformed(java.awt.event.ActionEvent evt) {
  414. openInEditorActionPerformed(evt);
  415. }
  416. });
  417. javax.swing.GroupLayout editingButtonsLayout = new javax.swing.GroupLayout(editingButtons);
  418. editingButtons.setLayout(editingButtonsLayout);
  419. editingButtonsLayout.setHorizontalGroup(
  420. editingButtonsLayout.createParallelGroup(javax.swing.GroupLayout.Alignment.LEADING)
  421. .addGroup(javax.swing.GroupLayout.Alignment.TRAILING, editingButtonsLayout.createSequentialGroup()
  422. .addComponent(openInEditor)
  423. .addPreferredGap(javax.swing.LayoutStyle.ComponentPlacement.RELATED, 198, Short.MAX_VALUE)
  424. .addComponent(saveButton)
  425. .addPreferredGap(javax.swing.LayoutStyle.ComponentPlacement.UNRELATED)
  426. .addComponent(cancelEdit))
  427. );
  428. editingButtonsLayout.setVerticalGroup(
  429. editingButtonsLayout.createParallelGroup(javax.swing.GroupLayout.Alignment.LEADING)
  430. .addGroup(editingButtonsLayout.createParallelGroup(javax.swing.GroupLayout.Alignment.BASELINE)
  431. .addComponent(openInEditor)
  432. .addComponent(cancelEdit)
  433. .addComponent(saveButton))
  434. );
  435. gridBagConstraints = new java.awt.GridBagConstraints();
  436. gridBagConstraints.gridx = 0;
  437. gridBagConstraints.gridy = 2;
  438. gridBagConstraints.gridwidth = 4;
  439. gridBagConstraints.fill = java.awt.GridBagConstraints.HORIZONTAL;
  440. descriptionPanel.add(editingButtons, gridBagConstraints);
  441. scriptTextArea.setEditable(false);
  442. scriptTextArea.setPreferredSize(new java.awt.Dimension(100, 50));
  443. scriptScrollPane.setViewportView(scriptTextArea);
  444. gridBagConstraints = new java.awt.GridBagConstraints();
  445. gridBagConstraints.gridx = 0;
  446. gridBagConstraints.gridy = 1;
  447. gridBagConstraints.gridwidth = 4;
  448. gridBagConstraints.fill = java.awt.GridBagConstraints.BOTH;
  449. gridBagConstraints.anchor = java.awt.GridBagConstraints.NORTHWEST;
  450. gridBagConstraints.weightx = 1.0;
  451. gridBagConstraints.weighty = 1.0;
  452. descriptionPanel.add(scriptScrollPane, gridBagConstraints);
  453. javax.swing.GroupLayout detailsPanelLayout = new javax.swing.GroupLayout(detailsPanel);
  454. detailsPanel.setLayout(detailsPanelLayout);
  455. detailsPanelLayout.setHorizontalGroup(
  456. detailsPanelLayout.createParallelGroup(javax.swing.GroupLayout.Alignment.LEADING)
  457. .addComponent(optionsPanel, javax.swing.GroupLayout.DEFAULT_SIZE, javax.swing.GroupLayout.DEFAULT_SIZE, Short.MAX_VALUE)
  458. .addComponent(descriptionPanel, javax.swing.GroupLayout.DEFAULT_SIZE, javax.swing.GroupLayout.DEFAULT_SIZE, Short.MAX_VALUE)
  459. );
  460. detailsPanelLayout.setVerticalGroup(
  461. detailsPanelLayout.createParallelGroup(javax.swing.GroupLayout.Alignment.LEADING)
  462. .addGroup(detailsPanelLayout.createSequentialGroup()
  463. .addComponent(optionsPanel, javax.swing.GroupLayout.DEFAULT_SIZE, 97, Short.MAX_VALUE)
  464. .addGap(12, 12, 12)
  465. .addComponent(descriptionPanel, javax.swing.GroupLayout.DEFAULT_SIZE, 175, Short.MAX_VALUE))
  466. );
  467. jSplitPane1.setRightComponent(detailsPanel);
  468. gridBagConstraints = new java.awt.GridBagConstraints();
  469. gridBagConstraints.gridx = 0;
  470. gridBagConstraints.gridy = 2;
  471. gridBagConstraints.fill = java.awt.GridBagConstraints.BOTH;
  472. gridBagConstraints.anchor = java.awt.GridBagConstraints.NORTHWEST;
  473. gridBagConstraints.weightx = 1.0;
  474. gridBagConstraints.weighty = 1.0;
  475. add(jSplitPane1, gridBagConstraints);
  476. org.openide.awt.Mnemonics.setLocalizedText(newButton, org.openide.util.NbBundle.getMessage(HintsPanel.class, "HintsPanel.newButton.text")); // NOI18N
  477. newButton.addActionListener(new java.awt.event.ActionListener() {
  478. public void actionPerformed(java.awt.event.ActionEvent evt) {
  479. newButtonActionPerformed(evt);
  480. }
  481. });
  482. org.openide.awt.Mnemonics.setLocalizedText(importButton, org.openide.util.NbBundle.getMessage(HintsPanel.class, "HintsPanel.importButton.text")); // NOI18N
  483. org.openide.awt.Mnemonics.setLocalizedText(exportButton, org.openide.util.NbBundle.getMessage(HintsPanel.class, "HintsPanel.exportButton.text")); // NOI18N
  484. org.openide.awt.Mnemonics.setLocalizedText(okButton, org.openide.util.NbBundle.getMessage(HintsPanel.class, "HintsPanel.okButton.text")); // NOI18N
  485. okButton.addActionListener(new java.awt.event.ActionListener() {
  486. public void actionPerformed(java.awt.event.ActionEvent evt) {
  487. okButtonActionPerformed(evt);
  488. }
  489. });
  490. org.openide.awt.Mnemonics.setLocalizedText(editScriptButton, org.openide.util.NbBundle.getMessage(HintsPanel.class, "HintsPanel.editScriptButton.text")); // NOI18N
  491. editScriptButton.addActionListener(new java.awt.event.ActionListener() {
  492. public void actionPerformed(java.awt.event.ActionEvent evt) {
  493. editScriptButtonActionPerformed(evt);
  494. }
  495. });
  496. org.openide.awt.Mnemonics.setLocalizedText(cancelButton, org.openide.util.NbBundle.getMessage(HintsPanel.class, "HintsPanel.cancelButton.text")); // NOI18N
  497. cancelButton.addActionListener(new java.awt.event.ActionListener() {
  498. public void actionPerformed(java.awt.event.ActionEvent evt) {
  499. cancelButtonActionPerformed(evt);
  500. }
  501. });
  502. javax.swing.GroupLayout buttonsPanelLayout = new javax.swing.GroupLayout(buttonsPanel);
  503. buttonsPanel.setLayout(buttonsPanelLayout);
  504. buttonsPanelLayout.setHorizontalGroup(
  505. buttonsPanelLayout.createParallelGroup(javax.swing.GroupLayout.Alignment.LEADING)
  506. .addGroup(buttonsPanelLayout.createSequentialGroup()
  507. .addComponent(newButton)
  508. .addPreferredGap(javax.swing.LayoutStyle.ComponentPlacement.RELATED)
  509. .addComponent(importButton)
  510. .addPreferredGap(javax.swing.LayoutStyle.ComponentPlacement.UNRELATED)
  511. .addComponent(exportButton)
  512. .addPreferredGap(javax.swing.LayoutStyle.ComponentPlacement.RELATED, 329, Short.MAX_VALUE)
  513. .addComponent(editScriptButton)
  514. .addGap(35, 35, 35)
  515. .addComponent(okButton)
  516. .addPreferredGap(javax.swing.LayoutStyle.ComponentPlacement.RELATED)
  517. .addComponent(cancelButton))
  518. );
  519. buttonsPanelLayout.setVerticalGroup(
  520. buttonsPanelLayout.createParallelGroup(javax.swing.GroupLayout.Alignment.LEADING)
  521. .addGroup(buttonsPanelLayout.createSequentialGroup()
  522. .addGap(5, 5, 5)
  523. .addGroup(buttonsPanelLayout.createParallelGroup(javax.swing.GroupLayout.Alignment.BASELINE)
  524. .addComponent(newButton)
  525. .addComponent(importButton)
  526. .addComponent(exportButton)
  527. .addComponent(editScriptButton)
  528. .addComponent(cancelButton)
  529. .addComponent(okButton)))
  530. );
  531. gridBagConstraints = new java.awt.GridBagConstraints();
  532. gridBagConstraints.gridx = 0;
  533. gridBagConstraints.gridy = 3;
  534. gridBagConstraints.gridwidth = 2;
  535. gridBagConstraints.fill = java.awt.GridBagConstraints.HORIZONTAL;
  536. add(buttonsPanel, gridBagConstraints);
  537. org.openide.awt.Mnemonics.setLocalizedText(configLabel, org.openide.util.NbBundle.getMessage(HintsPanel.class, "HintsPanel.configLabel.text")); // NOI18N
  538. configCombo.addActionListener(new java.awt.event.ActionListener() {
  539. public void actionPerformed(java.awt.event.ActionEvent evt) {
  540. configComboActionPerformed(evt);
  541. }
  542. });
  543. javax.swing.GroupLayout configurationsPanelLayout = new javax.swing.GroupLayout(configurationsPanel);
  544. configurationsPanel.setLayout(configurationsPanelLayout);
  545. configurationsPanelLayout.setHorizontalGroup(
  546. configurationsPanelLayout.createParallelGroup(javax.swing.GroupLayout.Alignment.LEADING)
  547. .addGroup(configurationsPanelLayout.createSequentialGroup()
  548. .addComponent(configLabel)
  549. .addPreferredGap(javax.swing.LayoutStyle.ComponentPlacement.RELATED)
  550. .addComponent(configCombo, 0, 642, Short.MAX_VALUE))
  551. );
  552. configurationsPanelLayout.setVerticalGroup(
  553. configurationsPanelLayout.createParallelGroup(javax.swing.GroupLayout.Alignment.LEADING)
  554. .addGroup(configurationsPanelLayout.createParallelGroup(javax.swing.GroupLayout.Alignment.BASELINE)
  555. .addComponent(configLabel)
  556. .addComponent(configCombo, javax.swing.GroupLayout.PREFERRED_SIZE, javax.swing.GroupLayout.DEFAULT_SIZE, javax.swing.GroupLayout.PREFERRED_SIZE))
  557. );
  558. gridBagConstraints = new java.awt.GridBagConstraints();
  559. gridBagConstraints.fill = java.awt.GridBagConstraints.HORIZONTAL;
  560. add(configurationsPanel, gridBagConstraints);
  561. org.openide.awt.Mnemonics.setLocalizedText(refactoringsLabel, org.openide.util.NbBundle.getMessage(HintsPanel.class, "HintsPanel.refactoringsLabel.text")); // NOI18N
  562. searchLabel.setLabelFor(searchTextField);
  563. org.openide.awt.Mnemonics.setLocalizedText(searchLabel, org.openide.util.NbBundle.getMessage(HintsPanel.class, "HintsPanel.searchLabel.text")); // NOI18N
  564. javax.swing.GroupLayout searchPanelLayout = new javax.swing.GroupLayout(searchPanel);
  565. searchPanel.setLayout(searchPanelLayout);
  566. searchPanelLayout.setHorizontalGroup(
  567. searchPanelLayout.createParallelGroup(javax.swing.GroupLayout.Alignment.LEADING)
  568. .addGroup(javax.swing.GroupLayout.Alignment.TRAILING, searchPanelLayout.createSequentialGroup()
  569. .addComponent(refactoringsLabel)
  570. .addPreferredGap(javax.swing.LayoutStyle.ComponentPlacement.RELATED, 493, Short.MAX_VALUE)
  571. .addComponent(searchLabel)
  572. .addPreferredGap(javax.swing.LayoutStyle.ComponentPlacement.RELATED)
  573. .addComponent(searchTextField, javax.swing.GroupLayout.PREFERRED_SIZE, 121, javax.swing.GroupLayout.PREFERRED_SIZE))
  574. );
  575. searchPanelLayout.setVerticalGroup(
  576. searchPanelLayout.createParallelGroup(javax.swing.GroupLayout.Alignment.LEADING)
  577. .addGroup(searchPanelLayout.createSequentialGroup()
  578. .addGap(5, 5, 5)
  579. .addGroup(searchPanelLayout.createParallelGroup(javax.swing.GroupLayout.Alignment.BASELINE)
  580. .addComponent(searchTextField, javax.swing.GroupLayout.PREFERRED_SIZE, javax.swing.GroupLayout.DEFAULT_SIZE, javax.swing.GroupLayout.PREFERRED_SIZE)
  581. .addComponent(searchLabel)
  582. .addComponent(refactoringsLabel)))
  583. );
  584. gridBagConstraints = new java.awt.GridBagConstraints();
  585. gridBagConstraints.gridx = 0;
  586. gridBagConstraints.gridy = 1;
  587. gridBagConstraints.fill = java.awt.GridBagConstraints.HORIZONTAL;
  588. gridBagConstraints.anchor = java.awt.GridBagConstraints.WEST;
  589. add(searchPanel, gridBagConstraints);
  590. getAccessibleContext().setAccessibleName(org.openide.util.NbBundle.getMessage(HintsPanel.class, "HintsPanel.AccessibleContext.accessibleName")); // NOI18N
  591. getAccessibleContext().setAccessibleDescription(org.openide.util.NbBundle.getMessage(HintsPanel.class, "HintsPanel.AccessibleContext.accessibleDescription")); // NOI18N
  592. }// </editor-fold>//GEN-END:initComponents
  593. private void okButtonActionPerformed(java.awt.event.ActionEvent evt) {//GEN-FIRST:event_okButtonActionPerformed
  594. applyChanges();
  595. confirmed = true;
  596. getRootPane().getParent().setVisible(false);
  597. }//GEN-LAST:event_okButtonActionPerformed
  598. private void configComboActionPerformed(java.awt.event.ActionEvent evt) {//GEN-FIRST:event_configComboActionPerformed
  599. if (configCombo.getSelectedItem() instanceof ActionListener) {
  600. ((ActionListener) configCombo.getSelectedItem()).actionPerformed(evt);
  601. }
  602. if (queryStatus == QueryStatus.ONLY_ENABLED) {
  603. errorTreeModel = constructTM(Utilities.getBatchSupportedHints(cpBased).keySet(), false);
  604. setModel(errorTreeModel);
  605. if (logic != null) {
  606. logic.errorTreeModel = errorTreeModel;
  607. }
  608. }
  609. }//GEN-LAST:event_configComboActionPerformed
  610. private void newButtonActionPerformed(java.awt.event.ActionEvent evt) {//GEN-FIRST:event_newButtonActionPerformed
  611. try {
  612. FileObject tempFO = FileUtil.getConfigFile(DECLARATIVE_HINT_TEMPLATE_LOCATION); // NOI18N
  613. FileObject folderFO = FileUtil.getConfigFile("rules");
  614. if (folderFO == null) {
  615. folderFO = FileUtil.getConfigRoot().createFolder("rules");
  616. }
  617. DataFolder folder = (DataFolder) DataObject.find(folderFO);
  618. DataObject template = DataObject.find(tempFO);
  619. DataObject newIfcDO = template.createFromTemplate(folder, null);
  620. RulesManager.getInstance().reload();
  621. cpBased.reset();
  622. errorTreeModel = constructTM(Utilities.getBatchSupportedHints(cpBased).keySet(), false);
  623. setModel(errorTreeModel);
  624. logic.errorTreeModel = errorTreeModel;
  625. HintMetadata newHint = getHintByName(newIfcDO.getPrimaryFile().getNameExt());
  626. HintsSettings.setEnabled(logic.getCurrentPrefernces(newHint.id), true);
  627. select(newHint);
  628. hasNewHints = true;
  629. } catch (IOException ex) {
  630. Exceptions.printStackTrace(ex);
  631. }
  632. }//GEN-LAST:event_newButtonActionPerformed
  633. private String customHintCodeBeforeEditing;
  634. private boolean wasModified;
  635. private void editScriptButtonActionPerformed(java.awt.event.ActionEvent evt) {//GEN-FIRST:event_editScriptButtonActionPerformed
  636. descriptionScrollPane.setVisible(false);
  637. scriptScrollPane.setVisible(true);
  638. editScriptButton.setVisible(false);
  639. editingButtons.setVisible(true);
  640. optionsPanel.setVisible(false);
  641. org.openide.awt.Mnemonics.setLocalizedText(descriptionLabel, org.openide.util.NbBundle.getMessage(HintsPanel.class, "CTL_Script_Border"));
  642. DataObject dob = getDataObject(getSelectedHint());
  643. EditorCookie ec = dob.getCookie(EditorCookie.class);
  644. try {
  645. final StyledDocument doc = ec.openDocument();
  646. doc.render(new Runnable() {
  647. @Override public void run() {
  648. try {
  649. customHintCodeBeforeEditing = doc.getText(0, doc.getLength());
  650. } catch (BadLocationException ex) {
  651. Exceptions.printStackTrace(ex);
  652. customHintCodeBeforeEditing = null;
  653. }
  654. }
  655. });
  656. wasModified = DataObject.getRegistry().getModifiedSet().contains(dob);
  657. scriptTextArea.setDocument(doc);
  658. } catch (IOException ex) {
  659. Exceptions.printStackTrace(ex);
  660. }
  661. newButton.setEnabled(false);
  662. searchTextField.setEnabled(false);
  663. configCombo.setEnabled(false);
  664. errorTree.setEnabled(false);
  665. okButton.setEnabled(false);
  666. validate();
  667. }//GEN-LAST:event_editScriptButtonActionPerformed
  668. private void cancelEditActionPerformed(java.awt.event.ActionEvent evt) {//GEN-FIRST:event_cancelEditActionPerformed
  669. descriptionScrollPane.setVisible(true);
  670. scriptScrollPane.setVisible(false);
  671. optionsPanel.setVisible(true);
  672. editingButtons.setVisible(false);
  673. editScriptButton.setVisible(true);
  674. org.openide.awt.Mnemonics.setLocalizedText(descriptionLabel, org.openide.util.NbBundle.getMessage(HintsPanel.class, "CTL_Description_Border"));
  675. if (customHintCodeBeforeEditing != null) {
  676. DataObject dob = getDataObject(getSelectedHint());
  677. EditorCookie ec = dob.getCookie(EditorCookie.class);
  678. try {
  679. final StyledDocument doc = ec.openDocument();
  680. NbDocument.runAtomic(doc, new Runnable() {
  681. @Override public void run() {
  682. try {
  683. doc.remove(0, doc.getLength());
  684. doc.insertString(0, customHintCodeBeforeEditing, null);
  685. } catch (BadLocationException ex) {
  686. Exceptions.printStackTrace(ex);
  687. }
  688. }
  689. });
  690. customHintCodeBeforeEditing = null;
  691. if (!wasModified) ec.saveDocument();
  692. } catch (IOException ex) {
  693. Exceptions.printStackTrace(ex);
  694. }
  695. }
  696. okButton.setEnabled(true);
  697. newButton.setEnabled(true);
  698. searchTextField.setEnabled(true);
  699. configCombo.setEnabled(true);
  700. errorTree.setEnabled(true);
  701. logic.valueChanged(null);
  702. }//GEN-LAST:event_cancelEditActionPerformed
  703. private void openInEditorActionPerformed(java.awt.event.ActionEvent evt) {//GEN-FIRST:event_openInEditorActionPerformed
  704. applyChanges();
  705. getRootPane().getParent().getParent().setVisible(false);
  706. DataObject dob = getDataObject(getSelectedHint());
  707. EditorCookie ec = dob.getCookie(EditorCookie.class);
  708. ec.open();
  709. }//GEN-LAST:event_openInEditorActionPerformed
  710. private void saveButtonActionPerformed(java.awt.event.ActionEvent evt) {//GEN-FIRST:event_saveButtonActionPerformed
  711. final HintMetadata selectedHint = getSelectedHint();
  712. final String selectedHintId = selectedHint.id;
  713. DataObject dob = getDataObject(selectedHint);
  714. EditorCookie ec = dob.getCookie(EditorCookie.class);
  715. try {
  716. ec.saveDocument();
  717. } catch (IOException ex) {
  718. Exceptions.printStackTrace(ex);
  719. }
  720. RulesManager.getInstance().reload();
  721. cpBased.reset();
  722. errorTreeModel = constructTM(Utilities.getBatchSupportedHints(cpBased).keySet(), false);
  723. setModel(errorTreeModel);
  724. select(getHintByName(selectedHintId));
  725. customHintCodeBeforeEditing = null;
  726. cancelEditActionPerformed(evt);
  727. hasNewHints = true;
  728. }//GEN-LAST:event_saveButtonActionPerformed
  729. private void cancelButtonActionPerformed(java.awt.event.ActionEvent evt) {//GEN-FIRST:event_cancelButtonActionPerformed
  730. getRootPane().getParent().setVisible(false);
  731. }//GEN-LAST:event_cancelButtonActionPerformed
  732. private HintMetadata getHintByName(String name) {
  733. for (HintMetadata meta:Utilities.getBatchSupportedHints(cpBased).keySet()) {
  734. if (meta.id.startsWith(name)) {
  735. return meta;
  736. }
  737. }
  738. return null;
  739. }
  740. synchronized void update(boolean inOptionsDialog) {
  741. if (!initialized.get()) return;
  742. if ( logic != null ) {
  743. logic.disconnect();
  744. }
  745. logic = new HintsPanelLogic();
  746. logic.connect(errorTree, errorTreeModel, severityLabel, severityComboBox, toProblemCheckBox, customizerPanel, descriptionTextArea, configCombo, editScriptButton, inOptionsDialog);
  747. }
  748. void cancel() {
  749. if (!initialized.get()) return;
  750. logic.disconnect();
  751. logic = null;
  752. }
  753. boolean isChanged() {
  754. return logic != null ? logic.isChanged() : false;
  755. }
  756. void applyChanges() {
  757. if (!initialized.get()) return;
  758. logic.applyChanges();
  759. logic.disconnect();
  760. logic = null;
  761. }
  762. public boolean isConfirmed() {
  763. return confirmed;
  764. }
  765. class JLabelRenderer implements TreeCellRenderer {
  766. private JLabel renderer = new JLabel();
  767. private DefaultTreeCellRenderer dr = new DefaultTreeCellRenderer();
  768. public Component getTreeCellRendererComponent(JTree tree, Object value, boolean selected, boolean expanded, boolean leaf, int row, boolean hasFocus) {
  769. renderer.setBackground(selected ? dr.getBackgroundSelectionColor() : dr.getBackgroundNonSelectionColor());
  770. renderer.setForeground(selected ? dr.getTextSelectionColor() : dr.getTextNonSelectionColor());
  771. renderer.setFont(renderer.getFont().deriveFont(Font.PLAIN));
  772. renderer.setOpaque(true);
  773. Object data = ((DefaultMutableTreeNode) value).getUserObject();
  774. if (data instanceof HintCategory) {
  775. HintCategory cat = ((HintCategory) data);
  776. renderer.setText(cat.displayName);
  777. } else if (data instanceof HintMetadata) {
  778. HintMetadata treeRule = (HintMetadata) data;
  779. if (treeRule.options.contains(Options.QUERY)) {
  780. renderer.setFont(renderer.getFont().deriveFont(Font.ITALIC));
  781. }
  782. renderer.setText(treeRule.displayName);
  783. } else {
  784. renderer.setText(value.toString());
  785. }
  786. return renderer;
  787. }
  788. }
  789. class CheckBoxRenderer implements TreeCellRenderer {
  790. private final TristateCheckBox renderer = new TristateCheckBox();
  791. private final DefaultTreeCellRenderer dr = new DefaultTreeCellRenderer();
  792. public Component getTreeCellRendererComponent(JTree tree, Object value, boolean selected, boolean expanded, boolean leaf, int row, boolean hasFocus) {
  793. renderer.setBackground(selected ? dr.getBackgroundSelectionColor() : dr.getBackgroundNonSelectionColor());
  794. renderer.setForeground(selected ? dr.getTextSelectionColor() : dr.getTextNonSelectionColor());
  795. renderer.setFont(renderer.getFont().deriveFont(Font.PLAIN));
  796. Object data = ((DefaultMutableTreeNode) value).getUserObject();
  797. if (data instanceof HintCategory) {
  798. HintCategory cat = ((HintCategory) data);
  799. renderer.setText(cat.displayName);
  800. if (logic != null) {
  801. renderer.setState(logic.isSelected((DefaultMutableTreeNode) value));
  802. }
  803. } else if (data instanceof HintMetadata) {
  804. HintMetadata treeRule = (HintMetadata) data;
  805. if (treeRule.options.contains(Options.QUERY)) {
  806. renderer.setFont(renderer.getFont().deriveFont(Font.ITALIC));
  807. }
  808. renderer.setText(treeRule.displayName);
  809. if (logic != null) {
  810. renderer.setSelected(logic.isEnabled(treeRule));
  811. }
  812. } else {
  813. renderer.setText(value.toString());
  814. if (value == extraNode && logic != null) {
  815. renderer.setSelected(logic.getCurrentDependencyTracking() != DepScanningSettings.DependencyTracking.DISABLED);
  816. }
  817. }
  818. return renderer;
  819. }
  820. }
  821. enum State {
  822. SELECTED, NOT_SELECTED, OTHER;
  823. };
  824. private static class TristateCheckBox extends JCheckBox {
  825. private final TristateDecorator model;
  826. public TristateCheckBox() {
  827. super(null, null);
  828. model = new TristateDecorator(getModel());
  829. setModel(model);
  830. setState(State.OTHER);
  831. }
  832. /** No one may add mouse listeners, not even Swing! */
  833. @Override
  834. public void addMouseListener(MouseListener l) { }
  835. /**
  836. * Set the new state to either SELECTED, NOT_SELECTED or
  837. * OTHER.
  838. */
  839. public void setState(State state) { model.setState(state); }
  840. /** Return the current state, which is determined by the
  841. * selection status of the model. */
  842. public State getState() { return model.getState(); }
  843. @Override
  844. public void setSelected(boolean b) {
  845. if (b) {
  846. setState(State.SELECTED);
  847. } else {
  848. setState(State.NOT_SELECTED);
  849. }
  850. }
  851. /**
  852. * Exactly which Design Pattern is this? Is it an Adapter,
  853. * a Proxy or a Decorator? In this case, my vote lies with the
  854. * Decorator, because we are extending functionality and
  855. * "decorating" the original model with a more powerful model.
  856. */
  857. private class TristateDecorator implements ButtonModel {
  858. private final ButtonModel other;
  859. private TristateDecorator(ButtonModel other) {
  860. this.other = other;
  861. }
  862. private void setState(State state) {
  863. if (state == State.NOT_SELECTED) {
  864. other.setArmed(false);
  865. setPressed(false);
  866. setSelected(false);
  867. } else if (state == State.SELECTED) {
  868. other.setArmed(false);
  869. setPressed(false);
  870. setSelected(true);
  871. } else { // either "null" or OTHER
  872. other.setArmed(true);
  873. setPressed(true);
  874. setSelected(true);
  875. }
  876. }
  877. /**
  878. * The current state is embedded in the selection / armed
  879. * state of the model.
  880. *
  881. * We return the SELECTED state when the checkbox is selected
  882. * but not armed, DONT_CARE state when the checkbox is
  883. * selected and armed (grey) and NOT_SELECTED when the
  884. * checkbox is deselected.
  885. */
  886. private State getState() {
  887. if (isSelected() && !isArmed()) {
  888. // normal black tick
  889. return State.SELECTED;
  890. } else if (isSelected() && isArmed()) {
  891. // don't care grey tick
  892. return State.OTHER;
  893. } else {
  894. // normal deselected
  895. return State.NOT_SELECTED;
  896. }
  897. }
  898. /** Filter: No one may change the armed status except us. */
  899. public void setArmed(boolean b) {
  900. }
  901. /** We disable focusing on the component when it is not
  902. * enabled. */
  903. public void setEnabled(boolean b) {
  904. setFocusable(b);
  905. other.setEnabled(b);
  906. }
  907. /** All these methods simply delegate to the "other" model
  908. * that is being decorated. */
  909. public boolean isArmed() { return other.isArmed(); }
  910. public boolean isSelected() { return other.isSelected(); }
  911. public boolean isEnabled() { return other.isEnabled(); }
  912. public boolean isPressed() { return other.isPressed(); }
  913. public boolean isRollover() { return other.isRollover(); }
  914. public void setSelected(boolean b) { other.setSelected(b); }
  915. public void setPressed(boolean b) { other.setPressed(b); }
  916. public void setRollover(boolean b) { other.setRollover(b); }
  917. public void setMnemonic(int key) { other.setMnemonic(key); }
  918. public int getMnemonic() { return other.getMnemonic(); }
  919. public void setActionCommand(String s) {
  920. other.setActionCommand(s);
  921. }
  922. public String getActionCommand() {
  923. return other.getActionCommand();
  924. }
  925. public void setGroup(ButtonGroup group) {
  926. other.setGroup(group);
  927. }
  928. public void addActionListener(ActionListener l) {
  929. other.addActionListener(l);
  930. }
  931. public void removeActionListener(ActionListener l