4 package com
.intellij
.unscramble
;
6 import com
.intellij
.execution
.ui
.ConsoleView
;
7 import com
.intellij
.ide
.IdeBundle
;
8 import com
.intellij
.ide
.util
.PropertiesComponent
;
9 import com
.intellij
.openapi
.actionSystem
.DefaultActionGroup
;
10 import com
.intellij
.openapi
.extensions
.Extensions
;
11 import com
.intellij
.openapi
.fileChooser
.FileChooser
;
12 import com
.intellij
.openapi
.fileChooser
.FileChooserDescriptor
;
13 import com
.intellij
.openapi
.fileChooser
.FileChooserDescriptorFactory
;
14 import com
.intellij
.openapi
.help
.HelpManager
;
15 import com
.intellij
.openapi
.project
.Project
;
16 import com
.intellij
.openapi
.ui
.DialogWrapper
;
17 import com
.intellij
.openapi
.util
.Comparing
;
18 import com
.intellij
.openapi
.util
.io
.FileUtil
;
19 import com
.intellij
.openapi
.vfs
.VirtualFile
;
20 import com
.intellij
.ui
.GuiUtils
;
21 import com
.intellij
.ui
.TextFieldWithHistory
;
22 import com
.intellij
.util
.ArrayUtil
;
23 import com
.intellij
.util
.text
.CharArrayUtil
;
24 import org
.jetbrains
.annotations
.NonNls
;
25 import org
.jetbrains
.annotations
.Nullable
;
29 import java
.awt
.event
.ActionEvent
;
30 import java
.awt
.event
.ActionListener
;
31 import java
.util
.ArrayList
;
32 import java
.util
.Arrays
;
33 import java
.util
.List
;
35 public class UnscrambleDialog
extends DialogWrapper
{
36 @NonNls private static final String PROPERTY_LOG_FILE_HISTORY_URLS
= "UNSCRAMBLE_LOG_FILE_URL";
37 @NonNls private static final String PROPERTY_LOG_FILE_LAST_URL
= "UNSCRAMBLE_LOG_FILE_LAST_URL";
38 @NonNls private static final String PROPERTY_UNSCRAMBLER_NAME_USED
= "UNSCRAMBLER_NAME_USED";
40 private final Project myProject
;
41 private JPanel myEditorPanel
;
42 private JPanel myLogFileChooserPanel
;
43 private JComboBox myUnscrambleChooser
;
44 private JPanel myPanel
;
45 private TextFieldWithHistory myLogFile
;
46 private JCheckBox myUseUnscrambler
;
47 private JPanel myUnscramblePanel
;
48 protected AnalyzeStacktraceUtil
.StacktraceEditorPanel myStacktraceEditorPanel
;
50 public UnscrambleDialog(Project project
) {
54 populateRegisteredUnscramblerList();
55 myUnscrambleChooser
.addActionListener(new ActionListener() {
56 public void actionPerformed(ActionEvent e
) {
57 UnscrambleSupport unscrambleSupport
= getSelectedUnscrambler();
58 GuiUtils
.enableChildren(myLogFileChooserPanel
, unscrambleSupport
!= null);
61 myUseUnscrambler
.addActionListener(new ActionListener() {
62 public void actionPerformed(ActionEvent e
) {
63 useUnscramblerChanged();
66 createLogFileChooser();
70 setTitle(IdeBundle
.message("unscramble.dialog.title"));
74 private void useUnscramblerChanged() {
75 boolean selected
= myUseUnscrambler
.isSelected();
76 GuiUtils
.enableChildren(myUnscramblePanel
, selected
, myUseUnscrambler
);
79 private void reset() {
80 final List
<String
> savedUrls
= getSavedLogFileUrls();
81 myLogFile
.setHistorySize(10);
82 myLogFile
.setHistory(savedUrls
);
84 String lastUrl
= getLastUsedLogUrl();
85 if (lastUrl
== null && !savedUrls
.isEmpty()) {
86 lastUrl
= savedUrls
.get(savedUrls
.size() - 1);
88 if (lastUrl
!= null) {
89 myLogFile
.setText(lastUrl
);
90 myLogFile
.setSelectedItem(lastUrl
);
92 final UnscrambleSupport selectedUnscrambler
= getSavedUnscrambler();
94 final int count
= myUnscrambleChooser
.getItemCount();
96 if (selectedUnscrambler
!= null) {
97 for (int i
= 0; i
< count
; i
++) {
98 final UnscrambleSupport unscrambleSupport
= (UnscrambleSupport
)myUnscrambleChooser
.getItemAt(i
);
99 if (unscrambleSupport
!= null && Comparing
.strEqual(unscrambleSupport
.getPresentableName(), selectedUnscrambler
.getPresentableName())) {
106 myUseUnscrambler
.setEnabled(true);
107 myUnscrambleChooser
.setSelectedIndex(index
);
108 myUseUnscrambler
.setSelected(selectedUnscrambler
!= null);
111 myUseUnscrambler
.setEnabled(false);
114 useUnscramblerChanged();
115 myStacktraceEditorPanel
.pasteTextFromClipboard();
118 public static String
getLastUsedLogUrl() {
119 return PropertiesComponent
.getInstance().getValue(PROPERTY_LOG_FILE_LAST_URL
);
123 public static UnscrambleSupport
getSavedUnscrambler() {
124 final List
<UnscrambleSupport
> registeredUnscramblers
= getRegisteredUnscramblers();
125 final String savedUnscramblerName
= PropertiesComponent
.getInstance().getValue(PROPERTY_UNSCRAMBLER_NAME_USED
);
126 UnscrambleSupport selectedUnscrambler
= null;
127 for (final UnscrambleSupport unscrambleSupport
: registeredUnscramblers
) {
128 if (Comparing
.strEqual(unscrambleSupport
.getPresentableName(), savedUnscramblerName
)) {
129 selectedUnscrambler
= unscrambleSupport
;
132 return selectedUnscrambler
;
135 public static List
<String
> getSavedLogFileUrls() {
136 final List
<String
> res
= new ArrayList
<String
>();
137 final String savedUrl
= PropertiesComponent
.getInstance().getValue(PROPERTY_LOG_FILE_HISTORY_URLS
);
138 final String
[] strings
= savedUrl
== null ? ArrayUtil
.EMPTY_STRING_ARRAY
: savedUrl
.split(":::");
139 for (int i
= 0; i
!= strings
.length
; ++i
) {
146 private UnscrambleSupport
getSelectedUnscrambler() {
147 if (!myUseUnscrambler
.isSelected()) return null;
148 return (UnscrambleSupport
)myUnscrambleChooser
.getSelectedItem();
151 private void createEditor() {
152 myStacktraceEditorPanel
= AnalyzeStacktraceUtil
.createEditorPanel(myProject
, myDisposable
);
153 myEditorPanel
.setLayout(new BorderLayout());
154 myEditorPanel
.add(myStacktraceEditorPanel
, BorderLayout
.CENTER
);
157 protected Action
[] createActions(){
158 return new Action
[]{new NormalizeTextAction(), getOKAction(), getCancelAction(), getHelpAction()};
161 private void createLogFileChooser() {
162 myLogFile
= new TextFieldWithHistory();
163 JPanel panel
= GuiUtils
.constructFieldWithBrowseButton(myLogFile
, new ActionListener() {
164 public void actionPerformed(ActionEvent e
) {
165 FileChooserDescriptor descriptor
= FileChooserDescriptorFactory
.createSingleFileNoJarsDescriptor();
166 VirtualFile
[] files
= FileChooser
.chooseFiles(myLogFile
, descriptor
);
167 if (files
.length
!= 0) {
168 myLogFile
.setText(FileUtil
.toSystemDependentName(files
[files
.length
-1].getPath()));
172 myLogFileChooserPanel
.setLayout(new BorderLayout());
173 myLogFileChooserPanel
.add(panel
, BorderLayout
.CENTER
);
176 private void populateRegisteredUnscramblerList() {
177 List
<UnscrambleSupport
> unscrambleComponents
= getRegisteredUnscramblers();
179 //myUnscrambleChooser.addItem(null);
180 for (final UnscrambleSupport unscrambleSupport
: unscrambleComponents
) {
181 myUnscrambleChooser
.addItem(unscrambleSupport
);
183 myUnscrambleChooser
.setRenderer(new DefaultListCellRenderer() {
184 public Component
getListCellRendererComponent(JList list
, Object value
, int index
, boolean isSelected
, boolean cellHasFocus
) {
185 super.getListCellRendererComponent(list
, value
, index
, isSelected
, cellHasFocus
);
186 UnscrambleSupport unscrambleSupport
= (UnscrambleSupport
)value
;
187 setText(unscrambleSupport
== null ? IdeBundle
.message("unscramble.no.unscrambler.item") : unscrambleSupport
.getPresentableName());
193 private static List
<UnscrambleSupport
> getRegisteredUnscramblers() {
194 final UnscrambleSupport
[] components
= Extensions
.getExtensions(UnscrambleSupport
.EP_NAME
);
195 return Arrays
.asList(components
);
198 protected JComponent
createCenterPanel() {
202 public void dispose() {
204 final List list
= myLogFile
.getHistory();
206 for (Object aList
: list
) {
207 final String s
= (String
)aList
;
212 res
= res
+ ":::" + s
;
215 PropertiesComponent
.getInstance().setValue(PROPERTY_LOG_FILE_HISTORY_URLS
, res
);
216 UnscrambleSupport selectedUnscrambler
= getSelectedUnscrambler();
217 PropertiesComponent
.getInstance().setValue(PROPERTY_UNSCRAMBLER_NAME_USED
, selectedUnscrambler
== null ?
null : selectedUnscrambler
.getPresentableName());
219 PropertiesComponent
.getInstance().setValue(PROPERTY_LOG_FILE_LAST_URL
, myLogFile
.getText());
224 public void setText(String trace
) {
225 myStacktraceEditorPanel
.setText(trace
);
228 private final class NormalizeTextAction
extends AbstractAction
{
229 public NormalizeTextAction(){
230 putValue(Action
.NAME
, IdeBundle
.message("unscramble.normalize.button"));
231 putValue(DEFAULT_ACTION
, Boolean
.FALSE
);
234 public void actionPerformed(ActionEvent e
){
235 String text
= myStacktraceEditorPanel
.getText();
236 myStacktraceEditorPanel
.setText(normalizeText(text
));
241 static String
normalizeText(@NonNls String text
) {
242 StringBuilder builder
= new StringBuilder(text
.length());
243 String
[] lines
= text
.split("\n");
244 boolean first
= true;
245 boolean inAuxInfo
= false;
246 for (String line
: lines
) {
247 //noinspection HardCodedStringLiteral
248 if (!inAuxInfo
&& (line
.startsWith("JNI global references") || line
.trim().equals("Heap"))) {
249 builder
.append("\n");
253 builder
.append(trimSuffix(line
)).append("\n");
256 if (!first
&& mustHaveNewLineBefore(line
)) {
257 builder
.append("\n");
258 if (line
.startsWith("\"")) builder
.append("\n"); // Additional linebreak for thread names
261 int i
= builder
.lastIndexOf("\n");
262 CharSequence lastLine
= i
== -1 ? builder
: builder
.subSequence(i
+ 1, builder
.length());
263 if (lastLine
.toString().matches("\\s*at") && !line
.matches("\\s+.*")) builder
.append(" "); // separate 'at' from file name
264 builder
.append(trimSuffix(line
));
266 return builder
.toString();
269 private static String
trimSuffix(final String line
) {
270 int len
= line
.length();
272 while ((0 < len
) && (line
.charAt(len
-1) <= ' ')) {
275 return (len
< line
.length()) ? line
.substring(0, len
) : line
;
278 private static boolean mustHaveNewLineBefore(String line
) {
279 final int nonws
= CharArrayUtil
.shiftForward(line
, 0, " \t");
280 if (nonws
< line
.length()) {
281 line
= line
.substring(nonws
);
284 if (line
.startsWith("at")) return true; // Start of the new stackframe entry
285 if (line
.startsWith("Caused")) return true; // Caused by message
286 if (line
.startsWith("- locked")) return true; // "Locked a monitor" logging
287 if (line
.startsWith("- waiting")) return true; // "Waiting for monitor" logging
288 if (line
.startsWith("- parking to wait")) return true;
289 if (line
.startsWith("java.lang.Thread.State")) return true;
290 if (line
.startsWith("\"")) return true; // Start of the new thread (thread name)
295 protected void doOKAction() {
296 if (performUnscramble()) {
297 myLogFile
.addCurrentTextToHistory();
302 public void doHelpAction() {
303 HelpManager
.getInstance().invokeHelp("find.analyzeStackTrace");
306 private boolean performUnscramble() {
307 UnscrambleSupport selectedUnscrambler
= getSelectedUnscrambler();
308 return showUnscrambledText(selectedUnscrambler
, myLogFile
.getText(), myProject
, myStacktraceEditorPanel
.getText());
311 static boolean showUnscrambledText(UnscrambleSupport unscrambleSupport
, String logName
, Project project
, String textToUnscramble
) {
312 String unscrambledTrace
= unscrambleSupport
== null ? textToUnscramble
: unscrambleSupport
.unscramble(project
,textToUnscramble
, logName
);
313 if (unscrambledTrace
== null) return false;
314 List
<ThreadState
> threadStates
= ThreadDumpParser
.parse(unscrambledTrace
);
315 final ConsoleView consoleView
= addConsole(project
, threadStates
);
316 AnalyzeStacktraceUtil
.printStacktrace(consoleView
, unscrambledTrace
);
320 public static ConsoleView
addConsole(final Project project
, final List
<ThreadState
> threadDump
) {
321 return AnalyzeStacktraceUtil
.addConsole(project
, threadDump
.size() > 1 ?
new AnalyzeStacktraceUtil
.ConsoleFactory() {
322 public JComponent
createConsoleComponent(ConsoleView consoleView
, DefaultActionGroup toolbarActions
) {
323 return new ThreadDumpPanel(project
, consoleView
, toolbarActions
, threadDump
);
325 } : null, IdeBundle
.message("unscramble.unscrambled.stacktrace.tab"));
328 protected String
getDimensionServiceKey(){
329 return "#com.intellij.unscramble.UnscrambleDialog";
332 public JComponent
getPreferredFocusedComponent() {
333 return myStacktraceEditorPanel
.getEditorComponent();