You can not select more than 25 topics Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.

ScannerReportViewerApp.java 22KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624625626627628629630631632633634635636637638639640641642643644645646647648649650651652653654
  1. /*
  2. * SonarQube
  3. * Copyright (C) 2009-2020 SonarSource SA
  4. * mailto:info AT sonarsource DOT com
  5. *
  6. * This program is free software; you can redistribute it and/or
  7. * modify it under the terms of the GNU Lesser General Public
  8. * License as published by the Free Software Foundation; either
  9. * version 3 of the License, or (at your option) any later version.
  10. *
  11. * This program is distributed in the hope that it will be useful,
  12. * but WITHOUT ANY WARRANTY; without even the implied warranty of
  13. * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
  14. * Lesser General Public License for more details.
  15. *
  16. * You should have received a copy of the GNU Lesser General Public License
  17. * along with this program; if not, write to the Free Software Foundation,
  18. * Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
  19. */
  20. package org.sonar.scanner.protocol.viewer;
  21. import java.awt.*;
  22. import java.io.File;
  23. import java.io.IOException;
  24. import java.io.PrintWriter;
  25. import java.io.StringWriter;
  26. import java.nio.charset.StandardCharsets;
  27. import java.sql.Date;
  28. import java.text.SimpleDateFormat;
  29. import java.util.List;
  30. import java.util.Map;
  31. import java.util.Scanner;
  32. import javax.annotation.CheckForNull;
  33. import javax.swing.*;
  34. import javax.swing.UIManager.*;
  35. import javax.swing.event.*;
  36. import javax.swing.tree.*;
  37. import org.apache.commons.io.FileUtils;
  38. import org.apache.commons.lang.StringUtils;
  39. import org.sonar.core.util.CloseableIterator;
  40. import org.sonar.scanner.protocol.output.FileStructure.Domain;
  41. import org.sonar.scanner.protocol.output.ScannerReport;
  42. import org.sonar.scanner.protocol.output.ScannerReport.Changesets;
  43. import org.sonar.scanner.protocol.output.ScannerReport.Changesets.Changeset;
  44. import org.sonar.scanner.protocol.output.ScannerReport.Component;
  45. import org.sonar.scanner.protocol.output.ScannerReport.Issue;
  46. import org.sonar.scanner.protocol.output.ScannerReport.Metadata;
  47. import org.sonar.scanner.protocol.output.ScannerReport.Metadata.Plugin;
  48. import org.sonar.scanner.protocol.output.ScannerReport.Metadata.QProfile;
  49. import org.sonar.scanner.protocol.output.ScannerReportReader;
  50. public class ScannerReportViewerApp {
  51. private JFrame frame;
  52. private ScannerReportReader reader;
  53. private Metadata metadata;
  54. private SimpleDateFormat sdf = new SimpleDateFormat("dd/MM/yyyy HH:mm:ss");
  55. private JTree componentTree;
  56. private JSplitPane splitPane;
  57. private JTabbedPane tabbedPane;
  58. private JScrollPane treeScrollPane;
  59. private JScrollPane componentDetailsTab;
  60. private JScrollPane highlightingTab;
  61. private JScrollPane symbolTab;
  62. private JEditorPane componentEditor;
  63. private JEditorPane highlightingEditor;
  64. private JEditorPane symbolEditor;
  65. private JScrollPane sourceTab;
  66. private JEditorPane sourceEditor;
  67. private JScrollPane coverageTab;
  68. private JEditorPane coverageEditor;
  69. private JScrollPane testsTab;
  70. private JEditorPane testsEditor;
  71. private TextLineNumber textLineNumber;
  72. private JScrollPane duplicationTab;
  73. private JEditorPane duplicationEditor;
  74. private JScrollPane issuesTab;
  75. private JEditorPane issuesEditor;
  76. private JScrollPane externalIssuesTab;
  77. private JEditorPane externalIssuesEditor;
  78. private JScrollPane measuresTab;
  79. private JEditorPane measuresEditor;
  80. private JScrollPane scmTab;
  81. private JEditorPane scmEditor;
  82. private JScrollPane activeRuleTab;
  83. private JEditorPane activeRuleEditor;
  84. private JScrollPane adHocRuleTab;
  85. private JEditorPane adHocRuleEditor;
  86. private JScrollPane qualityProfileTab;
  87. private JEditorPane qualityProfileEditor;
  88. private JScrollPane pluginTab;
  89. private JEditorPane pluginEditor;
  90. private JScrollPane cpdTextBlocksTab;
  91. private JEditorPane cpdTextBlocksEditor;
  92. private JScrollPane significantCodeTab;
  93. private JEditorPane significantCodeEditor;
  94. /**
  95. * Create the application.
  96. */
  97. public ScannerReportViewerApp() {
  98. initialize();
  99. }
  100. /**
  101. * Launch the application.
  102. */
  103. public static void main(String[] args) {
  104. EventQueue.invokeLater(new Runnable() {
  105. @Override
  106. public void run() {
  107. try {
  108. ScannerReportViewerApp window = new ScannerReportViewerApp();
  109. window.frame.setVisible(true);
  110. window.loadReport();
  111. } catch (Exception e) {
  112. e.printStackTrace();
  113. }
  114. }
  115. });
  116. }
  117. private void loadReport() {
  118. final JFileChooser fc = new JFileChooser();
  119. fc.setDialogTitle("Choose scanner report directory");
  120. File lastReport = getLastUsedReport();
  121. if (lastReport != null) {
  122. fc.setCurrentDirectory(lastReport);
  123. }
  124. fc.setFileSelectionMode(JFileChooser.DIRECTORIES_ONLY);
  125. fc.setFileHidingEnabled(false);
  126. fc.setApproveButtonText("Open scanner report");
  127. int returnVal = fc.showOpenDialog(frame);
  128. if (returnVal == JFileChooser.APPROVE_OPTION) {
  129. File file = fc.getSelectedFile();
  130. try {
  131. setLastUsedReport(file);
  132. loadReport(file);
  133. } catch (Exception e) {
  134. JOptionPane.showMessageDialog(frame, e.getMessage(), "Error", JOptionPane.ERROR_MESSAGE);
  135. exit();
  136. }
  137. } else {
  138. exit();
  139. }
  140. }
  141. @CheckForNull
  142. private File getLastUsedReport() {
  143. File f = new File(System.getProperty("java.io.tmpdir"), ".last_batch_report_dir");
  144. if (f.exists()) {
  145. String path;
  146. try {
  147. path = FileUtils.readFileToString(f, StandardCharsets.UTF_8);
  148. } catch (IOException e) {
  149. return null;
  150. }
  151. File lastReport = new File(path);
  152. if (lastReport.exists() && lastReport.isDirectory()) {
  153. return lastReport;
  154. }
  155. }
  156. return null;
  157. }
  158. private void setLastUsedReport(File lastReport) throws IOException {
  159. File f = new File(System.getProperty("java.io.tmpdir"), ".last_batch_report_dir");
  160. String fullPath = lastReport.getAbsolutePath();
  161. FileUtils.write(f, fullPath, StandardCharsets.UTF_8);
  162. }
  163. private void exit() {
  164. frame.setVisible(false);
  165. frame.dispose();
  166. }
  167. private void loadReport(File file) {
  168. reader = new ScannerReportReader(file);
  169. metadata = reader.readMetadata();
  170. updateTitle();
  171. loadComponents();
  172. updateActiveRules();
  173. updateAdHocRules();
  174. updateQualityProfiles();
  175. updatePlugins();
  176. }
  177. private void loadComponents() {
  178. int rootComponentRef = metadata.getRootComponentRef();
  179. Component component = reader.readComponent(rootComponentRef);
  180. DefaultMutableTreeNode project = createNode(component);
  181. loadChildren(component, project);
  182. getComponentTree().setModel(new DefaultTreeModel(project));
  183. }
  184. private static DefaultMutableTreeNode createNode(Component component) {
  185. return new DefaultMutableTreeNode(component) {
  186. @Override
  187. public String toString() {
  188. return getNodeName((Component) getUserObject());
  189. }
  190. };
  191. }
  192. private static String getNodeName(Component component) {
  193. switch (component.getType()) {
  194. case PROJECT:
  195. case MODULE:
  196. return component.getName();
  197. case DIRECTORY:
  198. case FILE:
  199. return component.getProjectRelativePath();
  200. default:
  201. throw new IllegalArgumentException("Unknow component type: " + component.getType());
  202. }
  203. }
  204. private void loadChildren(Component parentComponent, DefaultMutableTreeNode parentNode) {
  205. for (int ref : parentComponent.getChildRefList()) {
  206. Component child = reader.readComponent(ref);
  207. DefaultMutableTreeNode childNode = createNode(child);
  208. parentNode.add(childNode);
  209. loadChildren(child, childNode);
  210. }
  211. }
  212. private void updateTitle() {
  213. frame.setTitle(metadata.getProjectKey() + (StringUtils.isNotEmpty(metadata.getBranchName()) ? (" (" + metadata.getBranchName() + ")") : "") + " "
  214. + sdf.format(new Date(metadata.getAnalysisDate())));
  215. }
  216. private void updateDetails(Component component) {
  217. componentEditor.setText(component.toString());
  218. updateHighlighting(component);
  219. updateSymbols(component);
  220. updateSource(component);
  221. updateCoverage(component);
  222. updateDuplications(component);
  223. updateIssues(component);
  224. updateExternalIssues(component);
  225. updateMeasures(component);
  226. updateScm(component);
  227. updateCpdTextBlocks(component);
  228. updateSignificantCode(component);
  229. }
  230. private void updateCpdTextBlocks(Component component) {
  231. cpdTextBlocksEditor.setText("");
  232. if (reader.hasCoverage(component.getRef())) {
  233. try (CloseableIterator<ScannerReport.CpdTextBlock> it = reader.readCpdTextBlocks(component.getRef())) {
  234. while (it.hasNext()) {
  235. ScannerReport.CpdTextBlock textBlock = it.next();
  236. cpdTextBlocksEditor.getDocument().insertString(cpdTextBlocksEditor.getDocument().getLength(), textBlock + "\n", null);
  237. }
  238. } catch (Exception e) {
  239. throw new IllegalStateException("Can't read CPD text blocks for " + getNodeName(component), e);
  240. }
  241. }
  242. }
  243. private void updateSignificantCode(Component component) {
  244. significantCodeEditor.setText("");
  245. if (reader.hasCoverage(component.getRef())) {
  246. try (CloseableIterator<ScannerReport.LineSgnificantCode> it = reader.readComponentSignificantCode(component.getRef())) {
  247. if (it != null) {
  248. while (it.hasNext()) {
  249. ScannerReport.LineSgnificantCode textBlock = it.next();
  250. significantCodeEditor.getDocument().insertString(significantCodeEditor.getDocument().getLength(), textBlock + "\n", null);
  251. }
  252. }
  253. } catch (Exception e) {
  254. throw new IllegalStateException("Can't read significant code for " + getNodeName(component), e);
  255. }
  256. }
  257. }
  258. private void updateDuplications(Component component) {
  259. duplicationEditor.setText("");
  260. if (reader.hasCoverage(component.getRef())) {
  261. try (CloseableIterator<ScannerReport.Duplication> it = reader.readComponentDuplications(component.getRef())) {
  262. while (it.hasNext()) {
  263. ScannerReport.Duplication dup = it.next();
  264. duplicationEditor.getDocument().insertString(duplicationEditor.getDocument().getLength(), dup + "\n", null);
  265. }
  266. } catch (Exception e) {
  267. throw new IllegalStateException("Can't read duplications for " + getNodeName(component), e);
  268. }
  269. }
  270. }
  271. private void updateIssues(Component component) {
  272. issuesEditor.setText("");
  273. try (CloseableIterator<Issue> it = reader.readComponentIssues(component.getRef())) {
  274. while (it.hasNext()) {
  275. Issue issue = it.next();
  276. int offset = issuesEditor.getDocument().getLength();
  277. issuesEditor.getDocument().insertString(offset, issue.toString(), null);
  278. }
  279. } catch (Exception e) {
  280. throw new IllegalStateException("Can't read issues for " + getNodeName(component), e);
  281. }
  282. }
  283. private void updateExternalIssues(Component component) {
  284. externalIssuesEditor.setText("");
  285. try (CloseableIterator<ScannerReport.ExternalIssue> it = reader.readComponentExternalIssues(component.getRef())) {
  286. while (it.hasNext()) {
  287. ScannerReport.ExternalIssue issue = it.next();
  288. int offset = externalIssuesEditor.getDocument().getLength();
  289. externalIssuesEditor.getDocument().insertString(offset, issue.toString(), null);
  290. }
  291. } catch (Exception e) {
  292. throw new IllegalStateException("Can't read external issues for " + getNodeName(component), e);
  293. }
  294. }
  295. private void updateCoverage(Component component) {
  296. coverageEditor.setText("");
  297. try (CloseableIterator<ScannerReport.LineCoverage> it = reader.readComponentCoverage(component.getRef())) {
  298. while (it.hasNext()) {
  299. ScannerReport.LineCoverage coverage = it.next();
  300. coverageEditor.getDocument().insertString(coverageEditor.getDocument().getLength(), coverage + "\n", null);
  301. }
  302. } catch (Exception e) {
  303. throw new IllegalStateException("Can't read code coverage for " + getNodeName(component), e);
  304. }
  305. }
  306. private void updateSource(Component component) {
  307. File sourceFile = reader.getFileStructure().fileFor(Domain.SOURCE, component.getRef());
  308. sourceEditor.setText("");
  309. if (sourceFile.exists()) {
  310. try (Scanner s = new Scanner(sourceFile, StandardCharsets.UTF_8.name()).useDelimiter("\\Z")) {
  311. if (s.hasNext()) {
  312. sourceEditor.setText(s.next());
  313. }
  314. } catch (IOException ex) {
  315. StringWriter errors = new StringWriter();
  316. ex.printStackTrace(new PrintWriter(errors));
  317. sourceEditor.setText(errors.toString());
  318. }
  319. }
  320. }
  321. private void updateActiveRules() {
  322. activeRuleEditor.setText("");
  323. StringBuilder builder = new StringBuilder();
  324. try (CloseableIterator<ScannerReport.ActiveRule> activeRuleCloseableIterator = reader.readActiveRules()) {
  325. while (activeRuleCloseableIterator.hasNext()) {
  326. builder.append(activeRuleCloseableIterator.next().toString()).append("\n");
  327. }
  328. activeRuleEditor.setText(builder.toString());
  329. }
  330. }
  331. private void updateAdHocRules() {
  332. adHocRuleEditor.setText("");
  333. StringBuilder builder = new StringBuilder();
  334. try (CloseableIterator<ScannerReport.AdHocRule> adHocRuleCloseableIterator = reader.readAdHocRules()) {
  335. while (adHocRuleCloseableIterator.hasNext()) {
  336. builder.append(adHocRuleCloseableIterator.next().toString()).append("\n");
  337. }
  338. adHocRuleEditor.setText(builder.toString());
  339. }
  340. }
  341. private void updateQualityProfiles() {
  342. qualityProfileEditor.setText("");
  343. StringBuilder builder = new StringBuilder();
  344. for (Map.Entry<String, QProfile> qp : metadata.getQprofilesPerLanguage().entrySet()) {
  345. builder.append(qp.getKey()).append(":\n").append(qp.getValue()).append("\n\n");
  346. }
  347. qualityProfileEditor.setText(builder.toString());
  348. }
  349. private void updatePlugins() {
  350. pluginEditor.setText("");
  351. StringBuilder builder = new StringBuilder();
  352. for (Map.Entry<String, Plugin> p : metadata.getPluginsByKey().entrySet()) {
  353. builder.append(p.getKey()).append(":\n").append(p.getValue()).append("\n\n");
  354. }
  355. pluginEditor.setText(builder.toString());
  356. }
  357. private void updateHighlighting(Component component) {
  358. highlightingEditor.setText("");
  359. try (CloseableIterator<ScannerReport.SyntaxHighlightingRule> it = reader.readComponentSyntaxHighlighting(component.getRef())) {
  360. while (it.hasNext()) {
  361. ScannerReport.SyntaxHighlightingRule rule = it.next();
  362. int offset = highlightingEditor.getDocument().getLength();
  363. highlightingEditor.getDocument().insertString(offset, rule + "\n", null);
  364. }
  365. } catch (Exception e) {
  366. throw new IllegalStateException("Can't read syntax highlighting for " + getNodeName(component), e);
  367. }
  368. }
  369. private void updateMeasures(Component component) {
  370. measuresEditor.setText("");
  371. try (CloseableIterator<ScannerReport.Measure> it = reader.readComponentMeasures(component.getRef())) {
  372. while (it.hasNext()) {
  373. ScannerReport.Measure measure = it.next();
  374. measuresEditor.getDocument().insertString(measuresEditor.getDocument().getLength(), measure + "\n", null);
  375. }
  376. } catch (Exception e) {
  377. throw new IllegalStateException("Can't read measures for " + getNodeName(component), e);
  378. }
  379. }
  380. private void updateScm(Component component) {
  381. scmEditor.setText("");
  382. Changesets changesets = reader.readChangesets(component.getRef());
  383. if (changesets == null) {
  384. return;
  385. }
  386. List<Integer> changesetIndexByLine = changesets.getChangesetIndexByLineList();
  387. try {
  388. int index = 0;
  389. for (Changeset changeset : changesets.getChangesetList()) {
  390. scmEditor.getDocument().insertString(scmEditor.getDocument().getLength(), index + "\n", null);
  391. scmEditor.getDocument().insertString(scmEditor.getDocument().getLength(), changeset + "\n", null);
  392. index++;
  393. }
  394. scmEditor.getDocument().insertString(scmEditor.getDocument().getLength(), "\n", null);
  395. int line = 1;
  396. for (Integer idx : changesetIndexByLine) {
  397. scmEditor.getDocument().insertString(scmEditor.getDocument().getLength(), line + ": " + idx + "\n", null);
  398. line++;
  399. }
  400. } catch (Exception e) {
  401. throw new IllegalStateException("Can't read SCM for " + getNodeName(component), e);
  402. }
  403. }
  404. private void updateSymbols(Component component) {
  405. symbolEditor.setText("");
  406. try (CloseableIterator<ScannerReport.Symbol> it = reader.readComponentSymbols(component.getRef())) {
  407. while (it.hasNext()) {
  408. ScannerReport.Symbol symbol = it.next();
  409. symbolEditor.getDocument().insertString(symbolEditor.getDocument().getLength(), symbol + "\n", null);
  410. }
  411. } catch (Exception e) {
  412. throw new IllegalStateException("Can't read symbol references for " + getNodeName(component), e);
  413. }
  414. }
  415. /**
  416. * Initialize the contents of the frame.
  417. */
  418. private void initialize() {
  419. try {
  420. for (LookAndFeelInfo info : UIManager.getInstalledLookAndFeels()) {
  421. if ("Nimbus".equals(info.getName())) {
  422. UIManager.setLookAndFeel(info.getClassName());
  423. break;
  424. }
  425. }
  426. } catch (Exception e) {
  427. // If Nimbus is not available, you can set the GUI to another look and feel.
  428. }
  429. frame = new JFrame();
  430. frame.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
  431. splitPane = new JSplitPane();
  432. frame.getContentPane().add(splitPane, BorderLayout.CENTER);
  433. tabbedPane = new JTabbedPane(JTabbedPane.TOP);
  434. tabbedPane.setPreferredSize(new Dimension(500, 7));
  435. splitPane.setRightComponent(tabbedPane);
  436. componentDetailsTab = new JScrollPane();
  437. tabbedPane.addTab("Component details", null, componentDetailsTab, null);
  438. componentEditor = new JEditorPane();
  439. componentDetailsTab.setViewportView(componentEditor);
  440. sourceTab = new JScrollPane();
  441. tabbedPane.addTab("Source", null, sourceTab, null);
  442. sourceEditor = createSourceEditor();
  443. sourceEditor.setEditable(false);
  444. sourceTab.setViewportView(sourceEditor);
  445. textLineNumber = createTextLineNumber();
  446. sourceTab.setRowHeaderView(textLineNumber);
  447. highlightingTab = new JScrollPane();
  448. tabbedPane.addTab("Highlighting", null, highlightingTab, null);
  449. highlightingEditor = new JEditorPane();
  450. highlightingTab.setViewportView(highlightingEditor);
  451. symbolTab = new JScrollPane();
  452. tabbedPane.addTab("Symbol references", null, symbolTab, null);
  453. symbolEditor = new JEditorPane();
  454. symbolTab.setViewportView(symbolEditor);
  455. coverageTab = new JScrollPane();
  456. tabbedPane.addTab("Coverage", null, coverageTab, null);
  457. coverageEditor = new JEditorPane();
  458. coverageTab.setViewportView(coverageEditor);
  459. duplicationTab = new JScrollPane();
  460. tabbedPane.addTab("Duplications", null, duplicationTab, null);
  461. duplicationEditor = new JEditorPane();
  462. duplicationTab.setViewportView(duplicationEditor);
  463. testsTab = new JScrollPane();
  464. tabbedPane.addTab("Tests", null, testsTab, null);
  465. testsEditor = new JEditorPane();
  466. testsTab.setViewportView(testsEditor);
  467. issuesTab = new JScrollPane();
  468. tabbedPane.addTab("Issues", null, issuesTab, null);
  469. issuesEditor = new JEditorPane();
  470. issuesTab.setViewportView(issuesEditor);
  471. externalIssuesTab = new JScrollPane();
  472. tabbedPane.addTab("External Issues", null, externalIssuesTab, null);
  473. externalIssuesEditor = new JEditorPane();
  474. externalIssuesTab.setViewportView(externalIssuesEditor);
  475. measuresTab = new JScrollPane();
  476. tabbedPane.addTab("Measures", null, measuresTab, null);
  477. measuresEditor = new JEditorPane();
  478. measuresTab.setViewportView(measuresEditor);
  479. scmTab = new JScrollPane();
  480. tabbedPane.addTab("SCM", null, scmTab, null);
  481. scmEditor = new JEditorPane();
  482. scmTab.setViewportView(scmEditor);
  483. activeRuleTab = new JScrollPane();
  484. tabbedPane.addTab("Active Rules", null, activeRuleTab, null);
  485. activeRuleEditor = new JEditorPane();
  486. activeRuleTab.setViewportView(activeRuleEditor);
  487. adHocRuleTab = new JScrollPane();
  488. tabbedPane.addTab("Add Hoc Rules", null, adHocRuleTab, null);
  489. adHocRuleEditor = new JEditorPane();
  490. adHocRuleTab.setViewportView(adHocRuleEditor);
  491. qualityProfileTab = new JScrollPane();
  492. tabbedPane.addTab("Quality Profiles", null, qualityProfileTab, null);
  493. qualityProfileEditor = new JEditorPane();
  494. qualityProfileTab.setViewportView(qualityProfileEditor);
  495. pluginTab = new JScrollPane();
  496. tabbedPane.addTab("Plugins", null, pluginTab, null);
  497. pluginEditor = new JEditorPane();
  498. pluginTab.setViewportView(pluginEditor);
  499. cpdTextBlocksTab = new JScrollPane();
  500. tabbedPane.addTab("CPD Text Blocks", null, cpdTextBlocksTab, null);
  501. cpdTextBlocksEditor = new JEditorPane();
  502. cpdTextBlocksTab.setViewportView(cpdTextBlocksEditor);
  503. significantCodeTab = new JScrollPane();
  504. tabbedPane.addTab("Significant Code Ranges", null, significantCodeTab, null);
  505. significantCodeEditor = new JEditorPane();
  506. significantCodeTab.setViewportView(significantCodeEditor);
  507. treeScrollPane = new JScrollPane();
  508. treeScrollPane.setPreferredSize(new Dimension(200, 400));
  509. splitPane.setLeftComponent(treeScrollPane);
  510. componentTree = new JTree();
  511. componentTree.setModel(new DefaultTreeModel(
  512. new DefaultMutableTreeNode("empty") {
  513. {
  514. }
  515. }));
  516. treeScrollPane.setViewportView(componentTree);
  517. componentTree.getSelectionModel().setSelectionMode(TreeSelectionModel.SINGLE_TREE_SELECTION);
  518. componentTree.addTreeSelectionListener(new TreeSelectionListener() {
  519. @Override
  520. public void valueChanged(TreeSelectionEvent e) {
  521. DefaultMutableTreeNode node = (DefaultMutableTreeNode) componentTree.getLastSelectedPathComponent();
  522. if (node == null) {
  523. // Nothing is selected.
  524. return;
  525. }
  526. frame.setCursor(new Cursor(Cursor.WAIT_CURSOR));
  527. updateDetails((Component) node.getUserObject());
  528. frame.setCursor(new Cursor(Cursor.DEFAULT_CURSOR));
  529. }
  530. });
  531. frame.pack();
  532. }
  533. public JTree getComponentTree() {
  534. return componentTree;
  535. }
  536. /**
  537. * @wbp.factory
  538. */
  539. public static JPanel createComponentPanel() {
  540. JPanel panel = new JPanel();
  541. return panel;
  542. }
  543. protected JEditorPane getComponentEditor() {
  544. return componentEditor;
  545. }
  546. /**
  547. * @wbp.factory
  548. */
  549. public static JEditorPane createSourceEditor() {
  550. JEditorPane editorPane = new JEditorPane();
  551. return editorPane;
  552. }
  553. /**
  554. * @wbp.factory
  555. */
  556. public TextLineNumber createTextLineNumber() {
  557. TextLineNumber textLineNumber = new TextLineNumber(sourceEditor);
  558. return textLineNumber;
  559. }
  560. }