/******************************************************************************* * 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.

"); 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("
Select a message to show its description here.
"); } 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") 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
continuing...

still...
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(); 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 ""; } 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(); } }