1 package com
.intellij
.diagnostic
.logging
;
3 import com
.intellij
.diagnostic
.DiagnosticBundle
;
4 import com
.intellij
.execution
.filters
.TextConsoleBuilder
;
5 import com
.intellij
.execution
.filters
.TextConsoleBuilderFactory
;
6 import com
.intellij
.execution
.process
.ProcessAdapter
;
7 import com
.intellij
.execution
.process
.ProcessEvent
;
8 import com
.intellij
.execution
.process
.ProcessHandler
;
9 import com
.intellij
.execution
.process
.ProcessOutputTypes
;
10 import com
.intellij
.execution
.ui
.ConsoleView
;
11 import com
.intellij
.execution
.ui
.ConsoleViewContentType
;
12 import com
.intellij
.openapi
.actionSystem
.*;
13 import com
.intellij
.openapi
.application
.ApplicationManager
;
14 import com
.intellij
.openapi
.diagnostic
.Logger
;
15 import com
.intellij
.openapi
.editor
.Document
;
16 import com
.intellij
.openapi
.editor
.Editor
;
17 import com
.intellij
.openapi
.project
.Project
;
18 import com
.intellij
.openapi
.util
.Comparing
;
19 import com
.intellij
.openapi
.util
.Condition
;
20 import com
.intellij
.openapi
.util
.Disposer
;
21 import com
.intellij
.openapi
.util
.io
.FileUtil
;
22 import org
.jetbrains
.annotations
.NotNull
;
23 import org
.jetbrains
.annotations
.Nullable
;
26 import javax
.swing
.event
.ChangeEvent
;
27 import javax
.swing
.event
.ChangeListener
;
29 import java
.awt
.event
.ActionListener
;
30 import java
.awt
.event
.ActionEvent
;
32 import java
.util
.ArrayList
;
33 import java
.util
.List
;
39 public abstract class LogConsoleImpl
extends AdditionalTabComponent
40 implements LogConsole
, ChangeListener
, LogConsolePreferences
.FilterListener
{
41 private ConsoleView myConsole
;
42 private final LightProcessHandler myProcessHandler
= new LightProcessHandler();
43 private ReaderThread myReaderThread
;
44 private final long mySkippedContents
;
46 private StringBuffer myOriginalDocument
= null;
48 private String myPrevType
= null;
49 private String myLineUnderSelection
= null;
50 private int myLineOffset
= -1;
52 /*private FilterComponent myFilter = new FilterComponent("LOG_FILTER_HISTORY", 5) {
53 public void filter() {
54 getPreferences().updateCustomFilter(getFilter());
58 private LogContentPreprocessor myContentPreprocessor
;
59 private boolean myShowStandardFilters
= true;
61 private String myTitle
= null;
62 private final Project myProject
;
63 private final String myPath
;
64 private boolean myWasInitialized
;
65 private final JPanel myTopComponent
= new JPanel(new BorderLayout());
66 private ActionGroup myActions
;
67 private final boolean myBuildInActions
;
69 public LogConsoleImpl(Project project
, File file
, long skippedContents
, String title
, final boolean buildInActions
) {
70 super(new BorderLayout());
71 mySkippedContents
= skippedContents
;
74 myPath
= file
.getAbsolutePath();
75 myBuildInActions
= buildInActions
;
76 myReaderThread
= new ReaderThread(file
);
77 TextConsoleBuilder builder
= TextConsoleBuilderFactory
.getInstance().createBuilder(project
);
78 myConsole
= builder
.getConsole();
79 myConsole
.attachToProcess(myProcessHandler
);
80 getPreferences().addFilterListener(this);
83 public LogContentPreprocessor
getContentPreprocessor() {
84 return myContentPreprocessor
;
87 public void setContentPreprocessor(final LogContentPreprocessor contentPreprocessor
) {
88 myContentPreprocessor
= contentPreprocessor
;
91 public boolean isShowStandardFilters() {
92 return myShowStandardFilters
;
95 public void setShowStandardFilters(final boolean showStandardFilters
) {
96 myShowStandardFilters
= showStandardFilters
;
99 @SuppressWarnings({"NonStaticInitializer"})
100 private JComponent
createToolbar() {
103 myFilter.setSelectedItem(registrar.CUSTOM_FILTER != null ? registrar.CUSTOM_FILTER : "");
106 registerCustomShortcutSet(new CustomShortcutSet(KeyStroke.getKeyStroke(KeyEvent.VK_TAB, KeyEvent.SHIFT_DOWN_MASK)),
107 LogConsoleImpl.this);
110 public void actionPerformed(final AnActionEvent e) {
111 myFilter.requestFocusInWindow();
115 if (myBuildInActions
) {
116 final JComponent tbComp
=
117 ActionManager
.getInstance().createActionToolbar(ActionPlaces
.UNKNOWN
, getOrCreateActions(), true).getComponent();
118 myTopComponent
.add(tbComp
, BorderLayout
.CENTER
);
119 //myTopComponent.add(myFilter, BorderLayout.EAST);
123 return myTopComponent
;
126 public ActionGroup
getOrCreateActions() {
127 if (myActions
!= null) return myActions
;
128 DefaultActionGroup group
= new DefaultActionGroup();
130 final AnAction
[] actions
= myConsole
.createConsoleActions();
131 for (AnAction action
: actions
) {
135 group
.addSeparator();
137 /*for (final LogFilter filter : filters) {
138 group.add(new ToggleAction(filter.getName(), filter.getName(), filter.getIcon()) {
139 public boolean isSelected(AnActionEvent e) {
140 return prefs.isFilterSelected(filter);
143 public void setSelected(AnActionEvent e, boolean state) {
144 prefs.setFilterSelected(filter, state);
155 public void onFilterStateChange(final LogFilter filter
) {
156 filterConsoleOutput(new Condition
<String
>() {
157 public boolean value(final String line
) {
158 return filter
.isAcceptable(line
);
163 public void onTextFilterChange() {
164 filterConsoleOutput(new Condition
<String
>() {
165 public boolean value(final String line
) {
166 return getPreferences().isApplicable(line
, myPrevType
);
172 public JComponent
getComponent() {
173 if (!myWasInitialized
) {
174 myWasInitialized
= true;
175 add(myConsole
.getComponent(), BorderLayout
.CENTER
);
176 add(createToolbar(), BorderLayout
.NORTH
);
181 public abstract boolean isActive();
183 public void activate() {
184 if (myReaderThread
== null) return;
185 if (isActive() && !myReaderThread
.myRunning
) {
186 //myFilter.setSelectedItem(getPreferences().CUSTOM_FILTER);
187 myReaderThread
.startRunning();
188 ApplicationManager
.getApplication().executeOnPooledThread(myReaderThread
);
190 else if (!isActive() && myReaderThread
.myRunning
) {
191 myReaderThread
.stopRunning();
195 public void stateChanged(final ChangeEvent e
) {
199 public String
getTabTitle() {
204 public String
getTooltip() {
208 public String
getPath() {
212 public void dispose() {
213 getPreferences().removeFilterListener(this);
214 if (myReaderThread
!= null && myReaderThread
.myFileStream
!= null) {
215 myReaderThread
.stopRunning();
217 myReaderThread
.myFileStream
.close();
219 catch (IOException e
) {
222 myReaderThread
.myFileStream
= null;
223 myReaderThread
= null;
225 if (myConsole
!= null) {
226 Disposer
.dispose(myConsole
);
229 /*if (myFilter != null) {
233 myOriginalDocument
= null;
236 private void stopRunning() {
237 if (myReaderThread
!= null && !isActive()) {
238 myReaderThread
.stopRunning();
242 private void addMessage(final String text
) {
243 if (text
== null) return;
244 if (myContentPreprocessor
!= null) {
245 final List
<LogFragment
> fragments
= myContentPreprocessor
.parseLogLine(text
+ "\n");
246 myOriginalDocument
= getOriginalDocument();
247 for (LogFragment fragment
: fragments
) {
248 myProcessHandler
.notifyTextAvailable(fragment
.getText(), fragment
.getOutputType());
249 if (myOriginalDocument
!= null) {
250 myOriginalDocument
.append(fragment
.getText());
255 final String key
= LogConsolePreferences
.getType(text
);
256 if (getPreferences().isApplicable(text
, myPrevType
)) {
257 myProcessHandler
.notifyTextAvailable(text
+ "\n", key
!= null
258 ? LogConsolePreferences
.getProcessOutputTypes(key
)
259 : (myPrevType
== LogConsolePreferences
.ERROR
260 ? ProcessOutputTypes
.STDERR
261 : ProcessOutputTypes
.STDOUT
));
266 myOriginalDocument
= getOriginalDocument();
267 if (myOriginalDocument
!= null) {
268 myOriginalDocument
.append(text
).append("\n");
273 private LogConsolePreferences
getPreferences() {
274 return LogConsolePreferences
.getInstance(myProject
);
277 public void attachStopLogConsoleTrackingListener(final ProcessHandler process
) {
278 if (process
!= null) {
279 final ProcessAdapter stopListener
= new ProcessAdapter() {
280 public void processTerminated(final ProcessEvent event
) {
281 process
.removeProcessListener(this);
285 process
.addProcessListener(stopListener
);
289 private StringBuffer
getOriginalDocument() {
290 if (myOriginalDocument
== null) {
291 final Editor editor
= getEditor();
292 if (editor
!= null) {
293 myOriginalDocument
= new StringBuffer(editor
.getDocument().getText());
296 return myOriginalDocument
;
300 private Editor
getEditor() {
301 return myConsole
!= null ?
(Editor
)((DataProvider
)myConsole
).getData(DataConstants
.EDITOR
) : null;
304 private void filterConsoleOutput(Condition
<String
> isApplicable
) {
305 myOriginalDocument
= getOriginalDocument();
306 if (myOriginalDocument
!= null) {
307 final Editor editor
= getEditor();
308 LOG
.assertTrue(editor
!= null);
309 final Document document
= editor
.getDocument();
310 final int caretOffset
= editor
.getCaretModel().getOffset();
311 if (caretOffset
> -1) {
312 int line
= document
.getLineNumber(caretOffset
);
313 if (line
> -1 && line
< document
.getLineCount()) {
314 final int startOffset
= document
.getLineStartOffset(line
);
315 myLineUnderSelection
= document
.getText().substring(startOffset
, document
.getLineEndOffset(line
));
316 myLineOffset
= caretOffset
- startOffset
;
320 final String
[] lines
= myOriginalDocument
.toString().split("\n");
322 boolean caretPositioned
= false;
323 for (String line
: lines
) {
324 final String contentType
= LogConsolePreferences
.getType(line
);
325 if (isApplicable
.value(line
)) {
326 myConsole
.print(line
+ "\n", contentType
!= null
327 ? LogConsolePreferences
.getContentType(contentType
)
328 : (myPrevType
== LogConsolePreferences
.ERROR
329 ? ConsoleViewContentType
.ERROR_OUTPUT
330 : ConsoleViewContentType
.NORMAL_OUTPUT
));
331 if (!caretPositioned
) {
332 if (Comparing
.strEqual(myLineUnderSelection
, line
)) {
333 caretPositioned
= true;
334 offset
+= myLineOffset
!= -1 ? myLineOffset
: 0;
337 offset
+= line
.length() + 1;
341 if (contentType
!= null) {
342 myPrevType
= contentType
;
345 myConsole
.scrollTo(offset
);
349 private static class LightProcessHandler
extends ProcessHandler
{
350 protected void destroyProcessImpl() {
351 throw new UnsupportedOperationException();
354 protected void detachProcessImpl() {
355 throw new UnsupportedOperationException();
358 public boolean detachIsDefault() {
363 public OutputStream
getProcessInput() {
368 private static final Logger LOG
= Logger
.getInstance("com.intellij.diagnostic.logging.LogConsoleImpl");
370 private class ReaderThread
implements Runnable
{
371 private BufferedReader myFileStream
;
372 private boolean myRunning
= false;
374 @SuppressWarnings({"IOResourceOpenedButNotSafelyClosed"})
375 public ReaderThread(File file
) {
378 final FileInputStream inputStream
= new FileInputStream(file
);
379 myFileStream
= new BufferedReader(new InputStreamReader(inputStream
));
380 if (file
.length() >= mySkippedContents
) { //do not skip forward
381 inputStream
.skip(mySkippedContents
);
384 catch (FileNotFoundException e
) {
385 if (!FileUtil
.createIfDoesntExist(file
)) return;
386 myFileStream
= new BufferedReader(new FileReader(file
));
389 catch (Throwable e
) {
395 if (myFileStream
== null) return;
400 if (myRunning
&& myFileStream
!= null && myFileStream
.ready()) {
401 addMessage(myFileStream
.readLine());
407 synchronized (this) {
411 catch (IOException e
) {
414 catch (InterruptedException e
) {
415 Disposer
.dispose(LogConsoleImpl
.this);
420 public void startRunning() {
424 public void stopRunning() {
426 synchronized (this) {
432 public ActionGroup
getToolbarActions() {
433 return getOrCreateActions();
436 public String
getToolbarPlace() {
437 return ActionPlaces
.UNKNOWN
;
440 public JComponent
getToolbarContextComponent() {
441 return myConsole
.getComponent();
444 public JComponent
getPreferredFocusableComponent() {
445 return myConsole
.getPreferredFocusableComponent();
448 private List
<LogFilter
> getLogFilters(final LogConsolePreferences prefs
) {
449 abstract class MyFilter
extends StandartLogFilter
{
450 protected MyFilter(String name
) {
454 public boolean isAcceptable(String line
) {
455 return prefs
.isApplicable(line
, myPrevType
);
458 final ArrayList
<LogFilter
> filters
= new ArrayList
<LogFilter
>();
459 if (myShowStandardFilters
) {
460 filters
.add(new MyFilter(DiagnosticBundle
.message("log.console.filter.show.all")) {
462 public void selectFilter(LogConsolePreferences prefs
) {
463 prefs
.FILTER_ERRORS
= false;
464 prefs
.FILTER_INFO
= false;
465 prefs
.FILTER_WARNINGS
= false;
469 public boolean isSelected(LogConsolePreferences prefs
) {
470 return !prefs
.FILTER_ERRORS
&& !prefs
.FILTER_INFO
&& !prefs
.FILTER_WARNINGS
;
473 filters
.add(new MyFilter(DiagnosticBundle
.message("log.console.filter.show.errors.and.warnings")) {
475 public void selectFilter(LogConsolePreferences prefs
) {
476 prefs
.FILTER_ERRORS
= false;
477 prefs
.FILTER_INFO
= true;
478 prefs
.FILTER_WARNINGS
= false;
482 public boolean isSelected(LogConsolePreferences prefs
) {
483 return !prefs
.FILTER_ERRORS
&& prefs
.FILTER_INFO
&& !prefs
.FILTER_WARNINGS
;
486 filters
.add(new MyFilter(DiagnosticBundle
.message("log.console.filter.show.errors")) {
488 public void selectFilter(LogConsolePreferences prefs
) {
489 prefs
.FILTER_ERRORS
= false;
490 prefs
.FILTER_INFO
= true;
491 prefs
.FILTER_WARNINGS
= true;
495 public boolean isSelected(LogConsolePreferences prefs
) {
496 return !prefs
.FILTER_ERRORS
&& prefs
.FILTER_INFO
&& prefs
.FILTER_WARNINGS
;
500 filters
.addAll(prefs
.getRegisteredLogFilters());
504 public JComponent
getSearchComponent() {
505 final LogConsolePreferences prefs
= getPreferences();
506 List
<LogFilter
> filters
= getLogFilters(prefs
);
507 final JComboBox combo
= new JComboBox(filters
.toArray(new LogFilter
[filters
.size()]));
508 for (LogFilter filter
: filters
) {
509 if (prefs
.isFilterSelected(filter
)) {
510 combo
.setSelectedItem(filter
);
514 combo
.addActionListener(new ActionListener() {
515 public void actionPerformed(ActionEvent e
) {
516 LogFilter filter
= (LogFilter
)combo
.getSelectedItem();
517 prefs
.selectOnlyFilter(filter
);
523 public boolean isContentBuiltIn() {
524 return myBuildInActions
;