/*******************************************************************************
* Copyright (c) 2007, 2010 Association for Decentralized Information Management
* in Industry THTH ry.
* All rights reserved. This program and the accompanying materials
* are made available under the terms of the Eclipse Public License v1.0
* which accompanies this distribution, and is available at
* http://www.eclipse.org/legal/epl-v10.html
*
* Contributors:
* VTT Technical Research Centre of Finland - initial API and implementation
*******************************************************************************/
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 LogView
for our own purposes.
*
*
* The only thing that has changed is the the dependence on
* Activator.getLogFile()
instead of
* Platform.getLogFileLocation()
.
*
* @author Tuukka Lehtonen
* @see org.eclipse.ui.internal.views.LogView
*/
@SuppressWarnings("deprecation")
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 elements;
private Map groups;
private LogSession currentSession;
private List batchedEntries;
private boolean batchEntries;
private Clipboard fClipboard;
private IMemento fMemento;
private File fInputFile;
private String fDirectory;
private Comparator fComparator;
// hover text
private boolean fCanOpenTextShell;
private Text fTextLabel;
private Shell fTextShell;
private boolean fFirstEvent = true;
private TreeColumn fColumn1;
@SuppressWarnings("unused")
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();
groups = new HashMap();
batchedEntries = new ArrayList();
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("Select a message to show its description here.
"); //$NON-NLS-1$
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)) { //$NON-NLS-1$
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("Select a message to show its description here. "); //$NON-NLS-1$
} 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( NLS.bind(Messages.LogView_Truncated, msg.length() - (Short.MAX_VALUE - 100), msg.length()));
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")
private Action createTestAction() {
Action action = new Action("Test") { //$NON-NLS-1$
public void run() {
IStatus s1 = new Status(IStatus.INFO, Activator.PLUGIN_ID, "Test message 1", null); //$NON-NLS-1$
IStatus s2 = new Status(IStatus.WARNING, Activator.PLUGIN_ID, "Test message 2", null); //$NON-NLS-1$
IStatus s3 = new DetailStatus(IStatus.ERROR, Activator.PLUGIN_ID, "This is the short message.", HtmlUtil.p("A multi-lined message...\n continuing... still... Error occurred, report at {0}" + HtmlUtil.a("http://www.simantics.org", "simantics.org")), null); //$NON-NLS-3$ //$NON-NLS-4$ //$NON-NLS-1$ //$NON-NLS-2$ //$NON-NLS-1$ //$NON-NLS-1$
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()); //$NON-NLS-1$
s4.merge(new Status(IStatus.INFO, Activator.PLUGIN_ID, "MultiStatus Test 1", null)); //$NON-NLS-1$
s4.merge(new Status(IStatus.WARNING, Activator.PLUGIN_ID, "MultiStatus Test 2", null)); //$NON-NLS-1$
s4.merge(new Status(IStatus.ERROR, Activator.PLUGIN_ID, "MultiStatus Test 3", null)); //$NON-NLS-1$
MessageService.defaultLog(s4);
// Activator.getDefault().getLog().log(s4);
}
};
action.setImageDescriptor(ImageDescriptor.getMissingImageDescriptor());
action.setToolTipText("Produce test log entries"); //$NON-NLS-1$
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();
createColumns(fTree);
fTree.setLinesVisible(true);
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 result = new ArrayList();
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 ""; //$NON-NLS-1$
}
Map sources = LogFilesManager.getLogSources();
if (sources.containsValue(path)) {
for (Iterator 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 dateComparator = new Comparator() {
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 copy = new ArrayList(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 getComparator() {
return fComparator;
}
private void setComparator(byte sortType) {
if (sortType == DATE) {
fComparator = new Comparator() {
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() {
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() {
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 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();
}
}