blob: 6d089f42e2388e613f760d29c16c56f6fe4a2813 [file] [log] [blame]
/*
* Licensed to the Apache Software Foundation (ASF) under one
* or more contributor license agreements. See the NOTICE file
* distributed with this work for additional information
* regarding copyright ownership. The ASF licenses this file
* to you under the Apache License, Version 2.0 (the
* "License"); you may not use this file except in compliance
* with the License. You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing,
* software distributed under the License is distributed on an
* "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
* KIND, either express or implied. See the License for the
* specific language governing permissions and limitations
* under the License.
*/
package org.netbeans.modules.java.stackanalyzer;
import java.awt.Cursor;
import java.awt.Rectangle;
import java.awt.Toolkit;
import java.awt.datatransfer.Clipboard;
import java.awt.datatransfer.DataFlavor;
import java.awt.datatransfer.Transferable;
import java.awt.datatransfer.UnsupportedFlavorException;
import java.awt.event.ActionEvent;
import java.awt.event.KeyAdapter;
import java.awt.event.KeyEvent;
import java.awt.event.MouseAdapter;
import java.awt.event.MouseEvent;
import java.io.BufferedReader;
import java.io.IOException;
import java.io.Reader;
import java.io.Serializable;
import java.util.logging.Logger;
import javax.swing.AbstractAction;
import javax.swing.DefaultListModel;
import javax.swing.text.DefaultEditorKit;
import org.netbeans.modules.java.stackanalyzer.StackLineAnalyser.Link;
import org.openide.util.Exceptions;
import org.openide.util.HelpCtx;
import org.openide.util.NbBundle;
import org.openide.windows.TopComponent;
import org.openide.windows.WindowManager;
/**
* Analyser Stack Window implementation.
*
* @author Jan Becicka
*/
final class AnalyzeStackTopComponent extends TopComponent {
private static AnalyzeStackTopComponent instance;
private static final String PREFERRED_ID = "AnalyzeStackTopComponent";
private AnalyzeStackTopComponent () {
initComponents ();
setName (NbBundle.getMessage (AnalyzeStackTopComponent.class, "CTL_AnalyzeStackTopComponent"));
setToolTipText (NbBundle.getMessage (AnalyzeStackTopComponent.class, "HINT_AnalyzeStackTopComponent"));
getActionMap ().put (DefaultEditorKit.pasteAction, new PasteAction ());
insertButton.getActionMap ().put (DefaultEditorKit.pasteAction, new PasteAction ());
scrollPane.getActionMap ().put (DefaultEditorKit.pasteAction, new PasteAction ());
list.getActionMap ().put (DefaultEditorKit.pasteAction, new PasteAction ());
list.setCellRenderer (new AnalyserCellRenderer ());
list.addKeyListener (new KeyAdapter () {
@Override
public void keyTyped (KeyEvent e) {
if (e.getKeyChar () == KeyEvent.VK_ENTER) {
String currentLine = (String) list.getSelectedValue ();
open (currentLine);
}
}
});
list.addMouseListener (new MouseAdapter () {
@Override
public void mouseClicked (MouseEvent e) {
if (e.getClickCount () != 1) {
return;
}
int i = list.locationToIndex (e.getPoint ());
if (i < 0) {
return;
}
String currentLine = (String) list.getModel ().getElementAt (i);
open (currentLine);
}
});
list.addMouseMotionListener (new MouseAdapter () {
@Override
public void mouseMoved (MouseEvent e) {
int i = list.locationToIndex (e.getPoint ());
if (i >= 0) {
Rectangle r = list.getCellBounds (i, i);
if (r.contains (e.getPoint ())) {
String line = (String) list.getModel ().getElementAt (i);
Link link = StackLineAnalyser.analyse (line);
if (link != null) {
list.setCursor (Cursor.getPredefinedCursor (Cursor.HAND_CURSOR));
return;
}
}
}
list.setCursor (Cursor.getDefaultCursor ());
}
@Override
public void mouseExited (MouseEvent e) {
list.setCursor (Cursor.getDefaultCursor ());
}
});
}
public void fill(BufferedReader r) {
DefaultListModel model = new DefaultListModel ();
fillListModel(r, model);
if (!model.isEmpty()) {
list.setModel (model);
}
}
/**
* Reads the lines from the supplied reader and fills the supplied
* model with the lines.
* @param r
* @param model
*/
static void fillListModel(BufferedReader r, DefaultListModel model) {
String currentLine;
String lastLine = null;
try {
while ((currentLine = r.readLine()) != null) {
currentLine = currentLine.trim();
if (StackLineAnalyser.matches(currentLine)) {
if (lastLine != null) {
model.addElement(lastLine);
}
model.addElement(currentLine);
lastLine = null;
} else {
if (lastLine == null) {
lastLine = currentLine;
} else {
if (lastLine.endsWith("at")) { // NOI18N
lastLine += " "; // NOI18N
}
String together = lastLine + currentLine;
if (StackLineAnalyser.matches(together)) {
model.addElement(together);
lastLine = null;
} else {
model.addElement(lastLine);
lastLine = currentLine;
}
}
}
}
} catch (IOException ex) {
Exceptions.printStackTrace(ex);
}
}
/** This method is called from within the constructor to
* initialize the form.
* WARNING: Do NOT modify this code. The content of this method is
* always regenerated by the Form Editor.
*/
// <editor-fold defaultstate="collapsed" desc="Generated Code">//GEN-BEGIN:initComponents
private void initComponents() {
insertButton = new javax.swing.JButton();
scrollPane = new javax.swing.JScrollPane();
list = new javax.swing.JList();
setName("Form"); // NOI18N
org.openide.awt.Mnemonics.setLocalizedText(insertButton, org.openide.util.NbBundle.getBundle(AnalyzeStackTopComponent.class).getString("AnalyzeStackTopComponent.insertButton.text")); // NOI18N
insertButton.setName("insertButton"); // NOI18N
insertButton.addActionListener(new java.awt.event.ActionListener() {
public void actionPerformed(java.awt.event.ActionEvent evt) {
insertButtonActionPerformed(evt);
}
});
scrollPane.setName("scrollPane"); // NOI18N
list.setSelectionMode(javax.swing.ListSelectionModel.SINGLE_SELECTION);
list.setName("list"); // NOI18N
scrollPane.setViewportView(list);
javax.swing.GroupLayout layout = new javax.swing.GroupLayout(this);
this.setLayout(layout);
layout.setHorizontalGroup(
layout.createParallelGroup(javax.swing.GroupLayout.Alignment.LEADING)
.addGroup(layout.createSequentialGroup()
.addContainerGap()
.addGroup(layout.createParallelGroup(javax.swing.GroupLayout.Alignment.LEADING)
.addComponent(scrollPane, javax.swing.GroupLayout.DEFAULT_SIZE, 394, Short.MAX_VALUE)
.addComponent(insertButton))
.addContainerGap())
);
layout.setVerticalGroup(
layout.createParallelGroup(javax.swing.GroupLayout.Alignment.LEADING)
.addGroup(layout.createSequentialGroup()
.addContainerGap()
.addComponent(insertButton)
.addPreferredGap(javax.swing.LayoutStyle.ComponentPlacement.RELATED)
.addComponent(scrollPane, javax.swing.GroupLayout.DEFAULT_SIZE, 367, Short.MAX_VALUE)
.addContainerGap())
);
insertButton.getAccessibleContext().setAccessibleDescription(org.openide.util.NbBundle.getMessage(AnalyzeStackTopComponent.class, "AnalyzeStackTopComponent.insertButton.AccessibleContext.accessibleDescription")); // NOI18N
getAccessibleContext().setAccessibleName(org.openide.util.NbBundle.getMessage(AnalyzeStackTopComponent.class, "AnalyzeStackTopComponent.AccessibleContext.accessibleName")); // NOI18N
getAccessibleContext().setAccessibleDescription(org.openide.util.NbBundle.getMessage(AnalyzeStackTopComponent.class, "AnalyzeStackTopComponent.AccessibleContext.accessibleDescription")); // NOI18N
}// </editor-fold>//GEN-END:initComponents
private void insertButtonActionPerformed(java.awt.event.ActionEvent evt) {//GEN-FIRST:event_insertButtonActionPerformed
try {
Clipboard clipBoard = Toolkit.getDefaultToolkit ().getSystemClipboard ();
Transferable transferable = clipBoard.getContents (this);
if (!transferable.isDataFlavorSupported (DataFlavor.stringFlavor)) {
return;
}
Reader reader = DataFlavor.stringFlavor.getReaderForText (transferable);
BufferedReader r = new BufferedReader (reader);
fill(r);
} catch (UnsupportedFlavorException ex) {
Exceptions.printStackTrace (ex);
} catch (IOException ex) {
Exceptions.printStackTrace (ex);
}
}//GEN-LAST:event_insertButtonActionPerformed
// Variables declaration - do not modify//GEN-BEGIN:variables
private javax.swing.JButton insertButton;
private javax.swing.JList list;
private javax.swing.JScrollPane scrollPane;
// End of variables declaration//GEN-END:variables
/**
* Gets default instance. Do not use directly: reserved for *.settings files only,
* i.e. deserialization routines; otherwise you could get a non-deserialized instance.
* To obtain the singleton instance, use {@link findInstance}.
*/
public static synchronized AnalyzeStackTopComponent getDefault () {
if (instance == null) {
instance = new AnalyzeStackTopComponent ();
}
return instance;
}
/**
* Obtain the AnalyzeStackTopComponent instance. Never call {@link #getDefault} directly!
*/
public static synchronized AnalyzeStackTopComponent findInstance () {
TopComponent win = WindowManager.getDefault ().findTopComponent (PREFERRED_ID);
if (win == null) {
Logger.getLogger (AnalyzeStackTopComponent.class.getName ()).warning (
"Cannot find " + PREFERRED_ID + " component. It will not be located properly in the window system.");
AnalyzeStackTopComponent analyzeStackTopComponent = getDefault();
analyzeStackTopComponent.insertButtonActionPerformed(null);
return analyzeStackTopComponent;
}
if (win instanceof AnalyzeStackTopComponent) {
AnalyzeStackTopComponent analyzeStackTopComponent = (AnalyzeStackTopComponent) win;
analyzeStackTopComponent.insertButtonActionPerformed(null);
return analyzeStackTopComponent;
}
Logger.getLogger (AnalyzeStackTopComponent.class.getName ()).warning (
"There seem to be multiple components with the '" + PREFERRED_ID +
"' ID. That is a potential source of errors and unexpected behavior.");
return getDefault ();
}
@Override
public int getPersistenceType () {
return TopComponent.PERSISTENCE_ALWAYS;
}
@Override
public void componentOpened () {
// TODO add custom code on component opening
}
@Override
public void componentClosed () {
// TODO add custom code on component closing
}
/** replaces this in object stream */
@Override
public Object writeReplace () {
return new ResolvableHelper ();
}
@Override
protected String preferredID () {
return PREFERRED_ID;
}
@Override
public HelpCtx getHelpCtx() {
return new HelpCtx("org.netbeans.modules.java.stackanalyzer.AnalyzeStackTopComponent"); //NOI18N
}
final static class ResolvableHelper implements Serializable {
private static final long serialVersionUID = 1L;
public Object readResolve () {
return AnalyzeStackTopComponent.getDefault ();
}
}
private void open (String line) {
Link link = StackLineAnalyser.analyse (line);
if (link != null) {
link.show ();
}
}
private class PasteAction extends AbstractAction {
public PasteAction () {
}
@Override
public void actionPerformed (ActionEvent e) {
insertButtonActionPerformed (null);
}
}
}