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