package org.jactr.eclipse.runtime.ui.log2; /* * default logging */ import java.util.ArrayList; import java.util.Arrays; import java.util.Collection; import java.util.Optional; import org.apache.commons.logging.Log; import org.apache.commons.logging.LogFactory; import org.eclipse.jface.action.ActionContributionItem; import org.eclipse.jface.action.IAction; import org.eclipse.jface.action.IContributionItem; import org.eclipse.jface.preference.PreferenceConverter; import org.eclipse.jface.viewers.ISelection; import org.eclipse.jface.viewers.ISelectionChangedListener; import org.eclipse.jface.viewers.SelectionChangedEvent; import org.eclipse.jface.viewers.StructuredSelection; import org.eclipse.jface.viewers.TableViewer; import org.eclipse.swt.SWT; import org.eclipse.swt.custom.SashForm; import org.eclipse.swt.custom.StyleRange; import org.eclipse.swt.custom.StyledText; 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.graphics.Color; import org.eclipse.swt.graphics.Font; import org.eclipse.swt.graphics.RGB; import org.eclipse.swt.layout.FillLayout; import org.eclipse.swt.widgets.Composite; import org.eclipse.swt.widgets.Display; import org.eclipse.swt.widgets.Table; import org.eclipse.swt.widgets.TableColumn; import org.eclipse.ui.IViewSite; import org.eclipse.ui.PartInitException; import org.jactr.core.logging.Logger; import org.jactr.eclipse.runtime.RuntimePlugin; import org.jactr.eclipse.runtime.log2.ILogSessionDataStream; import org.jactr.eclipse.runtime.log2.LogData; import org.jactr.eclipse.runtime.session.data.ISessionData; import org.jactr.eclipse.runtime.session.stream.ISessionDataStream; import org.jactr.eclipse.runtime.ui.log2.live.ColumnListener; import org.jactr.eclipse.runtime.ui.log2.live.LiveLogDataContentProvider; import org.jactr.eclipse.runtime.ui.misc.AbstractRuntimeModelViewPart; import org.jactr.eclipse.runtime.ui.selection.SessionTimeSelection; import org.jactr.eclipse.runtime.ui.selection.SessionTimeSelectionProvider; public class ModelLogView2 extends AbstractRuntimeModelViewPart { /** * Logger definition */ static private final transient Log LOGGER = LogFactory .getLog(ModelLogView2.class); static public final String ID = ModelLogView2.class .getName(); static private String[] _expectedStreams = { Logger.Stream.TIME.name(), "MARKERS", Logger.Stream.OUTPUT.name(), Logger.Stream.GOAL.name(), Logger.Stream.IMAGINAL.name(), Logger.Stream.RETRIEVAL.name(), Logger.Stream.PROCEDURAL.name(), Logger.Stream.DECLARATIVE.name(), Logger.Stream.VISUAL.name(), Logger.Stream.AURAL.name(), Logger.Stream.MOTOR.name() }; private Color EXCEPTION_COLOR = new Color( Display.getCurrent(), new RGB(128, 0, 0)); private StyledText _reader; @Override public void dispose() { super.dispose(); EXCEPTION_COLOR.dispose(); } @Override public void init(IViewSite viewSite) throws PartInitException { super.init(viewSite); viewSite.setSelectionProvider(new SessionTimeSelectionProvider()); } @Override public void createPartControl(Composite parent) { /* * instead of create the models view folder as the primary, we create a sash * and stick it in there.. */ SashForm sashForm = new SashForm(parent, SWT.BORDER | SWT.VERTICAL); sashForm.setLayout(new FillLayout()); createModelViewsFolder(sashForm); /* * and the other component is the reader */ createReader(sashForm); partControlCreated(); } protected boolean hasLogData(ISessionData sessionData) { ILogSessionDataStream lsds = (ILogSessionDataStream) sessionData .getDataStream("log"); return lsds != null; } @Override protected Composite createModelComposite(String modelName, Object modelData, Composite parent) { if (LOGGER.isDebugEnabled()) LOGGER.debug(String.format("Creating log ui for %s", modelName)); ISessionData sessionData = (ISessionData) modelData; ILogSessionDataStream lsds = (ILogSessionDataStream) sessionData .getDataStream("log"); /* * just because a session is opened, and is even expecting log data, there * might not be any log data just yet. */ if (lsds == null) { if (LOGGER.isDebugEnabled()) LOGGER.debug(String.format("No log data available for %s jsut yet", modelName)); if (sessionData.isOpen()) { if (!wasDeferred(modelData)) { if (LOGGER.isDebugEnabled()) LOGGER.debug(String.format("Deferring add of %s", modelName)); deferAdd(modelName, modelData, 500); } else { if (LOGGER.isDebugEnabled()) LOGGER.debug(String.format( "%s Was previous deferred, assuming no data is coming.", modelName)); removeDeferred(modelData); } } else { if (LOGGER.isDebugEnabled()) LOGGER.debug(String.format("Session data is closed, ignoring %s", modelName)); removeDeferred(modelData); } return null; } /* * create the sash */ TableViewer viewer = createTableViewer(parent, lsds); viewer.setData("sessionData", sessionData); configureTable(viewer.getTable()); /* * this needs to be done last */ viewer.setInput(lsds); return viewer.getTable(); } protected void createReader(Composite parent) { _reader = new StyledText(parent, SWT.HORIZONTAL | SWT.VERTICAL); Font font = new Font(parent.getDisplay(), PreferenceConverter.getFontDataArray(RuntimePlugin.getDefault() .getPreferenceStore(), "log.font")); _reader.setFont(font); _reader.setEditable(false); /* * clean up the font */ _reader.addDisposeListener(new DisposeListener() { public void widgetDisposed(DisposeEvent e) { _reader.getFont().dispose(); } }); } protected TableViewer createTableViewer(Composite parent, ISessionDataStream<LogData> logStream) { /* * if the data is coming in live, we need a rolling content provider */ int properties = SWT.FULL_SELECTION | SWT.H_SCROLL | SWT.V_SCROLL | SWT.BORDER; final TableViewer viewer = new TableViewer(parent, properties); viewer.setLabelProvider(new TableLabelProvider(viewer.getTable())); // if (logStream instanceof ILiveSessionDataStream) LiveLogDataContentProvider contentProvider = new LiveLogDataContentProvider( viewer); viewer.setContentProvider(contentProvider); contentProvider.addColumnListener(new ColumnListener() { @Override public void added(final TableColumn column) { boolean updateActionBars = createActionForColumnOrAddColumnToExistingAction( viewer.getTable(), column, column.getText()); if (updateActionBars) getViewSite().getActionBars().updateActionBars(); } }); viewer.addSelectionChangedListener(new ISelectionChangedListener() { @SuppressWarnings("unchecked") public void selectionChanged(SelectionChangedEvent event) { ISelection selection = event.getSelection(); boolean clearContent = true; if (selection != null) { LogData row = (LogData) ((StructuredSelection) selection) .getFirstElement(); if (row != null) { clearContent = false; Collection<StyleRange> ranges = new ArrayList<StyleRange>(); StringBuilder sb = new StringBuilder(); for (String stream : row.getStreamNames()) { String content = row.get(stream); StyleRange streamStyle = new StyleRange(); streamStyle.start = sb.length(); sb.append(stream); streamStyle.length = stream.length(); streamStyle.fontStyle = SWT.BOLD | SWT.ITALIC; sb.append("\t:\t"); content = content.replace("\n", "\n\t\t\t\t"); if (stream.equalsIgnoreCase("exception")) { // need another style StyleRange oops = new StyleRange(); oops.start = sb.length(); oops.length = content.length(); oops.fontStyle = SWT.BOLD; oops.foreground = EXCEPTION_COLOR; ranges.add(oops); } sb.append(content); sb.append("\n"); ranges.add(streamStyle); } _reader.setText(sb.toString()); for (StyleRange style : ranges) _reader.setStyleRange(style); /* * propogate time selection event. */ TableViewer viewer = (TableViewer) event.getSelectionProvider(); ISessionData sessionData = (ISessionData) viewer .getData("sessionData"); String model = sessionData.getModelName(); getViewSite().getSelectionProvider().setSelection( new SessionTimeSelection(sessionData.getSession(), model, row .getTime())); } } if (clearContent) { _reader.setText(""); StyleRange streamStyle = new StyleRange(); streamStyle.start = 0; streamStyle.length = 0; streamStyle.fontStyle = SWT.NORMAL; _reader.setStyleRange(streamStyle); if (selection.isEmpty()) getViewSite().getSelectionProvider().setSelection( SessionTimeSelection.EMPTY); } } }); return viewer; } protected void configureTable(Table table) { table.setLinesVisible(true); table.setHeaderVisible(true); /* * populate the column headers & pack */ boolean updateActionBars = false; for (String stream : _expectedStreams) { TableColumn column = new TableColumn(table, SWT.LEFT); column.setText(stream); column.setMoveable(true); // column.setResizable(!stream.equals("TIME")); // if (stream.equals("TIME")) column.setWidth(TIME_COLUMN_WIDTH); updateActionBars |= createActionForColumnOrAddColumnToExistingAction( table, column, stream); } if (updateActionBars) getViewSite().getActionBars().updateActionBars(); table.addControlListener(new ControlAdapter() { @Override public void controlResized(ControlEvent ce) { adjustColumnSizes((Table) ce.widget); } }); table.pack(); } /** * @return True, if the action bars need to be updated. False, if not. */ protected boolean createActionForColumnOrAddColumnToExistingAction( Table table, TableColumn column, String columnText) { boolean updateActionBars = false; IToggleColumnAction action = getActionFor(columnText); if (action == null) { getViewSite().getActionBars().getMenuManager() .add(new ToggleColumnAction(this, table, column)); updateActionBars = true; } else action.add(column, table); return updateActionBars; } protected void adjustColumnSizes(Table table) { int resizableColumns = 0; int timeWidth = 0; for (TableColumn column : table.getColumns()) if (column.getText().equals("TIME")) { timeWidth = column.getWidth(); if (timeWidth <= 15) { timeWidth = 0; // effectively. resizableColumns++; } } else if (column.getResizable()) resizableColumns++; /* * resize */ // int size = (table.getClientArea().width - TIME_COLUMN_WIDTH) // / resizableColumns; int size = (table.getClientArea().width - timeWidth) / resizableColumns; table.setRedraw(false); for (TableColumn column : table.getColumns()) if (column.getResizable() && (!column.getText().equals("TIME") || timeWidth == 0)) column.setWidth(size); table.setRedraw(true); } @Override protected void disposeModelComposite(String modelName, Object modelData, Composite content) { content.dispose(); } @Override protected void newSessionData(ISessionData sessionData) { deferAdd(sessionData.getModelName(), sessionData, 250); } private IToggleColumnAction getActionFor(String columnName) { Optional<IContributionItem> firstMatchingItem = Arrays .stream(getViewSite().getActionBars().getMenuManager().getItems()) .filter( item -> { IAction action = null; boolean hasAction = item instanceof ActionContributionItem && (action = ((ActionContributionItem) item).getAction()) instanceof IToggleColumnAction && ((IToggleColumnAction) action).getColumnText().equals( columnName); return hasAction; }).findFirst(); if (firstMatchingItem.isPresent()) return (IToggleColumnAction) ((ActionContributionItem) firstMatchingItem .get()).getAction(); else return null; } }