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