d698b1cd603741c9bfe8fb1a6599746ce9321400
[phpeclipse.git] /
1 /***********************************************************************************************************************************
2  * Copyright (c) 2000, 2004 IBM Corporation and others. All rights reserved. This program and the accompanying materials are made
3  * available under the terms of the Common Public License v1.0 which accompanies this distribution, and is available at
4  * http://www.eclipse.org/legal/cpl-v10.html
5  * 
6  * Contributors: IBM Corporation - initial API and implementation
7  **********************************************************************************************************************************/
8
9 package net.sourceforge.phpeclipse.xdebug.ui.views.logview;
10
11 import java.io.BufferedReader;
12 import java.io.BufferedWriter;
13 import java.io.File;
14 import java.io.FileInputStream;
15 import java.io.FileOutputStream;
16 import java.io.IOException;
17 import java.io.InputStreamReader;
18 import java.io.OutputStreamWriter;
19 import java.io.PrintWriter;
20 import java.io.StringWriter;
21 import java.lang.reflect.InvocationTargetException;
22 import java.text.Collator;
23 import java.text.ParseException;
24 import java.text.SimpleDateFormat;
25 import java.util.ArrayList;
26 import java.util.Arrays;
27 import java.util.Comparator;
28 import java.util.Date;
29
30 import net.sourceforge.phpeclipse.xdebug.core.XDebugCorePlugin;
31 import net.sourceforge.phpeclipse.xdebug.ui.XDebugUIPlugin;
32 import net.sourceforge.phpeclipse.xdebug.ui.XDebugUIPluginImages;
33
34 import org.eclipse.core.runtime.ILogListener;
35 import org.eclipse.core.runtime.IProgressMonitor;
36 import org.eclipse.core.runtime.IStatus;
37 import org.eclipse.core.runtime.Path;
38 import org.eclipse.core.runtime.Platform;
39 import org.eclipse.jface.action.Action;
40 import org.eclipse.jface.action.IMenuListener;
41 import org.eclipse.jface.action.IMenuManager;
42 import org.eclipse.jface.action.IStatusLineManager;
43 import org.eclipse.jface.action.IToolBarManager;
44 import org.eclipse.jface.action.MenuManager;
45 import org.eclipse.jface.action.Separator;
46 import org.eclipse.jface.dialogs.MessageDialog;
47 import org.eclipse.jface.dialogs.ProgressMonitorDialog;
48 import org.eclipse.jface.operation.IRunnableWithProgress;
49 import org.eclipse.jface.viewers.ColumnPixelData;
50 import org.eclipse.jface.viewers.DoubleClickEvent;
51 import org.eclipse.jface.viewers.IDoubleClickListener;
52 import org.eclipse.jface.viewers.ISelection;
53 import org.eclipse.jface.viewers.ISelectionChangedListener;
54 import org.eclipse.jface.viewers.IStructuredSelection;
55 import org.eclipse.jface.viewers.ITreeViewerListener;
56 import org.eclipse.jface.viewers.SelectionChangedEvent;
57 import org.eclipse.jface.viewers.TableLayout;
58 import org.eclipse.jface.viewers.TableTreeViewer;
59 import org.eclipse.jface.viewers.TreeExpansionEvent;
60 import org.eclipse.jface.viewers.Viewer;
61 import org.eclipse.jface.viewers.ViewerSorter;
62 import org.eclipse.swt.SWT;
63 import org.eclipse.swt.custom.BusyIndicator;
64 import org.eclipse.swt.custom.TableTree;
65 import org.eclipse.swt.custom.TableTreeItem;
66 import org.eclipse.swt.dnd.Clipboard;
67 import org.eclipse.swt.dnd.TextTransfer;
68 import org.eclipse.swt.dnd.Transfer;
69 import org.eclipse.swt.events.DisposeEvent;
70 import org.eclipse.swt.events.DisposeListener;
71 import org.eclipse.swt.events.SelectionAdapter;
72 import org.eclipse.swt.events.SelectionEvent;
73 import org.eclipse.swt.graphics.Color;
74 import org.eclipse.swt.graphics.Font;
75 import org.eclipse.swt.graphics.FontData;
76 import org.eclipse.swt.graphics.Point;
77 import org.eclipse.swt.layout.GridData;
78 import org.eclipse.swt.layout.GridLayout;
79 import org.eclipse.swt.program.Program;
80 import org.eclipse.swt.widgets.Composite;
81 import org.eclipse.swt.widgets.Control;
82 import org.eclipse.swt.widgets.Display;
83 import org.eclipse.swt.widgets.Event;
84 import org.eclipse.swt.widgets.FileDialog;
85 import org.eclipse.swt.widgets.Listener;
86 import org.eclipse.swt.widgets.Menu;
87 import org.eclipse.swt.widgets.Shell;
88 import org.eclipse.swt.widgets.Table;
89 import org.eclipse.swt.widgets.TableColumn;
90 import org.eclipse.swt.widgets.TableItem;
91 import org.eclipse.swt.widgets.Text;
92 import org.eclipse.ui.IActionBars;
93 import org.eclipse.ui.IMemento;
94 import org.eclipse.ui.ISharedImages;
95 import org.eclipse.ui.IViewSite;
96 import org.eclipse.ui.IWorkbenchPage;
97 import org.eclipse.ui.PartInitException;
98 import org.eclipse.ui.PlatformUI;
99 import org.eclipse.ui.XMLMemento;
100 import org.eclipse.ui.actions.ActionFactory;
101 import org.eclipse.ui.part.ViewPart;
102
103 public class LogView extends ViewPart implements ILogListener {
104   public final static String ID_LOGVIEW = "net.sourceforge.phpdt.internal.debug.core.logview.LogView"; //$NON-NLS-1$
105
106   private TableTreeViewer tableTreeViewer;
107
108   private ArrayList logs = new ArrayList();
109
110   public static final String P_LOG_WARNING = "warning"; //$NON-NLS-1$
111
112   public static final String P_LOG_ERROR = "error"; //$NON-NLS-1$
113
114   public static final String P_LOG_INFO = "info"; //$NON-NLS-1$
115
116   public static final String P_LOG_LIMIT = "limit"; //$NON-NLS-1$
117
118   public static final String P_USE_LIMIT = "useLimit"; //$NON-NLS-1$
119
120   public static final String P_SHOW_ALL_SESSIONS = "allSessions"; //$NON-NLS-1$
121
122   private static final String P_COLUMN_1 = "column1"; //$NON-NLS-1$
123
124   private static final String P_COLUMN_2 = "column2"; //$NON-NLS-1$
125
126   private static final String P_COLUMN_3 = "column3"; //$NON-NLS-1$
127
128   private static final String P_COLUMN_4 = "column4"; //$NON-NLS-1$
129
130   public static final String P_ACTIVATE = "activate"; //$NON-NLS-1$
131
132   private int MESSAGE_ORDER = -1;
133
134   private int PLUGIN_ORDER = -1;
135
136   private int DATE_ORDER = -1;
137
138   public static byte MESSAGE = 0x0;
139
140   public static byte PLUGIN = 0x1;
141
142   public static byte DATE = 0x2;
143
144   private static int ASCENDING = 1;
145
146   private static int DESCENDING = -1;
147
148   private Action clearAction;
149
150   private Action copyAction;
151
152   private Action readLogAction;
153
154   private Action deleteLogAction;
155
156   private Action exportAction;
157
158   private Action importAction;
159
160   private Action activateViewAction;
161
162   private Action propertiesAction;
163
164   private Action viewLogAction;
165
166   private Action filterAction;
167
168   private Clipboard clipboard;
169
170   private IMemento memento;
171
172   private File inputFile;
173
174   private String directory;
175
176   private TableColumn column0;
177
178   private TableColumn column1;
179
180   private TableColumn column2;
181
182   private TableColumn column3;
183
184   private TableColumn column4;
185
186   private static Font boldFont;
187
188   private Comparator comparator;
189
190   private Collator collator;
191
192   // hover text
193   private boolean canOpenTextShell;
194
195   private Text textLabel;
196
197   private Shell textShell;
198
199   private boolean firstEvent = true;
200
201   public LogView() {
202     logs = new ArrayList();
203     inputFile = Platform.getLogFileLocation().toFile();
204   }
205
206   public void createPartControl(Composite parent) {
207     readLogFile();
208     TableTree tableTree = new TableTree(parent, SWT.FULL_SELECTION);
209     tableTree.setLayoutData(new GridData(GridData.FILL_BOTH));
210     createColumns(tableTree.getTable());
211     createViewer(tableTree);
212     createPopupMenuManager(tableTree);
213     makeActions(tableTree.getTable());
214     fillToolBar();
215     Platform.addLogListener(this);
216     getSite().setSelectionProvider(tableTreeViewer);
217     clipboard = new Clipboard(tableTree.getDisplay());
218     //        WorkbenchHelp.setHelp(tableTree, IHelpContextIds.LOG_VIEW);
219     tableTreeViewer.getTableTree().getTable().setToolTipText(""); //$NON-NLS-1$
220     initializeFonts();
221     applyFonts();
222   }
223
224   private void initializeFonts() {
225     Font tableFont = tableTreeViewer.getTableTree().getFont();
226     FontData[] fontDataList = tableFont.getFontData();
227     FontData fontData;
228     if (fontDataList.length > 0)
229       fontData = fontDataList[0];
230     else
231       fontData = new FontData();
232     fontData.setStyle(SWT.BOLD);
233     boldFont = new Font(tableTreeViewer.getTableTree().getDisplay(), fontData);
234   }
235
236   /*
237    * Set all rows where the tableTreeItem has children to have a <b>bold </b> font.
238    */
239   private void applyFonts() {
240     if (tableTreeViewer == null || tableTreeViewer.getTableTree().isDisposed())
241       return;
242     int max = tableTreeViewer.getTableTree().getItemCount();
243     int index = 0, tableIndex = 0;
244     while (index < max) {
245       LogEntry entry = (LogEntry) tableTreeViewer.getElementAt(index);
246       if (entry == null)
247         return;
248       if (entry.hasChildren()) {
249         tableTreeViewer.getTableTree().getItems()[index].setFont(boldFont);
250         tableIndex = applyChildFonts(entry, tableIndex);
251       } else {
252         tableTreeViewer.getTableTree().getItems()[index].setFont(tableTreeViewer.getTableTree().getFont());
253       }
254       index++;
255       tableIndex++;
256     }
257   }
258
259   private int applyChildFonts(LogEntry parent, int index) {
260     if (!tableTreeViewer.getExpandedState(parent) || !parent.hasChildren())
261       return index;
262     LogEntry[] children = getEntryChildren(parent);
263     for (int i = 0; i < children.length; i++) {
264       index++;
265       if (children[i].hasChildren()) {
266         TableItem tableItem = getTableItem(index);
267         if (tableItem != null) {
268           tableItem.setFont(boldFont);
269         }
270         index = applyChildFonts(children[i], index);
271       } else {
272         TableItem tableItem = getTableItem(index);
273         if (tableItem != null) {
274           tableItem.setFont(tableTreeViewer.getTableTree().getFont());
275         }
276       }
277     }
278     return index;
279   }
280
281   private LogEntry[] getEntryChildren(LogEntry parent) {
282     Object[] entryChildren = parent.getChildren(parent);
283     if (comparator != null)
284       Arrays.sort(entryChildren, comparator);
285     LogEntry[] children = new LogEntry[entryChildren.length];
286     System.arraycopy(entryChildren, 0, children, 0, entryChildren.length);
287     return children;
288   }
289
290   private TableItem getTableItem(int index) {
291     TableItem[] tableItems = tableTreeViewer.getTableTree().getTable().getItems();
292     if (index > tableItems.length - 1)
293       return null;
294     return tableItems[index];
295   }
296
297   private void fillToolBar() {
298     IActionBars bars = getViewSite().getActionBars();
299     bars.setGlobalActionHandler(ActionFactory.COPY.getId(), copyAction);
300     IToolBarManager toolBarManager = bars.getToolBarManager();
301     toolBarManager.add(exportAction);
302     toolBarManager.add(importAction);
303     toolBarManager.add(new Separator());
304     toolBarManager.add(clearAction);
305     toolBarManager.add(deleteLogAction);
306     toolBarManager.add(viewLogAction);
307     toolBarManager.add(readLogAction);
308     toolBarManager.add(new Separator());
309     IMenuManager mgr = bars.getMenuManager();
310     mgr.add(filterAction);
311     mgr.add(new Separator());
312     mgr.add(activateViewAction);
313   }
314
315   private void createViewer(TableTree tableTree) {
316     tableTreeViewer = new TableTreeViewer(tableTree);
317     tableTreeViewer.setContentProvider(new LogViewContentProvider(this));
318     tableTreeViewer.setLabelProvider(new LogViewLabelProvider());
319     tableTreeViewer.addSelectionChangedListener(new ISelectionChangedListener() {
320       public void selectionChanged(SelectionChangedEvent e) {
321         handleSelectionChanged(e.getSelection());
322         if (propertiesAction.isEnabled())
323           ((EventDetailsDialogAction) propertiesAction).resetSelection();
324       }
325     });
326     tableTreeViewer.addDoubleClickListener(new IDoubleClickListener() {
327       public void doubleClick(DoubleClickEvent event) {
328         ((EventDetailsDialogAction) propertiesAction).setComparator(comparator);
329         propertiesAction.run();
330       }
331     });
332     tableTreeViewer.addTreeListener(new ITreeViewerListener() {
333       public void treeCollapsed(TreeExpansionEvent event) {
334         applyFonts();
335       }
336
337       public void treeExpanded(TreeExpansionEvent event) {
338         applyFonts();
339       }
340     });
341     addMouseListeners();
342     tableTreeViewer.setInput(Platform.class);
343   }
344
345   private void createPopupMenuManager(TableTree tableTree) {
346     MenuManager popupMenuManager = new MenuManager();
347     IMenuListener listener = new IMenuListener() {
348       public void menuAboutToShow(IMenuManager mng) {
349         fillContextMenu(mng);
350       }
351     };
352     popupMenuManager.addMenuListener(listener);
353     popupMenuManager.setRemoveAllWhenShown(true);
354     Menu menu = popupMenuManager.createContextMenu(tableTree);
355     tableTree.setMenu(menu);
356   }
357
358   private void createColumns(Table table) {
359     column0 = new TableColumn(table, SWT.NULL);
360     column0.setText(""); //$NON-NLS-1$
361     column1 = new TableColumn(table, SWT.NULL);
362     column1.setText(XDebugUIPlugin.getString("LogView.column.severity")); //$NON-NLS-1$
363     column2 = new TableColumn(table, SWT.NULL);
364     column2.setText(XDebugUIPlugin.getString("LogView.column.message")); //$NON-NLS-1$
365     column2.addSelectionListener(new SelectionAdapter() {
366       public void widgetSelected(SelectionEvent e) {
367         MESSAGE_ORDER *= -1;
368         ViewerSorter sorter = getViewerSorter(MESSAGE);
369         tableTreeViewer.setSorter(sorter);
370         collator = sorter.getCollator();
371         boolean isComparatorSet = ((EventDetailsDialogAction) propertiesAction).resetSelection(MESSAGE, MESSAGE_ORDER);
372         setComparator(MESSAGE);
373         if (!isComparatorSet)
374           ((EventDetailsDialogAction) propertiesAction).setComparator(comparator);
375         applyFonts();
376       }
377     });
378     column3 = new TableColumn(table, SWT.NULL);
379     column3.setText(XDebugUIPlugin.getString("LogView.column.plugin"));  //$NON-NLS-1$
380     column3.addSelectionListener(new SelectionAdapter() {
381       public void widgetSelected(SelectionEvent e) {
382         PLUGIN_ORDER *= -1;
383         ViewerSorter sorter = getViewerSorter(PLUGIN);
384         tableTreeViewer.setSorter(sorter);
385         collator = sorter.getCollator();
386         boolean isComparatorSet = ((EventDetailsDialogAction) propertiesAction).resetSelection(PLUGIN, PLUGIN_ORDER);
387         setComparator(PLUGIN);
388         if (!isComparatorSet)
389           ((EventDetailsDialogAction) propertiesAction).setComparator(comparator);
390         applyFonts();
391       }
392     });
393     column4 = new TableColumn(table, SWT.NULL);
394     column4.setText(XDebugUIPlugin.getString("LogView.column.date")); //$NON-NLS-1$
395     column4.addSelectionListener(new SelectionAdapter() {
396       public void widgetSelected(SelectionEvent e) {
397         if (DATE_ORDER == ASCENDING) {
398           DATE_ORDER = DESCENDING;
399         } else {
400           DATE_ORDER = ASCENDING;
401         }
402         ViewerSorter sorter = getViewerSorter(DATE);
403         tableTreeViewer.setSorter(sorter);
404         collator = sorter.getCollator();
405         boolean isComparatorSet = ((EventDetailsDialogAction) propertiesAction).resetSelection(DATE, DATE_ORDER);
406         setComparator(DATE);
407         if (!isComparatorSet)
408           ((EventDetailsDialogAction) propertiesAction).setComparator(comparator);
409         applyFonts();
410       }
411     });
412     TableLayout tlayout = new TableLayout();
413     tlayout.addColumnData(new ColumnPixelData(21));
414     tlayout.addColumnData(new ColumnPixelData(memento.getInteger(P_COLUMN_1).intValue()));
415     tlayout.addColumnData(new ColumnPixelData(memento.getInteger(P_COLUMN_2).intValue()));
416     tlayout.addColumnData(new ColumnPixelData(memento.getInteger(P_COLUMN_3).intValue()));
417     tlayout.addColumnData(new ColumnPixelData(memento.getInteger(P_COLUMN_4).intValue()));
418     table.setLayout(tlayout);
419     table.setHeaderVisible(true);
420   }
421
422   private void makeActions(Table table) {
423     propertiesAction = new EventDetailsDialogAction(table.getShell(), tableTreeViewer);
424     propertiesAction.setImageDescriptor(XDebugUIPluginImages.getImageDescriptor(XDebugUIPluginImages.IMG_PROPERTIES));
425     propertiesAction.setDisabledImageDescriptor(XDebugUIPluginImages.getImageDescriptor(XDebugUIPluginImages.IMG_PROPERTIES));
426     propertiesAction.setToolTipText(XDebugUIPlugin.getString("LogView.properties.tooltip")); //$NON-NLS-1$
427     propertiesAction.setEnabled(false);
428     clearAction = new Action(XDebugUIPlugin.getString("LogView.clear")) { //$NON-NLS-1$
429       public void run() {
430         handleClear();
431       }
432     };
433     clearAction.setImageDescriptor(XDebugUIPluginImages.getImageDescriptor(XDebugUIPluginImages.IMG_CLEAR));
434     clearAction.setDisabledImageDescriptor(XDebugUIPluginImages.getImageDescriptor(XDebugUIPluginImages.IMG_CLEAR));
435     clearAction.setToolTipText(XDebugUIPlugin.getString("LogView.clear.tooltip")); //$NON-NLS-1$
436     clearAction.setText(XDebugUIPlugin.getString("LogView.clear")); //$NON-NLS-1$
437     readLogAction = new Action(XDebugUIPlugin.getString("LogView.readLog.restore")) { //$NON-NLS-1$
438       public void run() {
439         inputFile = Platform.getLogFileLocation().toFile();
440         reloadLog();
441       }
442     };
443     readLogAction.setToolTipText(XDebugUIPlugin.getString("LogView.readLog.restore.tooltip")); //$NON-NLS-1$
444     readLogAction.setImageDescriptor(XDebugUIPluginImages.getImageDescriptor(XDebugUIPluginImages.IMG_READ_LOG));
445     readLogAction.setDisabledImageDescriptor(XDebugUIPluginImages.getImageDescriptor(XDebugUIPluginImages.IMG_READ_LOG));
446     deleteLogAction = new Action(XDebugUIPlugin.getString("LogView.delete")) { //$NON-NLS-1$
447       public void run() {
448         doDeleteLog();
449       }
450     };
451     deleteLogAction.setToolTipText(XDebugUIPlugin.getString("LogView.delete.tooltip")); //$NON-NLS-1$
452     deleteLogAction.setImageDescriptor(XDebugUIPluginImages.getImageDescriptor(XDebugUIPluginImages.IMG_REMOVE_LOG));
453     deleteLogAction.setDisabledImageDescriptor(XDebugUIPluginImages.getImageDescriptor(XDebugUIPluginImages.IMG_REMOVE_LOG));
454     deleteLogAction.setEnabled(inputFile.exists() && inputFile.equals(Platform.getLogFileLocation().toFile()));
455     copyAction = new Action(XDebugUIPlugin.getString("LogView.copy")) { //$NON-NLS-1$
456       public void run() {
457         copyToClipboard(tableTreeViewer.getSelection());
458       }
459     };
460     copyAction.setImageDescriptor(PlatformUI.getWorkbench().getSharedImages().getImageDescriptor(ISharedImages.IMG_TOOL_COPY));
461     filterAction = new Action(XDebugUIPlugin.getString("LogView.filter")) { //$NON-NLS-1$
462       public void run() {
463         handleFilter();
464       }
465     };
466     filterAction.setToolTipText(XDebugUIPlugin.getString("LogView.filter")); //$NON-NLS-1$
467     filterAction.setImageDescriptor(XDebugUIPluginImages.getImageDescriptor(XDebugUIPluginImages.IMG_FILTER));
468     filterAction.setDisabledImageDescriptor(XDebugUIPluginImages.getImageDescriptor(XDebugUIPluginImages.IMG_FILTER));
469     exportAction = new Action(XDebugUIPlugin.getString("LogView.export")) { //$NON-NLS-1$
470       public void run() {
471         handleExport();
472       }
473     };
474     exportAction.setToolTipText(XDebugUIPlugin.getString("LogView.export.tooltip")); //$NON-NLS-1$
475     exportAction.setImageDescriptor(XDebugUIPluginImages.getImageDescriptor(XDebugUIPluginImages.IMG_EXPORT));
476     exportAction.setDisabledImageDescriptor(XDebugUIPluginImages.getImageDescriptor(XDebugUIPluginImages.IMG_EXPORT));
477     importAction = new Action(XDebugUIPlugin.getString("LogView.import")) { //$NON-NLS-1$
478       public void run() {
479         handleImport();
480       }
481     };
482     importAction.setToolTipText(XDebugUIPlugin.getString("LogView.import.tooltip")); //$NON-NLS-1$
483     importAction.setImageDescriptor(XDebugUIPluginImages.getImageDescriptor(XDebugUIPluginImages.IMG_IMPORT));
484     importAction.setDisabledImageDescriptor(XDebugUIPluginImages.getImageDescriptor(XDebugUIPluginImages.IMG_IMPORT));
485     activateViewAction = new Action(XDebugUIPlugin.getString("LogView.activate")) { //$NON-NLS-1$
486       public void run() {
487       }
488     };
489     activateViewAction.setChecked(memento.getString(P_ACTIVATE).equals("true")); //$NON-NLS-1$
490     viewLogAction = new Action(XDebugUIPlugin.getString("LogView.view.currentLog")) { //$NON-NLS-1$
491       public void run() {
492         if (inputFile.exists()) {
493           if (inputFile.length() > LogReader.MAX_FILE_LENGTH) {
494             OpenLogDialog openDialog = new OpenLogDialog(getViewSite().getShell(), inputFile);
495             openDialog.create();
496             openDialog.open();
497           } else {
498             boolean canLaunch = Program.launch(inputFile.getAbsolutePath());
499             if (!canLaunch) {
500               Program p = Program.findProgram(".txt"); //$NON-NLS-1$
501               if (p != null)
502                 p.execute(inputFile.getAbsolutePath());
503               else {
504                 OpenLogDialog openDialog = new OpenLogDialog(getViewSite().getShell(), inputFile);
505                 openDialog.create();
506                 openDialog.open();
507               }
508             }
509           }
510         }
511       }
512     };
513     viewLogAction.setImageDescriptor(XDebugUIPluginImages.getImageDescriptor(XDebugUIPluginImages.IMG_OPEN_LOG));
514     viewLogAction.setDisabledImageDescriptor(XDebugUIPluginImages.getImageDescriptor(XDebugUIPluginImages.IMG_OPEN_LOG));
515     viewLogAction.setEnabled(inputFile.exists());
516     viewLogAction.setToolTipText(XDebugUIPlugin.getString("LogView.view.currentLog.tooltip")); //$NON-NLS-1$
517   }
518
519   public void dispose() {
520     Platform.removeLogListener(this);
521     clipboard.dispose();
522     LogReader.reset();
523     boldFont.dispose();
524     super.dispose();
525   }
526
527   private void handleImport() {
528     FileDialog dialog = new FileDialog(getViewSite().getShell());
529     dialog.setFilterExtensions(new String[] { "*.log" }); //$NON-NLS-1$
530     if (directory != null)
531       dialog.setFilterPath(directory);
532     String path = dialog.open();
533     if (path != null && new Path(path).toFile().exists()) {
534       inputFile = new Path(path).toFile();
535       directory = inputFile.getParent();
536       IRunnableWithProgress op = new IRunnableWithProgress() {
537         public void run(IProgressMonitor monitor) throws InvocationTargetException, InterruptedException {
538           monitor.beginTask(XDebugUIPlugin.getString("LogView.operation.importing"), IProgressMonitor.UNKNOWN); //$NON-NLS-1$
539           readLogFile();
540         }
541       };
542       ProgressMonitorDialog pmd = new ProgressMonitorDialog(getViewSite().getShell());
543       try {
544         pmd.run(true, true, op);
545       } catch (InvocationTargetException e) {
546       } catch (InterruptedException e) {
547       } finally {
548         readLogAction.setText(XDebugUIPlugin.getString("LogView.readLog.reload")); //$NON-NLS-1$
549         readLogAction.setToolTipText(XDebugUIPlugin.getString("LogView.readLog.reload")); //$NON-NLS-1$
550         asyncRefresh(false);
551         resetDialogButtons();
552       }
553     }
554   }
555
556   private void handleExport() {
557     FileDialog dialog = new FileDialog(getViewSite().getShell(), SWT.SAVE);
558     dialog.setFilterExtensions(new String[] { "*.log" }); //$NON-NLS-1$
559     if (directory != null)
560       dialog.setFilterPath(directory);
561     String path = dialog.open();
562     if (path != null) {
563       if (!path.endsWith(".log")) //$NON-NLS-1$
564         path += ".log"; //$NON-NLS-1$
565       File outputFile = new Path(path).toFile();
566       directory = outputFile.getParent();
567       if (outputFile.exists()) {
568           String message = "LogView.confirmOverwrite.message";
569 //        String message = PHPDebugUIPlugin.getFormattedMessage("LogView.confirmOverwrite.message", //$NON-NLS-1$
570 //            outputFile.toString());
571         if (!MessageDialog.openQuestion(getViewSite().getShell(), exportAction.getText(), message))
572           return;
573       }
574       copy(inputFile, outputFile);
575     }
576   }
577
578   private void copy(File inputFile, File outputFile) {
579     BufferedReader reader = null;
580     BufferedWriter writer = null;
581     try {
582       reader = new BufferedReader(new InputStreamReader(new FileInputStream(inputFile), "UTF-8")); //$NON-NLS-1$
583       writer = new BufferedWriter(new OutputStreamWriter(new FileOutputStream(outputFile), "UTF-8")); //$NON-NLS-1$
584       while (reader.ready()) {
585         writer.write(reader.readLine());
586         writer.write(System.getProperty("line.separator")); //$NON-NLS-1$
587       }
588     } catch (IOException e) {
589     } finally {
590       try {
591         if (reader != null)
592           reader.close();
593         if (writer != null)
594           writer.close();
595       } catch (IOException e1) {
596       }
597     }
598   }
599
600   private void handleFilter() {
601     FilterDialog dialog = new FilterDialog(XDebugCorePlugin.getDefault().getWorkbench().getActiveWorkbenchWindow().getShell(), memento);
602     dialog.create();
603     dialog.getShell().setText(XDebugUIPlugin.getString("LogView.FilterDialog.title")); //$NON-NLS-1$
604     if (dialog.open() == FilterDialog.OK)
605       reloadLog();
606   }
607
608   private void doDeleteLog() {
609     String title = XDebugUIPlugin.getString("LogView.confirmDelete.title"); //$NON-NLS-1$
610     String message = XDebugUIPlugin.getString("LogView.confirmDelete.message"); //$NON-NLS-1$
611     if (!MessageDialog.openConfirm(tableTreeViewer.getControl().getShell(), title, message))
612       return;
613     if (inputFile.delete()) {
614       logs.clear();
615       asyncRefresh(false);
616       resetDialogButtons();
617     }
618   }
619
620   public void fillContextMenu(IMenuManager manager) {
621     manager.add(copyAction);
622     manager.add(new Separator());
623     manager.add(clearAction);
624     manager.add(deleteLogAction);
625     manager.add(viewLogAction);
626     manager.add(readLogAction);
627     manager.add(new Separator());
628     manager.add(exportAction);
629     manager.add(importAction);
630     manager.add(new Separator());
631     ((EventDetailsDialogAction) propertiesAction).setComparator(comparator);
632     manager.add(propertiesAction);
633   }
634
635   public LogEntry[] getLogs() {
636     return (LogEntry[]) logs.toArray(new LogEntry[logs.size()]);
637   }
638
639   protected void handleClear() {
640     BusyIndicator.showWhile(tableTreeViewer.getControl().getDisplay(), new Runnable() {
641       public void run() {
642         logs.clear();
643         asyncRefresh(false);
644         resetDialogButtons();
645       }
646     });
647   }
648
649   protected void reloadLog() {
650     IRunnableWithProgress op = new IRunnableWithProgress() {
651       public void run(IProgressMonitor monitor) throws InvocationTargetException, InterruptedException {
652         monitor.beginTask(XDebugUIPlugin.getString("LogView.operation.reloading"), //$NON-NLS-1$
653             IProgressMonitor.UNKNOWN);
654         readLogFile();
655       }
656     };
657     ProgressMonitorDialog pmd = new ProgressMonitorDialog(getViewSite().getShell());
658     try {
659       pmd.run(true, true, op);
660     } catch (InvocationTargetException e) {
661     } catch (InterruptedException e) {
662     } finally {
663       readLogAction.setText(XDebugUIPlugin.getString("LogView.readLog.restore")); //$NON-NLS-1$
664       readLogAction.setToolTipText(XDebugUIPlugin.getString("LogView.readLog.restore")); //$NON-NLS-1$
665       asyncRefresh(false);
666       resetDialogButtons();
667     }
668   }
669
670   private void readLogFile() {
671     logs.clear();
672     if (!inputFile.exists())
673       return;
674     if (inputFile.length() > LogReader.MAX_FILE_LENGTH)
675       LogReader.parseLargeFile(inputFile, logs, memento);
676     else
677       LogReader.parseLogFile(inputFile, logs, memento);
678   }
679
680   public void logging(IStatus status, String plugin) { 
681     if (!inputFile.equals(Platform.getLogFileLocation().toFile()))
682       return;
683     if (firstEvent) {
684       readLogFile();
685       asyncRefresh();
686       firstEvent = false;
687     } else {
688       pushStatus(status);
689     }
690   }
691
692   private void pushStatus(IStatus status) {
693       LogEntry entry = new LogEntry(status);
694       LogReader.addEntry(entry, logs, memento, true);
695       asyncRefresh();
696   }
697
698   private void asyncRefresh() {
699     asyncRefresh(true);
700   }
701
702   private void asyncRefresh(final boolean activate) {
703     final Control control = tableTreeViewer.getControl();
704     if (control.isDisposed())
705       return;
706     Display display = control.getDisplay();
707     final ViewPart view = this;
708     if (display != null) {
709       display.asyncExec(new Runnable() {
710         public void run() {
711           if (!control.isDisposed()) {
712             tableTreeViewer.refresh();
713             deleteLogAction.setEnabled(inputFile.exists() && inputFile.equals(Platform.getLogFileLocation().toFile()));
714             viewLogAction.setEnabled(inputFile.exists());
715             if (activate && activateViewAction.isChecked()) {
716               IWorkbenchPage page = XDebugCorePlugin.getDefault().getWorkbench().getActiveWorkbenchWindow().getActivePage();
717               if (page != null)
718                 page.bringToTop(view);
719             }
720           }
721           applyFonts();
722         }
723       });
724     }
725   }
726
727   public void setFocus() {
728     if (tableTreeViewer != null && !tableTreeViewer.getTableTree().isDisposed())
729       tableTreeViewer.getTableTree().getTable().setFocus();
730   }
731
732   private void handleSelectionChanged(ISelection selection) {
733     updateStatus(selection);
734     copyAction.setEnabled(!selection.isEmpty());
735     propertiesAction.setEnabled(!selection.isEmpty());
736   }
737
738   private void updateStatus(ISelection selection) {
739     IStatusLineManager status = getViewSite().getActionBars().getStatusLineManager();
740     if (selection.isEmpty())
741       status.setMessage(null);
742     else {
743       LogEntry entry = (LogEntry) ((IStructuredSelection) selection).getFirstElement();
744       status.setMessage(((LogViewLabelProvider) tableTreeViewer.getLabelProvider()).getColumnText(entry, 2));
745     }
746   }
747
748   private void copyToClipboard(ISelection selection) {
749     StringWriter writer = new StringWriter();
750     PrintWriter pwriter = new PrintWriter(writer);
751     if (selection.isEmpty())
752       return;
753     LogEntry entry = (LogEntry) ((IStructuredSelection) selection).getFirstElement();
754     entry.write(pwriter);
755     pwriter.flush();
756     String textVersion = writer.toString();
757     try {
758       pwriter.close();
759       writer.close();
760     } catch (IOException e) {
761     }
762     if (textVersion.trim().length() > 0) {
763       // set the clipboard contents
764       clipboard.setContents(new Object[] { textVersion }, new Transfer[] { TextTransfer.getInstance() });
765     }
766   }
767
768   public void init(IViewSite site, IMemento memento) throws PartInitException {
769     super.init(site, memento);
770     if (memento == null)
771       this.memento = XMLMemento.createWriteRoot("LOGVIEW"); //$NON-NLS-1$
772     else
773       this.memento = memento;
774     initializeMemento();
775   }
776
777   private void initializeMemento() {
778     if (memento.getString(P_USE_LIMIT) == null)
779       memento.putString(P_USE_LIMIT, "true"); //$NON-NLS-1$
780     if (memento.getInteger(P_LOG_LIMIT) == null)
781       memento.putInteger(P_LOG_LIMIT, 50);
782     if (memento.getString(P_LOG_INFO) == null)
783       memento.putString(P_LOG_INFO, "true"); //$NON-NLS-1$
784     if (memento.getString(P_LOG_WARNING) == null)
785       memento.putString(P_LOG_WARNING, "true"); //$NON-NLS-1$
786     if (memento.getString(P_LOG_ERROR) == null)
787       memento.putString(P_LOG_ERROR, "true"); //$NON-NLS-1$
788     if (memento.getString(P_SHOW_ALL_SESSIONS) == null)
789       memento.putString(P_SHOW_ALL_SESSIONS, "true"); //$NON-NLS-1$
790     Integer width = memento.getInteger(P_COLUMN_1);
791     if (width == null || width.intValue() == 0)
792       memento.putInteger(P_COLUMN_1, 20);
793     width = memento.getInteger(P_COLUMN_2);
794     if (width == null || width.intValue() == 0)
795       memento.putInteger(P_COLUMN_2, 300);
796     width = memento.getInteger(P_COLUMN_3);
797     if (width == null || width.intValue() == 0)
798       memento.putInteger(P_COLUMN_3, 150);
799     width = memento.getInteger(P_COLUMN_4);
800     if (width == null || width.intValue() == 0)
801       memento.putInteger(P_COLUMN_4, 150);
802     if (memento.getString(P_ACTIVATE) == null)
803       memento.putString(P_ACTIVATE, "true"); //$NON-NLS-1$
804   }
805
806   public void saveState(IMemento memento) {
807     if (this.memento == null || memento == null)
808       return;
809     this.memento.putInteger(P_COLUMN_1, column1.getWidth());
810     this.memento.putInteger(P_COLUMN_2, column2.getWidth());
811     this.memento.putInteger(P_COLUMN_3, column3.getWidth());
812     this.memento.putInteger(P_COLUMN_4, column4.getWidth());
813     this.memento.putString(P_ACTIVATE, activateViewAction.isChecked() ? "true" : "false"); //$NON-NLS-1$ //$NON-NLS-2$
814     memento.putMemento(this.memento);
815   }
816
817   private void addMouseListeners() {
818     Listener tableListener = new Listener() {
819       public void handleEvent(Event e) {
820         switch (e.type) {
821         case SWT.MouseMove:
822           onMouseMove(e);
823           break;
824         case SWT.MouseHover:
825           onMouseHover(e);
826           break;
827         case SWT.MouseDown:
828           onMouseDown(e);
829           break;
830         }
831       }
832     };
833     int[] tableEvents = new int[] { SWT.MouseDown, SWT.MouseMove, SWT.MouseHover };
834     for (int i = 0; i < tableEvents.length; i++) {
835       tableTreeViewer.getTableTree().getTable().addListener(tableEvents[i], tableListener);
836     }
837   }
838
839   private void makeHoverShell() {
840     Control control = tableTreeViewer.getControl();
841     textShell = new Shell(control.getShell(), SWT.NO_FOCUS | SWT.ON_TOP);
842     Display display = textShell.getDisplay();
843     textShell.setBackground(display.getSystemColor(SWT.COLOR_INFO_BACKGROUND));
844     GridLayout layout = new GridLayout(1, false);
845     int border = ((control.getShell().getStyle() & SWT.NO_TRIM) == 0) ? 0 : 1;
846     layout.marginHeight = border;
847     layout.marginWidth = border;
848     textShell.setLayout(layout);
849     textShell.setLayoutData(new GridData(GridData.FILL_HORIZONTAL));
850     Composite shellComposite = new Composite(textShell, SWT.NONE);
851     layout = new GridLayout();
852     layout.marginHeight = 0;
853     layout.marginWidth = 0;
854     shellComposite.setLayout(layout);
855     shellComposite.setLayoutData(new GridData(GridData.FILL_BOTH | GridData.VERTICAL_ALIGN_BEGINNING));
856     textLabel = new Text(shellComposite, SWT.WRAP | SWT.MULTI);
857     GridData gd = new GridData(GridData.FILL_BOTH);
858     gd.widthHint = 100;
859     gd.grabExcessHorizontalSpace = true;
860     textLabel.setLayoutData(gd);
861     Color c = control.getDisplay().getSystemColor(SWT.COLOR_INFO_BACKGROUND);
862     textLabel.setBackground(c);
863     c = control.getDisplay().getSystemColor(SWT.COLOR_INFO_FOREGROUND);
864     textLabel.setForeground(c);
865     textLabel.setEditable(false);
866     textShell.addDisposeListener(new DisposeListener() {
867       public void widgetDisposed(DisposeEvent e) {
868         onTextShellDispose(e);
869       }
870     });
871   }
872
873   void onTextShellDispose(DisposeEvent e) {
874     canOpenTextShell = true;
875     setFocus();
876   }
877
878   void onMouseDown(Event e) {
879     if (textShell != null && !textShell.isDisposed() && !textShell.isFocusControl()) {
880       textShell.close();
881       canOpenTextShell = true;
882     }
883   }
884
885   void onMouseHover(Event e) {
886     if (!canOpenTextShell)
887       return;
888     canOpenTextShell = false;
889     Point point = new Point(e.x, e.y);
890     TableTree table = tableTreeViewer.getTableTree();
891     TableTreeItem item = table.getItem(point);
892     if (item == null)
893       return;
894     String message = ((LogEntry) item.getData()).getStack();
895     if (message == null)
896       return;
897     makeHoverShell();
898     textLabel.setText(message);
899     int x = point.x + 5;
900     int y = point.y - (table.getItemHeight() * 2) - 20;
901     textShell.setLocation(table.toDisplay(x, y));
902     textShell.setSize(tableTreeViewer.getTableTree().getSize().x - x, 125);
903     textShell.open();
904     setFocus();
905   }
906
907   void onMouseMove(Event e) {
908     if (textShell != null && !textShell.isDisposed()) {
909       textShell.close();
910       canOpenTextShell = textShell.isDisposed() && e.x > column0.getWidth() && e.x < (column0.getWidth() + column1.getWidth());
911     } else {
912       canOpenTextShell = e.x > column0.getWidth() && e.x < (column0.getWidth() + column1.getWidth());
913     }
914   }
915
916   public Comparator getComparator() {
917     return comparator;
918   }
919
920   private void setComparator(byte sortType) {
921     if (sortType == DATE) {
922       comparator = new Comparator() {
923         public int compare(Object e1, Object e2) {
924           try {
925             SimpleDateFormat formatter = new SimpleDateFormat("MMM dd, yyyy HH:mm:ss.SS"); //$NON-NLS-1$
926             Date date1 = formatter.parse(((LogEntry) e1).getDate());
927             Date date2 = formatter.parse(((LogEntry) e2).getDate());
928             if (DATE_ORDER == ASCENDING)
929               return date1.before(date2) ? -1 : 1;
930             return date1.after(date2) ? -1 : 1;
931           } catch (ParseException e) {
932           }
933           return 0;
934         }
935       };
936     } else if (sortType == PLUGIN) {
937       comparator = new Comparator() {
938         public int compare(Object e1, Object e2) {
939           LogEntry entry1 = (LogEntry) e1;
940           LogEntry entry2 = (LogEntry) e2;
941           return collator.compare(entry1.getPluginId(), entry2.getPluginId()) * PLUGIN_ORDER;
942         }
943       };
944     } else {
945       comparator = new Comparator() {
946         public int compare(Object e1, Object e2) {
947           LogEntry entry1 = (LogEntry) e1;
948           LogEntry entry2 = (LogEntry) e2;
949           return collator.compare(entry1.getMessage(), entry2.getMessage()) * MESSAGE_ORDER;
950         }
951       };
952     }
953   }
954
955   private ViewerSorter getViewerSorter(byte sortType) {
956     if (sortType == PLUGIN) {
957       return new ViewerSorter() {
958         public int compare(Viewer viewer, Object e1, Object e2) {
959           LogEntry entry1 = (LogEntry) e1;
960           LogEntry entry2 = (LogEntry) e2;
961           return super.compare(viewer, entry1.getPluginId(), entry2.getPluginId()) * PLUGIN_ORDER;
962         }
963       };
964     } else if (sortType == MESSAGE) {
965       return new ViewerSorter() {
966         public int compare(Viewer viewer, Object e1, Object e2) {
967           LogEntry entry1 = (LogEntry) e1;
968           LogEntry entry2 = (LogEntry) e2;
969           return super.compare(viewer, entry1.getMessage(), entry2.getMessage()) * MESSAGE_ORDER;
970         }
971       };
972     } else {
973       return new ViewerSorter() {
974         public int compare(Viewer viewer, Object e1, Object e2) {
975           try {
976             SimpleDateFormat formatter = new SimpleDateFormat("MMM dd, yyyy HH:mm:ss.SS"); //$NON-NLS-1$
977             Date date1 = formatter.parse(((LogEntry) e1).getDate());
978             Date date2 = formatter.parse(((LogEntry) e2).getDate());
979             if (DATE_ORDER == ASCENDING)
980               return date1.before(date2) ? -1 : 1;
981             return date1.after(date2) ? -1 : 1;
982           } catch (ParseException e) {
983           }
984           return 0;
985         }
986       };
987     }
988   }
989
990   private void resetDialogButtons() {
991     ((EventDetailsDialogAction) propertiesAction).resetDialogButtons();
992   }
993 }