make copy file action work for all PsiClassOwners outside source roots
[fedora-idea.git] / platform / lang-impl / src / com / intellij / diagnostic / logging / LogConsoleImpl.java
blob7120575136a76d7312f18bb8674b81c2961e7eb8
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;
25 import javax.swing.*;
26 import javax.swing.event.ChangeEvent;
27 import javax.swing.event.ChangeListener;
28 import java.awt.*;
29 import java.awt.event.ActionListener;
30 import java.awt.event.ActionEvent;
31 import java.io.*;
32 import java.util.ArrayList;
33 import java.util.List;
35 /**
36 * User: anna
37 * Date: Apr 19, 2005
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());
56 };*/
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;
72 myTitle = title;
73 myProject = project;
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() {
102 /*myFilter.reset();
103 myFilter.setSelectedItem(registrar.CUSTOM_FILTER != null ? registrar.CUSTOM_FILTER : "");
104 new AnAction() {
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();
113 };*/
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) {
132 group.add(action);
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);
149 myActions = group;
151 return myActions;
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);
171 @NotNull
172 public JComponent getComponent() {
173 if (!myWasInitialized) {
174 myWasInitialized = true;
175 add(myConsole.getComponent(), BorderLayout.CENTER);
176 add(createToolbar(), BorderLayout.NORTH);
178 return this;
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) {
196 activate();
199 public String getTabTitle() {
200 return myTitle;
203 @Nullable
204 public String getTooltip() {
205 return myPath;
208 public String getPath() {
209 return myPath;
212 public void dispose() {
213 getPreferences().removeFilterListener(this);
214 if (myReaderThread != null && myReaderThread.myFileStream != null) {
215 myReaderThread.stopRunning();
216 try {
217 myReaderThread.myFileStream.close();
219 catch (IOException e) {
220 LOG.warn(e);
222 myReaderThread.myFileStream = null;
223 myReaderThread = null;
225 if (myConsole != null) {
226 Disposer.dispose(myConsole);
227 myConsole = null;
229 /*if (myFilter != null) {
230 myFilter.dispose();
231 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());
254 else {
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));
263 if (key != null) {
264 myPrevType = key;
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);
282 stopRunning();
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;
299 @Nullable
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;
319 myConsole.clear();
320 final String[] lines = myOriginalDocument.toString().split("\n");
321 int offset = 0;
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;
336 else {
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() {
359 return false;
362 @Nullable
363 public OutputStream getProcessInput() {
364 return null;
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) {
376 try {
377 try {
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) {
390 myFileStream = null;
394 public void run() {
395 if (myFileStream == null) return;
396 while (myRunning) {
397 try {
398 int i = 0;
399 while (i++ < 100) {
400 if (myRunning && myFileStream != null && myFileStream.ready()) {
401 addMessage(myFileStream.readLine());
403 else {
404 break;
407 synchronized (this) {
408 wait(100);
411 catch (IOException e) {
412 LOG.error(e);
414 catch (InterruptedException e) {
415 Disposer.dispose(LogConsoleImpl.this);
420 public void startRunning() {
421 myRunning = true;
424 public void stopRunning() {
425 myRunning = false;
426 synchronized (this) {
427 notifyAll();
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) {
451 super(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")) {
461 @Override
462 public void selectFilter(LogConsolePreferences prefs) {
463 prefs.FILTER_ERRORS = false;
464 prefs.FILTER_INFO = false;
465 prefs.FILTER_WARNINGS = false;
468 @Override
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")) {
474 @Override
475 public void selectFilter(LogConsolePreferences prefs) {
476 prefs.FILTER_ERRORS = false;
477 prefs.FILTER_INFO = true;
478 prefs.FILTER_WARNINGS = false;
481 @Override
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")) {
487 @Override
488 public void selectFilter(LogConsolePreferences prefs) {
489 prefs.FILTER_ERRORS = false;
490 prefs.FILTER_INFO = true;
491 prefs.FILTER_WARNINGS = true;
494 @Override
495 public boolean isSelected(LogConsolePreferences prefs) {
496 return !prefs.FILTER_ERRORS && prefs.FILTER_INFO && prefs.FILTER_WARNINGS;
500 filters.addAll(prefs.getRegisteredLogFilters());
501 return filters;
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);
511 break;
514 combo.addActionListener(new ActionListener() {
515 public void actionPerformed(ActionEvent e) {
516 LogFilter filter = (LogFilter)combo.getSelectedItem();
517 prefs.selectOnlyFilter(filter);
520 return combo;
523 public boolean isContentBuiltIn() {
524 return myBuildInActions;