]> gerrit.simantics Code Review - simantics/platform.git/blobdiff - bundles/org.simantics.message.ui/src/org/simantics/message/ui/LogView.java
Migrated source code from Simantics SVN
[simantics/platform.git] / bundles / org.simantics.message.ui / src / org / simantics / message / ui / LogView.java
diff --git a/bundles/org.simantics.message.ui/src/org/simantics/message/ui/LogView.java b/bundles/org.simantics.message.ui/src/org/simantics/message/ui/LogView.java
new file mode 100644 (file)
index 0000000..ab09409
--- /dev/null
@@ -0,0 +1,1934 @@
+/*******************************************************************************\r
+ * Copyright (c) 2007, 2010 Association for Decentralized Information Management\r
+ * in Industry THTH ry.\r
+ * All rights reserved. This program and the accompanying materials\r
+ * are made available under the terms of the Eclipse Public License v1.0\r
+ * which accompanies this distribution, and is available at\r
+ * http://www.eclipse.org/legal/epl-v10.html\r
+ *\r
+ * Contributors:\r
+ *     VTT Technical Research Centre of Finland - initial API and implementation\r
+ *******************************************************************************/\r
+package org.simantics.message.ui;
+
+import java.io.BufferedReader;
+import java.io.BufferedWriter;
+import java.io.File;
+import java.io.FileInputStream;
+import java.io.FileOutputStream;
+import java.io.IOException;
+import java.io.InputStreamReader;
+import java.io.OutputStreamWriter;
+import java.io.PrintWriter;
+import java.io.StringWriter;
+import java.lang.reflect.InvocationTargetException;
+import java.net.URI;
+import java.net.URISyntaxException;
+import java.util.ArrayList;
+import java.util.Arrays;
+import java.util.Collections;
+import java.util.Comparator;
+import java.util.Date;
+import java.util.HashMap;
+import java.util.Iterator;
+import java.util.List;
+import java.util.Map;
+
+import org.eclipse.core.runtime.IProgressMonitor;
+import org.eclipse.core.runtime.IStatus;
+import org.eclipse.core.runtime.MultiStatus;
+import org.eclipse.core.runtime.Path;
+import org.eclipse.core.runtime.Preferences;
+import org.eclipse.core.runtime.Status;
+import org.eclipse.core.runtime.jobs.Job;
+import org.eclipse.jface.action.Action;
+import org.eclipse.jface.action.IAction;
+import org.eclipse.jface.action.IContributionItem;
+import org.eclipse.jface.action.IMenuListener;
+import org.eclipse.jface.action.IMenuManager;
+import org.eclipse.jface.action.IStatusLineManager;
+import org.eclipse.jface.action.IToolBarManager;
+import org.eclipse.jface.action.MenuManager;
+import org.eclipse.jface.action.Separator;
+import org.eclipse.jface.dialogs.IDialogSettings;
+import org.eclipse.jface.dialogs.MessageDialog;
+import org.eclipse.jface.dialogs.ProgressMonitorDialog;
+import org.eclipse.jface.operation.IRunnableWithProgress;
+import org.eclipse.jface.resource.ImageDescriptor;
+import org.eclipse.jface.resource.JFaceResources;
+import org.eclipse.jface.resource.LocalResourceManager;
+import org.eclipse.jface.util.Policy;
+import org.eclipse.jface.viewers.DoubleClickEvent;
+import org.eclipse.jface.viewers.IDoubleClickListener;
+import org.eclipse.jface.viewers.ISelection;
+import org.eclipse.jface.viewers.ISelectionChangedListener;
+import org.eclipse.jface.viewers.IStructuredSelection;
+import org.eclipse.jface.viewers.SelectionChangedEvent;
+import org.eclipse.jface.viewers.TreeSelection;
+import org.eclipse.jface.viewers.Viewer;
+import org.eclipse.jface.viewers.ViewerComparator;
+import org.eclipse.jface.window.Window;
+import org.eclipse.osgi.util.NLS;
+import org.eclipse.swt.SWT;
+import org.eclipse.swt.SWTException;
+import org.eclipse.swt.browser.Browser;
+import org.eclipse.swt.browser.LocationEvent;
+import org.eclipse.swt.browser.LocationListener;
+import org.eclipse.swt.custom.BusyIndicator;
+import org.eclipse.swt.custom.SashForm;
+import org.eclipse.swt.dnd.Clipboard;
+import org.eclipse.swt.dnd.DND;
+import org.eclipse.swt.dnd.DragSource;
+import org.eclipse.swt.dnd.DragSourceAdapter;
+import org.eclipse.swt.dnd.DragSourceEvent;
+import org.eclipse.swt.dnd.TextTransfer;
+import org.eclipse.swt.dnd.Transfer;
+import org.eclipse.swt.events.ControlAdapter;
+import org.eclipse.swt.events.ControlEvent;
+import org.eclipse.swt.events.DisposeEvent;
+import org.eclipse.swt.events.DisposeListener;
+import org.eclipse.swt.events.SelectionAdapter;
+import org.eclipse.swt.events.SelectionEvent;
+import org.eclipse.swt.graphics.Color;
+import org.eclipse.swt.graphics.Image;
+import org.eclipse.swt.graphics.Point;
+import org.eclipse.swt.graphics.Rectangle;
+import org.eclipse.swt.layout.GridData;
+import org.eclipse.swt.layout.GridLayout;
+import org.eclipse.swt.program.Program;
+import org.eclipse.swt.widgets.Composite;
+import org.eclipse.swt.widgets.Display;
+import org.eclipse.swt.widgets.Event;
+import org.eclipse.swt.widgets.FileDialog;
+import org.eclipse.swt.widgets.Listener;
+import org.eclipse.swt.widgets.Menu;
+import org.eclipse.swt.widgets.Shell;
+import org.eclipse.swt.widgets.Text;
+import org.eclipse.swt.widgets.Tree;
+import org.eclipse.swt.widgets.TreeColumn;
+import org.eclipse.swt.widgets.TreeItem;
+import org.eclipse.ui.IActionBars;
+import org.eclipse.ui.IMemento;
+import org.eclipse.ui.IPerspectiveDescriptor;
+import org.eclipse.ui.IPerspectiveListener2;
+import org.eclipse.ui.ISharedImages;
+import org.eclipse.ui.IViewReference;
+import org.eclipse.ui.IViewSite;
+import org.eclipse.ui.IWorkbenchActionConstants;
+import org.eclipse.ui.IWorkbenchPage;
+import org.eclipse.ui.IWorkbenchPart;
+import org.eclipse.ui.IWorkbenchPartReference;
+import org.eclipse.ui.PartInitException;
+import org.eclipse.ui.PlatformUI;
+import org.eclipse.ui.XMLMemento;
+import org.eclipse.ui.actions.ActionFactory;
+import org.eclipse.ui.dialogs.FilteredTree;
+import org.eclipse.ui.dialogs.PatternFilter;
+import org.eclipse.ui.part.ViewPart;
+import org.simantics.message.DetailStatus;
+import org.simantics.message.ILogListener;
+import org.simantics.message.IMessageDataSchemeExtension;
+import org.simantics.message.IMessageSchemeManager;
+import org.simantics.message.MessageSchemeException;
+import org.simantics.message.MessageService;
+import org.simantics.message.ReferenceSerializationException;
+import org.simantics.message.util.HtmlUtil;
+import org.simantics.utils.ui.ErrorLogger;
+
+import com.ibm.icu.text.DateFormat;
+import com.ibm.icu.text.SimpleDateFormat;
+
+/**
+ * A direct rip of Eclipse's own <code>LogView</code> for our own purposes.
+ * 
+ * <p>
+ * The only thing that has changed is the the dependence on
+ * <code>Activator.getLogFile()</code> instead of
+ * <code>Platform.getLogFileLocation()</code>.
+ * 
+ * @author Tuukka Lehtonen
+ * @see org.eclipse.ui.internal.views.LogView
+ */
+@SuppressWarnings("deprecation")\r
+public class LogView extends ViewPart implements ILogListener {
+
+    public static final int      DEFAULT_EXPAND_LEVEL = 1;
+    
+    public static final String   P_LOG_WARNING       = "warning";         //$NON-NLS-1$
+    public static final String   P_LOG_ERROR         = "error";           //$NON-NLS-1$
+    public static final String   P_LOG_INFO          = "info";            //$NON-NLS-1$
+    public static final String   P_LOG_DEBUG         = "debug";           //$NON-NLS-1$
+    public static final String   P_LOG_LIMIT         = "limit";           //$NON-NLS-1$
+    public static final String   P_EXPAND_LEVEL      = "expandLevel";     //$NON-NLS-1$
+    public static final String   P_USE_LIMIT         = "useLimit";        //$NON-NLS-1$
+    public static final String   P_SHOW_ALL_SESSIONS = "allSessions";     //$NON-NLS-1$
+    private static final String  P_COLUMN_1          = "column2";         //$NON-NLS-1$
+    private static final String  P_COLUMN_2          = "column3";         //$NON-NLS-1$
+    private static final String  P_COLUMN_3          = "column4";         //$NON-NLS-1$
+    public static final String   P_ACTIVATE          = "activate";        //$NON-NLS-1$
+    public static final String   P_SHOW_FILTER_TEXT  = "show_filter_text"; //$NON-NLS-1$
+    public static final String   P_ORDER_TYPE        = "orderType";       //$NON-NLS-1$
+    public static final String   P_ORDER_VALUE       = "orderValue";      //$NON-NLS-1$
+    public static final String   P_IMPORT_LOG        = "importLog";       //$NON-NLS-1$
+    public static final String   P_GROUP_BY          = "groupBy";         //$NON-NLS-1$
+
+       private int                  MESSAGE_ORDER;
+    private int                  PLUGIN_ORDER;
+    private int                  DATE_ORDER;
+
+       public final static byte     MESSAGE             = 0x0;
+    public final static byte     PLUGIN              = 0x1;
+    public final static byte     DATE                = 0x2;
+    public static int            ASCENDING           = 1;
+    public static int            DESCENDING          = -1;
+
+       public static final int      GROUP_BY_NONE       = 0;
+    public static final int      GROUP_BY_SESSION    = 1;
+    public static final int      GROUP_BY_PLUGIN     = 2;
+
+       private List<Object>         elements;
+    private Map<Object, Object>  groups;
+    private LogSession           currentSession;
+
+       private List<Object>         batchedEntries;
+    private boolean              batchEntries;
+
+    private Clipboard            fClipboard;
+
+       private IMemento             fMemento;
+    private File                 fInputFile;
+    private String               fDirectory;
+
+       private Comparator<Object>   fComparator;
+
+       // hover text
+    private boolean              fCanOpenTextShell;
+    private Text                 fTextLabel;
+    private Shell                fTextShell;
+
+       private boolean              fFirstEvent         = true;
+
+       private TreeColumn           fColumn1;
+    @SuppressWarnings("unused")\r
+    private TreeColumn           fColumn2;
+    private TreeColumn           fColumn3;
+
+       private Tree                 fTree;
+       private FilteredTree         fFilteredTree;
+    private LogViewLabelProvider fLabelProvider;
+    //private ScrolledComposite    fMessageDescriptorComposite;
+    //private FormText             fMessageDescription;
+    private Browser              fMessageDescription;
+
+       private Action               fPropertiesAction;
+       private Action               fDeleteLogAction;
+       private Action               fReadLogAction;
+       private Action               fCopyAction;
+       private Action               fActivateViewAction;
+       private Action               fOpenLogAction;
+       private Action               fExportAction;
+
+       private LocalResourceManager resourceManager;
+
+       /**
+        * Action called when user selects "Group by -> ..." from menu.
+        */
+       class GroupByAction extends Action {
+               private int groupBy;
+
+               public GroupByAction(String text, int groupBy) {
+                       super(text, IAction.AS_RADIO_BUTTON);
+
+                       this.groupBy = groupBy;
+
+                       if (fMemento.getInteger(LogView.P_GROUP_BY).intValue() == groupBy) {
+                               setChecked(true);
+                       }
+               }
+
+               public void run() {
+                       if (fMemento.getInteger(LogView.P_GROUP_BY).intValue() != groupBy) {
+                               fMemento.putInteger(LogView.P_GROUP_BY, groupBy);
+                               reloadLog();
+                       }
+               }
+       }
+
+       /**
+        * Constructor
+        */
+       public LogView() {
+               elements = new ArrayList<Object>();
+               groups = new HashMap<Object, Object>();
+               batchedEntries = new ArrayList<Object>();
+               fInputFile = getPlatformLogFile();
+       }
+
+       /* (non-Javadoc)
+        * @see org.eclipse.ui.part.WorkbenchPart#createPartControl(org.eclipse.swt.widgets.Composite)
+        */
+       public void createPartControl(Composite parent) {
+           resourceManager = new LocalResourceManager(JFaceResources.getResources());
+           
+           SashForm sashForm = new SashForm(parent, SWT.VERTICAL | SWT.SMOOTH);
+           
+               final Composite composite = new Composite(sashForm, SWT.NONE);
+        GridLayout layout = new GridLayout();
+        layout.horizontalSpacing = 0;
+        layout.verticalSpacing = 0;
+        layout.marginWidth = 0;
+        layout.marginHeight = 0;
+        layout.marginBottom = 0;
+        layout.marginTop = 0;
+        layout.marginLeft = 0;
+        layout.marginRight = 0;
+        composite.setLayout(layout);
+
+               readLogFile();
+               createViewer(composite);
+               getSite().setSelectionProvider(fFilteredTree.getViewer());
+               createActions();
+               fClipboard = new Clipboard(fTree.getDisplay());
+               fTree.setToolTipText(""); //$NON-NLS-1$
+               initializeViewerSorter();
+
+               makeHoverShell();
+
+               /*
+               fMessageDescriptorComposite = new ScrolledComposite(sashForm, SWT.V_SCROLL | SWT.H_SCROLL | SWT.BORDER);
+               GridDataFactory.fillDefaults().grab(true, false).applyTo(fMessageDescriptorComposite);
+               TableWrapLayout layout2 = new TableWrapLayout();
+               layout2.bottomMargin = 0;
+               layout2.topMargin = 0;
+               layout2.leftMargin = 0;
+               layout2.rightMargin = 0;
+               fMessageDescriptorComposite.setLayout(layout2);
+
+               fMessageDescription = new FormText(fMessageDescriptorComposite, SWT.NONE);
+               fMessageDescription.setBackground(parent.getDisplay().getSystemColor(SWT.COLOR_INFO_BACKGROUND));
+               TableWrapData data = new TableWrapData(TableWrapData.FILL_GRAB, TableWrapData.FILL_GRAB);
+               fMessageDescription.setLayoutData(data);
+               TextColors.bindTo(resourceManager, fMessageDescription);
+               fMessageDescription.addHyperlinkListener(new IHyperlinkListener() {
+                   @Override
+                   public void linkActivated(HyperlinkEvent event) {
+                       String s = (String) event.data;
+                //System.out.println("link activated: " + s);
+                try {
+                    URI uri = new URI(s);
+                    String scheme = uri.getScheme();
+                    String schemeSpecificPart = uri.getSchemeSpecificPart();
+
+                    IMessageSchemeManager msm = org.simantics.message.internal.Activator.getDefault().getMessageSchemeManager();
+                    IMessageDataSchemeExtension[] exts = msm.getByScheme(scheme);
+
+                    for (IMessageDataSchemeExtension ext : exts) {
+                        Object data = ext.getSerializer().deserialize(schemeSpecificPart);
+                        ext.getHandler().perform(data);
+                        return;
+                    }
+                } catch (URISyntaxException e) {
+                    // TODO Auto-generated catch block
+                    e.printStackTrace();
+                } catch (ReferenceSerializationException e) {
+                    // TODO Auto-generated catch block
+                    e.printStackTrace();
+                }
+                   }
+                   @Override
+                   public void linkEntered(HyperlinkEvent e) {
+                       //System.out.println("link entered: " + e.data);
+                   }
+                   @Override
+                   public void linkExited(HyperlinkEvent e) {
+                       //System.out.println("link exited: " + e.data);
+                   }
+               });
+               fMessageDescription.setText("Select a message to show its description here.", false, false);
+
+        fMessageDescriptorComposite.setContent(fMessageDescription);
+        fMessageDescriptorComposite.setExpandVertical(true);
+        fMessageDescriptorComposite.setExpandHorizontal(true);
+               fMessageDescriptorComposite.addControlListener(new ControlAdapter() {
+                   public void controlResized(ControlEvent e) {
+                       Rectangle r = fMessageDescriptorComposite.getClientArea();
+                //System.out.println("scrolled composite resized: " + e + ", client area: " + r);
+                Point contentSize = fMessageDescription.computeSize(r.width, SWT.DEFAULT);                
+                //System.out.println("computed content size: " + contentSize);
+                       fMessageDescriptorComposite.setMinSize(contentSize);
+                   }
+               });
+               */
+               fMessageDescription = new Browser(sashForm, SWT.NONE);
+               fMessageDescription.setBackground(parent.getDisplay().getSystemColor(SWT.COLOR_INFO_BACKGROUND));
+               fMessageDescription.setText("<html><head></head><body><p>Select a message to show its description here.</p></body></html>");
+               fMessageDescription.addLocationListener(new LocationListener() {
+                   @Override
+                   public void changed(LocationEvent event) {
+                       //System.out.println("changed: " + event);
+                   }
+                   @Override
+                   public void changing(LocationEvent event) {
+                       //System.out.println("changing: " + event);
+                       String location = event.location;
+                       if ("about:blank".equals(location)) {
+                           event.doit = true;
+                       } else {
+                           event.doit = false;
+                           //System.out.println("link activated: " + location);
+                           try {
+                               URI uri = new URI(location);
+                               String scheme = uri.getScheme();
+                               //String schemeSpecificPart = uri.getSchemeSpecificPart();
+
+                               IMessageSchemeManager msm = org.simantics.message.internal.Activator.getDefault().getMessageSchemeManager();
+                               IMessageDataSchemeExtension[] exts = msm.getByScheme(scheme);
+
+                               for (IMessageDataSchemeExtension ext : exts) {
+                                   Object data = ext.getSerializer().deserialize(uri);
+                                   try {
+                                       ext.getHandler().perform(data);
+                                       return;
+                                   } catch (MessageSchemeException e) {
+                                       ErrorLogger.defaultLogError(e);
+                                   }
+                               }
+                               return;
+                           } catch (URISyntaxException e) {
+                               // TODO Auto-generated catch block
+                               e.printStackTrace();
+                           } catch (ReferenceSerializationException e) {
+                               // TODO Auto-generated catch block
+                               e.printStackTrace();
+                           }
+                       }
+                   }
+               });
+
+               sashForm.setWeights(new int[] { 5, 2 });
+               
+               fFilteredTree.getViewer().addSelectionChangedListener(new ISelectionChangedListener() {
+            @Override
+            public void selectionChanged(SelectionChangedEvent event) {
+                IStructuredSelection s = (IStructuredSelection) event.getSelection();
+                if (s.isEmpty()) {
+                    //fMessageDescription.setText("Select a message to show its description here.", false, false);
+                    fMessageDescription.setText("<html><head></head><body><pre>Select a message to show its description here.</pre></body></html>");
+                } else {
+                    AbstractEntry entry = (AbstractEntry) s.getFirstElement();
+                    if (entry instanceof LogEntry) {
+                        LogEntry logEntry = (LogEntry) entry;
+                        String msg = logEntry.getDetailedDescription();
+                        if (msg == null || msg.trim().isEmpty())
+                            msg = logEntry.getMessage();
+                        
+                        // FormText only supports texts of Short.MAX_VALUE length
+                        // since TextSegment.TextFragment uses shorts. This message
+                        // truncation enables us to show even lengthy messages.
+                        if (msg.length() > Short.MAX_VALUE) {
+                            StringBuilder truncated = new StringBuilder();
+                            truncated.append("... [truncated ");
+                            truncated.append(msg.length() - (Short.MAX_VALUE - 100));
+                            truncated.append(" out of ");
+                            truncated.append(msg.length());
+                            truncated.append(" characters]");
+                            msg = msg.substring(0, Short.MAX_VALUE - 100) + truncated;
+                        }
+                        try {
+                            //fMessageDescription.setText(FormTextUtil.form(msg), true, false);
+                            //fMessageDescription.setText(HtmlUtil.html(msg));
+                            fMessageDescription.setText(msg);
+                        } catch (SWTException e) {
+                            // Failed to parse markup, fall back to not parsing the input. 
+                            //fMessageDescription.setText(FormTextUtil.form(msg), false, false);
+                            fMessageDescription.setText(msg);
+                        }
+                    } else if (entry instanceof Group) {
+                        if (entry instanceof LogSession) {
+                            LogSession logSession = (LogSession) entry;
+                            //fMessageDescription.setText(logSession.getSessionData(), false, false);
+                            fMessageDescription.setText(logSession.getSessionData());
+                        } else {
+                            Group grp = (Group) entry;
+                            //fMessageDescription.setText(grp.toString(), false, false);
+                            fMessageDescription.setText(grp.toString());
+                        }
+                    }
+                }
+                //fMessageDescription.refresh();
+                //composite.layout(true);
+            }
+               });
+
+               MessageService.getDefault().addLogListener(this);
+//             PlatformUI.getWorkbench().getHelpSystem().setHelp(fTree, IHelpContextIds.LOG_VIEW);
+               getSite().getWorkbenchWindow().addPerspectiveListener(new IPerspectiveListener2() {
+
+                       public void perspectiveChanged(IWorkbenchPage page, IPerspectiveDescriptor perspective, IWorkbenchPartReference partRef, String changeId) {
+                               if (!(partRef instanceof IViewReference))
+                                       return;
+
+                               IWorkbenchPart part = partRef.getPart(false);
+                               if (part == null) {
+                                       return;
+                               }
+
+                               if (part.equals(LogView.this)) {
+                                       if (changeId.equals(IWorkbenchPage.CHANGE_VIEW_SHOW)) {
+                                               if (!batchedEntries.isEmpty()) {
+                                                       pushBatchedEntries();
+                                               }
+
+                                               batchEntries = false;
+                                       } else if (changeId.equals(IWorkbenchPage.CHANGE_VIEW_HIDE)) {
+                                               batchEntries = true;
+                                       }
+                               }
+                       }
+
+                       public void perspectiveActivated(IWorkbenchPage page, IPerspectiveDescriptor perspective) {
+                               // empty
+                       }
+
+                       public void perspectiveChanged(IWorkbenchPage page, IPerspectiveDescriptor perspective, String changeId) {
+                               // empty
+                       }
+
+               });
+       }
+
+       /**
+        * Creates the actions for the viewsite action bars
+        */
+       private void createActions() {
+               IActionBars bars = getViewSite().getActionBars();
+
+               fCopyAction = createCopyAction();
+               bars.setGlobalActionHandler(ActionFactory.COPY.getId(), fCopyAction);
+
+               IToolBarManager toolBarManager = bars.getToolBarManager();
+
+               fExportAction = createExportAction();
+               toolBarManager.add(fExportAction);
+
+               final Action importLogAction = createImportLogAction();
+               toolBarManager.add(importLogAction);
+
+        toolBarManager.add(new Separator());
+
+               final Action clearAction = createClearAction();
+               toolBarManager.add(clearAction);
+
+               fDeleteLogAction = createDeleteLogAction();
+               toolBarManager.add(fDeleteLogAction);
+
+               fOpenLogAction = createOpenLogAction();
+               toolBarManager.add(fOpenLogAction);
+
+               fReadLogAction = createReadLogAction();
+               toolBarManager.add(fReadLogAction);
+
+               toolBarManager.add(new Separator());
+               toolBarManager.add(createShowTextFilter());
+
+        // FOR TESTING
+//        toolBarManager.add(new Separator());
+//        final Action testAction = createTestAction();
+//        toolBarManager.add(testAction);
+        // FOR TESTING ENDS
+               
+               IMenuManager mgr = bars.getMenuManager();
+
+               mgr.add(createGroupByAction());
+
+               mgr.add(new Separator());
+
+               mgr.add(createFilterAction());
+
+               mgr.add(new Separator());
+
+               fActivateViewAction = createActivateViewAction();
+               mgr.add(fActivateViewAction);
+
+//             mgr.add(createShowTextFilter());
+
+               createPropertiesAction();
+
+               MenuManager popupMenuManager = new MenuManager("#PopupMenu"); //$NON-NLS-1$
+               IMenuListener listener = new IMenuListener() {
+                       public void menuAboutToShow(IMenuManager manager) {
+                               manager.add(fCopyAction);
+                               manager.add(new Separator());
+                               manager.add(clearAction);
+                               manager.add(fDeleteLogAction);
+                               manager.add(fOpenLogAction);
+                               manager.add(fReadLogAction);
+                               manager.add(new Separator());
+                               manager.add(fExportAction);
+                               manager.add(createImportLogAction());
+                               manager.add(new Separator());
+
+                               ((EventDetailsDialogAction) fPropertiesAction).setComparator(fComparator);
+                               TreeItem[] selection = fTree.getSelection();
+                               if ((selection.length > 0) && (selection[0].getData() instanceof LogEntry)) {
+                                       manager.add(fPropertiesAction);
+                               }
+
+                               manager.add(new Separator(IWorkbenchActionConstants.MB_ADDITIONS));
+                       }
+               };
+               popupMenuManager.addMenuListener(listener);
+               popupMenuManager.setRemoveAllWhenShown(true);
+               getSite().registerContextMenu(popupMenuManager, getSite().getSelectionProvider());
+               Menu menu = popupMenuManager.createContextMenu(fTree);
+               fTree.setMenu(menu);
+       }
+
+       private Action createActivateViewAction() {
+               Action action = new Action(Messages.LogView_activate) { //              
+                       public void run() {
+                               fMemento.putString(P_ACTIVATE, isChecked() ? "true" : "false"); //$NON-NLS-1$ //$NON-NLS-2$
+                       }
+               };
+               action.setChecked(fMemento.getString(P_ACTIVATE).equals("true")); //$NON-NLS-1$
+               return action;
+       }
+
+    @SuppressWarnings("unused")\r
+    private Action createTestAction() {
+        Action action = new Action("Test") {
+            public void run() {
+                IStatus s1 = new Status(IStatus.INFO, Activator.PLUGIN_ID, "Test message 1", null); 
+                IStatus s2 = new Status(IStatus.WARNING, Activator.PLUGIN_ID, "Test message 2", null); 
+                IStatus s3 = new DetailStatus(IStatus.ERROR, Activator.PLUGIN_ID, "This is the short message.", HtmlUtil.p("A multi-lined message...\n<br/>continuing...<br/><br/>still...<br/>Error occurred, report at " + HtmlUtil.a("http://www.simantics.org", "simantics.org")), null); 
+                MessageService.defaultLog(s1);
+                MessageService.defaultLog(s2);
+                MessageService.defaultLog(s3);
+//                Activator.getDefault().getLog().log(s1);
+//                Activator.getDefault().getLog().log(s2);
+//                Activator.getDefault().getLog().log(s3);
+
+                MultiStatus s4 = new MultiStatus(Activator.PLUGIN_ID, 0, "Test message 4", new Exception());
+                s4.merge(new Status(IStatus.INFO, Activator.PLUGIN_ID, "MultiStatus Test 1", null));
+                s4.merge(new Status(IStatus.WARNING, Activator.PLUGIN_ID, "MultiStatus Test 2", null));
+                s4.merge(new Status(IStatus.ERROR, Activator.PLUGIN_ID, "MultiStatus Test 3", null));
+                MessageService.defaultLog(s4);
+//                Activator.getDefault().getLog().log(s4);
+            }
+        };
+        action.setImageDescriptor(ImageDescriptor.getMissingImageDescriptor());
+        action.setToolTipText("Produce test log entries");
+        return action;
+    }
+
+    private Action createClearAction() {
+        Action action = new Action(Messages.LogView_clear) {
+            public void run() {
+                handleClear();
+            }
+        };
+        action.setImageDescriptor(SharedImages.getImageDescriptor(SharedImages.DESC_CLEAR));
+        action.setDisabledImageDescriptor(SharedImages.getImageDescriptor(SharedImages.DESC_CLEAR_DISABLED));
+        action.setToolTipText(Messages.LogView_clear_tooltip);
+        action.setText(Messages.LogView_clear);
+        return action;
+    }
+
+       private Action createCopyAction() {
+               Action action = new Action(Messages.LogView_copy) {
+                       public void run() {
+                               copyToClipboard(fFilteredTree.getViewer().getSelection());
+                       }
+               };
+               action.setImageDescriptor(PlatformUI.getWorkbench().getSharedImages().getImageDescriptor(ISharedImages.IMG_TOOL_COPY));
+               return action;
+       }
+
+       private Action createDeleteLogAction() {
+               Action action = new Action(Messages.LogView_delete) {
+                       public void run() {
+                               doDeleteLog();
+                       }
+               };
+               action.setToolTipText(Messages.LogView_delete_tooltip);
+               action.setImageDescriptor(SharedImages.getImageDescriptor(SharedImages.DESC_REMOVE_LOG));
+               action.setDisabledImageDescriptor(SharedImages.getImageDescriptor(SharedImages.DESC_REMOVE_LOG_DISABLED));
+               action.setEnabled(fInputFile.exists() && isPlatformLog(fInputFile));
+               return action;
+       }
+
+       private Action createExportAction() {
+               Action action = new Action(Messages.LogView_export) {
+                       public void run() {
+                               handleExport();
+                       }
+               };
+               action.setToolTipText(Messages.LogView_export_tooltip);
+               action.setImageDescriptor(SharedImages.getImageDescriptor(SharedImages.DESC_EXPORT));
+               action.setDisabledImageDescriptor(SharedImages.getImageDescriptor(SharedImages.DESC_EXPORT_DISABLED));
+               action.setEnabled(fInputFile.exists());
+               return action;
+       }
+
+       private Action createFilterAction() {
+               Action action = new Action(Messages.LogView_filter) {
+                       public void run() {
+                               handleFilter();
+                       }
+               };
+               action.setToolTipText(Messages.LogView_filter);
+               action.setImageDescriptor(SharedImages.getImageDescriptor(SharedImages.DESC_FILTER));
+               action.setDisabledImageDescriptor(SharedImages.getImageDescriptor(SharedImages.DESC_FILTER_DISABLED));
+               return action;
+       }
+
+       private Action createImportLogAction() {
+               Action action = new ImportLogAction(this, Messages.LogView_import, fMemento);
+               action.setToolTipText(Messages.LogView_import_tooltip);
+               action.setImageDescriptor(SharedImages.getImageDescriptor(SharedImages.DESC_IMPORT));
+               action.setDisabledImageDescriptor(SharedImages.getImageDescriptor(SharedImages.DESC_IMPORT_DISABLED));
+               return action;
+       }
+
+       private Action createOpenLogAction() {
+               Action action = null;
+               /*
+               try {
+                       // TODO this isn't the best way to check... we should be smarter and use package admin
+                       // check to see if org.eclipse.ui.ide is available
+                       Class.forName("org.eclipse.ui.ide.IDE"); //$NON-NLS-1$
+                       // check to see if org.eclipse.core.filesystem is available
+                       Class.forName("org.eclipse.core.filesystem.IFileStore"); //$NON-NLS-1$
+                       action = new OpenIDELogFileAction(this);
+               } catch (ClassNotFoundException e) {
+               */
+                       action = new Action() {
+                               public void run() {
+                                       if (fInputFile.exists()) {
+                                               Job job = getOpenLogFileJob();
+                                               job.setUser(false);
+                                               job.setPriority(Job.SHORT);
+                                               job.schedule();
+                                       }
+                               }
+                       };
+               //}
+               action.setText(Messages.LogView_view_currentLog);
+               action.setImageDescriptor(SharedImages.getImageDescriptor(SharedImages.DESC_OPEN_LOG));
+               action.setDisabledImageDescriptor(SharedImages.getImageDescriptor(SharedImages.DESC_OPEN_LOG_DISABLED));
+               action.setEnabled(fInputFile.exists());
+               action.setToolTipText(Messages.LogView_view_currentLog_tooltip);
+               return action;
+       }
+
+       private void createPropertiesAction() {
+               fPropertiesAction = new EventDetailsDialogAction(fTree.getShell(), fFilteredTree.getViewer(), fMemento);
+               fPropertiesAction.setImageDescriptor(SharedImages.getImageDescriptor(SharedImages.DESC_PROPERTIES));
+               fPropertiesAction.setDisabledImageDescriptor(SharedImages.getImageDescriptor(SharedImages.DESC_PROPERTIES_DISABLED));
+               fPropertiesAction.setToolTipText(Messages.LogView_properties_tooltip);
+               fPropertiesAction.setEnabled(false);
+       }
+
+       private Action createReadLogAction() {
+               Action action = new Action(Messages.LogView_readLog_restore) {
+                       public void run() {
+                               fInputFile = getPlatformLogFile();
+                               reloadLog();
+                       }
+               };
+               action.setToolTipText(Messages.LogView_readLog_restore_tooltip);
+               action.setImageDescriptor(SharedImages.getImageDescriptor(SharedImages.DESC_READ_LOG));
+               action.setDisabledImageDescriptor(SharedImages.getImageDescriptor(SharedImages.DESC_READ_LOG_DISABLED));
+               return action;
+       }
+
+       /**
+        * Creates the Show Text Filter view menu action 
+        * @return the new action for the Show Text Filter 
+        */
+       private Action createShowTextFilter() {
+               Action action = new Action(Messages.LogView_show_filter_text, Action.AS_CHECK_BOX) {
+                       public void run() {
+                               showFilterText(isChecked());
+                       }
+               };
+        action.setToolTipText(Messages.LogView_show_filter_tooltip);
+        action.setImageDescriptor(SharedImages.getImageDescriptor(SharedImages.DESC_SHOW_TEXT_FILTER));
+        boolean visible = fMemento.getBoolean(P_SHOW_FILTER_TEXT).booleanValue();
+        action.setChecked(visible);
+               showFilterText(visible);
+               return action;
+       }
+
+       /**
+        * Shows/hides the filter text control from the filtered tree. This method also sets the 
+        * P_SHOW_FILTER_TEXT preference to the visible state
+        * 
+        * @param visible if the filter text control should be shown or not
+        */
+       private void showFilterText(boolean visible) {
+               fMemento.putBoolean(P_SHOW_FILTER_TEXT, visible);
+               Composite ctrl = fFilteredTree.getFilterControl().getParent();
+               GridData gd = (GridData) ctrl.getLayoutData();
+               gd.exclude = !visible;
+               ctrl.setVisible(visible);
+               gd.verticalIndent = 8;
+               gd.horizontalIndent = 4;
+               if (!visible) // reset control if we aren't visible
+                       fFilteredTree.getFilterControl().setText(Messages.LogView_show_filter_initialText);
+               fFilteredTree.layout(false);
+       }
+
+       private IContributionItem createGroupByAction() {
+               IMenuManager manager = new MenuManager(Messages.LogView_GroupBy);
+               manager.add(new GroupByAction(Messages.LogView_GroupBySession, LogView.GROUP_BY_SESSION));
+               manager.add(new GroupByAction(Messages.LogView_GroupByPlugin, LogView.GROUP_BY_PLUGIN));
+               manager.add(new GroupByAction(Messages.LogView_GroupByNone, LogView.GROUP_BY_NONE));
+               return manager;
+       }
+
+       private void createViewer(Composite parent) {
+
+               fFilteredTree = new FilteredTree(parent, SWT.FULL_SELECTION, new PatternFilter() {
+                       protected boolean isLeafMatch(Viewer viewer, Object element) {
+                               if (element instanceof LogEntry) {
+                                       LogEntry logEntry = (LogEntry) element;
+                                       String message = logEntry.getMessage();
+                                       String plugin = logEntry.getPluginId();
+                                       String date = logEntry.getFormattedDate();
+                                       return wordMatches(message) || wordMatches(plugin) || wordMatches(date);
+                               }
+                               return false;
+                       }
+               });
+               fFilteredTree.setInitialText(Messages.LogView_show_filter_initialText);
+               fTree = fFilteredTree.getViewer().getTree();
+               fTree.setLinesVisible(true);
+               createColumns(fTree);
+               fFilteredTree.getViewer().setAutoExpandLevel(fMemento.getInteger(P_EXPAND_LEVEL).intValue());
+               fFilteredTree.getViewer().setContentProvider(new LogViewContentProvider(this));
+               fFilteredTree.getViewer().setLabelProvider(fLabelProvider = new LogViewLabelProvider(this));
+               fLabelProvider.connect(this);
+               fFilteredTree.getViewer().addSelectionChangedListener(new ISelectionChangedListener() {
+                       public void selectionChanged(SelectionChangedEvent e) {
+                               handleSelectionChanged(e.getSelection());
+                               if (fPropertiesAction.isEnabled())
+                                       ((EventDetailsDialogAction) fPropertiesAction).resetSelection();
+                       }
+               });
+               fFilteredTree.getViewer().addDoubleClickListener(new IDoubleClickListener() {
+                       public void doubleClick(DoubleClickEvent event) {
+                               ((EventDetailsDialogAction) fPropertiesAction).setComparator(fComparator);
+                               fPropertiesAction.run();
+                       }
+               });
+               fFilteredTree.getViewer().setInput(this);
+               addMouseListeners();
+               addDragSource();
+       }
+
+       private void createColumns(final Tree tree) {
+               fColumn1 = new TreeColumn(tree, SWT.LEFT);
+               fColumn1.setText(Messages.LogView_column_message);
+               fColumn1.setWidth(fMemento.getInteger(P_COLUMN_1).intValue());
+               fColumn1.addSelectionListener(new SelectionAdapter() {
+                       public void widgetSelected(SelectionEvent e) {
+                               MESSAGE_ORDER *= -1;
+                               ViewerComparator comparator = getViewerComparator(MESSAGE);
+                               fFilteredTree.getViewer().setComparator(comparator);
+                               boolean isComparatorSet = ((EventDetailsDialogAction) fPropertiesAction).resetSelection(MESSAGE, MESSAGE_ORDER);
+                               setComparator(MESSAGE);
+                               if (!isComparatorSet)
+                                       ((EventDetailsDialogAction) fPropertiesAction).setComparator(fComparator);
+                               fMemento.putInteger(P_ORDER_VALUE, MESSAGE_ORDER);
+                               fMemento.putInteger(P_ORDER_TYPE, MESSAGE);
+                               setColumnSorting(fColumn1, MESSAGE_ORDER);
+                       }
+               });
+               tree.addControlListener(new ControlAdapter() {
+
+                       @Override
+                       public void controlResized(ControlEvent e) {
+                               fColumn1.setWidth(tree.getSize().x - 20);
+                       }
+                       
+               });
+
+//             fColumn2 = new TreeColumn(tree, SWT.LEFT);
+//             fColumn2.setText(Messages.LogView_column_plugin);
+//             fColumn2.setWidth(fMemento.getInteger(P_COLUMN_2).intValue());
+//             fColumn2.addSelectionListener(new SelectionAdapter() {
+//                     public void widgetSelected(SelectionEvent e) {
+//                             PLUGIN_ORDER *= -1;
+//                             ViewerComparator comparator = getViewerComparator(PLUGIN);
+//                             fFilteredTree.getViewer().setComparator(comparator);
+//                             boolean isComparatorSet = ((EventDetailsDialogAction) fPropertiesAction).resetSelection(PLUGIN, PLUGIN_ORDER);
+//                             setComparator(PLUGIN);
+//                             if (!isComparatorSet)
+//                                     ((EventDetailsDialogAction) fPropertiesAction).setComparator(fComparator);
+//                             fMemento.putInteger(P_ORDER_VALUE, PLUGIN_ORDER);
+//                             fMemento.putInteger(P_ORDER_TYPE, PLUGIN);
+//                             setColumnSorting(fColumn2, PLUGIN_ORDER);
+//                     }
+//             });
+//
+//             fColumn3 = new TreeColumn(tree, SWT.LEFT);
+//             fColumn3.setText(Messages.LogView_column_date);
+//             fColumn3.setWidth(fMemento.getInteger(P_COLUMN_3).intValue());
+//             fColumn3.addSelectionListener(new SelectionAdapter() {
+//                     public void widgetSelected(SelectionEvent e) {
+//                             DATE_ORDER *= -1;
+//                             ViewerComparator comparator = getViewerComparator(DATE);
+//                             fFilteredTree.getViewer().setComparator(comparator);
+//                             setComparator(DATE);
+//                             ((EventDetailsDialogAction) fPropertiesAction).setComparator(fComparator);
+//                             fMemento.putInteger(P_ORDER_VALUE, DATE_ORDER);
+//                             fMemento.putInteger(P_ORDER_TYPE, DATE);
+//                             setColumnSorting(fColumn3, DATE_ORDER);
+//                     }
+//             });
+
+               tree.setHeaderVisible(true);
+       }
+
+       private void initializeViewerSorter() {
+               byte orderType = fMemento.getInteger(P_ORDER_TYPE).byteValue();
+               ViewerComparator comparator = getViewerComparator(orderType);
+               fFilteredTree.getViewer().setComparator(comparator);
+               if (orderType == MESSAGE)
+                       setColumnSorting(fColumn1, MESSAGE_ORDER);
+//             else if (orderType == PLUGIN)
+//                     setColumnSorting(fColumn2, PLUGIN_ORDER);
+//             else if (orderType == DATE)
+//                     setColumnSorting(fColumn3, DATE_ORDER);
+       }
+
+       private void setColumnSorting(TreeColumn column, int order) {
+               fTree.setSortColumn(column);
+               fTree.setSortDirection(order == ASCENDING ? SWT.UP : SWT.DOWN);
+       }
+
+       public void dispose() {
+               writeSettings();
+               MessageService.getDefault().removeLogListener(this);
+               fClipboard.dispose();
+               if (fTextShell != null)
+                       fTextShell.dispose();
+               fLabelProvider.disconnect(this);
+               fFilteredTree.dispose();
+               resourceManager.dispose();
+               super.dispose();
+       }
+
+       void handleImport() {
+               FileDialog dialog = new FileDialog(getViewSite().getShell());
+               dialog.setFilterExtensions(new String[] {"*.log"}); //$NON-NLS-1$
+               if (fDirectory != null)
+                       dialog.setFilterPath(fDirectory);
+               String path = dialog.open();
+               if (path == null) { // cancel
+                       return;
+               }
+
+               File file = new Path(path).toFile();
+               if (file.exists()) {
+                       handleImportPath(path);
+               } else {
+                       String msg = NLS.bind(Messages.LogView_FileCouldNotBeFound, file.getName());
+                       MessageDialog.openError(getViewSite().getShell(), Messages.LogView_OpenFile, msg);
+               }
+       }
+
+       public void handleImportPath(String path) {
+               if (path != null && new Path(path).toFile().exists()) {
+                       fInputFile = new Path(path).toFile();
+                       fDirectory = fInputFile.getParent();
+                       IRunnableWithProgress op = new IRunnableWithProgress() {
+                               public void run(IProgressMonitor monitor) {
+                                       monitor.beginTask(Messages.LogView_operation_importing, IProgressMonitor.UNKNOWN);
+                                       readLogFile();
+                               }
+                       };
+                       ProgressMonitorDialog pmd = new ProgressMonitorDialog(getViewSite().getShell());
+                       try {
+                               pmd.run(true, true, op);
+                       } catch (InvocationTargetException e) { // do nothing
+                       } catch (InterruptedException e) { // do nothing
+                       } finally {
+                               fReadLogAction.setText(Messages.LogView_readLog_reload);
+                               fReadLogAction.setToolTipText(Messages.LogView_readLog_reload);
+                               asyncRefresh(false);
+                               resetDialogButtons();
+                       }
+               }
+       }
+
+       private void handleExport() {
+               FileDialog dialog = new FileDialog(getViewSite().getShell(), SWT.SAVE);
+               dialog.setFilterExtensions(new String[] {"*.log"}); //$NON-NLS-1$
+               if (fDirectory != null)
+                       dialog.setFilterPath(fDirectory);
+               String path = dialog.open();
+               if (path != null) {
+                       if (path.indexOf('.') == -1 && !path.endsWith(".log")) //$NON-NLS-1$
+                               path += ".log"; //$NON-NLS-1$
+                       File outputFile = new Path(path).toFile();
+                       fDirectory = outputFile.getParent();
+                       if (outputFile.exists()) {
+                               String message = NLS.bind(Messages.LogView_confirmOverwrite_message, outputFile.toString());
+                               if (!MessageDialog.openQuestion(getViewSite().getShell(), Messages.LogView_exportLog, message))
+                                       return;
+                       }
+                       copy(fInputFile, outputFile);
+               }
+       }
+
+       private void copy(File inputFile, File outputFile) {
+               BufferedReader reader = null;
+               BufferedWriter writer = null;
+               try {
+                       reader = new BufferedReader(new InputStreamReader(new FileInputStream(inputFile), "UTF-8")); //$NON-NLS-1$
+                       writer = new BufferedWriter(new OutputStreamWriter(new FileOutputStream(outputFile), "UTF-8")); //$NON-NLS-1$
+                       while (reader.ready()) {
+                               writer.write(reader.readLine());
+                               writer.write(System.getProperty("line.separator")); //$NON-NLS-1$
+                       }
+               } catch (IOException e) { // do nothing
+               } finally {
+                       try {
+                               if (reader != null)
+                                       reader.close();
+                               if (writer != null)
+                                       writer.close();
+                       } catch (IOException e1) { // do nothing
+                       }
+               }
+       }
+
+       private void handleFilter() {
+               FilterDialog dialog = new FilterDialog(Activator.getDefault().getWorkbench().getActiveWorkbenchWindow().getShell(), fMemento);
+               dialog.create();
+               dialog.getShell().setText(Messages.LogView_FilterDialog_title);
+               if (dialog.open() == Window.OK)
+                       reloadLog();
+       }
+
+       private void doDeleteLog() {
+               String title = Messages.LogView_confirmDelete_title;
+               String message = Messages.LogView_confirmDelete_message;
+               if (!MessageDialog.openConfirm(fTree.getShell(), title, message))
+                       return;
+               if (fInputFile.delete() || elements.size() > 0) {
+                       elements.clear();
+                       groups.clear();
+                       currentSession.removeAllChildren();
+                       asyncRefresh(false);
+                       resetDialogButtons();
+               }
+       }
+
+       public void fillContextMenu(IMenuManager manager) { // nothing
+       }
+
+       public AbstractEntry[] getElements() {
+               return (AbstractEntry[]) elements.toArray(new AbstractEntry[elements.size()]);
+       }
+
+       protected void handleClear() {
+               BusyIndicator.showWhile(fTree.getDisplay(), new Runnable() {
+                       public void run() {
+                               elements.clear();
+                               groups.clear();
+                               currentSession.removeAllChildren();
+                               asyncRefresh(false);
+                               resetDialogButtons();
+                       }
+               });
+       }
+
+       protected void reloadLog() {
+               IRunnableWithProgress op = new IRunnableWithProgress() {
+                       public void run(IProgressMonitor monitor) {
+                               monitor.beginTask(Messages.LogView_operation_reloading, IProgressMonitor.UNKNOWN);
+                               readLogFile();
+                       }
+               };
+               ProgressMonitorDialog pmd = new ProgressMonitorDialog(getViewSite().getShell());
+               try {
+                       pmd.run(true, true, op);
+               } catch (InvocationTargetException e) { // do nothing
+               } catch (InterruptedException e) { // do nothing
+               } finally {
+                       fReadLogAction.setText(Messages.LogView_readLog_restore);
+                       fReadLogAction.setToolTipText(Messages.LogView_readLog_restore);
+                       asyncRefresh(false);
+                       resetDialogButtons();
+               }
+       }
+
+       private void readLogFile() {
+               if (!fInputFile.exists())
+                       return;
+
+               elements.clear();
+               groups.clear();
+
+               List<Object> result = new ArrayList<Object>();
+               currentSession = LogReader.parseLogFile(fInputFile, result, fMemento);
+               group(result);
+               limitEntriesCount();
+
+               getSite().getShell().getDisplay().asyncExec(new Runnable() {
+                       public void run() {
+                               setContentDescription(getTitleSummary());
+                       }
+               });
+
+       }
+
+       private String getTitleSummary() {
+               String path = ""; //$NON-NLS-1$
+               try {
+                       path = fInputFile.getCanonicalPath();
+               } catch (IOException e) { // log nothing
+               }
+
+               if (isPlatformLogOpen()) {
+                   // Remove the content description in this case
+                   // to save vertical space from the view.
+                       //return Messages.LogView_WorkspaceLogFile;
+                   return "";
+               }
+
+               Map<String, File> sources = LogFilesManager.getLogSources();
+               if (sources.containsValue(path)) {
+                       for (Iterator<String> i = sources.keySet().iterator(); i.hasNext();) {
+                               String key = i.next();
+                               if (sources.get(key).equals(path)) {
+                                       return NLS.bind(Messages.LogView_LogFileTitle, new String[] {key, path});
+                               }
+                       }
+               }
+
+               return path;
+       }
+
+       /**
+        * Add new entries to correct groups in the view.
+        * @param entries new entries to show up in groups in the view.
+        */
+       private void group(List<?> entries) {
+               if (fMemento.getInteger(P_GROUP_BY).intValue() == GROUP_BY_NONE) {
+                       elements.addAll(entries);
+               } else {
+                       for (Iterator<?> i = entries.iterator(); i.hasNext();) {
+                               LogEntry entry = (LogEntry) i.next();
+                               Group group = getGroup(entry);
+                               group.addChild(entry);
+                       }
+               }
+       }
+
+       /**
+        * Limits the number of entries according to the max entries limit set in
+        * memento.
+        */
+       private void limitEntriesCount() {
+               int limit = Integer.MAX_VALUE;
+               if (fMemento.getString(LogView.P_USE_LIMIT).equals("true")) {//$NON-NLS-1$
+                       limit = fMemento.getInteger(LogView.P_LOG_LIMIT).intValue();
+               }
+
+               int entriesCount = getEntriesCount();
+
+               if (entriesCount <= limit) {
+                       return;
+               }
+               Comparator<Object> dateComparator = new Comparator<Object>() {
+                       public int compare(Object o1, Object o2) {
+                               Date l1 = ((LogEntry) o1).getDate();
+                               Date l2 = ((LogEntry) o2).getDate();
+                               if ((l1 != null) && (l2 != null)) {
+                                       return l1.before(l2) ? -1 : 1;
+                               } else if ((l1 == null) && (l2 == null)) {
+                                       return 0;
+                               } else
+                                       return (l1 == null) ? -1 : 1;
+                       }
+               };
+
+               if (fMemento.getInteger(P_GROUP_BY).intValue() == GROUP_BY_NONE) {
+                       elements.subList(0, elements.size() - limit).clear();
+               } else {
+                       List<Object> copy = new ArrayList<Object>(entriesCount);
+                       for (Iterator<?> i = elements.iterator(); i.hasNext();) {
+                               AbstractEntry group = (AbstractEntry) i.next();
+                               copy.addAll(Arrays.asList(group.getChildren(group)));
+                       }
+
+                       Collections.sort(copy, dateComparator);
+                       List<?> toRemove = copy.subList(0, copy.size() - limit);
+
+                       for (Iterator<?> i = elements.iterator(); i.hasNext();) {
+                               AbstractEntry group = (AbstractEntry) i.next();
+                               group.removeChildren(toRemove);
+                       }
+               }
+
+       }
+
+       private int getEntriesCount() {
+               if (fMemento.getInteger(P_GROUP_BY).intValue() == GROUP_BY_NONE) {
+                       return elements.size();
+               }
+               int size = 0;
+               for (Iterator<?> i = elements.iterator(); i.hasNext();) {
+                       AbstractEntry group = (AbstractEntry) i.next();
+                       size += group.size();
+               }
+               return size;
+       }
+
+       /**
+        * Returns group appropriate for the entry. Group depends on P_GROUP_BY
+        * preference, or is null if grouping is disabled (GROUP_BY_NONE), or group
+        * could not be determined. May create group if it haven't existed before.
+        * 
+        * @param entry entry to be grouped
+        * @return group or null if grouping is disabled
+        */
+       protected Group getGroup(LogEntry entry) {
+               int groupBy = fMemento.getInteger(P_GROUP_BY).intValue();
+               Object elementGroupId = null;
+               String groupName = null;
+
+               switch (groupBy) {
+                       case GROUP_BY_PLUGIN :
+                               groupName = entry.getPluginId();
+                               elementGroupId = groupName;
+                               break;
+
+                       case GROUP_BY_SESSION :
+                               elementGroupId = entry.getSession();
+                               break;
+
+                       default : // grouping is disabled
+                               return null;
+               }
+
+               if (elementGroupId == null) { // could not determine group
+                       return null;
+               }
+
+               Group group = (Group) groups.get(elementGroupId);
+               if (group == null) {
+                       if (groupBy == GROUP_BY_SESSION) {
+                               group = entry.getSession();
+                       } else {
+                               group = new Group(groupName);
+                       }
+                       groups.put(elementGroupId, group);
+                       elements.add(group);
+               }
+
+               return group;
+       }
+
+       public void logging(IStatus status, String plugin) {
+               if (!isPlatformLog(fInputFile))
+                       return;
+
+               if (batchEntries) {
+                       // create LogEntry immediately to don't loose IStatus creation date.
+                       LogEntry entry = createLogEntry(status);
+                       batchedEntries.add(entry);
+                       return;
+               }
+
+               if (fFirstEvent) {
+                       readLogFile();
+                       asyncRefresh(true);
+                       fFirstEvent = false;
+               } else {
+                       LogEntry entry = createLogEntry(status);
+
+                       if (!batchedEntries.isEmpty()) {
+                               // batch new entry as well, to have only one asyncRefresh()
+                               batchedEntries.add(entry);
+                               pushBatchedEntries();
+                       } else {
+                               pushEntry(entry);
+                               asyncRefresh(true);
+                       }
+               }
+       }
+
+       /**
+        * Push batched entries to log view.
+        */
+       private void pushBatchedEntries() {
+               Job job = new Job(Messages.LogView_AddingBatchedEvents) {
+                       protected IStatus run(IProgressMonitor monitor) {
+                               for (int i = 0; i < batchedEntries.size(); i++) {
+                                       if (!monitor.isCanceled()) {
+                                               LogEntry entry = (LogEntry) batchedEntries.get(i);
+                                               pushEntry(entry);
+                                               batchedEntries.remove(i);
+                                       }
+                               }
+                               asyncRefresh(true);
+                               return Status.OK_STATUS;
+                       }
+               };
+               job.schedule();
+       }
+
+       private LogEntry createLogEntry(IStatus status) {
+               LogEntry entry = new LogEntry(status);
+               entry.setSession(currentSession);
+               return entry;
+       }
+
+       private synchronized void pushEntry(LogEntry entry) {
+               if (LogReader.isLogged(entry, fMemento)) {
+                       group(Collections.singletonList(entry));
+                       limitEntriesCount();
+               }
+               asyncRefresh(true);
+       }
+
+       private void asyncRefresh(final boolean activate) {
+               if (fTree.isDisposed())
+                       return;
+               Display display = fTree.getDisplay();
+               final ViewPart view = this;
+               if (display != null) {
+                       display.asyncExec(new Runnable() {
+                               public void run() {
+                                       if (!fTree.isDisposed()) {
+                                               fFilteredTree.getViewer().refresh();
+                                               fFilteredTree.getViewer().expandToLevel(fMemento.getInteger(P_EXPAND_LEVEL).intValue());
+                                               fDeleteLogAction.setEnabled(fInputFile.exists() && isPlatformLog(fInputFile));
+                                               fOpenLogAction.setEnabled(fInputFile.exists());
+                                               fExportAction.setEnabled(fInputFile.exists());
+                                               if (activate && fActivateViewAction.isChecked()) {
+                                                       IWorkbenchPage page = Activator.getDefault().getWorkbench().getActiveWorkbenchWindow().getActivePage();
+                                                       if (page != null)
+                                                               page.bringToTop(view);
+                                               }
+                                       }
+                               }
+                       });
+               }
+       }
+
+       public void setFocus() {
+               if (fFilteredTree != null && !fFilteredTree.isDisposed())
+                       fFilteredTree.setFocus();
+       }
+
+       private void handleSelectionChanged(ISelection selection) {
+               updateStatus(selection);
+               fCopyAction.setEnabled((!selection.isEmpty()) && ((IStructuredSelection) selection).getFirstElement() instanceof LogEntry);
+               fPropertiesAction.setEnabled(!selection.isEmpty());
+       }
+
+       private void updateStatus(ISelection selection) {
+               IStatusLineManager status = getViewSite().getActionBars().getStatusLineManager();
+               if (selection.isEmpty())
+                       status.setMessage(null);
+               else {
+                       Object element = ((IStructuredSelection) selection).getFirstElement();
+                       status.setMessage(((LogViewLabelProvider) fFilteredTree.getViewer().getLabelProvider()).getColumnText(element, 0));
+               }
+       }
+
+       /**
+        * Converts selected log view element to string.
+        * @return textual log entry representation or null if selection doesn't contain log entry
+        */
+       private static String selectionToString(ISelection selection) {
+               StringWriter writer = new StringWriter();
+               PrintWriter pwriter = new PrintWriter(writer);
+               if (selection.isEmpty())
+                       return null;
+               LogEntry entry = (LogEntry) ((IStructuredSelection) selection).getFirstElement();
+               entry.write(pwriter);
+               pwriter.flush();
+               String textVersion = writer.toString();
+               try {
+                       pwriter.close();
+                       writer.close();
+               } catch (IOException e) {
+                       // empty
+               }
+
+               return textVersion;
+       }
+
+       /**
+        * Copies selected element to clipboard.
+        */
+       private void copyToClipboard(ISelection selection) {
+               String textVersion = selectionToString(selection);
+               if ((textVersion != null) && (textVersion.trim().length() > 0)) {
+                       // set the clipboard contents
+                       fClipboard.setContents(new Object[] {textVersion}, new Transfer[] {TextTransfer.getInstance()});
+               }
+       }
+
+       public void init(IViewSite site, IMemento memento) throws PartInitException {
+               super.init(site, memento);
+               if (memento == null)
+                       this.fMemento = XMLMemento.createWriteRoot("LOGVIEW"); //$NON-NLS-1$
+               else
+                       this.fMemento = memento;
+               readSettings();
+
+               // initialize column ordering 
+               final byte type = this.fMemento.getInteger(P_ORDER_TYPE).byteValue();
+               switch (type) {
+                       case DATE :
+                               DATE_ORDER = this.fMemento.getInteger(P_ORDER_VALUE).intValue();
+                               MESSAGE_ORDER = DESCENDING;
+                               PLUGIN_ORDER = DESCENDING;
+                               break;
+                       case MESSAGE :
+                               MESSAGE_ORDER = this.fMemento.getInteger(P_ORDER_VALUE).intValue();
+                               DATE_ORDER = DESCENDING;
+                               PLUGIN_ORDER = DESCENDING;
+                               break;
+                       case PLUGIN :
+                               PLUGIN_ORDER = this.fMemento.getInteger(P_ORDER_VALUE).intValue();
+                               MESSAGE_ORDER = DESCENDING;
+                               DATE_ORDER = DESCENDING;
+                               break;
+                       default :
+                               DATE_ORDER = DESCENDING;
+                               MESSAGE_ORDER = DESCENDING;
+                               PLUGIN_ORDER = DESCENDING;
+               }
+               setComparator(fMemento.getInteger(P_ORDER_TYPE).byteValue());
+       }
+
+       private void initializeMemento() {
+        if (fMemento.getInteger(P_EXPAND_LEVEL) == null) {
+            fMemento.putInteger(P_EXPAND_LEVEL, DEFAULT_EXPAND_LEVEL);
+        }
+               if (fMemento.getString(P_USE_LIMIT) == null) {
+                       fMemento.putString(P_USE_LIMIT, "true"); //$NON-NLS-1$
+               }
+               if (fMemento.getInteger(P_LOG_LIMIT) == null) {
+                       fMemento.putInteger(P_LOG_LIMIT, 50);
+               }
+               if (fMemento.getString(P_LOG_INFO) == null) {
+                       fMemento.putString(P_LOG_INFO, "true"); //$NON-NLS-1$
+               }
+               if (fMemento.getString(P_LOG_WARNING) == null) {
+                       fMemento.putString(P_LOG_WARNING, "true"); //$NON-NLS-1$
+               }
+        if (fMemento.getString(P_LOG_ERROR) == null) {
+            fMemento.putString(P_LOG_ERROR, "true"); //$NON-NLS-1$
+        }
+        if (fMemento.getString(P_LOG_DEBUG) == null) {
+            fMemento.putString(P_LOG_DEBUG, "true"); //$NON-NLS-1$
+        }
+               if (fMemento.getString(P_SHOW_ALL_SESSIONS) == null) {
+                       fMemento.putString(P_SHOW_ALL_SESSIONS, "false"); //$NON-NLS-1$
+               }
+               Integer width = fMemento.getInteger(P_COLUMN_1);
+               if (width == null || width.intValue() == 0) {
+                       fMemento.putInteger(P_COLUMN_1, 300);
+               }
+               width = fMemento.getInteger(P_COLUMN_2);
+               if (width == null || width.intValue() == 0) {
+                       fMemento.putInteger(P_COLUMN_2, 150);
+               }
+               width = fMemento.getInteger(P_COLUMN_3);
+               if (width == null || width.intValue() == 0) {
+                       fMemento.putInteger(P_COLUMN_3, 150);
+               }
+               if (fMemento.getString(P_ACTIVATE) == null) {
+                       fMemento.putString(P_ACTIVATE, "false"); //$NON-NLS-1$
+               }
+               if (fMemento.getBoolean(P_SHOW_FILTER_TEXT) == null) {
+                       fMemento.putBoolean(P_SHOW_FILTER_TEXT, false);
+               }
+               fMemento.putInteger(P_ORDER_VALUE, DESCENDING);
+               fMemento.putInteger(P_ORDER_TYPE, DATE);
+               if (fMemento.getInteger(P_GROUP_BY) == null) {
+                       fMemento.putInteger(P_GROUP_BY, GROUP_BY_NONE);
+               }
+       }
+
+       public void saveState(IMemento memento) {
+               if (this.fMemento == null || memento == null)
+                       return;
+               this.fMemento.putInteger(P_COLUMN_1, fColumn1.getWidth());
+//             this.fMemento.putInteger(P_COLUMN_2, fColumn2.getWidth());
+//             this.fMemento.putInteger(P_COLUMN_3, fColumn3.getWidth());
+               this.fMemento.putString(P_ACTIVATE, fActivateViewAction.isChecked() ? "true" : "false"); //$NON-NLS-1$ //$NON-NLS-2$
+               memento.putMemento(this.fMemento);
+               writeSettings();
+       }
+
+       private void addMouseListeners() {
+               Listener tableListener = new Listener() {
+                       public void handleEvent(Event e) {
+                               switch (e.type) {
+                                       case SWT.MouseMove :
+                                               onMouseMove(e);
+                                               break;
+                                       case SWT.MouseHover :
+                                               onMouseHover(e);
+                                               break;
+                                       case SWT.MouseDown :
+                                               onMouseDown(e);
+                                               break;
+                               }
+                       }
+               };
+               int[] tableEvents = new int[] {SWT.MouseDown, SWT.MouseMove, SWT.MouseHover};
+               for (int i = 0; i < tableEvents.length; i++) {
+                       fTree.addListener(tableEvents[i], tableListener);
+               }
+       }
+
+       /**
+        * Adds drag source support to error log tree.
+        */
+       private void addDragSource() {
+               DragSource source = new DragSource(fTree, DND.DROP_COPY);
+               Transfer[] types = new Transfer[] {TextTransfer.getInstance()};
+               source.setTransfer(types);
+
+               source.addDragListener(new DragSourceAdapter() {
+
+                       public void dragStart(DragSourceEvent event) {
+                               ISelection selection = fFilteredTree.getViewer().getSelection();
+                               if (selection.isEmpty()) {
+                                       event.doit = false;
+                                       return;
+                               }
+
+                               AbstractEntry entry = (AbstractEntry) ((TreeSelection) selection).getFirstElement();
+                               if (!(entry instanceof LogEntry)) {
+                                       event.doit = false;
+                                       return;
+                               }
+                       }
+
+                       public void dragSetData(DragSourceEvent event) {
+                               if (!TextTransfer.getInstance().isSupportedType(event.dataType)) {
+                                       return;
+                               }
+
+                               ISelection selection = fFilteredTree.getViewer().getSelection();
+                               String textVersion = selectionToString(selection);
+                               event.data = textVersion;
+                       }
+               });
+       }
+
+       private void makeHoverShell() {
+               fTextShell = new Shell(fTree.getShell(), SWT.NO_FOCUS | SWT.ON_TOP | SWT.TOOL);
+               Display display = fTextShell.getDisplay();
+               fTextShell.setBackground(display.getSystemColor(SWT.COLOR_INFO_BACKGROUND));
+               GridLayout layout = new GridLayout(1, false);
+               int border = ((fTree.getShell().getStyle() & SWT.NO_TRIM) == 0) ? 0 : 1;
+               layout.marginHeight = border;
+               layout.marginWidth = border;
+               fTextShell.setLayout(layout);
+               fTextShell.setLayoutData(new GridData(GridData.FILL_HORIZONTAL));
+               Composite shellComposite = new Composite(fTextShell, SWT.NONE);
+               layout = new GridLayout();
+               layout.marginHeight = 0;
+               layout.marginWidth = 0;
+               shellComposite.setLayout(layout);
+               shellComposite.setLayoutData(new GridData(GridData.FILL_BOTH | GridData.VERTICAL_ALIGN_BEGINNING));
+               fTextLabel = new Text(shellComposite, SWT.WRAP | SWT.MULTI | SWT.READ_ONLY);
+               GridData gd = new GridData(GridData.FILL_BOTH);
+               gd.widthHint = 100;
+               gd.grabExcessHorizontalSpace = true;
+               fTextLabel.setLayoutData(gd);
+               Color c = fTree.getDisplay().getSystemColor(SWT.COLOR_INFO_BACKGROUND);
+               fTextLabel.setBackground(c);
+               c = fTree.getDisplay().getSystemColor(SWT.COLOR_INFO_FOREGROUND);
+               fTextLabel.setForeground(c);
+               fTextLabel.setEditable(false);
+               fTextShell.addDisposeListener(new DisposeListener() {
+                       public void widgetDisposed(DisposeEvent e) {
+                               onTextShellDispose(e);
+                       }
+               });
+       }
+
+       void onTextShellDispose(DisposeEvent e) {
+               fCanOpenTextShell = true;
+               setFocus();
+       }
+
+       void onMouseDown(Event e) {
+               if (fTextShell != null && !fTextShell.isDisposed() && !fTextShell.isFocusControl()) {
+                       fTextShell.setVisible(false);
+                       fCanOpenTextShell = true;
+               }
+       }
+
+       void onMouseHover(Event e) {
+               if (!fCanOpenTextShell || fTextShell == null || fTextShell.isDisposed())
+                       return;
+               fCanOpenTextShell = false;
+               Point point = new Point(e.x, e.y);
+               TreeItem item = fTree.getItem(point);
+               if (item == null)
+                       return;
+
+               String message = null;
+               if (item.getData() instanceof LogEntry) {
+                       message = ((LogEntry) item.getData()).getStack();
+               } else if (item.getData() instanceof LogSession) {
+                       LogSession session = ((LogSession) item.getData());
+                       message = Messages.LogView_SessionStarted;
+                       if (session.getDate() != null) {
+                               DateFormat formatter = new SimpleDateFormat(LogEntry.F_DATE_FORMAT);
+                               message += formatter.format(session.getDate());
+                       }
+               }
+
+               if (message == null)
+                       return;
+
+               fTextLabel.setText(message);
+               Rectangle bounds = fTree.getDisplay().getBounds();
+               Point cursorPoint = fTree.getDisplay().getCursorLocation();
+               int x = point.x;
+               int y = point.y + 25;
+               int width = fTree.getColumn(0).getWidth();
+               int height = 125;
+               if (cursorPoint.x + width > bounds.width)
+                       x -= width;
+               if (cursorPoint.y + height + 25 > bounds.height)
+                       y -= height + 27;
+
+               fTextShell.setLocation(fTree.toDisplay(x, y));
+               fTextShell.setSize(width, height);
+               fTextShell.setVisible(true);
+       }
+
+       void onMouseMove(Event e) {
+               if (fTextShell != null && !fTextShell.isDisposed() && fTextShell.isVisible())
+                       fTextShell.setVisible(false);
+
+               Point point = new Point(e.x, e.y);
+               TreeItem item = fTree.getItem(point);
+               if (item == null)
+                       return;
+               Image image = item.getImage();
+               Object data = item.getData();
+               if (data instanceof LogEntry) {
+                       LogEntry entry = (LogEntry) data;
+                       int parentCount = getNumberOfParents(entry);
+                       int startRange = 20 + Math.max(image.getBounds().width + 2, 7 + 2) * parentCount;
+                       int endRange = startRange + 16;
+                       fCanOpenTextShell = e.x >= startRange && e.x <= endRange;
+               }
+       }
+
+       private int getNumberOfParents(AbstractEntry entry) {
+               AbstractEntry parent = (AbstractEntry) entry.getParent(entry);
+               if (parent == null)
+                       return 0;
+               return 1 + getNumberOfParents(parent);
+       }
+
+       public Comparator<Object> getComparator() {
+               return fComparator;
+       }
+
+       private void setComparator(byte sortType) {
+               if (sortType == DATE) {
+                       fComparator = new Comparator<Object>() {
+                               public int compare(Object e1, Object e2) {
+                                       long date1 = 0;
+                                       long date2 = 0;
+                                       if ((e1 instanceof LogEntry) && (e2 instanceof LogEntry)) {
+                                               date1 = ((LogEntry) e1).getDate().getTime();
+                                               date2 = ((LogEntry) e2).getDate().getTime();
+                                       } else if ((e1 instanceof LogSession) && (e2 instanceof LogSession)) {
+                                               date1 = ((LogSession) e1).getDate() == null ? 0 : ((LogSession) e1).getDate().getTime();
+                                               date2 = ((LogSession) e2).getDate() == null ? 0 : ((LogSession) e2).getDate().getTime();
+                                       }
+                                       if (date1 == date2) {
+                                               int result = elements.indexOf(e2) - elements.indexOf(e1);
+                                               if (DATE_ORDER == DESCENDING)
+                                                       result *= DESCENDING;
+                                               return result;
+                                       }
+                                       if (DATE_ORDER == DESCENDING)
+                                               return date1 > date2 ? DESCENDING : ASCENDING;
+                                       return date1 < date2 ? DESCENDING : ASCENDING;
+                               }
+                       };
+               } else if (sortType == PLUGIN) {
+                       fComparator = new Comparator<Object>() {
+                               public int compare(Object e1, Object e2) {
+                                       if ((e1 instanceof LogEntry) && (e2 instanceof LogEntry)) {
+                                               LogEntry entry1 = (LogEntry) e1;
+                                               LogEntry entry2 = (LogEntry) e2;
+                                               return getDefaultComparator().compare(entry1.getPluginId(), entry2.getPluginId()) * PLUGIN_ORDER;
+                                       }
+                                       return 0;
+                               }
+                       };
+               } else {
+                       fComparator = new Comparator<Object>() {
+                               public int compare(Object e1, Object e2) {
+                                       if ((e1 instanceof LogEntry) && (e2 instanceof LogEntry)) {
+                                               LogEntry entry1 = (LogEntry) e1;
+                                               LogEntry entry2 = (LogEntry) e2;
+                                               return getDefaultComparator().compare(entry1.getMessage(), entry2.getMessage()) * MESSAGE_ORDER;
+                                       }
+                                       return 0;
+                               }
+                       };
+               }
+       }
+
+       @SuppressWarnings("unchecked")
+    private Comparator<Object> getDefaultComparator() {
+               return Policy.getComparator();
+       }
+
+       private ViewerComparator getViewerComparator(byte sortType) {
+               if (sortType == PLUGIN) {
+                       return new ViewerComparator() {
+                               @SuppressWarnings("unchecked")
+                public int compare(Viewer viewer, Object e1, Object e2) {
+                                       if ((e1 instanceof LogEntry) && (e2 instanceof LogEntry)) {
+                                               LogEntry entry1 = (LogEntry) e1;
+                                               LogEntry entry2 = (LogEntry) e2;
+                                               return getComparator().compare(entry1.getPluginId(), entry2.getPluginId()) * PLUGIN_ORDER;
+                                       }
+                                       return 0;
+                               }
+                       };
+               } else if (sortType == MESSAGE) {
+                       return new ViewerComparator() {
+                               @SuppressWarnings("unchecked")
+                public int compare(Viewer viewer, Object e1, Object e2) {
+                                       if ((e1 instanceof LogEntry) && (e2 instanceof LogEntry)) {
+                                               LogEntry entry1 = (LogEntry) e1;
+                                               LogEntry entry2 = (LogEntry) e2;
+                                               return getComparator().compare(entry1.getMessage(), entry2.getMessage()) * MESSAGE_ORDER;
+                                       }
+                                       return 0;
+                               }
+                       };
+               } else {
+                       return new ViewerComparator() {
+                           private int indexOf(Object[] array, Object o) {
+                               if (o == null)
+                                   return -1;
+                               for (int i = 0; i < array.length; ++i)
+                                   if (o.equals(array[i]))
+                                       return i;
+                               return -1;
+                           }
+                           
+                               public int compare(Viewer viewer, Object e1, Object e2) {
+                                       long date1 = 0;
+                                       long date2 = 0;
+                                       if ((e1 instanceof LogEntry) && (e2 instanceof LogEntry)) {
+                                               date1 = ((LogEntry) e1).getDate().getTime();
+                                               date2 = ((LogEntry) e2).getDate().getTime();
+                                       } else if ((e1 instanceof LogSession) && (e2 instanceof LogSession)) {
+                                               date1 = ((LogSession) e1).getDate() == null ? 0 : ((LogSession) e1).getDate().getTime();
+                                               date2 = ((LogSession) e2).getDate() == null ? 0 : ((LogSession) e2).getDate().getTime();
+                                       }
+
+                                       if (date1 == date2) {
+                           // Everything that appears in logview should be an AbstractEntry.
+                           AbstractEntry parent = (AbstractEntry) ((AbstractEntry) e1).getParent(null);
+                        Object[] children = null;
+                           if (parent != null)
+                               children = parent.getChildren(parent);
+                                           
+                                           int result = 0;
+                                           if (children != null) {
+                                               // The elements in children seem to be in reverse order,
+                                               // i.e. latest log message first, therefore index(e2)-index(e1)
+                            result = indexOf(children, e2) - indexOf(children, e1);
+                                           } else {
+                               result = elements.indexOf(e1) - elements.indexOf(e2);
+                                           }
+                                               if (DATE_ORDER == DESCENDING)
+                                                       result *= DESCENDING;
+                                               return result;
+                                       }
+                                       if (DATE_ORDER == DESCENDING)
+                                               return date1 > date2 ? DESCENDING : ASCENDING;
+                                       return date1 < date2 ? DESCENDING : ASCENDING;
+                               }
+                       };
+               }
+       }
+
+       private void resetDialogButtons() {
+               ((EventDetailsDialogAction) fPropertiesAction).resetDialogButtons();
+       }
+
+       /**
+        * Returns the filter dialog settings object used to maintain
+        * state between filter dialogs
+        * @return the dialog settings to be used
+        */
+       private IDialogSettings getLogSettings() {
+               IDialogSettings settings = Activator.getDefault().getDialogSettings();
+               return settings.getSection(getClass().getName());
+       }
+
+       /**
+        * Returns the plugin preferences used to maintain
+        * state of log view
+        * @return the plugin preferences
+        */
+       private Preferences getLogPreferences() {
+               return Activator.getDefault().getPluginPreferences();
+       }
+
+       private void readSettings() {
+               IDialogSettings s = getLogSettings();
+               Preferences p = getLogPreferences();
+               if (s == null || p == null) {
+                       initializeMemento();
+                       return;
+               }
+               try {
+                       fMemento.putString(P_USE_LIMIT, s.getBoolean(P_USE_LIMIT) ? "true" : "false"); //$NON-NLS-1$ //$NON-NLS-2$
+                       fMemento.putString(P_LOG_INFO, s.getBoolean(P_LOG_INFO) ? "true" : "false"); //$NON-NLS-1$ //$NON-NLS-2$
+                       fMemento.putString(P_LOG_WARNING, s.getBoolean(P_LOG_WARNING) ? "true" : "false"); //$NON-NLS-1$ //$NON-NLS-2$
+            fMemento.putString(P_LOG_ERROR, s.getBoolean(P_LOG_ERROR) ? "true" : "false"); //$NON-NLS-1$ //$NON-NLS-2$
+            fMemento.putString(P_LOG_DEBUG, s.getBoolean(P_LOG_DEBUG) ? "true" : "false"); //$NON-NLS-1$ //$NON-NLS-2$
+                       fMemento.putString(P_SHOW_ALL_SESSIONS, s.getBoolean(P_SHOW_ALL_SESSIONS) ? "true" : "false"); //$NON-NLS-1$ //$NON-NLS-2$
+            fMemento.putInteger(P_LOG_LIMIT, s.getInt(P_LOG_LIMIT));
+                       fMemento.putInteger(P_COLUMN_1, p.getInt(P_COLUMN_1) > 0 ? p.getInt(P_COLUMN_1) : 300);
+                       fMemento.putInteger(P_COLUMN_2, p.getInt(P_COLUMN_2) > 0 ? p.getInt(P_COLUMN_2) : 150);
+                       fMemento.putInteger(P_COLUMN_3, p.getInt(P_COLUMN_3) > 0 ? p.getInt(P_COLUMN_3) : 150);
+                       fMemento.putString(P_ACTIVATE, p.getBoolean(P_ACTIVATE) ? "true" : "false"); //$NON-NLS-1$ //$NON-NLS-2$
+                       int order = p.getInt(P_ORDER_VALUE);
+                       fMemento.putInteger(P_ORDER_VALUE, order == 0 ? DESCENDING : order);
+                       fMemento.putInteger(P_ORDER_TYPE, p.getInt(P_ORDER_TYPE));
+                       fMemento.putBoolean(P_SHOW_FILTER_TEXT, p.getBoolean(P_SHOW_FILTER_TEXT));
+                       fMemento.putInteger(P_GROUP_BY, p.getInt(P_GROUP_BY));
+            fMemento.putInteger(P_EXPAND_LEVEL, s.getInt(P_EXPAND_LEVEL));
+               } catch (NumberFormatException e) {
+            fMemento.putInteger(P_EXPAND_LEVEL, DEFAULT_EXPAND_LEVEL);
+                       fMemento.putInteger(P_LOG_LIMIT, 50);
+                       fMemento.putInteger(P_COLUMN_1, 300);
+                       fMemento.putInteger(P_COLUMN_2, 150);
+                       fMemento.putInteger(P_COLUMN_3, 150);
+                       fMemento.putInteger(P_ORDER_TYPE, DATE);
+                       fMemento.putInteger(P_ORDER_VALUE, DESCENDING);
+                       fMemento.putInteger(P_GROUP_BY, GROUP_BY_NONE);
+               }
+       }
+
+       private void writeSettings() {
+               writeViewSettings();
+               writeFilterSettings();
+       }
+
+       private void writeFilterSettings() {
+               IDialogSettings settings = getLogSettings();
+               if (settings == null)
+                       settings = Activator.getDefault().getDialogSettings().addNewSection(getClass().getName());
+               settings.put(P_USE_LIMIT, fMemento.getString(P_USE_LIMIT).equals("true")); //$NON-NLS-1$
+        settings.put(P_LOG_LIMIT, fMemento.getInteger(P_LOG_LIMIT).intValue());
+               settings.put(P_LOG_INFO, fMemento.getString(P_LOG_INFO).equals("true")); //$NON-NLS-1$
+               settings.put(P_LOG_WARNING, fMemento.getString(P_LOG_WARNING).equals("true")); //$NON-NLS-1$
+        settings.put(P_LOG_ERROR, fMemento.getString(P_LOG_ERROR).equals("true")); //$NON-NLS-1$
+        settings.put(P_LOG_DEBUG, fMemento.getString(P_LOG_DEBUG).equals("true")); //$NON-NLS-1$
+               settings.put(P_SHOW_ALL_SESSIONS, fMemento.getString(P_SHOW_ALL_SESSIONS).equals("true")); //$NON-NLS-1$
+       }
+
+       private void writeViewSettings() {
+               Preferences preferences = getLogPreferences();
+               preferences.setValue(P_COLUMN_1, fMemento.getInteger(P_COLUMN_1).intValue());
+               preferences.setValue(P_COLUMN_2, fMemento.getInteger(P_COLUMN_2).intValue());
+               preferences.setValue(P_COLUMN_3, fMemento.getInteger(P_COLUMN_3).intValue());
+               preferences.setValue(P_ACTIVATE, fMemento.getString(P_ACTIVATE).equals("true")); //$NON-NLS-1$
+               int order = fMemento.getInteger(P_ORDER_VALUE).intValue();
+               preferences.setValue(P_ORDER_VALUE, order == 0 ? DESCENDING : order);
+               preferences.setValue(P_ORDER_TYPE, fMemento.getInteger(P_ORDER_TYPE).intValue());
+               preferences.setValue(P_SHOW_FILTER_TEXT, fMemento.getBoolean(P_SHOW_FILTER_TEXT).booleanValue());
+               preferences.setValue(P_GROUP_BY, fMemento.getInteger(P_GROUP_BY).intValue());
+        preferences.setValue(P_EXPAND_LEVEL, fMemento.getInteger(P_EXPAND_LEVEL).intValue());
+       }
+
+       public void sortByDateDescending() {
+               setColumnSorting(fColumn3, DESCENDING);
+       }
+
+       protected Job getOpenLogFileJob() {
+               final Shell shell = getViewSite().getShell();
+               return new Job(Messages.OpenLogDialog_message) {
+                       protected IStatus run(IProgressMonitor monitor) {
+                               boolean failed = false;
+                               if (fInputFile.length() <= LogReader.MAX_FILE_LENGTH) {
+                                       failed = !Program.launch(fInputFile.getAbsolutePath());
+                                       if (failed) {
+                                               Program p = Program.findProgram(".txt"); //$NON-NLS-1$
+                                               if (p != null) {
+                                                       p.execute(fInputFile.getAbsolutePath());
+                                                       return Status.OK_STATUS;
+                                               }
+                                       }
+                               }
+                               if (failed) {
+                                       final OpenLogDialog openDialog = new OpenLogDialog(shell, fInputFile);
+                                       Display.getDefault().asyncExec(new Runnable() {
+                                               public void run() {
+                                                       openDialog.create();
+                                                       openDialog.open();
+                                               }
+                                       });
+                               }
+                               return Status.OK_STATUS;
+                       }
+               };
+       }
+
+       protected File getLogFile() {
+               return fInputFile;
+       }
+
+       /**
+        * Returns whether given session equals to currently displayed in LogView.
+        * @param session LogSession
+        * @return true if given session equals to currently displayed in LogView
+        */
+       public boolean isCurrentLogSession(LogSession session) {
+               return isPlatformLogOpen() && (currentSession != null) && (currentSession.equals(session));
+       }
+
+    /**
+     * Returns whether currently open log is platform log or imported file.
+     * @return true if currently open log is platform log, false otherwise
+     */
+    public boolean isPlatformLogOpen() {
+        return isPlatformLog(fInputFile);
+    }
+
+    /**
+     * Returns whether currently open log is platform log or imported file.
+     * @return true if currently open log is platform log, false otherwise
+     */
+    public boolean isPlatformLog(File file) {
+        return (file.equals(getPlatformLogFile()));
+    }
+    
+    public File getPlatformLogFile() {
+        return org.simantics.message.internal.Activator.getLogFile();
+    }
+}