Revision 34a5b297

View differences:

ide/sequencechart/META-INF/MANIFEST.MF
1
Manifest-Version: 1.0
2
Bundle-Name: OMNeT++ Sequence Chart
3
Bundle-Activator: org.omnetpp.sequencechart.SequenceChartPlugin
4
Bundle-Vendor: OpenSim Ltd.
5
Bundle-ManifestVersion: 2
6
Bundle-SymbolicName: org.omnetpp.sequencechart;singleton:=true
7
Export-Package: org.omnetpp.sequencechart,org.omnetpp.sequencechart.ed
8
 itors,org.omnetpp.sequencechart.widgets
9
Require-Bundle: org.eclipse.core.resources,
10
 org.eclipse.core.runtime,
11
 org.eclipse.ui,
12
 org.eclipse.ui.ide,
13
 org.eclipse.ui.views,
14
 org.eclipse.ui.editors,
15
 org.eclipse.jface.text,
16
 org.eclipse.draw2d,
17
 org.eclipse.ui.workbench.texteditor,
18
 org.omnetpp.common;resolution:=optional,
19
 org.omnetpp.ide.nativelibs,
20
 org.apache.batik.svggen;bundle-version="1.6.0";resolution:=optional,
21
 org.apache.batik.ext.awt;bundle-version="1.6.0";resolution:=optional,
22
 org.apache.batik.util;bundle-version="1.6.0";resolution:=optional,
23
 org.eclipse.gmf.runtime.draw2d.ui;bundle-version="1.1.0";resolution:=optional,
24
 org.eclipse.gmf.runtime.draw2d.ui.render;bundle-version="1.1.0";resolution:=optional,
25
 org.eclipse.gmf.runtime.draw2d.ui.render.awt;bundle-version="1.1.0";resolution:=optional
26
Bundle-Version: 4.1.0.100611-4b63c38
27
Eclipse-LazyStart: true
ide/sequencechart/build.properties
1
source.. = src/
2
output.. = bin/
3
bin.includes = META-INF/,\
4
               .,\
5
               lib/,\
6
               icons/,\
7
               plugin.properties
ide/sequencechart/plugin.properties
1
##Source Bundle Localization
2
#Fri Jun 11 18:46:14 CEST 2010
3
providerName=OpenSim Ltd.
4
pluginName=OMNeT++ Sequence Chart
ide/sequencechart/src/org/omnetpp/sequencechart/SequenceChartPlugin.java
1
/*--------------------------------------------------------------*
2
  Copyright (C) 2006-2008 OpenSim Ltd.
3

  
4
  This file is distributed WITHOUT ANY WARRANTY. See the file
5
  'License' for details on this and other legal matters.
6
*--------------------------------------------------------------*/
7

  
8
package org.omnetpp.sequencechart;
9

  
10
import org.eclipse.core.runtime.IStatus;
11
import org.eclipse.core.runtime.Status;
12
import org.eclipse.jface.resource.ImageDescriptor;
13
import org.eclipse.jface.resource.ImageRegistry;
14
import org.eclipse.swt.graphics.Image;
15
import org.eclipse.ui.plugin.AbstractUIPlugin;
16
import org.osgi.framework.BundleContext;
17

  
18
/**
19
 * The activator class controls the plug-in life cycle
20
 */
21
public class SequenceChartPlugin extends AbstractUIPlugin {
22

  
23
	// The plug-in ID
24
	public static String PLUGIN_ID;
25

  
26
	// The shared instance
27
	private static SequenceChartPlugin plugin;
28

  
29
	/**
30
	 * The constructor
31
	 */
32
	public SequenceChartPlugin() {
33
		plugin = this;
34
	}
35

  
36
	/*
37
	 * (non-Javadoc)
38
	 * @see org.eclipse.ui.plugin.AbstractUIPlugin#start(org.osgi.framework.BundleContext)
39
	 */
40
	@Override
41
    public void start(BundleContext context) throws Exception {
42
		super.start(context);
43
        PLUGIN_ID = getBundle().getSymbolicName();
44
	}
45

  
46
	/*
47
	 * (non-Javadoc)
48
	 * @see org.eclipse.ui.plugin.AbstractUIPlugin#stop(org.osgi.framework.BundleContext)
49
	 */
50
	@Override
51
    public void stop(BundleContext context) throws Exception {
52
		plugin = null;
53
		super.stop(context);
54
	}
55

  
56
	/**
57
	 * Logs an exception into the platform log file.
58
	 */
59
	public void logException(Throwable ex) {
60
		getLog().log(new Status(IStatus.ERROR, PLUGIN_ID, IStatus.OK, "An exception occurred", ex));
61
	}
62

  
63
	/**
64
	 * Returns the shared instance
65
	 *
66
	 * @return the shared instance
67
	 */
68
	public static SequenceChartPlugin getDefault() {
69
		return plugin;
70
	}
71

  
72
	/**
73
	 * Returns an image descriptor for the image file at the given
74
	 * plug-in relative path.
75
	 */
76
	public static ImageDescriptor getImageDescriptor(String path) {
77
		return imageDescriptorFromPlugin(PLUGIN_ID, path);
78
	}
79

  
80
	/**
81
	 * Creates an image. IMPORTANT: The image is NOT cached! Callers
82
	 * are responsible for disposal of the image.
83
	 */
84
	public static Image getImage(String path) {
85
		ImageDescriptor id = getImageDescriptor(path);
86
		if (id == null) {
87
			IllegalArgumentException e = new IllegalArgumentException("Cannot load image from: "+path);
88
			logError(e);
89
			throw e;
90
		}
91
		return id.createImage();
92
	}
93

  
94
	/**
95
	 * Like getImage(), but the image gets cached in an internal image registry,
96
	 * so clients do not need to (moreover, must not) dispose of the image.
97
	 */
98
	public static Image getCachedImage(String path) {
99
		ImageRegistry imageRegistry = getDefault().getImageRegistry();
100
		Image image = imageRegistry.get(path);
101
		if (image==null) {
102
			image = getImage(path);
103
			imageRegistry.put(path, image);
104
		}
105
		return image;
106
	}
107

  
108
    public static void logError(Throwable exception) {
109
        logError(exception.toString(), exception);
110
    }
111

  
112
    public static void logError(String message, Throwable exception) {
113
        log(getErrorStatus(0, message, exception));
114
    }
115

  
116
    public static void log(IStatus status) {
117
        if (status != null) {
118
            if (plugin != null) {
119
                plugin.getLog().log(status);
120
            }
121
            else {
122
                if (status.getMessage() != null)
123
                    System.err.println(status.getMessage());
124
                if (status.getException() != null)
125
                    status.getException().printStackTrace();
126
            }
127
        }
128
    }
129

  
130
    public static IStatus getWarningStatus(String message) {
131
        return getWarningStatus(0, message);
132
    }
133

  
134
    public static IStatus getWarningStatus(int code, String message) {
135
        return getStatus(IStatus.WARNING, code, message, null);
136
    }
137

  
138
    public static IStatus getErrorStatus(Throwable exception) {
139
        return getErrorStatus(0, exception.getLocalizedMessage(), exception);
140
    }
141

  
142
    public static IStatus getErrorStatus(int errorCode, String message, Throwable exception) {
143
        return getStatus(IStatus.ERROR, errorCode, message, exception);
144
    }
145

  
146
    public static IStatus getStatus(int severity, int code, String message, Throwable exception) {
147
        return new Status(severity, PLUGIN_ID, code, message, exception);
148
    }
149
}
ide/sequencechart/src/org/omnetpp/sequencechart/editors/ISequenceChartProvider.java
1
/*--------------------------------------------------------------*
2
  Copyright (C) 2006-2008 OpenSim Ltd.
3

  
4
  This file is distributed WITHOUT ANY WARRANTY. See the file
5
  'License' for details on this and other legal matters.
6
*--------------------------------------------------------------*/
7

  
8
package org.omnetpp.sequencechart.editors;
9

  
10
import org.omnetpp.sequencechart.widgets.SequenceChart;
11

  
12
public interface ISequenceChartProvider {
13
    public SequenceChart getSequenceChart();
14
}
ide/sequencechart/src/org/omnetpp/sequencechart/editors/SequenceChartContributor.java
1
/*--------------------------------------------------------------*
2
  Copyright (C) 2006-2008 OpenSim Ltd.
3

  
4
  This file is distributed WITHOUT ANY WARRANTY. See the file
5
  'License' for details on this and other legal matters.
6
*--------------------------------------------------------------*/
7

  
8
package org.omnetpp.sequencechart.editors;
9

  
10
import java.awt.RenderingHints;
11
import java.io.File;
12
import java.lang.reflect.Field;
13
import java.math.BigDecimal;
14
import java.math.MathContext;
15
import java.util.ArrayList;
16
import java.util.List;
17

  
18
import javax.xml.transform.OutputKeys;
19
import javax.xml.transform.Source;
20
import javax.xml.transform.Transformer;
21
import javax.xml.transform.TransformerConfigurationException;
22
import javax.xml.transform.TransformerException;
23
import javax.xml.transform.TransformerFactory;
24
import javax.xml.transform.TransformerFactoryConfigurationError;
25
import javax.xml.transform.dom.DOMSource;
26
import javax.xml.transform.stream.StreamResult;
27

  
28
import org.apache.batik.svggen.SVGGraphics2D;
29
import org.apache.commons.lang.ArrayUtils;
30
import org.apache.commons.lang.WordUtils;
31
import org.eclipse.core.commands.AbstractHandler;
32
import org.eclipse.core.commands.ExecutionEvent;
33
import org.eclipse.core.commands.ExecutionException;
34
import org.eclipse.core.resources.IFile;
35
import org.eclipse.core.resources.IMarker;
36
import org.eclipse.core.resources.IResource;
37
import org.eclipse.core.resources.ResourcesPlugin;
38
import org.eclipse.core.runtime.Assert;
39
import org.eclipse.core.runtime.CoreException;
40
import org.eclipse.core.runtime.IPath;
41
import org.eclipse.core.runtime.Path;
42
import org.eclipse.draw2d.geometry.Rectangle;
43
import org.eclipse.gmf.runtime.draw2d.ui.render.awt.internal.svg.export.GraphicsSVG;
44
import org.eclipse.jface.action.Action;
45
import org.eclipse.jface.action.IContributionItem;
46
import org.eclipse.jface.action.IMenuCreator;
47
import org.eclipse.jface.action.IMenuListener;
48
import org.eclipse.jface.action.IMenuManager;
49
import org.eclipse.jface.action.IStatusLineManager;
50
import org.eclipse.jface.action.IToolBarManager;
51
import org.eclipse.jface.action.MenuManager;
52
import org.eclipse.jface.action.Separator;
53
import org.eclipse.jface.dialogs.IDialogConstants;
54
import org.eclipse.jface.dialogs.IDialogSettings;
55
import org.eclipse.jface.dialogs.InputDialog;
56
import org.eclipse.jface.dialogs.MessageDialog;
57
import org.eclipse.jface.dialogs.TitleAreaDialog;
58
import org.eclipse.jface.resource.ImageDescriptor;
59
import org.eclipse.jface.viewers.ISelectionChangedListener;
60
import org.eclipse.jface.viewers.LabelProvider;
61
import org.eclipse.jface.viewers.SelectionChangedEvent;
62
import org.eclipse.jface.viewers.Viewer;
63
import org.eclipse.jface.viewers.ViewerFilter;
64
import org.eclipse.jface.window.Window;
65
import org.eclipse.osgi.util.NLS;
66
import org.eclipse.swt.SWT;
67
import org.eclipse.swt.events.ModifyEvent;
68
import org.eclipse.swt.events.ModifyListener;
69
import org.eclipse.swt.events.SelectionAdapter;
70
import org.eclipse.swt.events.SelectionEvent;
71
import org.eclipse.swt.graphics.Font;
72
import org.eclipse.swt.graphics.FontData;
73
import org.eclipse.swt.graphics.Point;
74
import org.eclipse.swt.layout.GridData;
75
import org.eclipse.swt.layout.GridLayout;
76
import org.eclipse.swt.widgets.Button;
77
import org.eclipse.swt.widgets.Composite;
78
import org.eclipse.swt.widgets.Control;
79
import org.eclipse.swt.widgets.Display;
80
import org.eclipse.swt.widgets.FileDialog;
81
import org.eclipse.swt.widgets.FontDialog;
82
import org.eclipse.swt.widgets.Group;
83
import org.eclipse.swt.widgets.Label;
84
import org.eclipse.swt.widgets.Menu;
85
import org.eclipse.swt.widgets.MenuItem;
86
import org.eclipse.swt.widgets.MessageBox;
87
import org.eclipse.swt.widgets.Scale;
88
import org.eclipse.swt.widgets.Shell;
89
import org.eclipse.swt.widgets.Text;
90
import org.eclipse.ui.IEditorPart;
91
import org.eclipse.ui.IWorkbenchPart;
92
import org.eclipse.ui.IWorkbenchWindow;
93
import org.eclipse.ui.PlatformUI;
94
import org.eclipse.ui.actions.ContributionItemFactory;
95
import org.eclipse.ui.dialogs.ElementListSelectionDialog;
96
import org.eclipse.ui.dialogs.ElementTreeSelectionDialog;
97
import org.eclipse.ui.dialogs.ListDialog;
98
import org.eclipse.ui.handlers.HandlerUtil;
99
import org.eclipse.ui.internal.Workbench;
100
import org.eclipse.ui.keys.IBindingService;
101
import org.eclipse.ui.menus.CommandContributionItem;
102
import org.eclipse.ui.menus.CommandContributionItemParameter;
103
import org.eclipse.ui.model.WorkbenchContentProvider;
104
import org.eclipse.ui.model.WorkbenchLabelProvider;
105
import org.eclipse.ui.part.EditorActionBarContributor;
106
import org.eclipse.ui.texteditor.StatusLineContributionItem;
107
import org.eclipse.ui.views.navigator.ResourceComparator;
108
import org.omnetpp.common.IConstants;
109
import org.omnetpp.common.eventlog.EventLogFilterParameters;
110
import org.omnetpp.common.eventlog.EventLogInput;
111
import org.omnetpp.common.eventlog.FilterEventLogDialog;
112
import org.omnetpp.common.eventlog.IEventLogChangeListener;
113
import org.omnetpp.common.eventlog.ModuleTreeItem;
114
import org.omnetpp.common.image.ImageFactory;
115
import org.omnetpp.common.util.TimeUtils;
116
import org.omnetpp.common.util.UIUtils;
117
import org.omnetpp.eventlog.engine.BeginSendEntry;
118
import org.omnetpp.eventlog.engine.FileReader;
119
import org.omnetpp.eventlog.engine.FilteredEventLog;
120
import org.omnetpp.eventlog.engine.IEvent;
121
import org.omnetpp.eventlog.engine.IEventLog;
122
import org.omnetpp.eventlog.engine.IMessageDependency;
123
import org.omnetpp.eventlog.engine.SequenceChartFacade;
124
import org.omnetpp.scave.engine.IDList;
125
import org.omnetpp.scave.engine.ResultFile;
126
import org.omnetpp.scave.engine.ResultFileManager;
127
import org.omnetpp.scave.engine.ResultItem;
128
import org.omnetpp.scave.engine.Run;
129
import org.omnetpp.scave.engine.RunList;
130
import org.omnetpp.scave.engine.XYArray;
131
import org.omnetpp.sequencechart.SequenceChartPlugin;
132
import org.omnetpp.sequencechart.widgets.SequenceChart;
133
import org.omnetpp.sequencechart.widgets.VectorFileUtil;
134
import org.omnetpp.sequencechart.widgets.SequenceChart.AxisSpacingMode;
135
import org.omnetpp.sequencechart.widgets.axisrenderer.AxisLineRenderer;
136
import org.omnetpp.sequencechart.widgets.axisrenderer.AxisVectorBarRenderer;
137

  
138

  
139
@SuppressWarnings("restriction")
140
public class SequenceChartContributor extends EditorActionBarContributor implements ISelectionChangedListener, IEventLogChangeListener {
141
    public final static String TOOL_IMAGE_DIR = "icons/full/etool16/";
142
    public final static String IMAGE_TIMELINE_MODE = TOOL_IMAGE_DIR + "timelinemode.png";
143
    public final static String IMAGE_AXIS_ORDERING_MODE = TOOL_IMAGE_DIR + "axisordering.gif";
144
    public final static String IMAGE_SHOW_EVENT_NUMBERS = TOOL_IMAGE_DIR + "eventnumbers.png";
145
    public final static String IMAGE_SHOW_SELF_MESSAGES = TOOL_IMAGE_DIR + "selfmessages.png";
146
    public final static String IMAGE_SHOW_MESSAGE_SENDS = TOOL_IMAGE_DIR + "messagesends.png";
147
    public final static String IMAGE_SHOW_MESSAGE_NAMES = TOOL_IMAGE_DIR + "messagenames.png";
148
    public final static String IMAGE_SHOW_REUSE_SELF_MESSAGES = TOOL_IMAGE_DIR + "selfmsgreusearrows.png";
149
    public final static String IMAGE_SHOW_REUSE_MESSAGES = TOOL_IMAGE_DIR + "reusearrows.png";
150
    public final static String IMAGE_SHOW_MODULE_METHOD_CALLS = TOOL_IMAGE_DIR + "modulemethodcall.png";
151
    public final static String IMAGE_SHOW_TRANSMISSION_DURATIONS = TOOL_IMAGE_DIR + "transmissiondurations.png";
152
    public final static String IMAGE_SHOW_ARROW_HEADS = TOOL_IMAGE_DIR + "arrowhead.png";
153
    public final static String IMAGE_SHOW_ZERO_TIME_REGIONS = TOOL_IMAGE_DIR + "zerotimeregions.png";
154
    public final static String IMAGE_SHOW_OVERLAPPING_EVENTS = TOOL_IMAGE_DIR + "overlappingevents.png";
155
    public final static String IMAGE_EVENT_LENGTH_MODE = TOOL_IMAGE_DIR + "eventlengthmode.png";
156
    public final static String IMAGE_JUMP_TO_NEXT_BOTTLENECK = TOOL_IMAGE_DIR + "nextbottleneck.png";
157
    public final static String IMAGE_JUMP_TO_PREVIOUS_BOTTLENECK = TOOL_IMAGE_DIR + "previousbottleneck.png";
158
    public final static String IMAGE_BOTTLENECK_PREFERENCES = TOOL_IMAGE_DIR + "bottleneckpreferences.png";
159
    public final static String IMAGE_INCREASE_SPACING = TOOL_IMAGE_DIR + "incr_spacing.png";
160
    public final static String IMAGE_DECREASE_SPACING = TOOL_IMAGE_DIR + "decr_spacing.png";
161
    public final static String IMAGE_DENSE_AXES = TOOL_IMAGE_DIR + "denseaxes.png";
162
    public final static String IMAGE_BALANCED_AXES = TOOL_IMAGE_DIR + "balancedaxes.png";
163
    public final static String IMAGE_ATTACH_VECTOR_TO_AXIS = TOOL_IMAGE_DIR + "attachvector.png";
164
    public final static String IMAGE_EXPORT_SVG = TOOL_IMAGE_DIR + "export_wiz.gif";
165

  
166
	private static SequenceChartContributor singleton;
167
	protected SequenceChart sequenceChart;
168
	
169
	protected Separator separatorAction;
170
	protected SequenceChartMenuAction timelineModeAction;
171
	protected SequenceChartMenuAction axisOrderingModeAction;
172
	protected SequenceChartMenuAction eventLengthModeAction;
173
	protected SequenceChartAction filterAction;
174
	protected SequenceChartAction showEventNumbersAction;
175
	
176
	protected SequenceChartAction showEventOverlappingAction;
177
	
178
	protected SequenceChartAction previousBottleneckAction;
179
	protected SequenceChartAction nextBottleneckAction;
180
	
181
	protected SequenceChartAction showBottleneckPreferencesAction;
182

  
183
	
184
	protected SequenceChartAction showMessageNamesAction;
185
    protected SequenceChartAction showMessageSendsAction;
186
    protected SequenceChartAction showSelfMessagesAction;
187
    protected SequenceChartAction showSelfMessageReusesAction;
188
	protected SequenceChartAction showOtherMessageReusesAction;
189
	protected SequenceChartAction showArrowHeadsAction;
190
    protected SequenceChartAction showZeroSimulationTimeRegionsAction;
191
    protected SequenceChartAction showAxisLabelsAction;
192
    protected SequenceChartAction showAxesWithoutEventsAction;
193
    protected SequenceChartAction showTransmissionDurationsAction;
194
    protected SequenceChartAction showModuleMethodCallsAction;
195
    protected SequenceChartAction changeFontAction;
196
    protected SequenceChartAction increaseSpacingAction;
197
	protected SequenceChartAction decreaseSpacingAction;
198
    protected SequenceChartAction defaultZoomAction;
199
    protected SequenceChartAction zoomToFitAction;
200
	protected SequenceChartAction zoomInAction;
201
	protected SequenceChartAction zoomOutAction;
202
	protected SequenceChartAction denseAxesAction;
203
	protected SequenceChartAction balancedAxesAction;
204
	protected SequenceChartAction toggleBookmarkAction;
205
    protected SequenceChartAction releaseMemoryAction;
206
    protected SequenceChartAction copyToClipboardAction;
207
    protected SequenceChartAction exportToSVGAction;
208
    protected SequenceChartAction refreshAction;
209
	protected StatusLineContributionItem timelineModeStatus;
210
	protected StatusLineContributionItem filterStatus;
211

  
212
	/*************************************************************************************
213
	 * CONSTRUCTION
214
	 */
215

  
216
	public SequenceChartContributor() {
217
		this.separatorAction = new Separator();
218
		this.timelineModeAction = createTimelineModeAction();
219
		this.axisOrderingModeAction = createAxisOrderingModeAction();
220
		this.eventLengthModeAction = createEventLengthModeAction();
221
		this.filterAction = createFilterAction();
222
		this.showEventNumbersAction = createShowEventNumbersAction();
223
		this.showEventOverlappingAction = createShowEventOverlappingAction();
224
		this.previousBottleneckAction = createPreviousBottleneckAction();
225
		this.nextBottleneckAction     = createNextBottleneckAction();
226
		this.showBottleneckPreferencesAction = createShowBottleneckPreferencesAction();
227
		this.showMessageNamesAction = createShowMessageNamesAction();
228
		this.showMessageSendsAction = createShowMessageSendsAction();
229
        this.showSelfMessagesAction = createShowSelfMessagesAction();
230
		this.showOtherMessageReusesAction = createShowOtherMessageReusesAction();
231
		this.showSelfMessageReusesAction = createShowSelfMessageReusesAction();
232
		this.showArrowHeadsAction = createShowArrowHeadsAction();
233
        this.showZeroSimulationTimeRegionsAction = createShowZeroSimulationTimeRegionsAction();
234
        this.showAxisLabelsAction = createShowAxisLabelsAction();
235
        this.showAxesWithoutEventsAction = createShowAxesWithoutEventsAction();
236
        this.showTransmissionDurationsAction = createShowTransmissionDurationsAction();
237
        this.showModuleMethodCallsAction = createShowModuleMethodCallsAction();
238
        this.changeFontAction = createChangeFontAction();
239
		this.increaseSpacingAction = createIncreaseSpacingAction();
240
		this.decreaseSpacingAction = createDecreaseSpacingAction();
241
        this.defaultZoomAction = createDefaultZoomAction();
242
        this.zoomToFitAction = createZoomToFitAction();
243
		this.zoomInAction = createZoomInAction();
244
		this.zoomOutAction = createZoomOutAction();
245
		this.denseAxesAction = createDenseAxesAction();
246
		this.balancedAxesAction = createBalancedAxesAction();
247
		this.toggleBookmarkAction = createToggleBookmarkAction();
248
		this.copyToClipboardAction = createCopyToClipboardAction();
249
		this.releaseMemoryAction = createReleaseMemoryAction();
250
		this.refreshAction = createRefreshAction();
251

  
252
		if (IConstants.IS_COMMERCIAL)
253
            this.exportToSVGAction = createExportToSVGAction();
254

  
255
		this.timelineModeStatus = createTimelineModeStatus();
256
		this.filterStatus = createFilterStatus();
257

  
258
		if (singleton == null)
259
			singleton = this;
260
}
261

  
262
	public SequenceChartContributor(SequenceChart sequenceChart) {
263
		this();
264
		this.sequenceChart = sequenceChart;
265
        sequenceChart.addSelectionChangedListener(this);
266
	}
267

  
268
	@Override
269
	public void dispose() {
270
	    if (sequenceChart != null)
271
	        sequenceChart.removeSelectionChangedListener(this);
272

  
273
	    sequenceChart = null;
274
		singleton = null;
275

  
276
		super.dispose();
277
	}
278

  
279
	private IEventLog getEventLog() {
280
		return sequenceChart.getEventLog();
281
	}
282

  
283
	public static SequenceChartContributor getDefault() {
284
		Assert.isTrue(singleton != null);
285

  
286
		return singleton;
287
	}
288

  
289
	/*************************************************************************************
290
	 * CONTRIBUTIONS
291
	 */
292

  
293
	public void contributeToPopupMenu(IMenuManager menuManager) {
294
		menuManager.setRemoveAllWhenShown(true);
295
		menuManager.addMenuListener(new IMenuListener() {
296
			public void menuAboutToShow(IMenuManager menuManager) {
297
				// dynamic menu
298
				ArrayList<IEvent> events = new ArrayList<IEvent>();
299
				ArrayList<IMessageDependency> msgs = new ArrayList<IMessageDependency>();
300
				Point p = sequenceChart.toControl(sequenceChart.getDisplay().getCursorLocation());
301
				sequenceChart.collectStuffUnderMouse(p.x, p.y, events, msgs, null);
302

  
303
				// events submenu
304
				for (final IEvent event : events) {
305
					IMenuManager subMenuManager = new MenuManager(sequenceChart.getEventText(event, false, null));
306
					menuManager.add(subMenuManager);
307

  
308
                    subMenuManager.add(createFilterEventCausesConsequencesAction(event));
309
                    subMenuManager.add(createSelectEventAction(event));
310
					subMenuManager.add(createCenterEventAction(event));
311
				}
312
				
313
				if (events.size() != 0)
314
					menuManager.add(separatorAction);
315

  
316
				// messages submenu
317
				for (final IMessageDependency msg : msgs) {
318
					IMenuManager subMenuManager = new MenuManager(sequenceChart.getMessageDependencyText(msg, false, null));
319
					menuManager.add(subMenuManager);
320

  
321
					subMenuManager.add(createFilterMessageAction(msg.getBeginSendEntry()));
322
					subMenuManager.add(createGotoCauseAction(msg));
323
					subMenuManager.add(createGotoConsequenceAction(msg));
324
                    subMenuManager.add(createZoomToMessageAction(msg));
325
				}
326

  
327
				if (msgs.size() != 0)
328
					menuManager.add(separatorAction);
329

  
330
				// axis submenu
331
				final ModuleTreeItem axisModule = sequenceChart.findAxisAt(p.y);
332
				if (axisModule != null) {
333
					IMenuManager subMenuManager = new MenuManager(sequenceChart.getAxisText(axisModule, false));
334
					menuManager.add(subMenuManager);
335

  
336
					if (sequenceChart.getAxisRenderer(axisModule) instanceof AxisLineRenderer)
337
						subMenuManager.add(createAttachVectorToAxisAction(axisModule));
338
					else
339
						subMenuManager.add(createDetachVectorFromAxisAction(axisModule));
340

  
341
                    subMenuManager.add(createZoomToAxisValueAction(axisModule, p.x));
342
                    subMenuManager.add(createCenterAxisAction(axisModule));
343

  
344
					menuManager.add(separatorAction);
345
				}
346
				
347
				// Show/Hide submenu
348
				IMenuManager showHideSubmenu = new MenuManager("Show/Hide");
349
                showHideSubmenu.add(showMessageSendsAction);
350
                showHideSubmenu.add(showSelfMessagesAction);
351
                showHideSubmenu.add(showOtherMessageReusesAction);
352
                showHideSubmenu.add(showSelfMessageReusesAction);
353
                showHideSubmenu.add(showModuleMethodCallsAction);
354
                showHideSubmenu.add(separatorAction);
355
                showHideSubmenu.add(showAxesWithoutEventsAction);
356
                showHideSubmenu.add(showTransmissionDurationsAction);
357
                showHideSubmenu.add(showZeroSimulationTimeRegionsAction);
358
                showHideSubmenu.add(separatorAction);
359
                showHideSubmenu.add(showEventNumbersAction);
360
                showHideSubmenu.add(showEventOverlappingAction);
361
                showHideSubmenu.add(showMessageNamesAction);
362
                showHideSubmenu.add(showArrowHeadsAction);
363
                showHideSubmenu.add(showAxisLabelsAction);
364
                showHideSubmenu.add(separatorAction);
365

  
366
                // Spacing submenu
367
                IMenuManager spacingSubmenu = new MenuManager("Spacing");
368
                spacingSubmenu.add(balancedAxesAction);
369
                spacingSubmenu.add(denseAxesAction);
370
                spacingSubmenu.add(increaseSpacingAction);
371
                spacingSubmenu.add(decreaseSpacingAction);
372

  
373
				// Zoom submenu
374
                IMenuManager zoomSubmenu = new MenuManager("Zoom");
375
                zoomSubmenu.add(defaultZoomAction);
376
                zoomSubmenu.add(zoomToFitAction);
377
                zoomSubmenu.add(zoomInAction);
378
                zoomSubmenu.add(zoomOutAction);
379
                
380
                // Show In submenu
381
                MenuManager showInSubmenu = new MenuManager(getShowInMenuLabel());
382
                IWorkbenchWindow workbenchWindow = PlatformUI.getWorkbench().getActiveWorkbenchWindow();
383
                IContributionItem showInViewItem = ContributionItemFactory.VIEWS_SHOW_IN.create(workbenchWindow);
384
                showInSubmenu.add(showInViewItem);
385

  
386
                // context menu static part
387
                menuManager.add(showHideSubmenu);
388
                menuManager.add(filterAction);
389
                menuManager.add(timelineModeAction);
390
                menuManager.add(axisOrderingModeAction);
391
                menuManager.add(eventLengthModeAction);
392
                menuManager.add(separatorAction);
393
                
394
                menuManager.add(createFindTextCommandContributionItem());
395
                menuManager.add(createFindNextCommandContributionItem());
396
                menuManager.add(separatorAction);
397
                
398
                menuManager.add(previousBottleneckAction);
399
                menuManager.add(nextBottleneckAction);
400
                menuManager.add(showBottleneckPreferencesAction);
401
                menuManager.add(separatorAction);
402
                
403
                menuManager.add(spacingSubmenu);
404
                menuManager.add(zoomSubmenu);
405
                menuManager.add(changeFontAction);
406
                menuManager.add(separatorAction);
407
                
408
                menuManager.add(toggleBookmarkAction);
409
                menuManager.add(copyToClipboardAction);
410
                if (IConstants.IS_COMMERCIAL)
411
                    menuManager.add(exportToSVGAction);
412
                menuManager.add(separatorAction);
413

  
414
                menuManager.add(createRefreshCommandContributionItem());
415
                menuManager.add(releaseMemoryAction);
416
				menuManager.add(separatorAction);
417

  
418
		        menuManager.add(showInSubmenu);
419

  
420
		        
421
			}
422
		});
423
	}
424

  
425
	@Override
426
	public void contributeToToolBar(IToolBarManager toolBarManager) {
427
		toolBarManager.add(timelineModeAction);
428
		toolBarManager.add(axisOrderingModeAction);
429
		toolBarManager.add(eventLengthModeAction);
430
        toolBarManager.add(filterAction);
431
        toolBarManager.add(separatorAction);
432
		toolBarManager.add(showEventNumbersAction);
433
		toolBarManager.add(showEventOverlappingAction);
434
		toolBarManager.add(showMessageNamesAction);
435
        toolBarManager.add(showMessageSendsAction);
436
        toolBarManager.add(showSelfMessagesAction);
437
        toolBarManager.add(showOtherMessageReusesAction);
438
        toolBarManager.add(showSelfMessageReusesAction);
439
        toolBarManager.add(showModuleMethodCallsAction);
440
		toolBarManager.add(separatorAction);
441
		toolBarManager.add(increaseSpacingAction);
442
		toolBarManager.add(decreaseSpacingAction);
443
		toolBarManager.add(separatorAction);
444
		toolBarManager.add(zoomInAction);
445
		toolBarManager.add(zoomOutAction);
446
		toolBarManager.add(separatorAction);
447
		toolBarManager.add(previousBottleneckAction);
448
		toolBarManager.add(nextBottleneckAction);
449
		toolBarManager.add(showBottleneckPreferencesAction);
450
		toolBarManager.add(separatorAction);
451
		toolBarManager.add(refreshAction);
452
	}
453

  
454
    @Override
455
    public void contributeToStatusLine(IStatusLineManager statusLineManager) {
456
    	statusLineManager.add(timelineModeStatus);
457
    	statusLineManager.add(filterStatus);
458
    }
459

  
460
	@Override
461
	public void setActiveEditor(IEditorPart targetEditor) {
462
		if (targetEditor instanceof SequenceChartEditor) {
463
			EventLogInput eventLogInput;
464
			if (sequenceChart != null) {
465
				eventLogInput = sequenceChart.getInput();
466
				if (eventLogInput != null)
467
					eventLogInput.removeEventLogChangedListener(this);
468

  
469
                sequenceChart.removeSelectionChangedListener(this);
470
			}
471

  
472
			sequenceChart = ((SequenceChartEditor)targetEditor).getSequenceChart();
473

  
474
			eventLogInput = sequenceChart.getInput();
475
			if (eventLogInput != null)
476
				eventLogInput.addEventLogChangedListener(this);
477

  
478
			sequenceChart.addSelectionChangedListener(this);
479

  
480
			update();
481
		}
482
		else
483
			sequenceChart = null;
484
	}
485

  
486
	public void update() {
487
		try {
488
			for (Field field : getClass().getDeclaredFields()) {
489
				Class<?> fieldType = field.getType();
490

  
491
				if (fieldType == SequenceChartAction.class ||
492
					fieldType == SequenceChartMenuAction.class)
493
				{
494
					SequenceChartAction fieldValue = (SequenceChartAction)field.get(this);
495

  
496
					if (fieldValue != null && sequenceChart != null) {
497
						fieldValue.setEnabled(true);
498
						fieldValue.update();
499
						if (sequenceChart.getInput().isLongRunningOperationInProgress())
500
							fieldValue.setEnabled(false);
501
					}
502
				}
503

  
504
				if (fieldType == StatusLineContributionItem.class)
505
				{
506
					StatusLineContributionItem fieldValue = (StatusLineContributionItem)field.get(this);
507
					if (sequenceChart != null)
508
						fieldValue.update();
509
				}
510
			}
511
		}
512
		catch (Exception e) {
513
			throw new RuntimeException(e);
514
		}
515
	}
516

  
517
    private String getShowInMenuLabel() {
518
        String keyBinding = null;
519

  
520
        IBindingService bindingService = (IBindingService)PlatformUI.getWorkbench().getAdapter(IBindingService.class);
521
        if (bindingService != null)
522
            keyBinding = bindingService.getBestActiveBindingFormattedFor("org.eclipse.ui.navigate.showInQuickMenu");
523

  
524
        if (keyBinding == null)
525
            keyBinding = "";
526

  
527
        return NLS.bind("Show In \t{0}", keyBinding);
528
    }
529

  
530
    /*************************************************************************************
531
	 * NOTIFICATIONS
532
	 */
533

  
534
    public void selectionChanged(SelectionChangedEvent event) {
535
        update();
536
    }
537

  
538
    public void eventLogAppended() {
539
		// void
540
	}
541

  
542
    public void eventLogOverwritten() {
543
        // void
544
    }
545

  
546
    public void eventLogFilterRemoved() {
547
		update();
548
	}
549

  
550
	public void eventLogFiltered() {
551
		update();
552
	}
553

  
554
	public void eventLogLongOperationEnded() {
555
		update();
556
	}
557

  
558
	public void eventLogLongOperationStarted() {
559
		update();
560
	}
561

  
562
	public void eventLogProgress() {
563
		// void
564
	}
565

  
566
	/*************************************************************************************
567
	 * ACTIONS
568
	 */
569

  
570
    private CommandContributionItem createFindTextCommandContributionItem() {
571
        CommandContributionItemParameter parameter = new CommandContributionItemParameter(Workbench.getInstance(), null, "org.omnetpp.sequencechart.findText", SWT.PUSH);
572
        parameter.icon = ImageFactory.getDescriptor(ImageFactory.TOOLBAR_IMAGE_SEARCH);
573
        return new CommandContributionItem(parameter);
574
    }
575

  
576
    private CommandContributionItem createFindNextCommandContributionItem() {
577
        CommandContributionItemParameter parameter = new CommandContributionItemParameter(Workbench.getInstance(), null, "org.omnetpp.sequencechart.findNext", SWT.PUSH);
578
        parameter.icon = ImageFactory.getDescriptor(ImageFactory.TOOLBAR_IMAGE_SEARCH_NEXT);
579
        return new CommandContributionItem(parameter);
580
    }
581

  
582
	private SequenceChartMenuAction createTimelineModeAction() {
583
		return new SequenceChartMenuAction("Timeline Mode", Action.AS_DROP_DOWN_MENU, SequenceChartPlugin.getImageDescriptor(IMAGE_TIMELINE_MODE)) {
584
			@Override
585
			protected void doRun() {
586
				sequenceChart.setTimelineMode(SequenceChart.TimelineMode.values()[(sequenceChart.getTimelineMode().ordinal() + 1) % SequenceChart.TimelineMode.values().length]);
587
				timelineModeStatus.update();
588
				update();
589
			}
590

  
591
			@Override
592
			protected int getMenuIndex() {
593
				return sequenceChart.getTimelineMode().ordinal();
594
			}
595

  
596
			@Override
597
			public IMenuCreator getMenuCreator() {
598
				return new AbstractMenuCreator() {
599
					@Override
600
					protected void createMenu(Menu menu) {
601
						addSubMenuItem(menu, "Linear", SequenceChart.TimelineMode.SIMULATION_TIME);
602
						addSubMenuItem(menu, "Event number", SequenceChart.TimelineMode.EVENT_NUMBER);
603
						addSubMenuItem(menu, "Step", SequenceChart.TimelineMode.STEP);
604
						addSubMenuItem(menu, "Nonlinear", SequenceChart.TimelineMode.NONLINEAR);
605

  
606
						MenuItem subMenuItem = new MenuItem(menu, SWT.RADIO);
607
						subMenuItem.setText("Custom nonlinear...");
608
						subMenuItem.addSelectionListener( new SelectionAdapter() {
609
							@Override
610
							public void widgetSelected(SelectionEvent e) {
611
								TitleAreaDialog dialog = new CustomNonlinearOptionsDialog(Display.getCurrent().getActiveShell(), sequenceChart);
612
								dialog.open();
613
							}
614
						});
615
					}
616

  
617
					private void addSubMenuItem(Menu menu, String text, final SequenceChart.TimelineMode timelineMode) {
618
						MenuItem subMenuItem = new MenuItem(menu, SWT.RADIO);
619
						subMenuItem.setText(text);
620
						subMenuItem.addSelectionListener( new SelectionAdapter() {
621
							@Override
622
                            public void widgetSelected(SelectionEvent e) {
623
								MenuItem menuItem = (MenuItem)e.widget;
624

  
625
								if (menuItem.getSelection()) {
626
									sequenceChart.setTimelineMode(timelineMode);
627
									timelineModeStatus.update();
628
									if(timelineMode != SequenceChart.TimelineMode.SIMULATION_TIME) {
629
									    sequenceChart.setEventLengthMode(SequenceChart.EventLengthMode.NONE);
630
									}
631
									update();
632
								}
633
							}
634
						});
635
					}
636
				};
637
			}
638
		};
639
	}
640

  
641
	private SequenceChartMenuAction createAxisOrderingModeAction() {
642
		return new SequenceChartMenuAction("Axis Ordering Mode", Action.AS_DROP_DOWN_MENU, SequenceChartPlugin.getImageDescriptor(IMAGE_AXIS_ORDERING_MODE)) {
643
			@Override
644
			protected void doRun() {
645
				sequenceChart.setAxisOrderingMode(SequenceChart.AxisOrderingMode.values()[(sequenceChart.getAxisOrderingMode().ordinal() + 1) % SequenceChart.AxisOrderingMode.values().length]);
646
				update();
647
			}
648

  
649
			@Override
650
			protected int getMenuIndex() {
651
				return sequenceChart.getAxisOrderingMode().ordinal();
652
			}
653

  
654
			@Override
655
			public IMenuCreator getMenuCreator() {
656
				return new AbstractMenuCreator() {
657
					@Override
658
					protected void createMenu(Menu menu) {
659
						addSubMenuItem(menu, "Manual...", SequenceChart.AxisOrderingMode.MANUAL);
660
						addSubMenuItem(menu, "Module Id", SequenceChart.AxisOrderingMode.MODULE_ID);
661
						addSubMenuItem(menu, "Module Name", SequenceChart.AxisOrderingMode.MODULE_FULL_PATH);
662
						addSubMenuItem(menu, "Minimize Crossings", SequenceChart.AxisOrderingMode.MINIMIZE_CROSSINGS);
663
					}
664

  
665
					private void addSubMenuItem(Menu menu, String text, final SequenceChart.AxisOrderingMode axisOrderingMode) {
666
						MenuItem subMenuItem = new MenuItem(menu, SWT.RADIO);
667
						subMenuItem.setText(text);
668
						subMenuItem.addSelectionListener( new SelectionAdapter() {
669
							@Override
670
                            public void widgetSelected(SelectionEvent e) {
671
								MenuItem menuItem = (MenuItem)e.widget;
672

  
673
								if (menuItem.getSelection()) {
674
								    if (axisOrderingMode == SequenceChart.AxisOrderingMode.MANUAL &&
675
								        sequenceChart.showManualOrderingDialog() == Window.CANCEL)
676
								        return;
677

  
678
								    sequenceChart.setAxisOrderingMode(axisOrderingMode);
679
									update();
680
								}
681
							}
682
						});
683
					}
684
				};
685
			}
686
		};
687
	}
688

  
689
	private SequenceChartMenuAction createEventLengthModeAction() {
690
		return new SequenceChartMenuAction("Event Length Mode", Action.AS_DROP_DOWN_MENU, SequenceChartPlugin.getImageDescriptor(IMAGE_EVENT_LENGTH_MODE)) {
691
			@Override
692
			protected void doRun() {
693
				sequenceChart.setEventLengthMode(SequenceChart.EventLengthMode.values()[(sequenceChart.getEventLengthMode().ordinal() + 1) % SequenceChart.EventLengthMode.values().length]);
694
				update();
695
			}
696

  
697
			@Override
698
			protected int getMenuIndex() {
699
				return sequenceChart.getEventLengthMode().ordinal();
700
			}
701
			
702
			@Override
703
			public boolean isEnabled() {
704
				return sequenceChart!=null && !sequenceChart.isLegacyTrace();
705
			}
706

  
707
			@Override
708
			public IMenuCreator getMenuCreator() {
709
				return new AbstractMenuCreator() {
710
					@Override
711
					protected void createMenu(Menu menu) {
712
						addSubMenuItem(menu, "None", SequenceChart.EventLengthMode.NONE);
713
						addSubMenuItem(menu, "Duration", SequenceChart.EventLengthMode.DURATION);
714
						addSubMenuItem(menu, "Complexity", SequenceChart.EventLengthMode.COMPLEXITY);
715
					}
716

  
717
					private void addSubMenuItem(Menu menu, String text, final SequenceChart.EventLengthMode eventLengthMode) {
718
						MenuItem subMenuItem = new MenuItem(menu, SWT.RADIO);
719
						subMenuItem.setText(text);
720
						subMenuItem.addSelectionListener( new SelectionAdapter() {
721
							@Override
722
                            public void widgetSelected(SelectionEvent e) {
723
								MenuItem menuItem = (MenuItem)e.widget;
724

  
725
								if (menuItem.getSelection()) {
726
								    sequenceChart.setEventLengthMode(eventLengthMode);
727
								    if (eventLengthMode != SequenceChart.EventLengthMode.NONE){
728
								    	sequenceChart.setTimelineMode(SequenceChart.TimelineMode.SIMULATION_TIME);
729
										timelineModeStatus.update();
730
								    }
731
									update();
732
								}
733
							}
734
						});
735
					}
736
				};
737
			}
738
		};
739
	}
740

  
741
	
742
	private SequenceChartAction createFilterAction() {
743
        return new SequenceChartMenuAction("Filter", Action.AS_DROP_DOWN_MENU, ImageFactory.getDescriptor(ImageFactory.TOOLBAR_IMAGE_FILTER)) {
744
            @Override
745
            protected void doRun() {
746
                if (isFilteredEventLog())
747
                    removeFilter();
748
                else
749
                    filter();
750
            }
751

  
752
            @Override
753
            protected int getMenuIndex() {
754
                if (isFilteredEventLog())
755
                    return 1;
756
                else
757
                    return 0;
758
            }
759

  
760
            private boolean isFilteredEventLog() {
761
                return getEventLog() instanceof FilteredEventLog;
762
            }
763

  
764
            @Override
765
            public IMenuCreator getMenuCreator() {
766
                return new AbstractMenuCreator() {
767
                    @Override
768
                    protected void createMenu(Menu menu) {
769
                        addSubMenuItem(menu, "Show All", new Runnable() {
770
                            public void run() {
771
                                removeFilter();
772
                            }
773
                        });
774
                        addSubMenuItem(menu, "Filter...", new Runnable() {
775
                            public void run() {
776
                                filter();
777
                            }
778
                        });
779
                    }
780

  
781
                    private void addSubMenuItem(Menu menu, String text, final Runnable runnable) {
782
                        MenuItem subMenuItem = new MenuItem(menu, SWT.RADIO);
783
                        subMenuItem.setText(text);
784
                        subMenuItem.addSelectionListener( new SelectionAdapter() {
785
                            @Override
786
                            public void widgetSelected(SelectionEvent e) {
787
                                MenuItem menuItem = (MenuItem)e.widget;
788

  
789
                                if (menuItem.getSelection()) {
790
                                    runnable.run();
791
                                    update();
792
                                }
793
                            }
794
                        });
795
                    }
796
                };
797
            }
798

  
799
			private void filter() {
800
                if (sequenceChart.getInput().openFilterDialog() == Window.OK)
801
                    SequenceChartContributor.this.filter();
802
			}
803
		};
804
	}
805

  
806
    private void removeFilter() {
807
        final EventLogInput eventLogInput = sequenceChart.getInput();
808
        final boolean wasCanceled = eventLogInput.isCanceled();
809
        eventLogInput.resetCanceled();
810

  
811
        eventLogInput.runWithProgressMonitor(new Runnable() {
812
            public void run() {
813
                org.omnetpp.common.engine.BigDecimal centerSimulationTime = org.omnetpp.common.engine.BigDecimal.getMinusOne();
814

  
815
                if (!wasCanceled)
816
                    centerSimulationTime = sequenceChart.getViewportCenterSimulationTime();
817

  
818
                eventLogInput.removeFilter();
819
                sequenceChart.setInput(eventLogInput);
820

  
821
                if (!wasCanceled) {
822
                    sequenceChart.scrollToSimulationTimeWithCenter(centerSimulationTime);
823
                    sequenceChart.defaultZoom();
824
                }
825
                else
826
                    sequenceChart.scrollToBegin();
827

  
828
                update();
829
            }
830
        });
831
    }
832

  
833
    private void filter() {
834
        final EventLogInput eventLogInput = sequenceChart.getInput();
835
        final boolean wasCanceled = eventLogInput.isCanceled();
836

  
837
        eventLogInput.runWithProgressMonitor(new Runnable() {
838
            public void run() {
839
                org.omnetpp.common.engine.BigDecimal centerSimulationTime = org.omnetpp.common.engine.BigDecimal.getMinusOne();
840

  
841
                if (!wasCanceled)
842
                    centerSimulationTime = sequenceChart.getViewportCenterSimulationTime();
843

  
844
                eventLogInput.filter();
845
                sequenceChart.setInput(eventLogInput);
846

  
847
                if (!wasCanceled) {
848
                    sequenceChart.scrollToSimulationTimeWithCenter(centerSimulationTime);
849
                    sequenceChart.defaultZoom();
850
                }
851
                else
852
                    sequenceChart.scrollToBegin();
853

  
854
                update();
855
            }
856
        });
857
    }
858

  
859
    private StatusLineContributionItem createFilterStatus() {
860
		return new StatusLineContributionItem("Filter") {
861
			@Override
862
		    public void update() {
863
				setText(isFilteredEventLog() ? "Filtered" : "Unfiltered");
864
		    }
865

  
866
			private boolean isFilteredEventLog() {
867
				return getEventLog() instanceof FilteredEventLog;
868
			}
869
		};
870
	}
871

  
872
	private SequenceChartAction createShowEventNumbersAction() {
873
		return new SequenceChartAction("Show Event Numbers", Action.AS_CHECK_BOX, SequenceChartPlugin.getImageDescriptor(IMAGE_SHOW_EVENT_NUMBERS)) {
874
			@Override
875
			protected void doRun() {
876
				sequenceChart.setShowEventNumbers(!sequenceChart.getShowEventNumbers());
877
				update();
878
			}
879

  
880
			@Override
881
			public void update() {
882
				setChecked(sequenceChart.getShowEventNumbers());
883
			}
884
		};
885
	}
886
	
887
	private SequenceChartAction createShowEventOverlappingAction() {
888
		return new SequenceChartAction("Show Event Overlapping", Action.AS_CHECK_BOX, SequenceChartPlugin.getImageDescriptor(IMAGE_SHOW_OVERLAPPING_EVENTS)) {
889
			@Override
890
			protected void doRun() {
891
				sequenceChart.setShowEventOverlapping(!sequenceChart.getShowEventOverlapping());
892
				update();
893
			}
894

  
895
			@Override
896
			public void update() {
897
				setChecked(sequenceChart.getShowEventOverlapping());
898
			}
899
			@Override
900
			public boolean isEnabled() {
901
				return sequenceChart!=null && !sequenceChart.isLegacyTrace();
902
			}
903
		};
904
	}
905

  
906
	private SequenceChartAction createPreviousBottleneckAction() {
907
		return new SequenceChartAction("Jump to previous Bottleneck", Action.AS_PUSH_BUTTON, SequenceChartPlugin.getImageDescriptor(IMAGE_JUMP_TO_PREVIOUS_BOTTLENECK)) {
908
			@Override
909
			protected void doRun() {
910
				sequenceChart.setShowEventOverlapping(true);
911
			    if (sequenceChart.getEventLengthMode() != SequenceChart.EventLengthMode.NONE){
912
			    	sequenceChart.setTimelineMode(SequenceChart.TimelineMode.SIMULATION_TIME);
913
					timelineModeStatus.update();
914
			    }
915
				sequenceChart.selectPreviousBottleneck();
916
			}
917
			@Override
918
			public boolean isEnabled() {
919
				return sequenceChart!=null && !sequenceChart.isLegacyTrace();
920
			}
921
		};
922
	}
923

  
924
	private SequenceChartAction createNextBottleneckAction() {
925
		return new SequenceChartAction("Jump to next Bottleneck", Action.AS_PUSH_BUTTON, SequenceChartPlugin.getImageDescriptor(IMAGE_JUMP_TO_NEXT_BOTTLENECK)) {
926
			@Override
927
			protected void doRun() {
928
				sequenceChart.setShowEventOverlapping(true);
929
				sequenceChart.selectNextBottleneck();
930
			}
931
			@Override
932
			public boolean isEnabled() {
933
				return sequenceChart!=null && !sequenceChart.isLegacyTrace();
934
			}
935
		};
936
	}
937

  
938
	private SequenceChartAction createShowBottleneckPreferencesAction() {
939
		return new SequenceChartAction("Bottleneck Preferences...", Action.AS_PUSH_BUTTON, SequenceChartPlugin.getImageDescriptor(IMAGE_BOTTLENECK_PREFERENCES)) {
940
			@Override
941
			protected void doRun() {
942
				TitleAreaDialog dialog = new CustomBottleneckOptionsDialog(Display.getCurrent().getActiveShell(), sequenceChart);
943
				dialog.open();
944
			}
945
			@Override
946
			public boolean isEnabled() {
947
				return sequenceChart!=null && !sequenceChart.isLegacyTrace();
948
			}
949
		};
950
	}
951
	
952
	
953
	private SequenceChartAction createShowMessageNamesAction() {
954
		return new SequenceChartAction("Show Message Names", Action.AS_CHECK_BOX, SequenceChartPlugin.getImageDescriptor(IMAGE_SHOW_MESSAGE_NAMES)) {
955
			@Override
956
			protected void doRun() {
957
				sequenceChart.setShowMessageNames(!sequenceChart.getShowMessageNames());
958
				update();
959
			}
960

  
961
			@Override
962
			public void update() {
963
				setChecked(sequenceChart.getShowMessageNames());
964
			}
965
		};
966
	}
967

  
968
    private SequenceChartAction createShowMessageSendsAction() {
969
        return new SequenceChartAction("Show Message Sends", Action.AS_CHECK_BOX, SequenceChartPlugin.getImageDescriptor(IMAGE_SHOW_MESSAGE_SENDS)) {
970
            @Override
971
            protected void doRun() {
972
                sequenceChart.setShowMessageSends(!sequenceChart.getShowMessageSends());
973
                update();
974
            }
975

  
976
            @Override
977
            public void update() {
978
                setChecked(sequenceChart.getShowMessageSends());
979
            }
980
        };
981
    }
982

  
983
	private SequenceChartAction createShowSelfMessagesAction() {
984
		return new SequenceChartAction("Show Self-Messages", Action.AS_CHECK_BOX, SequenceChartPlugin.getImageDescriptor(IMAGE_SHOW_SELF_MESSAGES)) {
985
			@Override
986
			protected void doRun() {
987
				sequenceChart.setShowSelfMessages(!sequenceChart.getShowSelfMessages());
988
				update();
989
			}
990

  
991
			@Override
992
			public void update() {
993
				setChecked(sequenceChart.getShowSelfMessages());
994
			}
995
		};
996
	}
997

  
998
    private SequenceChartAction createShowOtherMessageReusesAction() {
999
        return new SequenceChartAction("Show Other Message Reuses", Action.AS_CHECK_BOX, SequenceChartPlugin.getImageDescriptor(IMAGE_SHOW_REUSE_MESSAGES)) {
1000
            @Override
1001
            protected void doRun() {
1002
                sequenceChart.setShowOtherMessageReuses(!sequenceChart.getShowOtherMessageReuses());
1003
                update();
1004
            }
1005

  
1006
            @Override
1007
            public void update() {
1008
                setChecked(sequenceChart.getShowOtherMessageReuses());
1009
            }
1010
        };
1011
    }
1012

  
1013
    private SequenceChartAction createShowSelfMessageReusesAction() {
1014
        return new SequenceChartAction("Show Self-Message Reuses", Action.AS_CHECK_BOX, SequenceChartPlugin.getImageDescriptor(IMAGE_SHOW_REUSE_SELF_MESSAGES)) {
1015
            @Override
1016
            protected void doRun() {
1017
                sequenceChart.setShowSelfMessageReuses(!sequenceChart.getShowSelfMessageReuses());
1018
                update();
1019
            }
1020

  
1021
            @Override
1022
            public void update() {
1023
                setChecked(sequenceChart.getShowSelfMessageReuses());
1024
            }
1025
        };
1026
    }
1027

  
1028
	private SequenceChartAction createShowArrowHeadsAction() {
1029
		return new SequenceChartAction("Show Arrowheads", Action.AS_CHECK_BOX, SequenceChartPlugin.getImageDescriptor(IMAGE_SHOW_ARROW_HEADS)) {
1030
			@Override
1031
			protected void doRun() {
1032
				sequenceChart.setShowArrowHeads(!sequenceChart.getShowArrowHeads());
1033
				update();
1034
			}
1035

  
1036
			@Override
1037
			public void update() {
1038
				setChecked(sequenceChart.getShowArrowHeads());
1039
			}
1040
		};
1041
	}
1042

  
1043
    private SequenceChartAction createShowZeroSimulationTimeRegionsAction() {
1044
        return new SequenceChartAction("Show Zero Simulation Time Regions", Action.AS_CHECK_BOX, SequenceChartPlugin.getImageDescriptor(IMAGE_SHOW_ZERO_TIME_REGIONS)) {
1045
            @Override
1046
            protected void doRun() {
1047
                sequenceChart.setShowZeroSimulationTimeRegions(!sequenceChart.getShowZeroSimulationTimeRegions());
1048
                update();
1049
            }
1050

  
1051
            @Override
1052
            public void update() {
1053
                setChecked(sequenceChart.getShowZeroSimulationTimeRegions());
1054
            }
1055
        };
1056
    }
1057

  
1058
    private SequenceChartAction createShowAxisLabelsAction() {
1059
        return new SequenceChartAction("Show Axis Labels", Action.AS_CHECK_BOX) {
1060
            @Override
1061
            protected void doRun() {
1062
                sequenceChart.setShowAxisLabels(!sequenceChart.getShowAxisLabels());
1063
                update();
1064
            }
1065

  
1066
            @Override
1067
            public void update() {
1068
                setChecked(sequenceChart.getShowAxisLabels());
1069
            }
1070
        };
1071
    }
1072

  
1073
    private SequenceChartAction createShowAxesWithoutEventsAction() {
1074
        return new SequenceChartAction("Show Axes Without Events", Action.AS_CHECK_BOX) {
1075
            @Override
1076
            protected void doRun() {
1077
                sequenceChart.setShowAxesWithoutEvents(!sequenceChart.getShowAxesWithoutEvents());
1078
                update();
1079
            }
1080

  
1081
            @Override
1082
            public void update() {
1083
                setChecked(sequenceChart.getShowAxesWithoutEvents());
1084
            }
1085
        };
1086
    }
1087

  
1088
    private SequenceChartAction createShowTransmissionDurationsAction() {
1089
        return new SequenceChartAction("Show Transmission Durations", Action.AS_CHECK_BOX, SequenceChartPlugin.getImageDescriptor(IMAGE_SHOW_TRANSMISSION_DURATIONS)) {
1090
            @Override
1091
            protected void doRun() {
1092
                sequenceChart.setShowTransmissionDurations(!sequenceChart.getShowTransmissionDurations());
1093
                update();
1094
            }
1095

  
1096
            @Override
1097
            public void update() {
1098
                setChecked(sequenceChart.getShowTransmissionDurations());
1099
            }
1100
        };
1101
    }
1102

  
1103
    private SequenceChartAction createShowModuleMethodCallsAction() {
1104
        return new SequenceChartAction("Show Module Method Calls", Action.AS_CHECK_BOX, SequenceChartPlugin.getImageDescriptor(IMAGE_SHOW_MODULE_METHOD_CALLS)) {
1105
            @Override
1106
            protected void doRun() {
1107
                sequenceChart.setShowModuleMethodCalls(!sequenceChart.getShowModuleMethodCalls());
1108
                update();
1109
            }
1110

  
1111
            @Override
1112
            public void update() {
1113
                setChecked(sequenceChart.getShowModuleMethodCalls());
1114
            }
1115
        };
1116
    }
1117

  
1118
    private SequenceChartAction createChangeFontAction() {
1119
        return new SequenceChartAction("Change Font...", Action.AS_PUSH_BUTTON) {
1120
            @Override
1121
            protected void doRun() {
1122
                FontDialog dialog = new FontDialog(Display.getCurrent().getActiveShell());
1123
                dialog.setFontList(sequenceChart.getFont().getFontData());
1124
                FontData fontData = dialog.open();
1125
                if (fontData != null)
1126
                    sequenceChart.setFont(new Font(Display.getDefault(), fontData));
1127
            }
1128
        };
1129
    }
1130

  
1131
	private SequenceChartAction createIncreaseSpacingAction() {
1132
		return new SequenceChartAction("Increase Spacing", Action.AS_PUSH_BUTTON, SequenceChartPlugin.getImageDescriptor(IMAGE_INCREASE_SPACING)) {
1133
			@Override
1134
			protected void doRun() {
1135
			    sequenceChart.setAxisSpacingMode(AxisSpacingMode.MANUAL);
1136
				sequenceChart.setAxisSpacing(sequenceChart.getAxisSpacing() + 5);
1137
			}
1138
		};
1139
	}
1140

  
1141
	private SequenceChartAction createDecreaseSpacingAction() {
1142
		return new SequenceChartAction("Decrease Spacing", Action.AS_PUSH_BUTTON, SequenceChartPlugin.getImageDescriptor(IMAGE_DECREASE_SPACING)) {
1143
			@Override
1144
			protected void doRun() {
1145
			    sequenceChart.setAxisSpacingMode(AxisSpacingMode.MANUAL);
1146
				sequenceChart.setAxisSpacing(sequenceChart.getAxisSpacing() - 5);
1147
			}
1148
		};
1149
	}
1150

  
1151
    private SequenceChartAction createDefaultZoomAction() {
1152
        return new SequenceChartAction("Default Zoom", Action.AS_PUSH_BUTTON, ImageFactory.getDescriptor(ImageFactory.TOOLBAR_IMAGE_ZOOM)) {
1153
            @Override
1154
            protected void doRun() {
1155
                sequenceChart.defaultZoom();
1156
            }
1157
        };
1158
    }
1159

  
1160
    private SequenceChartAction createZoomToFitAction() {
1161
        return new SequenceChartAction("Zoom to Fit", Action.AS_PUSH_BUTTON, ImageFactory.getDescriptor(ImageFactory.TOOLBAR_IMAGE_ZOOM)) {
1162
            @Override
1163
            protected void doRun() {
1164
                sequenceChart.zoomToFit();
1165
            }
1166
        };
1167
    }
1168

  
1169
	private SequenceChartAction createZoomInAction() {
1170
		return new SequenceChartAction("Zoom In", Action.AS_PUSH_BUTTON, ImageFactory.getDescriptor(ImageFactory.TOOLBAR_IMAGE_ZOOMPLUS)) {
1171
			@Override
1172
			protected void doRun() {
1173
				sequenceChart.zoomIn();
1174
			}
1175
		};
1176
	}
1177

  
1178
	private SequenceChartAction createZoomOutAction() {
1179
		return new SequenceChartAction("Zoom Out", Action.AS_PUSH_BUTTON, ImageFactory.getDescriptor(ImageFactory.TOOLBAR_IMAGE_ZOOMMINUS)) {
1180
			@Override
1181
			protected void doRun() {
1182
				sequenceChart.zoomOut();
1183
			}
1184
		};
1185
	}
1186

  
1187
	private SequenceChartAction createDenseAxesAction() {
1188
		return new SequenceChartAction("Dense Axes", Action.AS_PUSH_BUTTON, SequenceChartPlugin.getImageDescriptor(IMAGE_DENSE_AXES)) {
1189
			@Override
1190
			protected void doRun() {
1191
			    sequenceChart.setAxisSpacingMode(AxisSpacingMode.MANUAL);
1192
				sequenceChart.setAxisSpacing(sequenceChart.getFontHeight(null) + 1);
1193
			}
1194
		};
1195
	}
1196

  
1197
	private SequenceChartAction createBalancedAxesAction() {
1198
		return new SequenceChartAction("Balanced Axes", Action.AS_PUSH_BUTTON, SequenceChartPlugin.getImageDescriptor(IMAGE_BALANCED_AXES)) {
1199
			@Override
1200
			protected void doRun() {
1201
				sequenceChart.setAxisSpacingMode(AxisSpacingMode.AUTO);
1202
			}
1203
		};
1204
	}
1205

  
1206
	private SequenceChartAction createCenterEventAction(final IEvent event) {
1207
		return new SequenceChartAction("Center", Action.AS_PUSH_BUTTON) {
1208
			@Override
1209
			protected void doRun() {
1210
				sequenceChart.scrollToSimulationTimeWithCenter(event.getSimulationTime());
1211
			}
1212
		};
1213
	}
1214

  
1215
	private SequenceChartAction createSelectEventAction(final IEvent event) {
1216
		return new SequenceChartAction("Select", Action.AS_PUSH_BUTTON) {
1217
			@Override
1218
			protected void doRun() {
1219
				sequenceChart.setSelectionEvent(event);
1220
			}
1221
		};
1222
	}
1223

  
1224
	private SequenceChartAction createFilterEventCausesConsequencesAction(final IEvent event) {
1225
		return new SequenceChartAction("Filter Causes/Consequences...", Action.AS_PUSH_BUTTON) {
1226
			@Override
1227
			protected void doRun() {
1228
				EventLogInput eventLogInput = sequenceChart.getInput();
1229
				EventLogFilterParameters filterParameters = eventLogInput.getFilterParameters();
1230

  
1231
                filterParameters.enableTraceFilter = true;
1232
                filterParameters.tracedEventNumber = event.getEventNumber();
1233

  
1234
				if (!(getEventLog() instanceof FilteredEventLog) &&
1235
    				(filterParameters.isAnyEventFilterEnabled() || filterParameters.isAnyMessageFilterEnabled() || filterParameters.isAnyModuleFilterEnabled()))
1236
				{
1237
			        FilterEventLogDialog dialog = new FilterEventLogDialog(Display.getCurrent().getActiveShell(), eventLogInput, filterParameters);
1238

  
1239
			        if (dialog.open("Cause/consequence filter") == Window.OK)
1240
			            filter();
1241
			    }
1242
				else
1243
				    filter();
1244
			}
1245
		};
1246
	}
1247

  
1248
    private SequenceChartAction createFilterMessageAction(final BeginSendEntry beginSendEntry) {
1249
        return new SequenceChartAction("Filter Message...", Action.AS_PUSH_BUTTON) {
1250
            @Override
1251
            protected void doRun() {
1252
                EventLogInput eventLogInput = sequenceChart.getInput();
1253
                EventLogFilterParameters filterParameters = eventLogInput.getFilterParameters();
1254

  
1255
                // message filter
1256
                filterParameters.enableMessageFilter = true;
1257
                filterParameters.enableMessageEncapsulationTreeIdFilter = true;
1258

  
1259
                EventLogFilterParameters.EnabledInt enabledInt = null;
1260

  
1261
                if (filterParameters.messageEncapsulationTreeIds != null) {
1262
                    for (EventLogFilterParameters.EnabledInt messageEncapsulationTreeId : filterParameters.messageEncapsulationTreeIds) {
1263
                        if (messageEncapsulationTreeId.value == beginSendEntry.getMessageEncapsulationId()) {
1264
                            enabledInt = messageEncapsulationTreeId;
1265
                            messageEncapsulationTreeId.enabled = true;
1266
                        }
1267
                        else
1268
                            messageEncapsulationTreeId.enabled = false;
1269
                    }
1270
                }
1271

  
1272
                if (enabledInt == null) {
1273
                    enabledInt = new EventLogFilterParameters.EnabledInt(true, beginSendEntry.getMessageEncapsulationTreeId());
1274
                    filterParameters.messageEncapsulationTreeIds = (EventLogFilterParameters.EnabledInt[])ArrayUtils.add(filterParameters.messageEncapsulationTreeIds, enabledInt);
1275
                }
1276

  
1277
                // range filter
1278
                filterParameters.enableRangeFilter = true;
1279
                filterParameters.enableEventNumberFilter = true;
1280
                filterParameters.lowerEventNumberLimit = Math.max(0, beginSendEntry.getEvent().getEventNumber() - 1000);
1281
                filterParameters.upperEventNumberLimit = Math.min(getEventLog().getLastEvent().getEventNumber(), beginSendEntry.getEvent().getEventNumber() + 1000);
1282

  
1283
                if (!(getEventLog() instanceof FilteredEventLog) &&
1284
                    (filterParameters.isAnyEventFilterEnabled() || filterParameters.isAnyMessageFilterEnabled() || filterParameters.isAnyModuleFilterEnabled()))
1285
                {
1286
                    FilterEventLogDialog dialog = new FilterEventLogDialog(Display.getCurrent().getActiveShell(), eventLogInput, filterParameters);
1287

  
1288
                    if (dialog.open("Range") == Window.OK)
1289
                        filter();
1290
                }
1291
                else
1292
                    filter();
1293
            }
1294
        };
1295
    }
1296

  
1297
	private SequenceChartAction createZoomToMessageAction(final IMessageDependency messageDependency) {
1298
		return new SequenceChartAction("Zoom to Message", Action.AS_PUSH_BUTTON) {
1299
			@Override
1300
			protected void doRun() {
1301
				sequenceChart.zoomToMessageDependency(messageDependency);
1302
			}
1303
		};
1304
	}
1305

  
1306
	private SequenceChartAction createGotoCauseAction(final IMessageDependency messageDependency) {
1307
		return new SequenceChartAction("Goto Cause Event", Action.AS_PUSH_BUTTON) {
1308
			@Override
1309
			protected void doRun() {
1310
				sequenceChart.gotoElement(messageDependency.getCauseEvent());
1311
			}
1312
		};
1313
	}
1314

  
1315
	private SequenceChartAction createGotoConsequenceAction(final IMessageDependency messageDependency) {
1316
		return new SequenceChartAction("Goto Consequence Event", Action.AS_PUSH_BUTTON) {
1317
			@Override
1318
			protected void doRun() {
1319
				sequenceChart.gotoElement(messageDependency.getConsequenceEvent());
1320
			}
1321
		};
1322
	}
1323

  
1324
	private SequenceChartAction createCenterAxisAction(final ModuleTreeItem axisModule) {
1325
		return new SequenceChartAction("Center", Action.AS_PUSH_BUTTON) {
1326
			@Override
1327
			protected void doRun() {
1328
				sequenceChart.scrollToAxisModule(axisModule);
1329
			}
1330
		};
1331
	}
1332

  
1333
	private SequenceChartAction createZoomToAxisValueAction(final ModuleTreeItem axisModule, final int x) {
1334
		return new SequenceChartAction("Zoom to Value", Action.AS_PUSH_BUTTON) {
1335
			@Override
1336
			protected void doRun() {
1337
				sequenceChart.zoomToAxisValue(axisModule, sequenceChart.getSimulationTimeForViewportCoordinate(x));
1338
			}
1339
		};
1340
	}
1341

  
1342
	private SequenceChartAction createAttachVectorToAxisAction(final ModuleTreeItem axisModule) {
1343
		return new SequenceChartAction("Attach Vector to Axis", Action.AS_PUSH_BUTTON, SequenceChartPlugin.getImageDescriptor(IMAGE_ATTACH_VECTOR_TO_AXIS)) {
1344
			@Override
1345
			protected void doRun() {
1346
				// open a vector file with the same name as the sequence chart's input file name with .vec extension by default
1347
				EventLogInput eventLogInput = sequenceChart.getInput();
1348
				IFile inputFile = eventLogInput.getFile();
1349
                String inputFileName = inputFile.getName();
1350
				IFile vectorFile = inputFile.getParent().getFile(new Path(inputFileName.substring(0, inputFileName.indexOf(".")) + ".vec"));
1351

  
1352
				// select a vector file
1353
		        ElementTreeSelectionDialog vectorFileDialog = new ElementTreeSelectionDialog(Display.getDefault().getActiveShell(), new WorkbenchLabelProvider(), new WorkbenchContentProvider());
1354
		        vectorFileDialog.setTitle("Select File");
1355
		        vectorFileDialog.setMessage("Select a vector file to browse for runs and vectors:");
1356
		        vectorFileDialog.setInput(ResourcesPlugin.getWorkspace().getRoot());
1357
		        vectorFileDialog.setComparator(new ResourceComparator(ResourceComparator.NAME));
1358
		        vectorFileDialog.setAllowMultiple(false);
1359
		        vectorFileDialog.setInitialSelection(vectorFile.exists() ? vectorFile : inputFile.getParent());
1360
                vectorFileDialog.addFilter(new ViewerFilter() {
1361
                    @Override
1362
                    public boolean select(Viewer viewer, Object parentElement, Object element) {
1363
                        return !(element instanceof IFile) || "vec".equals(((IFile)element).getFileExtension());
1364
                    }
1365
                });
1366

  
1367
		        if (vectorFileDialog.open() == IDialogConstants.CANCEL_ID)
1368
		            return;
1369

  
1370
                String vectorFileName = ((IResource)vectorFileDialog.getFirstResult()).getLocation().toOSString();
1371

  
1372
				// load vector file
1373
                ResultFile resultFile = null;
1374
                final ResultFileManager resultFileManager = new ResultFileManager();
1375
				try {
1376
					resultFile = resultFileManager.loadFile(vectorFileName);
1377
				}
1378
				catch (Throwable te) {
1379
					MessageDialog.openError(null, "Error", "Could not load vector file " + vectorFileName);
1380
					return;
1381
				}
1382

  
1383
				// select a run
1384
				Run run = null;
1385
				RunList runList = resultFileManager.getRunsInFile(resultFile);
1386
                String eventlogRunName = getEventLog().getSimulationBeginEntry().getRunId();
1387
				if (runList.size() == 0) {
1388
                    MessageBox messageBox = new MessageBox(Display.getCurrent().getActiveShell(), SWT.OK | SWT.APPLICATION_MODAL | SWT.ICON_ERROR);
1389
                    messageBox.setText("No runs in result file");
1390
                    messageBox.setMessage("The result file " + vectorFileName + " does not contain any runs");
1391
                    messageBox.open();
1392
                    return;
1393
				}
1394
				else if (runList.size() == 1)
1395
				    run = runList.get(0);
1396
				else if (runList.size() > 1) {
1397
                    ElementListSelectionDialog dialog = new ElementListSelectionDialog(null, new LabelProvider() {
1398
                        @Override
1399
                        public String getText(Object element) {
1400
                            Run run = (Run)element;
1401

  
1402
                            return run.getRunName();
1403
                        }
1404
                    });
1405
                    dialog.setFilter(eventlogRunName);
1406
                    dialog.setElements(runList.toArray());
1407
                    dialog.setTitle("Run selection");
1408
                    dialog.setMessage("Select a run to browse for vectors:");
1409
                    if (dialog.open() == ListDialog.CANCEL)
1410
                        return;
1411
                    run = (Run)dialog.getFirstResult();
1412
				}
1413

  
1414
                // compare eventlog run id against vector file's run id
1415
				String vectorRunName = run.getRunName();
1416
				if (!eventlogRunName.equals(vectorRunName)) {
1417
                    MessageBox messageBox = new MessageBox(Display.getCurrent().getActiveShell(), SWT.OK | SWT.CANCEL | SWT.APPLICATION_MODAL | SWT.ICON_WARNING);
1418
                    messageBox.setText("Run ID mismatch");
1419
                    messageBox.setMessage("The eventlog run ID: " + eventlogRunName + " and the vector file run ID: " + vectorRunName + " does not match. Do you want to continue?");
1420

  
1421
                    if (messageBox.open() == SWT.CANCEL)
1422
                        return;
1423
				}
1424

  
1425
				// select a vector from the loaded file and run
1426
				long id;
1427
                IDList idList = resultFileManager.getVectorsInFileRun(resultFileManager.getFileRun(resultFile, run));
1428

  
1429
				if (idList.size() == 0) {
1430
                    MessageBox messageBox = new MessageBox(Display.getCurrent().getActiveShell(), SWT.OK | SWT.APPLICATION_MODAL | SWT.ICON_ERROR);
1431
                    messageBox.setText("No vectors in run");
1432
                    messageBox.setMessage("The run " + run.getRunName() + " in the vector file " + vectorFileName + " does not contain any vectors");
1433
                    messageBox.open();
1434
                    return;
1435
				}
1436
				else {
1437
                    ElementListSelectionDialog dialog = new ElementListSelectionDialog(null, new LabelProvider() {
1438
    					@Override
1439
    					public String getText(Object element) {
1440
    						long id = (Long)element;
1441
    						ResultItem resultItem = resultFileManager.getItem(id);
1442

  
1443
    						return resultItem.getModuleName() + ":" + resultItem.getName();
1444
    					}
1445
    				});
1446
    				dialog.setFilter(axisModule.getModuleFullPath());
1447
    				dialog.setElements(idList.toArray());
1448
                    dialog.setTitle("Vector selection");
1449
    				dialog.setMessage("Select a vector to attach:");
1450
    				if (dialog.open() == ListDialog.CANCEL)
1451
    				    return;
1452
                    id = (Long)dialog.getFirstResult();
1453
				}
1454

  
1455
				// attach vector data
1456
				ResultItem resultItem = resultFileManager.getItem(id);
1457
				XYArray data = VectorFileUtil.getDataOfVector(resultFileManager, id, true);
1458
				sequenceChart.setAxisRenderer(axisModule,
1459
			        new AxisVectorBarRenderer(sequenceChart, vectorFileName, vectorRunName, resultItem.getModuleName(), resultItem.getName(), resultItem, data));
1460
			}
1461
		};
1462
	}
1463

  
1464
	private SequenceChartAction createDetachVectorFromAxisAction(final ModuleTreeItem axisModule) {
1465
		return new SequenceChartAction("Detach Vector from Axis", Action.AS_PUSH_BUTTON, SequenceChartPlugin.getImageDescriptor(IMAGE_ATTACH_VECTOR_TO_AXIS)) {
1466
			@Override
1467
			protected void doRun() {
1468
				sequenceChart.setAxisRenderer(axisModule, new AxisLineRenderer(sequenceChart, axisModule));
1469
			}
1470
		};
1471
	}
1472

  
1473

  
1474
	private SequenceChartAction createToggleBookmarkAction() {
1475
		return new SequenceChartAction("Toggle bookmark", Action.AS_PUSH_BUTTON, ImageFactory.getDescriptor(ImageFactory.TOOLBAR_IMAGE_TOGGLE_BOOKMARK)) {
1476
			@Override
1477
			protected void doRun() {
1478
				try {
1479
					EventLogInput eventLogInput = sequenceChart.getInput();
1480
					IEvent event = sequenceChart.getSelectionEvent();
1481

  
1482
					if (event != null) {
1483
						boolean found = false;
1484
						IMarker[] markers = eventLogInput.getFile().findMarkers(IMarker.BOOKMARK, true, IResource.DEPTH_ZERO);
1485

  
1486
						for (IMarker marker : markers)
1487
							if (marker.getAttribute("EventNumber", "-1").equals(String.valueOf(event.getEventNumber()))) {
1488
								marker.delete();
1489
								found = true;
1490
							}
1491

  
1492
                        if (!found) {
1493
                            InputDialog dialog = new InputDialog(null, "Add Bookmark", "Enter Bookmark name:", "", null);
1494

  
1495
                            if (dialog.open() == Window.OK) {
1496
                                IMarker marker = eventLogInput.getFile().createMarker(IMarker.BOOKMARK);
1497
                                marker.setAttribute(IMarker.LOCATION, "# " + event.getEventNumber());
1498
                                marker.setAttribute("EventNumber", String.valueOf(event.getEventNumber()));
1499
                                marker.setAttribute(IMarker.MESSAGE, dialog.getValue());
1500
                            }
1501
                        }
1502

  
1503
						update();
1504
						sequenceChart.redraw();
1505
					}
1506
				}
1507
				catch (CoreException e) {
1508
					throw new RuntimeException(e);
1509
				}
1510
			}
1511

  
1512
			@Override
1513
			public void update() {
1514
				setEnabled(sequenceChart.getSelectionEvent() != null);
1515
			}
1516
		};
1517
	}
1518

  
1519
	private SequenceChartAction createCopyToClipboardAction() {
1520
	    return new SequenceChartAction("Copy to Clipboard", Action.AS_PUSH_BUTTON) {
1521
	        @Override
1522
	        protected void doRun() {
1523
	            sequenceChart.copyToClipboard();
1524
	        }
1525
	    };
1526
	}
1527

  
1528
	private SequenceChartAction createExportToSVGAction() {
1529
		return new SequenceChartAction("Export to SVG...", Action.AS_PUSH_BUTTON, SequenceChartPlugin.getImageDescriptor(IMAGE_EXPORT_SVG)) {
1530
			@Override
1531
			protected void doRun() {
1532
			    long[] exportRegion = askExportRegion();
1533

  
1534
				if (exportRegion != null) {
1535
					String fileName = askFileName();
1536

  
1537
					if (fileName != null) {
1538
					    long exportBeginX = exportRegion[0];
1539
					    long exportEndX = exportRegion[1];
1540
						GraphicsSVG graphics = createGraphics(exportBeginX, exportEndX);
1541

  
1542
						long top = sequenceChart.getViewportTop();
1543
						long left = sequenceChart.getViewportLeft();
1544

  
1545
						try {
1546
							sequenceChart.scrollHorizontalTo(exportBeginX + sequenceChart.getViewportLeft());
1547
							sequenceChart.scrollVerticalTo(0);
1548
							sequenceChart.paintArea(graphics);
1549
							writeXML(graphics, fileName);
1550
				        }
1551
				        catch (Exception e) {
1552
				        	throw new RuntimeException(e);
1553
				        }
1554
				        finally {
1555
				            graphics.dispose();
1556
				            sequenceChart.scrollHorizontalTo(left);
1557
				            sequenceChart.scrollVerticalTo(top);
1558
				        }
1559
					}
1560
				}
1561
			}
1562

  
1563
			private String askFileName() {
1564
				FileDialog fileDialog = new FileDialog(Display.getCurrent().getActiveShell(), SWT.SAVE);
1565
				IPath location = sequenceChart.getInput().getFile().getLocation().makeAbsolute();
1566
				fileDialog.setFileName(location.removeFileExtension().addFileExtension("svg").lastSegment());
1567
				fileDialog.setFilterPath(location.removeLastSegments(1).toOSString());
1568
				String fileName = fileDialog.open();
1569

  
1570
				if (fileName != null) {
1571
                    File file = new File(fileName);
1572

  
1573
                    if (file.exists()) {
1574
    		            MessageBox messageBox = new MessageBox(Display.getCurrent().getActiveShell(), SWT.OK | SWT.CANCEL | SWT.APPLICATION_MODAL | SWT.ICON_WARNING);
1575
    		            messageBox.setText("File already exists");
1576
    		            messageBox.setMessage("The file " + fileName + " already exists and will be overwritten. Do you want to continue the operation?");
1577

  
1578
    		            if (messageBox.open() == SWT.CANCEL)
1579
    		                fileName = null;
1580
                    }
1581
				}
1582

  
1583
                return fileName;
1584
			}
1585

  
1586
			private long[] askExportRegion() {
1587
				ExportToSVGDialog dialog = new ExportToSVGDialog(Display.getCurrent().getActiveShell());
1588

  
1589
				if (dialog.open() == Window.OK) {
1590
					IEventLog eventLog = getEventLog();
1591

  
1592
					long exportBeginX;
1593
					long exportEndX;
1594

  
1595
					switch (dialog.getSelectedRangeType()) {
1596
						case 0:
1597
							List<IEvent> selectionEvents = sequenceChart.getSelectionEvents();
1598

  
1599
							IEvent e0 = selectionEvents.get(0);
1600
							IEvent e1 = selectionEvents.get(1);
1601

  
1602
							if (e0.getEventNumber() < e1.getEventNumber()) {
1603
								exportBeginX = sequenceChart.getEventXViewportCoordinate(e0.getCPtr());
1604
								exportEndX = sequenceChart.getEventXViewportCoordinate(e1.getCPtr());
1605
							}
1606
							else {
1607
								exportBeginX = sequenceChart.getEventXViewportCoordinate(e1.getCPtr());
1608
								exportEndX = sequenceChart.getEventXViewportCoordinate(e0.getCPtr());
1609
							}
1610
							break;
1611
						case 1:
1612
							exportBeginX = 0;
1613
							exportEndX = sequenceChart.getViewportWidth();
1614
							break;
1615
						case 2:
1616
							exportBeginX = sequenceChart.getEventXViewportCoordinate(eventLog.getFirstEvent().getCPtr());
1617
							exportEndX = sequenceChart.getEventXViewportCoordinate(eventLog.getLastEvent().getCPtr());
1618
							break;
1619
						default:
1620
							return null;
1621
					}
1622

  
1623
					int extraSpace = dialog.getExtraSpace();
1624

  
1625
					return new long[] {exportBeginX - extraSpace, exportEndX + extraSpace};
1626
				}
1627
				else
1628
					return null;
1629
			}
1630

  
1631
			private GraphicsSVG createGraphics(long exportBeginX, long exportEndX) {
1632
			    int width = (int)(exportEndX - exportBeginX);
1633
			    int height = (int)sequenceChart.getVirtualHeight() + sequenceChart.getGutterHeight(null) * 2 + 2;
1634

  
1635
				GraphicsSVG graphics = GraphicsSVG.getInstance(new Rectangle(0, -1, width, height));
1636
				SVGGraphics2D g = graphics.getSVGGraphics2D();
1637
				g.setClip(0, 0, width, height);
1638
				g.setRenderingHint(RenderingHints.KEY_TEXT_ANTIALIASING, RenderingHints.VALUE_TEXT_ANTIALIAS_ON);
1639
                //graphics.setClip(new Rectangle(-1000, -100, 1000, 100));
1640
				graphics.translate(0, 1);
1641
				graphics.setAntialias(SWT.ON);
1642

  
1643
				return graphics;
1644
			}
1645

  
1646
			private void writeXML(GraphicsSVG graphics, String fileName)
1647
				throws TransformerConfigurationException, TransformerFactoryConfigurationError, TransformerException
1648
			{
1649
				Source source = new DOMSource(graphics.getRoot());
1650
				StreamResult streamResult = new StreamResult(new File(fileName));
1651
				Transformer transformer = TransformerFactory.newInstance().newTransformer();
1652
				transformer.setOutputProperty(OutputKeys.INDENT, "yes");
1653
				transformer.transform(source, streamResult);
1654
			}
1655

  
1656
			@Override
1657
			public void update() {
1658
				setEnabled(sequenceChart.getInput() != null);
1659
			}
1660

  
1661
			class ExportToSVGDialog extends TitleAreaDialog {
1662
				private int extraSpace;
1663

  
1664
				private int selectedRangeType;
1665

  
1666
				public ExportToSVGDialog(Shell shell) {
1667
					super(shell);
1668
			        setShellStyle(getShellStyle() | SWT.RESIZE);
1669
				}
1670

  
1671
				public int getExtraSpace() {
1672
					return extraSpace;
1673
				}
1674

  
1675
				public int getSelectedRangeType() {
1676
					return selectedRangeType;
1677
				}
1678

  
1679
				@Override
1680
				protected IDialogSettings getDialogBoundsSettings() {
1681
				    return UIUtils.getDialogSettings(SequenceChartPlugin.getDefault(), getClass().getName());
1682
				}
1683

  
1684
				@Override
1685
				protected Control createDialogArea(Composite parent) {
1686
					setHelpAvailable(false);
1687

  
1688
					Composite container = new Composite((Composite)super.createDialogArea(parent), SWT.NONE);
1689
					container.setLayoutData(new GridData(SWT.FILL, SWT.FILL, true, true));
1690
					container.setLayout(new GridLayout(2, false));
1691

  
1692
					Group group = new Group(container, SWT.NONE);
1693
					GridData gridData = new GridData(SWT.FILL, SWT.BEGINNING, true, false);
1694
					gridData.horizontalSpan = 2;
1695
					group.setText("Select range to export");
1696
					group.setLayoutData(gridData);
1697
					group.setLayout(new GridLayout(1, false));
1698

  
1699
			        // radio buttons
1700
					createButton(group, "Range of two selected events", 0).setEnabled(sequenceChart.getSelectionEvents().size() == 2);
1701
					createButton(group, "Visible area only", 1);
1702
					createButton(group, "Whole event log", 2);
1703

  
1704
					Label label = new Label(container, SWT.NONE);
1705
					label.setText("Extra space in pixels around both ends: ");
1706
					label.setLayoutData(new GridData(SWT.BEGINNING, SWT.CENTER, false, false));
1707

  
1708
					final Text text = new Text(container, SWT.BORDER | SWT.SINGLE);
1709
					text.setLayoutData(new GridData(SWT.FILL, SWT.BEGINNING, true, false));
1710
					text.setText(String.valueOf(extraSpace));
1711
					text.addModifyListener(new ModifyListener() {
1712
						public void modifyText(ModifyEvent e) {
1713
							try {
1714
								extraSpace = Integer.parseInt(text.getText());
1715
							}
1716
							catch (Exception x) {
1717
								// void
1718
							}
1719
						}
1720
					});
1721

  
1722
					setTitle("Export to SVG");
1723
					setMessage("Please select which part of the event log should be exported");
1724

  
1725
					return container;
1726
				}
1727

  
1728
				private Button createButton(Group group, String text, final int type) {
1729
					Button button = new Button(group, SWT.RADIO);
1730
					button.setText(text);
1731
					button.addSelectionListener(new SelectionAdapter() {
1732
						@Override
1733
						public void widgetSelected(SelectionEvent e) {
1734
							selectedRangeType = type;
1735
						}
1736
					});
1737

  
1738
					return button;
1739
				}
1740

  
1741
				@Override
1742
				protected void configureShell(Shell newShell) {
1743
					newShell.setText("Export to SVG");
1744
					super.configureShell(newShell);
1745
				}
1746
			};
1747
		};
1748
	}
1749

  
1750
    private SequenceChartAction createRefreshAction() {
1751
        return new SequenceChartAction("Refresh", Action.AS_PUSH_BUTTON, ImageFactory.getDescriptor(ImageFactory.TOOLBAR_IMAGE_REFRESH)) {
1752
            @Override
1753
            protected void doRun() {
1754
                sequenceChart.refresh();
1755
            }
1756
        };
1757
    }
1758

  
1759
	private CommandContributionItem createRefreshCommandContributionItem() {
1760
        CommandContributionItemParameter parameter = new CommandContributionItemParameter(Workbench.getInstance(), null, "org.omnetpp.sequencechart.refresh", SWT.PUSH);
1761
        parameter.icon = ImageFactory.getDescriptor(ImageFactory.TOOLBAR_IMAGE_REFRESH);
1762
        return new CommandContributionItem(parameter);
1763
	}
1764

  
1765
    private SequenceChartAction createReleaseMemoryAction() {
1766
        return new SequenceChartAction("Release Memory", Action.AS_PUSH_BUTTON) {
1767
            @Override
1768
            protected void doRun() {
1769
                sequenceChart.getInput().synchronize(FileReader.FileChangedState.OVERWRITTEN);
1770
            }
1771
        };
1772
    }
1773

  
1774
	private StatusLineContributionItem createTimelineModeStatus() {
1775
		return new StatusLineContributionItem("Timeline Mode", true, "SIMULATION_TIME".length()) {
1776
			@Override
1777
		    public void update() {
1778
			    String timelineModeName = sequenceChart.getTimelineMode().name();
1779
				setText(WordUtils.capitalize(timelineModeName.replaceAll("_", " ").toLowerCase()));
1780
		    }
1781
		};
1782
	}
1783
	
1784
	static class CustomBottleneckOptionsDialog extends TitleAreaDialog {
1785
		private SequenceChart sequenceChart;
1786
		private Scale maximum;
1787
		private Label maximumLabel;
1788
		
1789
        private CustomBottleneckOptionsDialog(Shell parentShell, SequenceChart sequenceChart) {
1790
            super(parentShell);
1791
            this.sequenceChart = sequenceChart;
1792
            setShellStyle(getShellStyle() | SWT.RESIZE);
1793
        }
1794

  
1795
        @Override
1796
        protected Control createDialogArea(Composite parent) {
1797

  
1798
        	setHelpAvailable(false);
1799
        	setTitle("Bottleneck Finder Preferences");
1800
        	setMessage("Please choose the maximum number of parallel events to be identified as a bottleneck.");
1801

  
1802
        	Composite container = new Composite((Composite)super.createDialogArea(parent), SWT.NONE);
1803
        	container.setLayoutData(new GridData(SWT.FILL, SWT.FILL, true, true));
1804
        	container.setLayout(new GridLayout());
1805

  
1806
        	maximumLabel = new Label(container, SWT.NONE);
1807
        	maximumLabel.setLayoutData(new GridData(SWT.FILL, SWT.BEGINNING, true, false));
1808
        	maximumLabel.setText("Identify Bottlenecks with less or equal than: " + sequenceChart.getBottleneckThreshold() + " events.");
1809
        	maximum = new Scale(container, SWT.NONE);
1810
        	maximum.setLayoutData(new GridData(SWT.FILL, SWT.BEGINNING, true, false));
1811
        	maximum.setMinimum(1);
1812
        	maximum.setMaximum(100);
1813
        	maximum.setSelection(sequenceChart.getBottleneckThreshold());
1814
        	maximum.addSelectionListener(new SelectionAdapter() {
1815
        		@Override
1816
        		public void widgetSelected(SelectionEvent e) {
1817
        			setMaximumText();
1818
        			apply();
1819
        		}
1820
        	});
1821
        	return container;
1822
        }
1823

  
1824
        @Override
1825
        protected void configureShell(Shell newShell) {
1826
        	newShell.setText("Bottleneck Finder Preferences");
1827
        	super.configureShell(newShell);
1828
        }
1829

  
1830
        @Override
1831
        protected void okPressed() {
1832
        	apply();
1833
        	super.okPressed();
1834
        }
1835

  
1836
        @Override
1837
        protected void cancelPressed() {
1838
        	super.cancelPressed();
1839
        }
1840

  
1841
        public void apply() {
1842
        	sequenceChart.setBottleneckThreshold(maximum.getSelection());
1843
        }
1844
        
1845
        public void setMaximumText() {
1846
        	maximumLabel.setText("Identify Bottlenecks with less or equal than: " + maximum.getSelection() + " events.");
1847

  
1848
        }
1849

  
1850
    }
1851

  
1852
	static class CustomNonlinearOptionsDialog extends TitleAreaDialog {
1853
	    private SequenceChart sequenceChart;
1854
        private SequenceChartFacade sequenceChartFacade;
1855
        private double oldNonLinearMinimumTimelineCoordinateDelta;
1856
        private double oldNonLinearFocus;
1857
        private org.omnetpp.common.engine.BigDecimal[] oldLeftRightSimulationTimeRange;
1858
        private Label minimumLabel;
1859
        private Label focusLabel;
1860
        private Scale minimum;
1861
        private Scale focus;
1862

  
1863
        private CustomNonlinearOptionsDialog(Shell parentShell, SequenceChart sequenceChart) {
1864
            super(parentShell);
1865
            this.sequenceChart = sequenceChart;
1866
            setShellStyle(getShellStyle() | SWT.RESIZE);
1867
        }
1868

  
1869
        @Override
1870
        protected Control createDialogArea(Composite parent) {
1871
        	sequenceChartFacade = sequenceChart.getInput().getSequenceChartFacade();
1872
        	oldLeftRightSimulationTimeRange = sequenceChart.getViewportSimulationTimeRange();
1873
        	oldNonLinearMinimumTimelineCoordinateDelta = sequenceChartFacade.getNonLinearMinimumTimelineCoordinateDelta();
1874
        	oldNonLinearFocus = sequenceChartFacade.getNonLinearFocus();
1875

  
1876
        	setHelpAvailable(false);
1877
        	setTitle("Custom nonlinear timeline mode");
1878
        	setMessage("Please select appropriate nonlinearity factors");
1879

  
1880
        	Composite container = new Composite((Composite)super.createDialogArea(parent), SWT.NONE);
1881
        	container.setLayoutData(new GridData(SWT.FILL, SWT.FILL, true, true));
1882
        	container.setLayout(new GridLayout());
1883

  
1884
        	minimumLabel = new Label(container, SWT.NONE);
1885
        	minimumLabel.setLayoutData(new GridData(SWT.FILL, SWT.BEGINNING, true, false));
1886

  
1887
        	minimum = new Scale(container, SWT.NONE);
1888
        	minimum.setLayoutData(new GridData(SWT.FILL, SWT.BEGINNING, true, false));
1889
        	minimum.setMinimum(0);
1890
        	minimum.setMaximum(1000);
1891
        	minimum.addSelectionListener(new SelectionAdapter() {
1892
        		@Override
1893
        		public void widgetSelected(SelectionEvent e) {
1894
        			setNonLinearMinimumTimelineCoordinateDeltaText();
1895
        			apply();
1896
        		}
1897
        	});
1898
        	minimum.setSelection(getNonLinearMinimumTimelineCoordinateDeltaScale());
1899
        	setNonLinearMinimumTimelineCoordinateDeltaText();
1900

  
1901
        	focusLabel = new Label(container, SWT.NONE);
1902
        	focusLabel.setLayoutData(new GridData(SWT.FILL, SWT.BEGINNING, true, false));
1903

  
1904
        	focus = new Scale(container, SWT.NONE);
1905
        	focus.setLayoutData(new GridData(SWT.FILL, SWT.BEGINNING, true, false));
1906
        	focus.setMinimum(0);
1907
        	focus.setMaximum(1000);
1908
        	focus.addSelectionListener(new SelectionAdapter() {
1909
        		@Override
1910
        		public void widgetSelected(SelectionEvent e) {
1911
        			setNonLinearFocusText();
1912
        			apply();
1913
        		}
1914
        	});
1915
        	focus.setSelection(getNonLinearFocusScale());
1916
        	setNonLinearFocusText();
1917

  
1918
        	return container;
1919
        }
1920

  
1921
        @Override
1922
        protected void configureShell(Shell newShell) {
1923
        	newShell.setText("Custom nonlinear timeline mode");
1924
        	super.configureShell(newShell);
1925
        }
1926

  
1927
        @Override
1928
        protected void okPressed() {
1929
        	apply();
1930
        	super.okPressed();
1931
        }
1932

  
1933
        @Override
1934
        protected void cancelPressed() {
1935
        	sequenceChartFacade.setNonLinearMinimumTimelineCoordinateDelta(oldNonLinearMinimumTimelineCoordinateDelta);
1936
        	sequenceChartFacade.setNonLinearFocus(oldNonLinearFocus);
1937

  
1938
        	redrawSequenceChart();
1939

  
1940
        	super.cancelPressed();
1941
        }
1942

  
1943
        private void apply() {
1944
        	sequenceChartFacade.setNonLinearFocus(getNonLinearFocus());
1945
        	sequenceChartFacade.setNonLinearMinimumTimelineCoordinateDelta(getNonLinearMinimumTimelineCoordinateDelta());
1946

  
1947
        	redrawSequenceChart();
1948
        }
1949

  
1950
        private void redrawSequenceChart() {
1951
        	sequenceChartFacade.relocateTimelineCoordinateSystem(sequenceChartFacade.getTimelineCoordinateSystemOriginEvent());
1952
        	sequenceChart.setViewportSimulationTimeRange(oldLeftRightSimulationTimeRange);
1953
        }
1954

  
1955
        private void setNonLinearMinimumTimelineCoordinateDeltaText() {
1956
            BigDecimal value = new BigDecimal(100 * getNonLinearMinimumTimelineCoordinateDelta());
1957
            value = value.round(new MathContext(3));
1958
        	minimumLabel.setText("Relative minimum distance to maximum distance: " + value + "%");
1959
        }
1960

  
1961
        private int getNonLinearMinimumTimelineCoordinateDeltaScale() {
1962
        	return (int)(1000 * sequenceChartFacade.getNonLinearMinimumTimelineCoordinateDelta());
1963
        }
1964

  
1965
        private double getNonLinearMinimumTimelineCoordinateDelta() {
1966
        	return (double)minimum.getSelection() / 1000;
1967
        }
1968

  
1969
        private int getNonLinearFocusScale() {
1970
        	return (int)((Math.log10(sequenceChartFacade.getNonLinearFocus()) + 18) * 40);
1971
        }
1972

  
1973
        private double getNonLinearFocus() {
1974
        	return Math.pow(10, ((double)focus.getSelection() / 40) - 18);
1975
        }
1976

  
1977
        private void setNonLinearFocusText() {
1978
            BigDecimal value = new BigDecimal(getNonLinearFocus());
1979
            value = value.round(new MathContext(3));
1980
        	focusLabel.setText("Nonlinear simulation time focus: " + TimeUtils.secondsToTimeString(value));
1981
        }
1982
    }
1983

  
1984
    private abstract class SequenceChartAction extends Action {
1985
		public SequenceChartAction(String text, int style) {
1986
			super(text, style);
1987
		}
1988

  
1989
		public SequenceChartAction(String text, int style, ImageDescriptor image) {
1990
			super(text, style);
1991
			setImageDescriptor(image);
1992
		}
1993

  
1994
		public void update() {
1995
		}
1996

  
1997
		@Override
1998
		public void run() {
1999
	        try {
2000
	            doRun();
2001
	        }
2002
	        catch (Exception e) {
2003
	            MessageDialog.openError(Display.getCurrent().getActiveShell(), "Error", "Internal error: " + e.toString());
2004
	            SequenceChartPlugin.logError(e);
2005
	        }
2006
		}
2007

  
2008
        protected abstract void doRun();
2009
	}
2010

  
2011
	private abstract class SequenceChartMenuAction extends SequenceChartAction {
2012
		protected ArrayList<Menu> menus = new ArrayList<Menu>();
2013

  
2014
		public SequenceChartMenuAction(String text, int style, ImageDescriptor image) {
2015
			super(text, style, image);
2016
		}
2017

  
2018
		@Override
2019
		public void update() {
2020
			for (Menu menu : menus)
2021
				if (!menu.isDisposed())
2022
					updateMenu(menu);
2023
		}
2024

  
2025
		protected void addMenu(Menu menu) {
2026
			Assert.isTrue(menu != null);
2027

  
2028
			menus.add(menu);
2029
			updateMenu(menu);
2030
		}
2031

  
2032
		protected void removeMenu(Menu menu) {
2033
			Assert.isTrue(menu != null);
2034

  
2035
			menus.remove(menu);
2036
		}
2037

  
2038
		protected abstract int getMenuIndex();
2039

  
2040
		protected void updateMenu(Menu menu) {
2041
			for (int i = 0; i < menu.getItemCount(); i++) {
2042
				boolean selection = i == getMenuIndex();
2043
				MenuItem menuItem = menu.getItem(i);
2044

  
2045
				if (menuItem.getSelection() != selection)
2046
					menuItem.setSelection(selection);
2047
			}
2048
		}
2049

  
2050
		protected abstract class AbstractMenuCreator implements IMenuCreator {
2051
			private Menu controlMenu;
2052

  
2053
			private Menu parentMenu;
2054

  
2055
			public void dispose() {
2056
				if (controlMenu != null) {
2057
					controlMenu.dispose();
2058
					removeMenu(controlMenu);
2059
				}
2060

  
2061
				if (parentMenu != null) {
2062
					parentMenu.dispose();
2063
					removeMenu(parentMenu);
2064
				}
2065
			}
2066

  
2067
			public Menu getMenu(Control parent) {
2068
				if (controlMenu == null) {
2069
					controlMenu = new Menu(parent);
2070
					createMenu(controlMenu);
2071
					addMenu(controlMenu);
2072
				}
2073

  
2074
				return controlMenu;
2075
			}
2076

  
2077
			public Menu getMenu(Menu parent) {
2078
				if (parentMenu == null) {
2079
					parentMenu = new Menu(parent);
2080
					createMenu(parentMenu);
2081
					addMenu(parentMenu);
2082
				}
2083

  
2084
				return parentMenu;
2085
			}
2086

  
2087
			protected abstract void createMenu(Menu menu);
2088
		}
2089
	}
2090

  
2091
    public static class FindTextHandler extends AbstractHandler {
2092
        public Object execute(ExecutionEvent event) throws ExecutionException {
2093
            IWorkbenchPart part = HandlerUtil.getActivePartChecked(event);
2094

  
2095
            if (part instanceof ISequenceChartProvider)
2096
                ((ISequenceChartProvider)part).getSequenceChart().findText(false);
2097

  
2098
            return null;
2099
        }
2100
    }
2101

  
2102
    public static class FindNextHandler extends AbstractHandler {
2103
        public Object execute(ExecutionEvent event) throws ExecutionException {
2104
            IWorkbenchPart part = HandlerUtil.getActivePartChecked(event);
2105

  
2106
            if (part instanceof ISequenceChartProvider)
2107
                ((ISequenceChartProvider)part).getSequenceChart().findText(true);
2108

  
2109
            return null;
2110
        }
2111
    }
2112

  
2113
    public static class RefreshHandler extends AbstractHandler {
2114
        public Object execute(ExecutionEvent event) throws ExecutionException {
2115
            IWorkbenchPart part = HandlerUtil.getActivePartChecked(event);
2116

  
2117
            if (part instanceof ISequenceChartProvider)
2118
                ((ISequenceChartProvider)part).getSequenceChart().refresh();
2119

  
2120
            return null;
2121
        }
2122
    }
2123
}
ide/sequencechart/src/org/omnetpp/sequencechart/editors/SequenceChartEditor.java
1
/*--------------------------------------------------------------*
2
  Copyright (C) 2006-2008 OpenSim Ltd.
3

  
4
  This file is distributed WITHOUT ANY WARRANTY. See the file
5
  'License' for details on this and other legal matters.
6
*--------------------------------------------------------------*/
7

  
8
package org.omnetpp.sequencechart.editors;
9

  
10
import org.eclipse.core.resources.IMarker;
11
import org.eclipse.core.resources.IResource;
12
import org.eclipse.core.resources.IResourceChangeEvent;
13
import org.eclipse.core.resources.IResourceChangeListener;
14
import org.eclipse.core.resources.IResourceDelta;
15
import org.eclipse.core.resources.IResourceDeltaVisitor;
16
import org.eclipse.core.resources.ResourcesPlugin;
17
import org.eclipse.core.runtime.CoreException;
18
import org.eclipse.jface.viewers.ISelection;
19
import org.eclipse.swt.SWT;
20
import org.eclipse.swt.layout.GridData;
21
import org.eclipse.swt.widgets.Composite;
22
import org.eclipse.swt.widgets.Display;
23
import org.eclipse.ui.IEditorInput;
24
import org.eclipse.ui.IEditorPart;
25
import org.eclipse.ui.IEditorSite;
26
import org.eclipse.ui.IFileEditorInput;
27
import org.eclipse.ui.IMemento;
28
import org.eclipse.ui.INavigationLocation;
29
import org.eclipse.ui.INavigationLocationProvider;
30
import org.eclipse.ui.ISelectionListener;
31
import org.eclipse.ui.IWorkbenchPart;
32
import org.eclipse.ui.PartInitException;
33
import org.eclipse.ui.contexts.IContextService;
34
import org.eclipse.ui.ide.IGotoMarker;
35
import org.eclipse.ui.part.FileEditorInput;
36
import org.eclipse.ui.part.IShowInSource;
37
import org.eclipse.ui.part.IShowInTargetList;
38
import org.eclipse.ui.part.ShowInContext;
39
import org.omnetpp.common.IConstants;
40
import org.omnetpp.common.eventlog.EventLogEditor;
41
import org.omnetpp.common.eventlog.IEventLogSelection;
42
import org.omnetpp.sequencechart.SequenceChartPlugin;
43
import org.omnetpp.sequencechart.widgets.SequenceChart;
44

  
45
/**
46
 * Sequence chart display tool. (It is not actually an editor; it is only named so
47
 * because it extends EditorPart).
48
 *
49
 * @author levy
50
 */
51
public class SequenceChartEditor
52
    extends EventLogEditor
53
    implements ISequenceChartProvider, INavigationLocationProvider, IGotoMarker, IShowInSource, IShowInTargetList
54
{
55
	private ResourceChangeListener resourceChangeListener = new ResourceChangeListener();
56

  
57
	private SequenceChart sequenceChart;
58

  
59
	private ISelectionListener selectionListener;
60

  
61
	public SequenceChart getSequenceChart() {
62
		return sequenceChart;
63
	}
64

  
65
	@Override
66
	public void init(IEditorSite site, IEditorInput input) throws PartInitException {
67
		super.init(site, input);
68
		ResourcesPlugin.getWorkspace().addResourceChangeListener(resourceChangeListener);
69

  
70
		IContextService contextService = (IContextService)site.getService(IContextService.class);
71
        contextService.activateContext("org.omnetpp.context.SequenceChart");
72

  
73
		// try to open the log view
74
		try {
75
			// Eclipse feature: during startup, showView() throws "Abnormal Workbench Condition" because perspective is null
76
			if (site.getPage().getPerspective() != null)
77
				site.getPage().showView("org.omnetpp.eventlogtable.editors.EventLogTableView");
78
		}
79
		catch (PartInitException e) {
80
			SequenceChartPlugin.getDefault().logException(e);
81
		}
82
	}
83

  
84
	@Override
85
	public void dispose() {
86
		if (resourceChangeListener != null)
87
			ResourcesPlugin.getWorkspace().removeResourceChangeListener(resourceChangeListener);
88

  
89
		if (selectionListener != null)
90
			getSite().getPage().removeSelectionListener(selectionListener);
91

  
92
		super.dispose();
93
	}
94

  
95
	@Override
96
	public void createPartControl(Composite parent) {
97
		sequenceChart = new SequenceChart(parent, SWT.DOUBLE_BUFFERED);
98
		sequenceChart.setFollowSelection(false);
99
		sequenceChart.setInput(eventLogInput);
100
		sequenceChart.setLayoutData(new GridData(SWT.FILL, SWT.FILL, true, true));
101
		sequenceChart.setSequenceChartContributor(SequenceChartContributor.getDefault());
102

  
103
		getSite().setSelectionProvider(sequenceChart);
104
		addLocationProviderPaintListener(sequenceChart);
105

  
106
		// follow selection
107
		selectionListener = new ISelectionListener() {
108
			public void selectionChanged(IWorkbenchPart part, ISelection selection) {
109
				if (part != SequenceChartEditor.this && selection instanceof IEventLogSelection) {
110
					IEventLogSelection eventLogSelection = (IEventLogSelection)selection;
111

  
112
					if (eventLogSelection.getEventLogInput() == sequenceChart.getInput()) {
113
						sequenceChart.setSelection(selection);
114
						markLocation();
115
					}
116
				}
117
			}
118
		};
119
		getSite().getPage().addSelectionListener(selectionListener);
120
	}
121

  
122
	@Override
123
	public void setFocus() {
124
		sequenceChart.setFocus();
125
	}
126

  
127
	public class SequenceChartLocation implements INavigationLocation {
128
		// TODO: ambiguous when restored
129
		private org.omnetpp.common.engine.BigDecimal startSimulationTime;
130

  
131
		private org.omnetpp.common.engine.BigDecimal endSimulationTime;
132

  
133
		public SequenceChartLocation(org.omnetpp.common.engine.BigDecimal startSimulationTime, org.omnetpp.common.engine.BigDecimal endSimulationTime) {
134
			this.startSimulationTime = startSimulationTime;
135
			this.endSimulationTime = endSimulationTime;
136
		}
137

  
138
		public void dispose() {
139
			// void
140
		}
141

  
142
		public Object getInput() {
143
			return SequenceChartEditor.this.getEditorInput();
144
		}
145

  
146
		public String getText() {
147
			return SequenceChartEditor.this.getPartName() + ": " + startSimulationTime + "s - " + endSimulationTime + "s";
148
		}
149

  
150
		public boolean mergeInto(INavigationLocation currentLocation) {
151
            return equals(currentLocation);
152
		}
153

  
154
		public void releaseState() {
155
			// void
156
		}
157

  
158
		public void restoreLocation() {
159
			sequenceChart.zoomToSimulationTimeRange(startSimulationTime, endSimulationTime);
160
		}
161

  
162
		public void restoreState(IMemento memento) {
163
		    String value = memento.getString("StartSimulationTime");
164
            if (value != null)
165
                startSimulationTime = org.omnetpp.common.engine.BigDecimal.parse(value);
166

  
167
            value = memento.getString("EndSimulationTime");
168
            if (value != null)
169
                endSimulationTime = org.omnetpp.common.engine.BigDecimal.parse(value);
170
		}
171

  
172
		public void saveState(IMemento memento) {
173
            memento.putString("StartSimulationTime", startSimulationTime.toString());
174
            memento.putString("EndSimulationTime", endSimulationTime.toString());
175
		}
176

  
177
		public void setInput(Object input) {
178
			SequenceChartEditor.this.setInput((IFileEditorInput)input);
179
		}
180

  
181
		public void update() {
182
			// void
183
		}
184

  
185
        @Override
186
        public int hashCode() {
187
            final int prime = 31;
188
            int result = 1;
189
            result = prime * result + getOuterType().hashCode();
190
            result = prime * result + ((endSimulationTime == null) ? 0 : endSimulationTime.hashCode());
191
            result = prime * result + ((startSimulationTime == null) ? 0 : startSimulationTime.hashCode());
192
            return result;
193
        }
194

  
195
        @Override
196
        public boolean equals(Object obj) {
197
            if (this == obj)
198
                return true;
199
            if (obj == null)
200
                return false;
201
            if (getClass() != obj.getClass())
202
                return false;
203
            SequenceChartLocation other = (SequenceChartLocation) obj;
204
            if (!getOuterType().equals(other.getOuterType()))
205
                return false;
206
            if (endSimulationTime == null) {
207
                if (other.endSimulationTime != null)
208
                    return false;
209
            }
210
            else if (!endSimulationTime.equals(other.endSimulationTime))
211
                return false;
212
            if (startSimulationTime == null) {
213
                if (other.startSimulationTime != null)
214
                    return false;
215
            }
216
            else if (!startSimulationTime.equals(other.startSimulationTime))
217
                return false;
218
            return true;
219
        }
220

  
221
        private SequenceChartEditor getOuterType() {
222
            return SequenceChartEditor.this;
223
        }
224
	}
225

  
226
	public INavigationLocation createEmptyNavigationLocation() {
227
		return new SequenceChartLocation(org.omnetpp.common.engine.BigDecimal.getZero(), org.omnetpp.common.engine.BigDecimal.getNaN());
228
	}
229

  
230
	@Override
231
	protected boolean canCreateNavigationLocation() {
232
		return !eventLogInput.isCanceled() && super.canCreateNavigationLocation();
233
	}
234

  
235
	public INavigationLocation createNavigationLocation() {
236
		if (!canCreateNavigationLocation())
237
			return null;
238
		else
239
			return new SequenceChartLocation(sequenceChart.getViewportLeftSimulationTime(), sequenceChart.getViewportRightSimulationTime());
240
	}
241

  
242
    public void gotoMarker(IMarker marker)
243
    {
244
		long eventNumber = Long.parseLong(marker.getAttribute("EventNumber", "-1"));
245
		sequenceChart.gotoElement(eventLogInput.getEventLog().getEventForEventNumber(eventNumber));
246
    }
247

  
248
	private class ResourceChangeListener implements IResourceChangeListener, IResourceDeltaVisitor {
249
		public void resourceChanged(IResourceChangeEvent event) {
250
            try {
251
                // close editor on project close
252
                if (event.getType() == IResourceChangeEvent.PRE_CLOSE) {
253
                    final IEditorPart thisEditor = SequenceChartEditor.this;
254
                    final IResource resource = event.getResource();
255
                    Display.getDefault().asyncExec(new Runnable(){
256
                        public void run(){
257
                            if (((FileEditorInput)thisEditor.getEditorInput()).getFile().getProject().equals(resource)) {
258
                                thisEditor.getSite().getPage().closeEditor(thisEditor, true);
259
                            }
260
                        }
261
                    });
262
                }
263

  
264
                IResourceDelta delta = event.getDelta();
265

  
266
                if (delta != null)
267
                	delta.accept(this);
268
            }
269
            catch (CoreException e) {
270
            	throw new RuntimeException(e);
271
            }
272
		}
273

  
274
        public boolean visit(IResourceDelta delta) {
275
            if (delta != null && delta.getResource() != null && delta.getResource().equals(eventLogInput.getFile())) {
276
            	Display.getDefault().asyncExec(new Runnable() {
277
					public void run() {
278
                        if (!sequenceChart.isDisposed())
279
                            sequenceChart.clearCanvasCacheAndRedraw();
280
					}
281
            	});
282
            }
283

  
284
            return true;
285
        }
286
	}
287

  
288
    /* (non-Javadoc)
289
     * Method declared on IShowInSource
290
     */
291
    public ShowInContext getShowInContext() {
292
        return new ShowInContext(getEditorInput(), getSite().getSelectionProvider().getSelection());
293
    }
294

  
295
    /* (non-Javadoc)
296
     * Method declared on IShowInTargetList
297
     */
298
    public String[] getShowInTargetIds() {
299
        // contents of the "Show In..." context menu
300
        return new String[] {
301
                IConstants.EVENTLOG_VIEW_ID,
302
                //TODO IConstants.MODULEHIERARCHY_VIEW_ID,
303
                };
304
    }
305
}
ide/sequencechart/src/org/omnetpp/sequencechart/editors/SequenceChartView.java
1
/*--------------------------------------------------------------*
2
  Copyright (C) 2006-2008 OpenSim Ltd.
3

  
4
  This file is distributed WITHOUT ANY WARRANTY. See the file
5
  'License' for details on this and other legal matters.
6
*--------------------------------------------------------------*/
7

  
8
package org.omnetpp.sequencechart.editors;
9

  
10
import org.eclipse.jface.viewers.ISelection;
11
import org.eclipse.swt.SWT;
12
import org.eclipse.swt.widgets.Composite;
13
import org.eclipse.swt.widgets.Control;
14
import org.eclipse.ui.IEditorPart;
15
import org.eclipse.ui.IPartListener;
16
import org.eclipse.ui.ISelectionListener;
17
import org.eclipse.ui.IViewSite;
18
import org.eclipse.ui.IWorkbenchPart;
19
import org.eclipse.ui.contexts.IContextService;
20
import org.omnetpp.common.eventlog.EventLogView;
21
import org.omnetpp.common.eventlog.IEventLogSelection;
22
import org.omnetpp.eventlog.engine.IEventLog;
23
import org.omnetpp.sequencechart.widgets.SequenceChart;
24

  
25
/**
26
 * View for displaying causes and consequences of events.
27
 */
28
public class SequenceChartView extends EventLogView implements ISequenceChartProvider {
29
	private SequenceChart sequenceChart;
30

  
31
    private SequenceChartContributor sequenceChartContributor;
32

  
33
	private ISelectionListener selectionListener;
34

  
35
	private IPartListener partListener;
36

  
37
    public SequenceChart getSequenceChart() {
38
        return sequenceChart;
39
    }
40

  
41
	@Override
42
	public void createPartControl(Composite parent) {
43
		super.createPartControl(parent);
44

  
45
		// we want to provide selection for the sequence chart tool (an IEditPart)
46
		IViewSite viewSite = (IViewSite)getSite();
47
		viewSite.setSelectionProvider(sequenceChart);
48
        IContextService contextService = (IContextService)viewSite.getService(IContextService.class);
49
        contextService.activateContext("org.omnetpp.context.SequenceChart");
50

  
51
		// contribute to toolbar
52
		sequenceChartContributor = new SequenceChartContributor(sequenceChart);
53
		sequenceChart.setSequenceChartContributor(sequenceChartContributor);
54
		sequenceChartContributor.contributeToToolBar(viewSite.getActionBars().getToolBarManager());
55

  
56
		// follow selection
57
		selectionListener = new ISelectionListener() {
58
			public void selectionChanged(IWorkbenchPart part, ISelection selection) {
59
				if (part != SequenceChartView.this && selection instanceof IEventLogSelection)
60
					updateSelection(selection);
61
			}
62
		};
63
		viewSite.getPage().addSelectionListener(selectionListener);
64

  
65
		// follow active editor changes
66
		partListener = new IPartListener() {
67
			public void partActivated(IWorkbenchPart part) {
68
			}
69

  
70
			public void partBroughtToTop(IWorkbenchPart part) {
71
			    if (part instanceof IEditorPart && !sequenceChart.isDisposed())
72
			        updateSelectionFromActiveEditor();
73
			}
74

  
75
			public void partClosed(IWorkbenchPart part) {
76
                if (part instanceof IEditorPart && !sequenceChart.isDisposed())
77
                    updateSelectionFromActiveEditor();
78
			}
79

  
80
			public void partDeactivated(IWorkbenchPart part) {
81
			}
82

  
83
			public void partOpened(IWorkbenchPart part) {
84
                if (part instanceof IEditorPart && !sequenceChart.isDisposed())
85
                    updateSelectionFromActiveEditor();
86
			}
87
		};
88
		viewSite.getPage().addPartListener(partListener);
89

  
90
		// bootstrap with current selection
91
		selectionListener.selectionChanged(null, getActiveEditorSelection());
92
	}
93

  
94
	@Override
95
	public IEventLog getEventLog() {
96
	    return sequenceChart.getEventLog();
97
	}
98

  
99
	@Override
100
	public void dispose() {
101
		IViewSite viewSite = (IViewSite)getSite();
102

  
103
		if (selectionListener != null)
104
			viewSite.getPage().removeSelectionListener(selectionListener);
105

  
106
		if (partListener != null)
107
			viewSite.getPage().removePartListener(partListener);
108

  
109
		super.dispose();
110
	}
111

  
112
	@Override
113
	public void setFocus() {
114
		sequenceChart.setFocus();
115
	}
116

  
117
	@Override
118
	protected Control createViewControl(Composite parent) {
119
		sequenceChart = new SequenceChart(parent, SWT.DOUBLE_BUFFERED);
120

  
121
		return sequenceChart;
122
	}
123

  
124
    private void updateSelectionFromActiveEditor() {
125
        updateSelection(getActiveEditorSelection());
126
    }
127

  
128
    private void updateSelection(ISelection selection) {
129
		if (selection instanceof IEventLogSelection) {
130
			hideMessage();
131
			sequenceChart.setSelection(selection);
132
		}
133
		else {
134
			sequenceChart.setInput(null);
135
			showMessage("No event log available");
136
		}
137
	}
138
}
ide/sequencechart/src/org/omnetpp/sequencechart/widgets/SequenceChart.java
1
/*--------------------------------------------------------------*
2
  Copyright (C) 2006-2008 OpenSim Ltd.
3

  
4
  This file is distributed WITHOUT ANY WARRANTY. See the file
5
  'License' for details on this and other legal matters.
6
*--------------------------------------------------------------*/
7

  
8
package org.omnetpp.sequencechart.widgets;
9

  
10
import java.io.Serializable;
11
import java.math.BigDecimal;
12
import java.math.BigInteger;
13
import java.math.MathContext;
14
import java.math.RoundingMode;
15
import java.util.ArrayList;
16
import java.util.HashMap;
17
import java.util.HashSet;
18
import java.util.List;
19
import java.util.ListIterator;
20
import java.util.Map;
21
import java.util.Set;
22

  
23
import org.eclipse.core.resources.IMarker;
24
import org.eclipse.core.resources.IResource;
25
import org.eclipse.core.runtime.Assert;
26
import org.eclipse.core.runtime.CoreException;
27
import org.eclipse.core.runtime.ListenerList;
28
import org.eclipse.draw2d.Graphics;
29
import org.eclipse.draw2d.SWTGraphics;
30
import org.eclipse.draw2d.geometry.Rectangle;
31
import org.eclipse.jface.action.MenuManager;
32
import org.eclipse.jface.dialogs.MessageDialog;
33
import org.eclipse.jface.util.SafeRunnable;
34
import org.eclipse.jface.viewers.ISelection;
35
import org.eclipse.jface.viewers.ISelectionChangedListener;
36
import org.eclipse.jface.viewers.ISelectionProvider;
37
import org.eclipse.jface.viewers.SelectionChangedEvent;
38
import org.eclipse.jface.window.Window;
39
import org.eclipse.swt.SWT;
40
import org.eclipse.swt.events.ControlAdapter;
41
import org.eclipse.swt.events.ControlEvent;
42
import org.eclipse.swt.events.DisposeEvent;
43
import org.eclipse.swt.events.DisposeListener;
44
import org.eclipse.swt.events.KeyAdapter;
45
import org.eclipse.swt.events.KeyEvent;
46
import org.eclipse.swt.events.MouseAdapter;
47
import org.eclipse.swt.events.MouseEvent;
48
import org.eclipse.swt.events.MouseMoveListener;
49
import org.eclipse.swt.events.MouseTrackAdapter;
50
import org.eclipse.swt.events.SelectionEvent;
51
import org.eclipse.swt.events.SelectionListener;
52
import org.eclipse.swt.graphics.Color;
53
import org.eclipse.swt.graphics.Cursor;
54
import org.eclipse.swt.graphics.Font;
55
import org.eclipse.swt.graphics.FontData;
56
import org.eclipse.swt.graphics.GC;
57
import org.eclipse.swt.graphics.Point;
58
import org.eclipse.swt.graphics.Transform;
59
import org.eclipse.swt.widgets.Composite;
60
import org.eclipse.swt.widgets.Control;
61
import org.eclipse.swt.widgets.Display;
62
import org.eclipse.swt.widgets.Event;
63
import org.eclipse.swt.widgets.Listener;
64
import org.eclipse.swt.widgets.ScrollBar;
65
import org.omnetpp.common.Debug;
66
import org.omnetpp.common.canvas.CachingCanvas;
67
import org.omnetpp.common.canvas.LargeRect;
68
import org.omnetpp.common.canvas.RubberbandSupport;
69
import org.omnetpp.common.color.ColorFactory;
70
import org.omnetpp.common.eventlog.EventLogFindTextDialog;
71
import org.omnetpp.common.eventlog.EventLogInput;
72
import org.omnetpp.common.eventlog.EventLogSelection;
73
import org.omnetpp.common.eventlog.IEventLogChangeListener;
74
import org.omnetpp.common.eventlog.IEventLogSelection;
75
import org.omnetpp.common.eventlog.ModuleTreeItem;
76
import org.omnetpp.common.ui.HoverSupport;
77
import org.omnetpp.common.ui.IHoverTextProvider;
78
import org.omnetpp.common.ui.SizeConstraint;
79
import org.omnetpp.common.util.GraphicsUtils;
80
import org.omnetpp.common.util.PersistentResourcePropertyManager;
81
import org.omnetpp.common.util.StringUtils;
82
import org.omnetpp.common.util.TimeUtils;
83
import org.omnetpp.common.virtualtable.IVirtualContentWidget;
84
import org.omnetpp.eventlog.engine.BeginSendEntry;
85
import org.omnetpp.eventlog.engine.EventEndEntry;
86
import org.omnetpp.eventlog.engine.EventLogEntry;
87
import org.omnetpp.eventlog.engine.EventLogMessageEntry;
88
import org.omnetpp.eventlog.engine.FilteredEventLog;
89
import org.omnetpp.eventlog.engine.FilteredMessageDependency;
90
import org.omnetpp.eventlog.engine.IEvent;
91
import org.omnetpp.eventlog.engine.IEventLog;
92
import org.omnetpp.eventlog.engine.IMessageDependency;
93
import org.omnetpp.eventlog.engine.IMessageDependencyList;
94
import org.omnetpp.eventlog.engine.ModuleCreatedEntry;
95
import org.omnetpp.eventlog.engine.ModuleMethodBeginEntry;
96
import org.omnetpp.eventlog.engine.PtrVector;
97
import org.omnetpp.eventlog.engine.SequenceChartFacade;
98
import org.omnetpp.scave.engine.FileRun;
99
import org.omnetpp.scave.engine.ResultFile;
100
import org.omnetpp.scave.engine.ResultFileManager;
101
import org.omnetpp.scave.engine.ResultItem;
102
import org.omnetpp.scave.engine.XYArray;
103
import org.omnetpp.sequencechart.SequenceChartPlugin;
104
import org.omnetpp.sequencechart.editors.SequenceChartContributor;
105
import org.omnetpp.sequencechart.widgets.axisorder.AxisOrderByModuleId;
106
import org.omnetpp.sequencechart.widgets.axisorder.AxisOrderByModuleName;
107
import org.omnetpp.sequencechart.widgets.axisorder.FlatAxisOrderByMinimizingCost;
108
import org.omnetpp.sequencechart.widgets.axisorder.ManualAxisOrder;
109
import org.omnetpp.sequencechart.widgets.axisrenderer.AxisLineRenderer;
110
import org.omnetpp.sequencechart.widgets.axisrenderer.AxisVectorBarRenderer;
111
import org.omnetpp.sequencechart.widgets.axisrenderer.IAxisRenderer;
112

  
113
/**
114
 * The sequence chart figure shows the events and the messages passed along between several modules.
115
 * The chart consists of a series of horizontal lines each representing a simple or compound module.
116
 * Message dependencies are represented by elliptic arrows pointing from the cause event to the consequence event.
117
 *
118
 * Zooming, scrolling, tooltips and event selections are also provided.
119
 *
120
 * @author andras, levy
121
 */
122
// TODO: proper "hand" cursor - current one is not very intuitive
123
public class SequenceChart
124
	extends CachingCanvas
125
	implements IVirtualContentWidget<IEvent>, ISelectionProvider, IEventLogChangeListener
126
{
127
	private static final boolean debug = false;
128
	private static final boolean debug2 = true;
129

  
130
	public static final String STATE_PROPERTY = "SequenceChartState";
131

  
132
	/*************************************************************************************
133
	 * DRAWING PARAMETERS
134
	 */
135

  
136
	private static final Color CHART_BACKGROUND_COLOR = ColorFactory.WHITE;
137
	private static final Color LABEL_COLOR = ColorFactory.BLACK;
138

  
139
	private static final Color TICK_LINE_COLOR = ColorFactory.DARK_GREY;
140
	private static final Color MOUSE_TICK_LINE_COLOR = ColorFactory.BLACK;
141
	private static final Color TICK_LABEL_COLOR = ColorFactory.BLACK;
142
	private static final Color INFO_BACKGROUND_COLOR = ColorFactory.LIGHT_CYAN;
143

  
144
	private static final Color GUTTER_BACKGROUND_COLOR = new Color(null, 255, 255, 160);
145
	private static final Color GUTTER_BORDER_COLOR = ColorFactory.BLACK;
146

  
147
    private static final Color INITIALIZATION_EVENT_BORDER_COLOR = ColorFactory.BLACK;
148
    private static final Color INITIALIZATION_EVENT_BACKGROUND_COLOR = ColorFactory.WHITE;
149
	private static final Color EVENT_BORDER_COLOR = ColorFactory.RED4;
150
	private static final Color EVENT_BACKGROUND_COLOR = ColorFactory.RED;
151
	private static final Color SELF_EVENT_BORDER_COLOR = ColorFactory.GREEN4;
152
	private static final Color OVERLAPPING_EVENT_BACKGROUND_COLOR = ColorFactory.DARK_BLUE;
153
	private static final Color NON_OVERLAPPING_EVENT_BACKGROUND_COLOR = ColorFactory.LIGHT_BLUE;
154
	private static final Color SELF_EVENT_BACKGROUND_COLOR = ColorFactory.GREEN2;
155

  
156
	private static final Color EVENT_SELECTION_COLOR = ColorFactory.ORANGE;
157
	private static final Color EVENT_BOOKMARK_COLOR = ColorFactory.CYAN;
158

  
159
	private static final Color ARROW_HEAD_COLOR = null; // defaults to line color
160
	private static final Color LONG_ARROW_HEAD_COLOR = ColorFactory.WHITE; // defaults to line color
161
	private static final Color MESSAGE_LABEL_COLOR = null; // defaults to line color
162

  
163
	private static final Color MESSAGE_SEND_COLOR = ColorFactory.BLUE;
164
	private static final Color MESSAGE_REUSE_COLOR = ColorFactory.GREEN4;
165
    private static final Color MODULE_METHOD_CALL_COLOR = ColorFactory.ORANGE3;
166

  
167
	private static final Color ZERO_SIMULATION_TIME_REGION_COLOR = ColorFactory.GREY90;
168

  
169
	private static final Cursor DRAG_CURSOR = new Cursor(null, SWT.CURSOR_SIZEALL);
170

  
171
	private static final int[] DOTTED_LINE_PATTERN = new int[] {2,2}; // 2px black, 2px gap
172

  
173
	private static final int ANTIALIAS_TURN_ON_AT_MSEC = 100;
174
	private static final int ANTIALIAS_TURN_OFF_AT_MSEC = 300;
175
	private static final int MOUSE_TOLERANCE = 3;
176

  
177
	private static final int MINIMUM_HALF_ELLIPSE_HEIGHT = 15; // vertical radius of ellipse for message arrows on one axis
178
	private static final int LONG_MESSAGE_ARROW_WIDTH = 80; // width for too long message lines and half ellipses
179
	private static final int ARROWHEAD_LENGTH = 10; // length of message arrow head
180
	private static final int ARROWHEAD_WIDTH = 7; // width of message arrow head
181
	private static final int EVENT_SELECTION_RADIUS = 10; // radius of event selection mark circle
182
	private static final int TICK_SPACING = 100; // space between ticks in pixels
183
	private static final int AXIS_OFFSET = 20;  // extra y distance before and after first and last axes
184

  
185
//	private static Font font = new Font(Display.getDefault(), "Arial", 8, SWT.NONE);
186
	private int fontHeight = -1; // cached for cases where a graphics is not available
187

  
188
	/*************************************************************************************
189
	 * INTERNAL STATE
190
	 */
191

  
192
	private IEventLog eventLog; // the C++ wrapper for the data to be displayed
193
	private EventLogInput eventLogInput; // the Java input object
194
	private SequenceChartFacade sequenceChartFacade; // helpful C++ facade on eventlog
195
    private SequenceChartContributor sequenceChartContributor; // for popup menu
196

  
197
	private long fixPointViewportCoordinate; // the viewport coordinate of the coordinate system's origin event stored in the facade
198

  
199
	private double pixelPerTimelineUnit = 0; // horizontal zoom factor
200

  
201
	private boolean invalidAxisSpacing = true; // true means that the spacing value must be recalculated due to axis spacing mode is set to auto
202
	private double axisSpacing = 0; // y distance between two axes, might be fractional pixels to have precise positioning for several axes
203
	private AxisSpacingMode axisSpacingMode = AxisSpacingMode.AUTO;
204

  
205
	private boolean showArrowHeads = true; // show or hide arrow heads
206
	private boolean showMessageNames = true; // show or hide message names
207
    private boolean showMessageSends = true; // show or hide message send arrows
208
    private boolean showSelfMessages = true; // show or hide self message arrows
209
    private boolean showSelfMessageReuses = false; // show or hide self message reuse arrows
210
	private boolean showOtherMessageReuses = false; // show or hide reuse message arrows
211
    private boolean showModuleMethodCalls = false; // show or hide module method call arrows
212
	private boolean showEventNumbers = true;
213
	private boolean showEventOverlapping = false;
214
    private boolean showZeroSimulationTimeRegions = true;
215
    private boolean showAxisLabels = true;
216
    private boolean showAxesWithoutEvents = false;
217
    private boolean showTransmissionDurations = true;
218
    
219
    private int bottleneckThreshold = 2;
220

  
221
    private AxisOrderingMode axisOrderingMode = AxisOrderingMode.MODULE_ID; // specifies the ordering mode of axes
222

  
223
    private EventLengthMode eventLengthMode = EventLengthMode.NONE; // specifies the mode that event lengths are drawn
224
    
225
    private HoverSupport hoverSupport;
226
    private RubberbandSupport rubberbandSupport;
227

  
228
	private boolean isDragging; // indicates ongoing drag operation
229
	private int dragStartX = -1, dragStartY = -1, dragDeltaX, dragDeltaY; // temporary variables for drag handling
230

  
231
	private ArrayList<BigDecimal> ticks; // a list of simulation times drawn on the axis as tick marks
232
	private BigDecimal tickPrefix; // the common part of all ticks on the gutter
233

  
234
    private ManualAxisOrder manualAxisOrder = new ManualAxisOrder(); // remembers manual ordering
235

  
236
	private boolean invalidAxisModules = true; // requests recalculation
237
	private ArrayList<ModuleTreeItem> axisModules; // the modules (in no particular order) which will have an axis (they must be part of the module tree!) on the chart
238

  
239
	private boolean invalidModuleIdToAxisModuleIndexMap = true; // requests recalculation
240
    private Map<Integer, Integer> moduleIdToAxisModuleIndexMap; // some modules do not have axis but events occurred in them are still drawn on the chart
241

  
242
    private boolean invalidAxisRenderers = true; // requests recalculation
243
	private IAxisRenderer[] axisRenderers; // used to draw the axis (parallel to axisModules)
244

  
245
	private boolean invalidModuleIdToAxisRendererMap; // requests recalculation
246
    private Map<Integer, IAxisRenderer> moduleIdToAxisRendererMap = new HashMap<Integer, IAxisRenderer>(); // this map is not cleared when the eventlog is filtered or the filter is removed
247

  
248
    private boolean invalidAxisModulePositions = true; // requests recalculation
249
	private int[] axisModulePositions; // specifies y order of the axis modules (in the same order as axisModules); this is a permutation of the 0 .. axisModule.size() - 1 numbers
250

  
251
	private boolean invalidAxisModuleYs = true; // requests recalculation
252
	private int[] axisModuleYs; // top y coordinates of axis bounding boxes
253

  
254
	private boolean invalidVirtualSize = false; // requests recalculation
255

  
256
    private boolean invalidViewportSize = false; // requests recalculation
257

  
258
    private boolean drawStuffUnderMouse = false; // true means axes, events, message dependencies will be highlighted under the mouse
259
    private boolean drawWithAntialias = true; // antialias gets turned on/off automatically
260

  
261
    private boolean paintHasBeenFinished = false; // true means the user did not cancel the last paint
262
    private boolean internalErrorHappenedDuringPaint = false; // if this is true, then paint only draws an error message
263

  
264
	private boolean followEnd = false; // when the eventlog changes should we follow it or not?
265

  
266
	/*************************************************************************************
267
	 * SELECTION STATE
268
	 */
269

  
270
	/**
271
	 * True means the chart will jump to the selection and switch input automatically when it gets notified about a selection change
272
	 * even if the input is different from the current one.
273
	 */
274
	private boolean followSelection = true;
275

  
276
	private ArrayList<SelectionListener> selectionListenerList = new ArrayList<SelectionListener>(); // SWT selection listeners
277
	private List<Long> selectionEventNumbers = new ArrayList<Long>(); // the selection
278
    private ListenerList selectionChangedListeners = new ListenerList(); // list of selection change listeners (type ISelectionChangedListener).
279

  
280
    private org.omnetpp.common.engine.BigDecimal smallestParallelEndtime = new org.omnetpp.common.engine.BigDecimal(0);
281
	private ParallelSelectionUpdater parallelSelectionUpdater;
282
    /*************************************************************************************
283
	 * PUBLIC INNER TYPES
284
	 */
285

  
286
    /**
287
     * Specifies how the vertical spacing between axes is determined.
288
     */
289
	public enum AxisSpacingMode {
290
		MANUAL,
291
		AUTO
292
	}
293

  
294
	/**
295
	 * Timeline mode determines the horizontal coordinate system in the sequence chart.
296
	 * Simulation time and event number based means proportional to distance measured in pixels.
297
	 * Step means subsequent events follow each other with a constant distance.
298
	 * Nonlinear mode means distance measured in pixels is proportional to a nonlinear function of the
299
	 * simulation time difference between subsequent events.
300
	 */
301
	public enum TimelineMode {
302
		SIMULATION_TIME,
303
		EVENT_NUMBER,
304
		STEP,
305
		NONLINEAR
306
	}
307

  
308
	/**
309
	 * Determines the order of visible axes on the sequence chart.
310
	 */
311
	public enum AxisOrderingMode {
312
		MANUAL,
313
		MODULE_ID,
314
		MODULE_FULL_PATH,
315
		MINIMIZE_CROSSINGS
316
	}
317
	/**
318
	 * Determines meaning of event length 
319
	 */
320
	public enum EventLengthMode {
321
		NONE,
322
		DURATION,
323
		COMPLEXITY
324
	}
325

  
326

  
327
	/*************************************************************************************
328
	 * CONSTRUCTOR, GETTERS, SETTERS
329
	 */
330

  
331
	/**
332
     * Constructor.
333
     */
334
	public SequenceChart(Composite parent, int style) {
335
		super(parent, style);
336
		setBackground(CHART_BACKGROUND_COLOR);
337

  
338
		setupHoverSupport();
339
        setupRubberbandSupport();
340

  
341
        setupMouseListener();
342
        setupKeyListener();
343
		setupListeners();
344
		
345
		parallelSelectionUpdater = new ParallelSelectionUpdater(this);
346
	}
347

  
348
    private void setupHoverSupport() {
349
        hoverSupport = new HoverSupport();
350
    	hoverSupport.setHoverSizeConstaints(700, 200);
351
    	hoverSupport.adapt(this, new IHoverTextProvider() {
352
			public String getHoverTextFor(Control control, int x, int y, SizeConstraint outSizeConstraint) {
353
			    if (!internalErrorHappenedDuringPaint)
354
			        return HoverSupport.addHTMLStyleSheet(getTooltipText(x, y, outSizeConstraint));
355
			    else
356
			        return null;
357
			}
358
    	});
359
    }
360

  
361
    private void setupRubberbandSupport() {
362
    	rubberbandSupport = new RubberbandSupport(this, SWT.MOD1) {
363
			@Override
364
			public void rubberBandSelectionMade(Rectangle r) {
365
				zoomToRectangle(r);
366
			}
367
		};
368
    }
369

  
370
    private void setupListeners() {
371
        addDisposeListener(new DisposeListener() {
372
            public void widgetDisposed(DisposeEvent e) {
373
                if (eventLogInput != null) {
374
                    storeState(eventLogInput.getFile());
375
                    eventLogInput.removeEventLogChangedListener(SequenceChart.this);
376
                }
377
            }
378
        });
379

  
380
        addControlListener(new ControlAdapter() {
381
            @Override
382
            public void controlResized(ControlEvent e) {
383
                if (eventLogInput != null) {
384
                    if (eventLogInput != null) {
385
                        invalidateViewportSize();
386
                        invalidateAxisSpacing();
387
                    }
388
                }
389
            }
390
        });
391
    }
392

  
393
    /**
394
     * Setup keyboard event handling.
395
     */
396
    private void setupKeyListener() {
397
		addKeyListener(new KeyAdapter() {
398
			@Override
399
            public void keyPressed(KeyEvent e) {
400
				if (e.keyCode == SWT.F5)
401
					refresh();
402
				else if (e.keyCode == SWT.ARROW_LEFT) {
403
				    if (e.stateMask == 0)
404
				        moveSelection(-1);
405
				    else if (e.stateMask == SWT.MOD1) {
406
				        IEvent event = getSelectionEvent();
407

  
408
				        if (event != null) {
409
				            event = event.getCauseEvent();
410

  
411
				            if (event != null)
412
			                    gotoClosestElement(event);
413
				        }
414
				    }
415
                    else if (e.stateMask == SWT.SHIFT) {
416
                        IEvent event = getSelectionEvent();
417

  
418
                        if (event != null) {
419
                            int moduleId = event.getModuleId();
420

  
421
                            while (event != null) {
422
                                event = event.getPreviousEvent();
423

  
424
                                if (event != null && moduleId == event.getModuleId()) {
425
                                    gotoClosestElement(event);
426
                                    break;
427
                                }
428
                            }
429
                        }
430
                    }
431
				}
432
				else if (e.keyCode == SWT.ARROW_RIGHT) {
433
                    if (e.stateMask == 0)
434
                        moveSelection(1);
435
                    else if (e.stateMask == SWT.MOD1) {
436
                        IEvent event = getSelectionEvent();
437

  
438
                        if (event != null) {
439
                            IMessageDependencyList consequences = event.getConsequences();
440

  
441
                            if (consequences.size() > 0) {
442
                                event = consequences.get(0).getConsequenceEvent();
443

  
444
                                if (event != null)
445
                                    gotoClosestElement(event);
446
                            }
447
                        }
448
                    }
449
                    else if (e.stateMask == SWT.SHIFT) {
450
                        IEvent event = getSelectionEvent();
451

  
452
                        if (event != null) {
453
                            int moduleId = event.getModuleId();
454

  
455
                            while (event != null) {
456
                                event = event.getNextEvent();
457

  
458
                                if (event != null && moduleId == event.getModuleId()) {
459
                                    gotoClosestElement(event);
460
                                    break;
461
                                }
462
                            }
463
                        }
464
                    }
465
				}
466
				else if (e.keyCode == SWT.ARROW_UP)
467
				    scrollVertical((int)Math.floor(-getAxisSpacing() - 1));
468
				else if (e.keyCode == SWT.ARROW_DOWN)
469
				    scrollVertical((int)Math.ceil(getAxisSpacing() + 1));
470
				else if (e.keyCode == SWT.PAGE_UP)
471
				    scrollVertical(-getViewportHeight());
472
				else if (e.keyCode == SWT.PAGE_DOWN)
473
				    scrollVertical(getViewportHeight());
474
				else if (e.keyCode == SWT.HOME)
475
					gotoBegin();
476
				else if (e.keyCode == SWT.END)
477
					gotoEnd();
478
				else if (e.keyCode == SWT.KEYPAD_ADD || e.character == '+' || e.character == '=')
479
					zoomIn();
480
				else if (e.keyCode == SWT.KEYPAD_SUBTRACT || e.character == '-')
481
					zoomOut();
482
			}
483
		});
484
    }
485

  
486
    /**
487
     * Sets the contributor used to build the pop-up menu on the chart.
488
     */
489
    public void setSequenceChartContributor(SequenceChartContributor sequenceChartContributor) {
490
        this.sequenceChartContributor = sequenceChartContributor;
491
        MenuManager menuManager = new MenuManager();
492
        sequenceChartContributor.contributeToPopupMenu(menuManager);
493
        setMenu(menuManager.createContextMenu(this));
494
    }
495

  
496
    @Override
497
    public void setFont(Font font) {
498
        super.setFont(font);
499
        fontHeight = -1;
500
        invalidateAxisModules();
501
        invalidateViewportSize();
502
        clearCanvasCacheAndRedraw();
503
    }
504

  
505
    /**
506
	 * See setFollowSelection().
507
	 */
508
	public boolean getFollowSelection() {
509
		return followSelection;
510
	}
511

  
512
	/**
513
	 * Sets whether this widget should always switch to the element which comes in
514
	 * the selection (=true), or stick to the input set with setInput() (=false).
515
	 * The proper setting typically depends on whether the widget is used in an
516
	 * editor (false) or in a view (true).
517
	 *
518
	 * Default is true.
519
	 */
520
	public void setFollowSelection(boolean followSelection) {
521
		this.followSelection = followSelection;
522
	}
523

  
524
	/**
525
	 * Returns whether message names are displayed on the arrows.
526
	 */
527
	public boolean getShowMessageNames() {
528
		return showMessageNames;
529
	}
530

  
531
	/**
532
	 * Hide/show message names on the arrows.
533
	 */
534
	public void setShowMessageNames(boolean showMessageNames) {
535
		this.showMessageNames = showMessageNames;
536
		clearCanvasCacheAndRedraw();
537
	}
538

  
539
    /**
540
     * Returns whether message sends are shown on the chart.
541
     */
542
	public boolean getShowMessageSends() {
543
	    return showMessageSends;
544
    }
545

  
546
    /**
547
     * Shows/Hides message sends.
548
     */
549
	public void setShowMessageSends(boolean showMessageSends) {
550
        this.showMessageSends = showMessageSends;
551
        clearCanvasCacheAndRedraw();
552
    }
553

  
554
    /**
555
     * Returns whether self messages are shown on the chart.
556
     */
557
    public boolean getShowSelfMessages() {
558
        return showSelfMessages;
559
    }
560

  
561
    /**
562
     * Shows/Hides self messages.
563
     */
564
    public void setShowSelfMessages(boolean showSelfMessages) {
565
        this.showSelfMessages = showSelfMessages;
566
        clearCanvasCacheAndRedraw();
567
    }
568

  
569
	/**
570
	 * Returns whether reuse messages are shown on the chart.
571
	 */
572
	public boolean getShowOtherMessageReuses() {
573
		return showOtherMessageReuses;
574
	}
575

  
576
	/**
577
	 * Shows/Hides reuse messages.
578
	 */
579
	public void setShowOtherMessageReuses(boolean showOtherMessageReuses) {
580
		this.showOtherMessageReuses = showOtherMessageReuses;
581
		clearCanvasCacheAndRedraw();
582
	}
583

  
584
    /**
585
     * Returns whether reuse messages are shown on the chart.
586
     */
587
    public boolean getShowSelfMessageReuses() {
588
        return showSelfMessageReuses;
589
    }
590

  
591
    /**
592
     * Shows/Hides reuse messages.
593
     */
594
    public void setShowSelfMessageReuses(boolean showSelfMessageReuses) {
595
        this.showSelfMessageReuses = showSelfMessageReuses;
596
        clearCanvasCacheAndRedraw();
597
    }
598

  
599
    /**
600
     * Shows/hides module method calls.
601
     */
602
    public boolean getShowModuleMethodCalls() {
603
        return showModuleMethodCalls;
604
    }
605

  
606
    /**
607
     * Returns whether module method calls are shown on the chart.
608
     */
609
    public void setShowModuleMethodCalls(boolean showModuleMethodCalls) {
610
        this.showModuleMethodCalls = showModuleMethodCalls;
611
        clearCanvasCacheAndRedraw();
612
    }
613

  
614
	/**
615
	 * Returns whether event numbers are shown on the chart.
616
	 */
617
	public boolean getShowEventNumbers() {
618
		return showEventNumbers;
619
	}
620

  
621
	/**
622
	 * Shows/Hides event numbers.
623
	 */
624
	public void setShowEventNumbers(boolean showEventNumbers) {
625
		this.showEventNumbers = showEventNumbers;
626
		clearCanvasCacheAndRedraw();
627
	}
628

  
629
	/**
630
	 * Returns whether event overlappings are shown on the chart.
631
	 */
632
	public boolean getShowEventOverlapping() {
633
		return showEventOverlapping;
634
	}
635

  
636
	/**
637
	 * Shows/Hides event numbers.
638
	 */
639
	public void setShowEventOverlapping(boolean showEventOverlapping) {
640
		this.showEventOverlapping = showEventOverlapping;
641
		clearCanvasCacheAndRedraw();
642
	}
643

  
644
	
645
	/**
646
	 * Shows/hides arrow heads.
647
	 */
648
	public boolean getShowArrowHeads() {
649
		return showArrowHeads;
650
	}
651

  
652
	/**
653
	 * Returns whether arrow heads are shown on the chart.
654
	 */
655
	public void setShowArrowHeads(boolean showArrowHeads) {
656
		this.showArrowHeads = showArrowHeads;
657
		clearCanvasCacheAndRedraw();
658
	}
659

  
660
    /**
661
     * Shows/hides zero simulation time regions.
662
     */
663
    public boolean getShowZeroSimulationTimeRegions() {
664
        return showZeroSimulationTimeRegions;
665
    }
666

  
667
    /**
668
     * Returns whether zero simulation time regions are shown on the chart.
669
     */
670
    public void setShowZeroSimulationTimeRegions(boolean showZeroSimulationTimeRegions) {
671
        this.showZeroSimulationTimeRegions = showZeroSimulationTimeRegions;
672
        clearCanvasCacheAndRedraw();
673
    }
674

  
675
    /**
676
     * Shows/hides zero simulation time regions.
677
     */
678
    public boolean getShowAxisLabels() {
679
        return showAxisLabels;
680
    }
681

  
682
    /**
683
     * Returns whether zero simulation time regions are shown on the chart.
684
     */
685
    public void setShowAxisLabels(boolean showAxisLabels) {
686
        this.showAxisLabels = showAxisLabels;
687
        clearCanvasCacheAndRedraw();
688
    }
689

  
690
    /**
691
     * Shows/hides axes without events.
692
     */
693
    public boolean getShowAxesWithoutEvents() {
694
        return showAxesWithoutEvents;
695
    }
696

  
697
    /**
698
     * Returns whether axes without events are shown on the chart.
699
     */
700
    public void setShowAxesWithoutEvents(boolean showAxesWithoutEvents) {
701
        this.showAxesWithoutEvents = showAxesWithoutEvents;
702
        clearAxisModules();
703
    }
704

  
705
    /**
706
     * Shows/hides transmission durations.
707
     */
708
    public boolean getShowTransmissionDurations() {
709
        return showTransmissionDurations;
710
    }
711

  
712
    /**
713
     * Returns whether axes without events are shown on the chart.
714
     */
715
    public void setShowTransmissionDurations(boolean showTransmissionDurations) {
716
        this.showTransmissionDurations = showTransmissionDurations;
717
        clearCanvasCacheAndRedraw();
718
    }
719

  
720
    /**
721
	 * Returns the current timeline mode.
722
	 */
723
	public TimelineMode getTimelineMode() {
724
		return TimelineMode.values()[sequenceChartFacade.getTimelineMode()];
725
	}
726

  
727
	/**
728
	 * Sets the timeline mode and updates the figure accordingly.
729
	 * Tries to show the current simulation time range which was visible before the change
730
	 * after changing the timeline coordinate system.
731
	 */
732
	public void setTimelineMode(TimelineMode timelineMode) {
733
	    org.omnetpp.common.engine.BigDecimal[] leftRightSimulationTimes = null;
734

  
735
	    if (!eventLog.isEmpty())
736
	        leftRightSimulationTimes = getViewportSimulationTimeRange();
737

  
738
	    sequenceChartFacade.setTimelineMode(timelineMode.ordinal());
739

  
740
	    if (!eventLog.isEmpty())
741
	        setViewportSimulationTimeRange(leftRightSimulationTimes);
742
	}
743

  
744
	/**
745
	 * Returns event length mode.
746
	 */
747
	public EventLengthMode getEventLengthMode() {
748
		return eventLengthMode;
749
	}
750

  
751
	/**
752
	 * Sets the event length mode.
753
	 */
754
	public void setEventLengthMode(EventLengthMode eventLengthMode) {
755
        this.eventLengthMode = eventLengthMode;
756
        clearCanvasCacheAndRedraw();
757
	}
758
	
759
	/**
760
	 * Returns the current axis ordering mode.
761
	 */
762
	public AxisOrderingMode getAxisOrderingMode() {
763
		return axisOrderingMode;
764
	}
765

  
766
	/**
767
	 * Sets the axis ordering mode and updates the figure accordingly.
768
	 */
769
	public void setAxisOrderingMode(AxisOrderingMode axisOrderingMode) {
770
        this.axisOrderingMode = axisOrderingMode;
771
        invalidateAxisModulePositions();
772
	}
773

  
774
	/**
775
	 * Shows the manual ordering dialog partially filled up with the current ordering.
776
	 */
777
    public int showManualOrderingDialog() {
778
        ModuleTreeItem[] sortedAxisModules = new ModuleTreeItem[getAxisModules().size()];
779

  
780
        for (int i = 0; i < sortedAxisModules.length; i++)
781
            sortedAxisModules[getAxisModulePositions()[i]] = getAxisModules().get(i);
782

  
783
        return manualAxisOrder.showManualOrderDialog(sortedAxisModules);
784
    }
785

  
786
	/**
787
	 * Returns the currently visible range of simulation times as an array of two simulation times.
788
	 */
789
	public org.omnetpp.common.engine.BigDecimal[] getViewportSimulationTimeRange()
790
	{
791
		return new org.omnetpp.common.engine.BigDecimal[] {getViewportLeftSimulationTime(), getViewportRightSimulationTime()};
792
	}
793

  
794
	/**
795
	 * Sets the range of visible simulation times as an array of two simulation times.
796
	 */
797
	public void setViewportSimulationTimeRange(org.omnetpp.common.engine.BigDecimal[] leftRightSimulationTimes) {
798
        zoomToSimulationTimeRange(leftRightSimulationTimes[0], leftRightSimulationTimes[1]);
799
	}
800

  
801
	/**
802
	 * Returns the smallest visible simulation time within the viewport.
803
	 */
804
	public org.omnetpp.common.engine.BigDecimal getViewportLeftSimulationTime() {
805
        return getSimulationTimeForViewportCoordinate(0);
806
	}
807

  
808
	/**
809
	 * Returns the simulation time visible at the viewport's center.
810
	 */
811
	public org.omnetpp.common.engine.BigDecimal getViewportCenterSimulationTime() {
812
        return getSimulationTimeForViewportCoordinate(getViewportWidth() / 2);
813
	}
814

  
815
	/**
816
	 * Returns the biggest visible simulation time within the viewport.
817
	 */
818
	public org.omnetpp.common.engine.BigDecimal getViewportRightSimulationTime() {
819
        return getSimulationTimeForViewportCoordinate(getViewportWidth());
820
	}
821

  
822
	/*************************************************************************************
823
	 * SCROLLING, GOTOING
824
	 */
825

  
826
	private void relocateFixPoint(IEvent event, long fixPointViewportCoordinate) {
827
		this.fixPointViewportCoordinate = fixPointViewportCoordinate;
828
		invalidateAxisModules();
829

  
830
		// the new event will be the origin of the timeline coordinate system
831
		if (event != null)
832
		    sequenceChartFacade.relocateTimelineCoordinateSystem(event);
833
		else
834
            sequenceChartFacade.undefineTimelineCoordinateSystem();
835

  
836
		if (eventLog != null && !eventLog.isEmpty()) {
837
		    // don't go after the very end
838
			if (eventLog.getLastEvent().getSimulationTime().less(getViewportRightSimulationTime())) {
839
				this.fixPointViewportCoordinate = getViewportWidth();
840
				sequenceChartFacade.relocateTimelineCoordinateSystem(eventLog.getLastEvent());
841
			}
842

  
843
			// don't go before the very beginning
844
			if (getSimulationTimeForViewportCoordinate(0).less(org.omnetpp.common.engine.BigDecimal.getZero())) {
845
				this.fixPointViewportCoordinate = 0;
846
				sequenceChartFacade.relocateTimelineCoordinateSystem(eventLog.getFirstEvent());
847
			}
848
		}
849
	}
850

  
851
	@Override
852
	protected long clipX(long x) {
853
		// the position of the visible area is not limited to a [0, max] range
854
	    // this is due to the fact that the coordinate system is linked to the fixPoint event
855
		return x;
856
	}
857

  
858
	@Override
859
	protected int configureHorizontalScrollBar(ScrollBar scrollBar, long virtualSize, long virtualPos, int widgetSize) {
860
		ScrollBar horizontalBar = getHorizontalBar();
861
		horizontalBar.setMinimum(0);
862

  
863
		long[] eventPtrRange = null;
864

  
865
		if (eventLog != null && !eventLogInput.isCanceled())
866
			eventPtrRange = getFirstLastEventPtrForViewportRange(0, getViewportWidth());
867

  
868
		if (eventPtrRange != null && eventPtrRange[0] != 0 && eventPtrRange[1] != 0 &&
869
			(sequenceChartFacade.IEvent_getPreviousEvent(eventPtrRange[0]) != 0 || sequenceChartFacade.IEvent_getNextEvent(eventPtrRange[1]) != 0))
870
		{
871
			long numberOfElements = eventLog.getApproximateNumberOfEvents();
872
			horizontalBar.setMaximum((int)Math.max(numberOfElements, 1E+6));
873
			horizontalBar.setThumb((int)((double)horizontalBar.getMaximum() / numberOfElements));
874
			horizontalBar.setIncrement(1);
875
			horizontalBar.setPageIncrement(10);
876
			horizontalBar.setVisible(true);
877
		}
878
		else {
879
			horizontalBar.setMaximum(0);
880
			horizontalBar.setThumb(0);
881
			horizontalBar.setIncrement(0);
882
			horizontalBar.setPageIncrement(0);
883
			horizontalBar.setVisible(false);
884
		}
885

  
886
		return 0;
887
	}
888

  
889
	/**
890
	 * Update horizontal scrollbar position based on the first and last visible events.
891
	 */
892
	@Override
893
	protected void adjustHorizontalScrollBar() {
894
		if (eventLog != null && !eventLogInput.isCanceled()) {
895
			long[] eventPtrRange = getFirstLastEventPtrForViewportRange(0, getViewportWidth());
896
			long startEventPtr = eventPtrRange[0];
897
			long endEventPtr = eventPtrRange[1];
898
			double topPercentage = startEventPtr == 0 ? 0 : eventLog.getApproximatePercentageForEventNumber(sequenceChartFacade.IEvent_getEventNumber(startEventPtr));
899
			double bottomPercentage = endEventPtr == 0 ? 1 : eventLog.getApproximatePercentageForEventNumber(sequenceChartFacade.IEvent_getEventNumber(endEventPtr));
900
			double topWeight = 1 / topPercentage;
901
			double bottomWeight = 1 / (1 - bottomPercentage);
902
			double percentage;
903

  
904
			if (Double.isInfinite(topWeight))
905
				percentage = topPercentage;
906
			else if (Double.isInfinite(bottomWeight))
907
				percentage = bottomPercentage;
908
			else
909
				percentage = (topPercentage * topWeight + bottomPercentage * bottomWeight) / (topWeight + bottomWeight);
910

  
911
			ScrollBar horizontalBar = getHorizontalBar();
912
			horizontalBar.setSelection((int)((horizontalBar.getMaximum() - horizontalBar.getThumb()) * percentage));
913
		}
914
	}
915

  
916
	@Override
917
	protected void horizontalScrollBarChanged(SelectionEvent e) {
918
		ScrollBar scrollBar = getHorizontalBar();
919
		double percentage = (double)scrollBar.getSelection() / (scrollBar.getMaximum() - scrollBar.getThumb());
920
		followEnd = false;
921

  
922
		if (e.detail == SWT.ARROW_UP)
923
		    scrollHorizontal(-10);
924
		else if (e.detail == SWT.ARROW_DOWN)
925
		    scrollHorizontal(10);
926
		else if (e.detail == SWT.PAGE_UP)
927
		    scrollHorizontal(-getViewportWidth());
928
		else if (e.detail == SWT.PAGE_DOWN)
929
            scrollHorizontal(getViewportWidth());
930
		else if (percentage == 0)
931
			scrollToBegin();
932
		else if (percentage == 1)
933
			scrollToEnd();
934
		else
935
			scrollToElement(eventLog.getApproximateEventAt(percentage));
936
	}
937

  
938
	@Override
939
	public void scrollHorizontalTo(long x) {
940
		fixPointViewportCoordinate -= x - getViewportLeft();
941
		followEnd = false; // don't follow eventlog's end after a horizontal scroll
942
		super.scrollHorizontalTo(x);
943
	}
944

  
945
	public void scrollToBegin() {
946
		if (!eventLogInput.isCanceled() && !eventLog.isEmpty())
947
			scrollToElement(eventLog.getFirstEvent(), EVENT_SELECTION_RADIUS * 2);
948
	}
949

  
950
	public void scrollToEnd() {
951
		if (!eventLogInput.isCanceled() && !eventLog.isEmpty()) {
952
			scrollToElement(eventLog.getLastEvent(), getViewportWidth() - EVENT_SELECTION_RADIUS * 2);
953
			followEnd = true;
954
		}
955
	}
956

  
957
	public void scroll(int numberOfEvents) {
958
		long[] eventPtrRange = getFirstLastEventPtrForViewportRange(0, getViewportWidth());
959
		long startEventPtr = eventPtrRange[0];
960
		long endEventPtr = eventPtrRange[1];
961
		long eventPtr;
962

  
963
		if (numberOfEvents < 0) {
964
			eventPtr = startEventPtr;
965
			numberOfEvents++;
966
		}
967
		else {
968
			eventPtr = endEventPtr;
969
			numberOfEvents--;
970
		}
971

  
972
		IEvent neighbourEvent = eventLog.getNeighbourEvent(sequenceChartFacade.IEvent_getEvent(eventPtr), numberOfEvents);
973

  
974
		if (neighbourEvent != null)
975
			scrollToElement(neighbourEvent);
976
	}
977

  
978
	public void scrollToElement(IEvent event) {
979
		scrollToElement(event, getViewportWidth() / 2);
980
	}
981

  
982
	/**
983
	 * Scroll both horizontally and vertically to the given element.
984
	 */
985
	public void scrollToElement(IEvent event, int viewportX) {
986
        Assert.isTrue(event.getEventLog().equals(eventLog));
987

  
988
        boolean found = false;
989
	    int d = EVENT_SELECTION_RADIUS * 2;
990

  
991
		if (sequenceChartFacade.getTimelineCoordinateSystemOriginEventNumber() != -1) {
992
            long[] eventPtrRange = getFirstLastEventPtrForViewportRange(0, getViewportWidth());
993
            long startEventPtr = eventPtrRange[0];
994
            long endEventPtr = eventPtrRange[1];
995

  
996
            if (startEventPtr != 0 && endEventPtr != 0) {
997
        		// look one event backward
998
        		long previousEventPtr = sequenceChartFacade.IEvent_getPreviousEvent(startEventPtr);
999
        		if (previousEventPtr != 0)
1000
        			startEventPtr = previousEventPtr;
1001

  
1002
        		// and forward so that one additional event scrolling can be done with less distraction
1003
        		long nextEventPtr = sequenceChartFacade.IEvent_getNextEvent(endEventPtr);
1004
        		if (nextEventPtr != 0)
1005
        			endEventPtr = nextEventPtr;
1006

  
1007
        		for (long eventPtr = startEventPtr;; eventPtr = sequenceChartFacade.IEvent_getNextEvent(eventPtr)) {
1008
        			if (eventPtr == event.getCPtr())
1009
        				found = true;
1010

  
1011
        			if (eventPtr == endEventPtr)
1012
        				break;
1013
        		}
1014
            }
1015
		}
1016

  
1017
		if (!found)
1018
			relocateFixPoint(event, viewportX);
1019
		else {
1020
			long x = getViewportLeft() + getEventXViewportCoordinate(event.getCPtr());
1021
			scrollHorizontalToRange(x - d, x + d);
1022

  
1023
	        if (!getModuleIdToAxisModuleIndexMap().containsKey(event.getModuleId()))
1024
	            invalidateAxisModules();
1025
		}
1026

  
1027
		long y = getViewportTop() + (isInitializationEvent(event) ? getViewportHeight() / 2 : getEventYViewportCoordinate(event.getCPtr()));
1028
		scrollVerticalToRange(y - d, y + d);
1029
		adjustHorizontalScrollBar();
1030

  
1031
		followEnd = false;
1032

  
1033
		redraw();
1034
	}
1035

  
1036
	public void scrollToSelectionElement() {
1037
		IEvent event = getSelectionEvent();
1038

  
1039
		if (event != null)
1040
			scrollToElement(event);
1041
	}
1042

  
1043
	/**
1044
	 * Scroll the canvas making the simulation time visible at the center of the viewport.
1045
	 */
1046
	public void scrollToSimulationTimeWithCenter(org.omnetpp.common.engine.BigDecimal simulationTime) {
1047
		scrollHorizontal(getViewportCoordinateForSimulationTime(simulationTime) - getViewportWidth() / 2);
1048
		redraw();
1049
	}
1050

  
1051
	/**
1052
	 * Scroll vertically to make the axis module visible.
1053
	 */
1054
	public void scrollToAxisModule(ModuleTreeItem axisModule) {
1055
		for (int i = 0; i < getAxisModules().size(); i++)
1056
			if (getAxisModules().get(i) == axisModule)
1057
				scrollVerticalTo(getAxisModuleYs()[i] - getAxisRenderers()[i].getHeight() / 2 - getViewportHeight() / 2);
1058
	}
1059

  
1060
	public void moveSelection(int numberOfEvents) {
1061
		IEvent selectionEvent = getSelectionEvent();
1062

  
1063
		if (selectionEvent != null) {
1064
			IEvent neighbourEvent = eventLog.getNeighbourEvent(selectionEvent, numberOfEvents);
1065

  
1066
			if (neighbourEvent != null)
1067
				gotoElement(neighbourEvent);
1068
		}
1069
	}
1070

  
1071
	public void gotoBegin() {
1072
		IEvent firstEvent = eventLog.getFirstEvent();
1073

  
1074
		if (firstEvent != null)
1075
			setSelectionEvent(firstEvent);
1076

  
1077
		scrollToBegin();
1078
	}
1079

  
1080
	public void gotoEnd() {
1081
		IEvent lastEvent = eventLog.getLastEvent();
1082

  
1083
		if (lastEvent != null)
1084
			setSelectionEvent(lastEvent);
1085

  
1086
		scrollToEnd();
1087
	}
1088

  
1089
	public void gotoElement(IEvent event) {
1090
		setSelectionEvent(event);
1091
		scrollToElement(event);
1092
	}
1093

  
1094
	public void gotoClosestElement(IEvent event) {
1095
	    if (eventLog instanceof FilteredEventLog) {
1096
    	    FilteredEventLog filteredEventLog = (FilteredEventLog)eventLogInput.getEventLog();
1097
            IEvent closestEvent = filteredEventLog.getMatchingEventInDirection(sequenceChartFacade.getTimelineCoordinateSystemOriginEventNumber(), false);
1098

  
1099
            if (closestEvent != null)
1100
                gotoElement(closestEvent);
1101
            else {
1102
                closestEvent = filteredEventLog.getMatchingEventInDirection(sequenceChartFacade.getTimelineCoordinateSystemOriginEventNumber(), true);
1103

  
1104
                if (closestEvent != null)
1105
                    gotoElement(closestEvent);
1106
            }
1107
        }
1108
	    else
1109
	        gotoElement(event);
1110
	}
1111

  
1112
	/*************************************************************************************
1113
	 * ZOOMING
1114
	 */
1115

  
1116
	/**
1117
	 * Sets zoom level so that the default number of events fit into the viewport.
1118
	 */
1119
	public void defaultZoom() {
1120
        eventLogInput.runWithProgressMonitor(new Runnable() {
1121
            public void run() {
1122
                setDefaultPixelPerTimelineUnit(getViewportWidth());
1123
            }
1124
        });
1125
	}
1126

  
1127
    /**
1128
     * Sets zoom level so that the default number of events fit into the viewport.
1129
     */
1130
    public void zoomToFit() {
1131
        eventLogInput.runWithProgressMonitor(new Runnable() {
1132
            public void run() {
1133
                int padding = 20;
1134
                double firstTimelineCoordinate = sequenceChartFacade.getTimelineCoordinate(eventLog.getFirstEvent());
1135
                double lastTimelineCoordinate = sequenceChartFacade.getTimelineCoordinate(eventLog.getLastEvent());
1136
                double timelineCoordinateDelta = lastTimelineCoordinate - firstTimelineCoordinate;
1137
                if (timelineCoordinateDelta == 0)
1138
                    setPixelPerTimelineUnit(1);
1139
                else
1140
                    setPixelPerTimelineUnit((getViewportWidth() - padding * 2) / timelineCoordinateDelta);
1141
                scrollToBegin();
1142
            }
1143
        });
1144
    }
1145

  
1146
	/**
1147
	 * Increases pixels per timeline coordinate.
1148
	 */
1149
	public void zoomIn() {
1150
		zoomBy(1.5);
1151
	}
1152

  
1153
	/**
1154
	 * Decreases pixels per timeline coordinate.
1155
	 */
1156
	public void zoomOut() {
1157
		zoomBy(1.0 / 1.5);
1158
	}
1159

  
1160
	/**
1161
	 * Multiplies pixel per timeline coordinate by zoomFactor.
1162
	 */
1163
	public void zoomBy(final double zoomFactor) {
1164
		eventLogInput.runWithProgressMonitor(new Runnable() {
1165
			public void run() {
1166
			    org.omnetpp.common.engine.BigDecimal simulationTime = null;
1167

  
1168
			    if (!eventLog.isEmpty())
1169
			        simulationTime = getViewportCenterSimulationTime();
1170

  
1171
			    setPixelPerTimelineUnit(getPixelPerTimelineUnit() * zoomFactor);
1172

  
1173
			    if (!eventLog.isEmpty())
1174
			        scrollToSimulationTimeWithCenter(simulationTime);
1175
			}
1176
		});
1177
	}
1178

  
1179
	/**
1180
	 * Zoom to the given rectangle, given by viewport coordinates relative to the
1181
	 * top-left corner of the canvas.
1182
	 */
1183
	public void zoomToRectangle(final Rectangle r) {
1184
		eventLogInput.runWithProgressMonitor(new Runnable() {
1185
			public void run() {
1186
				double timelineCoordinate = getTimelineCoordinateForViewportCoordinate(r.x);
1187
				double timelineCoordinateDelta = getTimelineCoordinateForViewportCoordinate(r.right()) - timelineCoordinate;
1188
				setPixelPerTimelineUnit(getViewportWidth() / timelineCoordinateDelta);
1189
				scrollHorizontal(getViewportCoordinateForTimelineCoordinate(timelineCoordinate));
1190
			}
1191
		});
1192
	}
1193

  
1194
	/**
1195
	 * Zoom and scroll to make the given start and end simulation times visible.
1196
	 */
1197
	public void zoomToSimulationTimeRange(final org.omnetpp.common.engine.BigDecimal startSimulationTime, final org.omnetpp.common.engine.BigDecimal endSimulationTime) {
1198
		eventLogInput.runWithProgressMonitor(new Runnable() {
1199
			public void run() {
1200
				if (!endSimulationTime.isNaN() && !startSimulationTime.equals(endSimulationTime)) {
1201
					double timelineUnitDelta = sequenceChartFacade.getTimelineCoordinateForSimulationTime(endSimulationTime) - sequenceChartFacade.getTimelineCoordinateForSimulationTime(startSimulationTime);
1202

  
1203
					if (timelineUnitDelta > 0)
1204
						setPixelPerTimelineUnit(getViewportWidth() / timelineUnitDelta);
1205
				}
1206

  
1207
				scrollHorizontal(getViewportCoordinateForSimulationTime(startSimulationTime));
1208
			}
1209
		});
1210
	}
1211

  
1212
	/**
1213
	 * Zoom and scroll to make the given start and end simulation times visible, but leave some extra pixels on both sides.
1214
	 */
1215
	public void zoomToSimulationTimeRange(org.omnetpp.common.engine.BigDecimal startSimulationTime, org.omnetpp.common.engine.BigDecimal endSimulationTime, int pixelInset) {
1216
		if (pixelInset > 0) {
1217
			// NOTE: we can't go directly there, so here is an approximation
1218
			for (int i = 0; i < 3; i++) {
1219
			    org.omnetpp.common.engine.BigDecimal newStartSimulationTime = getSimulationTimeForViewportCoordinate(getViewportCoordinateForSimulationTime(startSimulationTime) - pixelInset);
1220
			    org.omnetpp.common.engine.BigDecimal newEndSimulationTime = getSimulationTimeForViewportCoordinate(getViewportCoordinateForSimulationTime(endSimulationTime) + pixelInset);
1221

  
1222
				zoomToSimulationTimeRange(newStartSimulationTime, newEndSimulationTime);
1223
			}
1224
		}
1225
		else
1226
			zoomToSimulationTimeRange(startSimulationTime, endSimulationTime);
1227
	}
1228

  
1229
	/**
1230
	 * Zoom and scroll to the given message dependency so that it fits into the viewport.
1231
	 */
1232
	public void zoomToMessageDependency(IMessageDependency messageDependency) {
1233
		zoomToSimulationTimeRange(messageDependency.getCauseEvent().getSimulationTime(), messageDependency.getConsequenceEvent().getSimulationTime(), (int)(getViewportWidth() * 0.1));
1234
	}
1235

  
1236
	/**
1237
	 * Zoom and scroll to make the value at the given simulation time visible at once.
1238
	 */
1239
	public void zoomToAxisValue(ModuleTreeItem axisModule, org.omnetpp.common.engine.BigDecimal simulationTime) {
1240
		for (int i = 0; i < getAxisModules().size(); i++)
1241
			if (getAxisModules().get(i) == axisModule) {
1242
				IAxisRenderer axisRenderer = getAxisRenderers()[i];
1243

  
1244
				if (axisRenderer instanceof AxisVectorBarRenderer) {
1245
					AxisVectorBarRenderer axisVectorBarRenderer = (AxisVectorBarRenderer)axisRenderer;
1246
					zoomToSimulationTimeRange(
1247
						axisVectorBarRenderer.getSimulationTime(axisVectorBarRenderer.getIndex(simulationTime, true)),
1248
						axisVectorBarRenderer.getSimulationTime(axisVectorBarRenderer.getIndex(simulationTime, false)),
1249
						(int)(getViewportWidth() * 0.1));
1250
				}
1251
			}
1252
	}
1253

  
1254
	/*************************************************************************************
1255
	 * INPUT HANDLING
1256
	 */
1257

  
1258
	/**
1259
	 * Returns the currently displayed EventLogInput object.
1260
	 */
1261
	public EventLogInput getInput() {
1262
		return eventLogInput;
1263
	}
1264

  
1265
	/**
1266
	 * Returns the eventlog (data) to be displayed on the chart.
1267
	 */
1268
	public IEventLog getEventLog() {
1269
		return eventLog;
1270
	}
1271

  
1272
	/**
1273
	 * Sets a new EventLogInput to be displayed.
1274
	 */
1275
	public void setInput(final EventLogInput input) {
1276
		// store current settings
1277
		if (eventLogInput != null) {
1278
			eventLogInput.runWithProgressMonitor(new Runnable() {
1279
				public void run() {
1280
					eventLogInput.removeEventLogChangedListener(SequenceChart.this);
1281
					storeState(eventLogInput.getFile());
1282
				}
1283
			});
1284
		}
1285

  
1286
		// remember input
1287
		eventLogInput = input;
1288
		eventLog = eventLogInput == null ? null : eventLogInput.getEventLog();
1289
		sequenceChartFacade = eventLogInput == null ? null : eventLogInput.getSequenceChartFacade();
1290

  
1291
		if (eventLogInput != null) {
1292
			eventLogInput.runWithProgressMonitor(new Runnable() {
1293
				public void run() {
1294
					// restore last known settings
1295
					if (eventLogInput != null) {
1296
						eventLogInput.addEventLogChangedListener(SequenceChart.this);
1297

  
1298
						if (!restoreState(eventLogInput.getFile()) &&
1299
						    !eventLog.isEmpty() && sequenceChartFacade.getTimelineCoordinateSystemOriginEventNumber() == -1)
1300
						{
1301
						    // don't use relocateFixPoint, because viewportWidth is not yet set during initializing
1302
						    sequenceChartFacade.relocateTimelineCoordinateSystem(eventLog.getFirstEvent());
1303
							fixPointViewportCoordinate = 0;
1304
						}
1305
					}
1306

  
1307
					clearSelection();
1308
                    clearAxisModules();
1309
				}
1310
			});
1311
		}
1312
	}
1313

  
1314
    /**
1315
     * Restore persistent sequence chart settings for the given resource.
1316
     * NOTE: the state of the filter menu Show all/filtered is intentionally not saved
1317
     * because a the log file can change between saved sessions. So there is no guarantee how
1318
     * a filter will perform next time if the user opens the sequence chart. It can throw error
1319
     * or run too long to be acceptable.
1320
     */
1321
	public boolean restoreState(IResource resource) {
1322
		PersistentResourcePropertyManager manager = new PersistentResourcePropertyManager(SequenceChartPlugin.PLUGIN_ID, getClass().getClassLoader());
1323

  
1324
		try {
1325
			if (manager.hasProperty(resource, STATE_PROPERTY)) {
1326
				SequenceChartState sequenceChartState = (SequenceChartState)manager.getProperty(resource, STATE_PROPERTY);
1327
				IEvent fixPointEvent = eventLog.getEventForEventNumber(sequenceChartState.fixPointEventNumber);
1328

  
1329
				if (fixPointEvent != null) {
1330
					clearAxisModules();
1331

  
1332
                    setPixelPerTimelineUnit(sequenceChartState.pixelPerTimelineCoordinate);
1333
                    relocateFixPoint(fixPointEvent, sequenceChartState.fixPointViewportCoordinate);
1334
                    scrollVerticalTo(sequenceChartState.viewportTop);
1335

  
1336
					// restore attached vectors
1337
					if (sequenceChartState.axisStates != null) {
1338
						ResultFileManager resultFileManager = new ResultFileManager();
1339

  
1340
						for (int i = 0; i < sequenceChartState.axisStates.length; i++) {
1341
							AxisState axisState = sequenceChartState.axisStates[i];
1342

  
1343
							if (axisState.vectorFileName != null) {
1344
								ResultFile resultFile = resultFileManager.loadFile(axisState.vectorFileName);
1345
								FileRun fileRun = resultFileManager.getFileRun(resultFile, resultFileManager.getRunByName(axisState.vectorRunName));
1346
								long id = resultFileManager.getItemByName(fileRun, axisState.vectorModuleFullPath, axisState.vectorName);
1347
								// TODO: compare vector's run against log file's run
1348
								ResultItem resultItem = resultFileManager.getItem(id);
1349
								XYArray data = VectorFileUtil.getDataOfVector(resultFileManager, id, true);
1350
								setAxisRenderer(eventLogInput.getModuleTreeRoot().findDescendantModule(axisState.moduleFullPath),
1351
							        new AxisVectorBarRenderer(this, axisState.vectorFileName, axisState.vectorRunName, axisState.vectorModuleFullPath, axisState.vectorName, resultItem, data));
1352
							}
1353
						}
1354
					}
1355

  
1356
					// restore axis order
1357
					if (sequenceChartState.axisOrderingMode != null)
1358
					    axisOrderingMode = sequenceChartState.axisOrderingMode;
1359
					if (sequenceChartState.moduleFullPathesManualAxisOrder != null) {
1360
                        ArrayList<ModuleTreeItem> axisOrder = new ArrayList<ModuleTreeItem>();
1361

  
1362
                        for (int i = 0; i < sequenceChartState.moduleFullPathesManualAxisOrder.length; i++)
1363
                            axisOrder.add(eventLogInput.getModuleTreeRoot().findDescendantModule(sequenceChartState.moduleFullPathesManualAxisOrder[i]));
1364

  
1365
                        manualAxisOrder.setAxisOrder(axisOrder);
1366
                    }
1367

  
1368
                    // restore options
1369
					if (sequenceChartState.axisSpacingMode != null)
1370
					    axisSpacingMode = sequenceChartState.axisSpacingMode;
1371
					if (sequenceChartState.axisSpacing != -1)
1372
					    axisSpacing = sequenceChartState.axisSpacing;
1373
					if (sequenceChartState.showMessageNames != null)
1374
						setShowMessageNames(sequenceChartState.showMessageNames);
1375
					if (sequenceChartState.showEventNumbers != null)
1376
						setShowEventNumbers(sequenceChartState.showEventNumbers);
1377
                    if (sequenceChartState.showMessageSends != null)
1378
                        setShowMessageSends(sequenceChartState.showMessageSends);
1379
					if (sequenceChartState.showOtherMessageReuses != null)
1380
						setShowOtherMessageReuses(sequenceChartState.showOtherMessageReuses);
1381
					if (sequenceChartState.showSelfMessages != null)
1382
                        setShowSelfMessages(sequenceChartState.showSelfMessages);
1383
					if (sequenceChartState.showSelfMessageReuses != null)
1384
                        setShowSelfMessageReuses(sequenceChartState.showSelfMessageReuses);
1385
                    if (sequenceChartState.showModuleMethodCalls != null)
1386
                        setShowModuleMethodCalls(sequenceChartState.showModuleMethodCalls);
1387
					if (sequenceChartState.showArrowHeads != null)
1388
                        setShowArrowHeads(sequenceChartState.showArrowHeads);
1389
					if (sequenceChartState.showZeroSimulationTimeRegions != null)
1390
                        setShowZeroSimulationTimeRegions(sequenceChartState.showZeroSimulationTimeRegions);
1391
					if (sequenceChartState.showAxisLabels != null)
1392
                        setShowAxisLabels(sequenceChartState.showAxisLabels);
1393
					if (sequenceChartState.showAxesWithoutEvents != null)
1394
                        setShowAxesWithoutEvents(sequenceChartState.showAxesWithoutEvents);
1395
					if (sequenceChartState.showTransmissionDurations != null)
1396
                        setShowTransmissionDurations(sequenceChartState.showTransmissionDurations);
1397

  
1398
                    // restore timeline mode
1399
                    if (sequenceChartState.timelineMode != null)
1400
                        setTimelineMode(sequenceChartState.timelineMode);
1401

  
1402
					return true;
1403
				}
1404
			}
1405

  
1406
			return false;
1407
		}
1408
		catch (Exception e) {
1409
			manager.removeProperty(resource, STATE_PROPERTY);
1410

  
1411
			throw new RuntimeException(e);
1412
		}
1413
	}
1414

  
1415
	/**
1416
	 * Store persistent sequence chart settings for the given resource.
1417
	 */
1418
	public void storeState(IResource resource) {
1419
		try {
1420
			PersistentResourcePropertyManager manager = new PersistentResourcePropertyManager(SequenceChartPlugin.PLUGIN_ID);
1421

  
1422
			if (sequenceChartFacade.getTimelineCoordinateSystemOriginEventNumber() == -1)
1423
				manager.removeProperty(resource, STATE_PROPERTY);
1424
			else {
1425
				SequenceChartState sequenceChartState = new SequenceChartState();
1426
				sequenceChartState.viewportTop = (int)getViewportTop();
1427
				sequenceChartState.fixPointEventNumber = sequenceChartFacade.getTimelineCoordinateSystemOriginEventNumber();
1428
				sequenceChartState.fixPointViewportCoordinate = fixPointViewportCoordinate;
1429
				sequenceChartState.pixelPerTimelineCoordinate = getPixelPerTimelineUnit();
1430

  
1431
			    // store attached vectors
1432
				AxisState[] axisStates = new AxisState[getAxisModules().size()];
1433

  
1434
				for (int i = 0; i < getAxisModules().size(); i++) {
1435
					AxisState axisState = axisStates[i] = new AxisState();
1436
					axisState.moduleFullPath = getAxisModules().get(i).getModuleFullPath();
1437

  
1438
					if (getAxisRenderers()[i] instanceof AxisVectorBarRenderer) {
1439
						AxisVectorBarRenderer renderer = (AxisVectorBarRenderer)getAxisRenderers()[i];
1440
						axisState.vectorFileName = renderer.getVectorFileName();
1441
                        axisState.vectorRunName = renderer.getVectorRunName();
1442
                        axisState.vectorModuleFullPath = renderer.getVectorModuleFullPath();
1443
                        axisState.vectorName = renderer.getVectorName();
1444
					}
1445
				}
1446

  
1447
				sequenceChartState.axisStates = axisStates;
1448

  
1449
				// store manual axis order
1450
				sequenceChartState.axisOrderingMode = axisOrderingMode;
1451
				ArrayList<ModuleTreeItem> axisOrder = manualAxisOrder.getAxisOrder();
1452
				String[] moduleFullPathesManualAxisOrder = new String[axisOrder.size()];
1453
				for (int i = 0; i < moduleFullPathesManualAxisOrder.length; i++) {
1454
				    ModuleTreeItem axisModule = axisOrder.get(i);
1455

  
1456
				    if (axisModule != null)
1457
				        moduleFullPathesManualAxisOrder[i] = axisModule.getModuleFullPath();
1458
				}
1459
				sequenceChartState.moduleFullPathesManualAxisOrder = moduleFullPathesManualAxisOrder;
1460

  
1461
                // store timeline mode
1462
				sequenceChartState.timelineMode = getTimelineMode();
1463

  
1464
                // store options
1465
                sequenceChartState.axisSpacingMode = getAxisSpacingMode();
1466
                sequenceChartState.axisSpacing = getAxisSpacing();
1467
                sequenceChartState.showMessageNames = getShowMessageNames();
1468
                sequenceChartState.showEventNumbers = getShowEventNumbers();
1469
                sequenceChartState.showMessageSends = getShowMessageSends();
1470
                sequenceChartState.showOtherMessageReuses = getShowOtherMessageReuses();
1471
                sequenceChartState.showSelfMessages = getShowSelfMessages();
1472
                sequenceChartState.showSelfMessageReuses = getShowSelfMessageReuses();
1473
                sequenceChartState.showModuleMethodCalls = getShowModuleMethodCalls();
1474
                sequenceChartState.showArrowHeads = getShowArrowHeads();
1475
                sequenceChartState.showZeroSimulationTimeRegions = getShowZeroSimulationTimeRegions();
1476
                sequenceChartState.showAxisLabels = getShowAxisLabels();
1477
                sequenceChartState.showAxesWithoutEvents = getShowAxesWithoutEvents();
1478
                sequenceChartState.showTransmissionDurations = getShowTransmissionDurations();
1479

  
1480
				manager.setProperty(resource, STATE_PROPERTY, sequenceChartState);
1481
			}
1482
		}
1483
		catch (Exception e) {
1484
			throw new RuntimeException(e);
1485
		}
1486
	}
1487

  
1488
    /*************************************************************************************
1489
     * EVENTLOG NOTIFICATIONS
1490
     */
1491

  
1492
	public void eventLogAppended() {
1493
		eventLogChanged();
1494
	}
1495

  
1496
    public void eventLogOverwritten() {
1497
        clearAxisModules();
1498
        eventLogChanged();
1499
    }
1500

  
1501
    private void eventLogChanged() {
1502
        if (eventLog.isEmpty())
1503
            relocateFixPoint(null, 0);
1504
        else if (sequenceChartFacade.getTimelineCoordinateSystemOriginEventNumber() == -1 ||
1505
                 sequenceChartFacade.getTimelineCoordinateSystemOriginEvent() == null)
1506
            scrollToBegin();
1507

  
1508
        if (debug)
1509
			Debug.println("SequenceChart got notification about eventlog change");
1510

  
1511
		configureScrollBars();
1512
		adjustHorizontalScrollBar();
1513
		clearCanvasCache();
1514

  
1515
		if (followEnd)
1516
		{
1517
			if (debug)
1518
				Debug.println("Scrolling to follow eventlog change");
1519

  
1520
            if (!eventLog.isEmpty())
1521
                scrollToEnd();
1522
		}
1523
		else
1524
			redraw();
1525
    }
1526

  
1527
	public void eventLogFiltered() {
1528
		eventLog = eventLogInput.getEventLog();
1529

  
1530
		if (eventLog.isEmpty())
1531
		    relocateFixPoint(null, 0);
1532
		else if (sequenceChartFacade.getTimelineCoordinateSystemOriginEventNumber() != -1) {
1533
			FilteredEventLog filteredEventLog = (FilteredEventLog)eventLogInput.getEventLog();
1534
			IEvent closestEvent = filteredEventLog.getMatchingEventInDirection(sequenceChartFacade.getTimelineCoordinateSystemOriginEventNumber(), false);
1535

  
1536
			if (closestEvent != null)
1537
				relocateFixPoint(closestEvent, 0);
1538
			else {
1539
				closestEvent = filteredEventLog.getMatchingEventInDirection(sequenceChartFacade.getTimelineCoordinateSystemOriginEventNumber(), true);
1540

  
1541
				if (closestEvent != null)
1542
					relocateFixPoint(closestEvent, 0);
1543
				else
1544
				    scrollToBegin();
1545
			}
1546
		}
1547
		else
1548
		    scrollToBegin();
1549

  
1550
		// remove selected events that are not visible in the filter
1551
        for (long selectedEventNumber : new ArrayList<Long>(selectionEventNumbers))
1552
            if (eventLog.getEventForEventNumber(selectedEventNumber) == null)
1553
                selectionEventNumbers.remove(selectedEventNumber);
1554

  
1555
        sequenceChartContributor.update();
1556
        clearAxisModules();
1557
	}
1558

  
1559
	public void eventLogFilterRemoved() {
1560
		eventLog = eventLogInput.getEventLog();
1561

  
1562
		if (sequenceChartFacade.getTimelineCoordinateSystemOriginEventNumber() != -1)
1563
			relocateFixPoint(sequenceChartFacade.getTimelineCoordinateSystemOriginEvent(), 0);
1564
		else
1565
		    scrollToBegin();
1566

  
1567
        sequenceChartContributor.update();
1568
        clearAxisModules();
1569
	}
1570

  
1571
	public void eventLogLongOperationStarted() {
1572
	}
1573

  
1574
	public void eventLogLongOperationEnded() {
1575
	    if (!paintHasBeenFinished)
1576
	        redraw();
1577
	}
1578

  
1579
	public void eventLogProgress() {
1580
		if (eventLogInput.getEventLogProgressManager().isCanceled())
1581
			redraw();
1582
	}
1583

  
1584
    /*************************************************************************************
1585
     * FIND
1586
     */
1587

  
1588
	/**
1589
	 * Starts or continues a find operation and immediately jumps to the result.
1590
	 */
1591
    public void findText(boolean continueSearch) {
1592
        String findText = null;
1593
        EventLogEntry foundEventLogEntry = null;
1594

  
1595
        EventLogFindTextDialog findTextDialog = eventLogInput.getFindTextDialog();
1596

  
1597
        if (continueSearch || findTextDialog.open() == Window.OK) {
1598
            findText = findTextDialog.getValue();
1599

  
1600
            if (findText != null) {
1601
                try {
1602
                    IEvent event = getSelectionEvent();
1603

  
1604
                    if (event == null) {
1605
                        long[] eventPtrRange = getFirstLastEventPtrForViewportRange(0, 0);
1606
                        event = sequenceChartFacade.IEvent_getEvent(eventPtrRange[0]);
1607
                        if (event == null)
1608
                            return;
1609
                    }
1610

  
1611
                    EventLogEntry startEventLogEntry = null;
1612
                    if (findTextDialog.isBackward()) {
1613
                        event = event.getPreviousEvent();
1614
                        if (event == null)
1615
                            return;
1616
                        startEventLogEntry = event.getEventLogEntry(event.getNumEventLogEntries() - 1);
1617
                    }
1618
                    else {
1619
                        event = event.getNextEvent();
1620
                        if (event == null)
1621
                            return;
1622
                        startEventLogEntry = event.getEventEntry();
1623
                    }
1624

  
1625
                    foundEventLogEntry = eventLog.findEventLogEntry(startEventLogEntry, findText, !findTextDialog.isBackward(), !findTextDialog.isCaseInsensitive());
1626
                }
1627
                finally {
1628
                    if (foundEventLogEntry != null)
1629
                        gotoClosestElement(foundEventLogEntry.getEvent());
1630
                    else
1631
                        MessageDialog.openInformation(null, "Find raw text", "No more matches found for " + findText);
1632
                }
1633
            }
1634
        }
1635
    }
1636

  
1637
    /*************************************************************************************
1638
     * AXIS MODULES
1639
     */
1640

  
1641
	/**
1642
     * Returns which modules have axes on the chart, lazily updates the list if necessary.
1643
     * The returned value should not be modified.
1644
     */
1645
	public ArrayList<ModuleTreeItem> getAxisModules() {
1646
	    if (invalidAxisModules) {
1647
	        calculateAxisModules();
1648
	        invalidAxisModules = false;
1649
	    }
1650

  
1651
	    return axisModules;
1652
	}
1653

  
1654
    /**
1655
     * Clears the list of axis modules and makes this list invalid.
1656
     */
1657
    public void clearAxisModules() {
1658
        this.axisModules = new ArrayList<ModuleTreeItem>();
1659
        invalidateAxisModules();
1660
    }
1661

  
1662
    /**
1663
     * Marks the current set of axis modules invalid but don't clear the list.
1664
     * New axes will be added on demand.
1665
     */
1666
    private void invalidateAxisModules() {
1667
        if (debug) {
1668
            Debug.println("invalidateAxisModules(): enter");
1669
        }
1670

  
1671
        invalidAxisModules = true;
1672
        invalidAxisRenderers = true;
1673
        invalidAxisSpacing = true;
1674
        invalidVirtualSize = true;
1675
        invalidAxisModuleYs = true;
1676
        invalidAxisModulePositions = true;
1677
        invalidModuleIdToAxisModuleIndexMap = true;
1678
        invalidModuleIdToAxisRendererMap = true;
1679
        clearCanvasCacheAndRedraw();
1680
    }
1681

  
1682
    /**
1683
     * Checks if the current axis modules represent all currently visible modules.
1684
     */
1685
    private boolean validateAxisModules() {
1686
        int numberOfAxisModules = axisModules.size();
1687
        calculateAxisModules();
1688

  
1689
        return numberOfAxisModules == axisModules.size();
1690
    }
1691

  
1692
    /**
1693
     * Checks if the current axis modules are valid, if not then issues an invalidate.
1694
     */
1695
    private void revalidateAxisModules() {
1696
        if (!invalidAxisModules && !validateAxisModules())
1697
            invalidateAxisModules();
1698
    }
1699

  
1700
    /**
1701
     * Collects the modules which need to have an axis in the currently visible region.
1702
     * It considers all events and all message dependencies within the viewport.
1703
     */
1704
    private Set<Integer> collectModuleIdsForVisibleModules() {
1705
        Set<Integer> axisModuleIds = new HashSet<Integer>();
1706

  
1707
        // consider visible events
1708
        int extraClipping = getExtraClippingForEvents() + 30; // add an extra for the caching canvas tile cache width (clipping may be negative in paint)
1709
        long[] eventPtrRange = getFirstLastEventPtrForViewportRange(-extraClipping, getViewportWidth() + extraClipping);
1710
        long startEventPtr = eventPtrRange[0];
1711
        long endEventPtr = eventPtrRange[1];
1712

  
1713
        if (startEventPtr != 0 && endEventPtr != 0) {
1714
            if (debug)
1715
                Debug.println("Collecting axis modules for events using event range: " + sequenceChartFacade.IEvent_getEventNumber(startEventPtr) + " -> " + sequenceChartFacade.IEvent_getEventNumber(endEventPtr));
1716

  
1717
            for (long eventPtr = startEventPtr;; eventPtr = sequenceChartFacade.IEvent_getNextEvent(eventPtr)) {
1718
                if (!isInitializationEvent(eventPtr))
1719
                    axisModuleIds.add(sequenceChartFacade.IEvent_getModuleId(eventPtr));
1720

  
1721
                if (eventPtr == endEventPtr)
1722
                    break;
1723
            }
1724
        }
1725

  
1726
        // consider visible message dependencies
1727
        eventPtrRange = getFirstLastEventPtrForMessageDependencies();
1728
        startEventPtr = eventPtrRange[0];
1729
        endEventPtr = eventPtrRange[1];
1730

  
1731
        if (startEventPtr != 0 && endEventPtr != 0) {
1732
            if (debug)
1733
                Debug.println("Collecting axis modules for message dependencies using event range: " + sequenceChartFacade.IEvent_getEventNumber(startEventPtr) + " -> " + sequenceChartFacade.IEvent_getEventNumber(endEventPtr));
1734

  
1735
            PtrVector messageDependencies = sequenceChartFacade.getIntersectingMessageDependencies(startEventPtr, endEventPtr);
1736

  
1737
            for (int i = 0; i < messageDependencies.size(); i++) {
1738
                long messageDependencyPtr = messageDependencies.get(i);
1739
                long causeEventPtr = sequenceChartFacade.IMessageDependency_getCauseEvent(messageDependencyPtr);
1740
                long consequenceEventPtr = sequenceChartFacade.IMessageDependency_getConsequenceEvent(messageDependencyPtr);
1741

  
1742
                if (causeEventPtr != 0) {
1743
//                    if (debug)
1744
//                        Debug.println("Collecting axis module for message dependency cause event: #" + sequenceChartFacade.IEvent_getEventNumber(causeEventPtr));
1745

  
1746
                    if (isInitializationEvent(causeEventPtr))
1747
                        axisModuleIds.add(getInitializationEventContextModuleId(messageDependencyPtr));
1748
                    else
1749
                        axisModuleIds.add(sequenceChartFacade.IEvent_getModuleId(causeEventPtr));
1750
                }
1751

  
1752
                if (consequenceEventPtr != 0) {
1753
//                    if (debug)
1754
//                        Debug.println("Collecting axis module for message dependency consequence event: #" + sequenceChartFacade.IEvent_getEventNumber(consequenceEventPtr));
1755

  
1756
                    axisModuleIds.add(sequenceChartFacade.IEvent_getModuleId(consequenceEventPtr));
1757
                }
1758
            }
1759
        }
1760

  
1761
        // consider visible module method calls
1762
        extraClipping = getExtraClippingForEvents();
1763
        eventPtrRange = getFirstLastEventPtrForViewportRange(-extraClipping, getViewportWidth() + extraClipping);
1764
        startEventPtr = eventPtrRange[0];
1765
        endEventPtr = eventPtrRange[1];
1766

  
1767
        if (startEventPtr != 0 && endEventPtr != 0) {
1768
            if (debug)
1769
                Debug.println("Collecting axis modules for module method calls using event range: " + sequenceChartFacade.IEvent_getEventNumber(startEventPtr) + " -> " + sequenceChartFacade.IEvent_getEventNumber(endEventPtr));
1770

  
1771
            PtrVector moduleMethodBeginEntries = sequenceChartFacade.getModuleMethodBeginEntries(startEventPtr, endEventPtr);
1772

  
1773
            for (int i = 0; i < moduleMethodBeginEntries.size(); i++) {
1774
                long moduleMethodCallPtr = moduleMethodBeginEntries.get(i);
1775
                int fromModuleId = sequenceChartFacade.ModuleMethodBeginEntry_getFromModuleId(moduleMethodCallPtr);
1776
                int toModuleId = sequenceChartFacade.ModuleMethodBeginEntry_getToModuleId(moduleMethodCallPtr);
1777
                axisModuleIds.add(fromModuleId);
1778
                axisModuleIds.add(toModuleId);
1779
            }
1780
        }
1781

  
1782
        if (debug)
1783
            Debug.println("Module ids that will have axes: " + axisModuleIds);
1784

  
1785
        return axisModuleIds;
1786
    }
1787

  
1788
    /**
1789
     * Makes sure all axes are present which will be needed to draw the chart
1790
     * in the currently visible region.
1791
     */
1792
    private void calculateAxisModules() {
1793
        long startMillis = System.currentTimeMillis();
1794
        if (debug)
1795
            Debug.println("calculateAxisModules(): enter");
1796

  
1797
        if (showAxesWithoutEvents) {
1798
            eventLogInput.getModuleTreeRoot().visitLeaves(new ModuleTreeItem.IModuleTreeItemVisitor() {
1799
                public void visit(ModuleTreeItem moduleTreeItem) {
1800
                    if (isSelectedAxisModule(moduleTreeItem) && !axisModules.contains(moduleTreeItem))
1801
                        axisModules.add(moduleTreeItem);
1802
                }
1803
            });
1804
        }
1805
        else {
1806
            for (int moduleId : collectModuleIdsForVisibleModules()) {
1807
                ModuleTreeItem moduleTreeRoot = eventLogInput.getModuleTreeRoot();
1808
                ModuleTreeItem moduleTreeItem = moduleTreeRoot.findDescendantModule(moduleId);
1809

  
1810
                // check if module already has an associated axis?
1811
                for (ModuleTreeItem axisModule : axisModules)
1812
                    if (axisModule == moduleTreeItem || (axisModule.isCompoundModule() && axisModule.isDescendantModule(moduleTreeItem)))
1813
                        continue;
1814

  
1815
                // create module tree item on demand
1816
                if (moduleTreeItem == null) {
1817
                    ModuleCreatedEntry entry = eventLog.getModuleCreatedEntry(moduleId);
1818

  
1819
                    if (entry != null)
1820
                        moduleTreeItem = moduleTreeRoot.addDescendantModule(entry.getParentModuleId(), entry.getModuleId(), entry.getModuleClassName(), entry.getFullName(), entry.getCompoundModule());
1821
                    else
1822
                        // FIXME: this is not correct and will not be replaced automagically when the ModuleCreatedEntry is found later on
1823
                        moduleTreeItem = new ModuleTreeItem(moduleId, "<unknown>", "<unknown>", moduleTreeRoot, false);
1824
                }
1825

  
1826
                // find the selected module axis and add it
1827
                while (moduleTreeItem != null) {
1828
                    if (isSelectedAxisModule(moduleTreeItem) && !axisModules.contains(moduleTreeItem)) {
1829
                        axisModules.add(moduleTreeItem);
1830
                        break;
1831
                    }
1832

  
1833
                    moduleTreeItem = moduleTreeItem.getParentModule();
1834
                }
1835
            }
1836
        }
1837

  
1838
        long totalMillis = System.currentTimeMillis() - startMillis;
1839
        if (debug)
1840
            Debug.println("calculateAxisModules(): leave after " + totalMillis + "ms");
1841
    }
1842

  
1843
    /**
1844
     * True means the module is selected to have an axis. Even if a module is selected it
1845
     * might still be excluded depending on the showAxesWithoutEvents flag.
1846
     */
1847
    private boolean isSelectedAxisModule(ModuleTreeItem moduleTreeItem) {
1848
        if (eventLog instanceof FilteredEventLog && eventLogInput.getFilterParameters().enableModuleFilter) {
1849
            ModuleCreatedEntry moduleCreatedEntry = eventLog.getModuleCreatedEntry(moduleTreeItem.getModuleId());
1850
            Assert.isTrue(moduleCreatedEntry != null);
1851
            return ((FilteredEventLog)eventLog).matchesModuleCreatedEntry(moduleCreatedEntry);
1852
        }
1853
        else
1854
            return !moduleTreeItem.isCompoundModule();
1855
    }
1856

  
1857
    /*************************************************************************************
1858
     * AXIS RENDERERS
1859
     */
1860

  
1861
    /**
1862
     * Returns the list of axis renderers, lazily updates the list if necessary.
1863
     */
1864
    public IAxisRenderer[] getAxisRenderers() {
1865
        if (invalidAxisRenderers) {
1866
            calculateAxisRenderers();
1867
            invalidAxisRenderers = false;
1868
        }
1869

  
1870
        return axisRenderers;
1871
    }
1872

  
1873
    private void calculateAxisRenderers() {
1874
        axisRenderers = new IAxisRenderer[getAxisModules().size()];
1875

  
1876
        for (int i = 0; i < axisRenderers.length; i++)
1877
            axisRenderers[i] = getAxisRenderer(getAxisModules().get(i));
1878
    }
1879

  
1880
    /*************************************************************************************
1881
     * MODULE ID TO AXIS RENDERER MAP
1882
     */
1883

  
1884
    /**
1885
     * Returns the map from module ids to axis renderers, lazily updates the map if necessary.
1886
     */
1887
    public Map<Integer, IAxisRenderer> getModuleIdToAxisRendererMap() {
1888
        if (invalidModuleIdToAxisRendererMap) {
1889
            calculateModuleIdToAxisRendererMap();
1890
            invalidModuleIdToAxisRendererMap = false;
1891
        }
1892

  
1893
        return moduleIdToAxisRendererMap;
1894
    }
1895

  
1896
    /**
1897
     * Returns the axis renderer associated with the module.
1898
     */
1899
    public IAxisRenderer getAxisRenderer(ModuleTreeItem axisModule) {
1900
		return getModuleIdToAxisRendererMap().get(axisModule.getModuleId());
1901
	}
1902

  
1903
	/**
1904
	 * Associates the axis renderer with the given axis module.
1905
	 */
1906
	public void setAxisRenderer(ModuleTreeItem axisModule, IAxisRenderer axisRenderer) {
1907
		moduleIdToAxisRendererMap.put(axisModule.getModuleId(), axisRenderer);
1908
		int index = getAxisModules().indexOf(axisModule);
1909

  
1910
		if (index != -1) {
1911
		    getAxisRenderers()[index] = axisRenderer;
1912
		    invalidateAxisSpacing();
1913
		}
1914
	}
1915

  
1916
    private void calculateModuleIdToAxisRendererMap() {
1917
        for (ModuleTreeItem axisModule : getAxisModules()) {
1918
            IAxisRenderer axisRenderer = moduleIdToAxisRendererMap.get(axisModule.getModuleId());
1919

  
1920
            if (axisRenderer == null)
1921
                moduleIdToAxisRendererMap.put(axisModule.getModuleId(), new AxisLineRenderer(this, axisModule));
1922
        }
1923
    }
1924

  
1925
    /*************************************************************************************
1926
     * AXIS MODULE POSITIONS
1927
     */
1928

  
1929
    /**
1930
     * Returns the axis module positions as an array, lazily updates the array if necessary.
1931
     * The nth value specifies the position of the nth axis module.
1932
     */
1933
	public int[] getAxisModulePositions() {
1934
	    if (invalidAxisModulePositions) {
1935
	        calculateAxisModulePositions();
1936
	        invalidAxisModulePositions = false;
1937
	    }
1938

  
1939
	    return axisModulePositions;
1940
	}
1941

  
1942
    private void invalidateAxisModulePositions() {
1943
        if (debug)
1944
            Debug.println("invalidateAxisModulePositions(): enter");
1945

  
1946
        invalidAxisModulePositions = true;
1947
        invalidAxisModuleYs = true;
1948
        invalidModuleIdToAxisModuleIndexMap = true;
1949
        clearCanvasCacheAndRedraw();
1950
    }
1951

  
1952
    /**
1953
     * Sorts axis modules depending on timeline ordering mode.
1954
     */
1955
    private void calculateAxisModulePositions() {
1956
        eventLogInput.runWithProgressMonitor(new Runnable() {
1957
            public void run() {
1958
                ModuleTreeItem[] axisModulesArray = getAxisModules().toArray(new ModuleTreeItem[0]);
1959

  
1960
                switch (axisOrderingMode) {
1961
                    case MANUAL:
1962
                        axisModulePositions = manualAxisOrder.calculateOrdering(axisModulesArray);
1963
                        break;
1964
                    case MODULE_ID:
1965
                        axisModulePositions = new AxisOrderByModuleId().calculateOrdering(axisModulesArray);
1966
                        break;
1967
                    case MODULE_FULL_PATH:
1968
                        axisModulePositions = new AxisOrderByModuleName().calculateOrdering(axisModulesArray);
1969
                        break;
1970
                    case MINIMIZE_CROSSINGS:
1971
                        axisModulesArray = manualAxisOrder.getCurrentAxisModuleOrder(axisModulesArray).toArray(new ModuleTreeItem[0]);
1972
                        axisModulePositions = new FlatAxisOrderByMinimizingCost(eventLogInput).calculateOrdering(axisModulesArray, getModuleIdToAxisModuleIndexMap());
1973
                        break;
1974
                    default:
1975
                        throw new RuntimeException("Unknown axis ordering mode");
1976
                }
1977
            }
1978
        });
1979
    }
1980

  
1981
	/*************************************************************************************
1982
     * AXIS YS
1983
     */
1984

  
1985
    /**
1986
     * Returns the list of axis module vertical positions, lazily updates the list if necessary.
1987
     */
1988
    public int[] getAxisModuleYs() {
1989
        if (invalidAxisModuleYs) {
1990
            calculateAxisYs();
1991
            invalidAxisModuleYs = false;
1992
        }
1993

  
1994
        return axisModuleYs;
1995
    }
1996

  
1997
    /**
1998
     * Calculates top y coordinates of axis bounding boxes based on height returned by each axis.
1999
     */
2000
    private void calculateAxisYs() {
2001
        axisModuleYs = new int[getAxisModules().size()];
2002

  
2003
        for (int i = 0; i < axisModuleYs.length; i++) {
2004
            double y = 0;
2005

  
2006
            for (int j = 0; j < axisModuleYs.length; j++)
2007
                if (getAxisModulePositions()[j] < getAxisModulePositions()[i])
2008
                    y += getAxisSpacing() + getAxisRenderers()[j].getHeight();
2009

  
2010
            axisModuleYs[i] = (int)Math.round((AXIS_OFFSET + getAxisSpacing() + y));
2011
        }
2012
    }
2013

  
2014
    /*************************************************************************************
2015
     * MODULE ID TO AXIS MODULE INDEX MAP
2016
     */
2017

  
2018
    /**
2019
     * Returns a map from module id to axis module index, lazily updates the map if necessary.
2020
     */
2021
    public Map<Integer, Integer> getModuleIdToAxisModuleIndexMap() {
2022
        if (invalidModuleIdToAxisModuleIndexMap) {
2023
            calculateModuleIdToAxisModuleIndexMap();
2024
            invalidModuleIdToAxisModuleIndexMap = false;
2025
        }
2026

  
2027
        return moduleIdToAxisModuleIndexMap;
2028
    }
2029

  
2030
    /**
2031
     * Calculates axis indices for all modules by finding an axis module ancestor.
2032
     */
2033
    private void calculateModuleIdToAxisModuleIndexMap() {
2034
        if (debug)
2035
            Debug.println("calculateModuleIdToAxisModuleIndexMap()");
2036

  
2037
        moduleIdToAxisModuleIndexMap = new HashMap<Integer, Integer>();
2038

  
2039
        // this algorithm allows to have two module axes on the chart
2040
        // which are in ancestor-descendant relationship,
2041
        // and allows events still be drawn on the most specific axis
2042
        eventLogInput.getModuleTreeRoot().visitLeaves(new ModuleTreeItem.IModuleTreeItemVisitor() {
2043
            public void visit(ModuleTreeItem descendantAxisModule) {
2044
                ModuleTreeItem axisModule = descendantAxisModule;
2045

  
2046
                while (axisModule != null) {
2047
                    int index = getAxisModules().indexOf(axisModule);
2048

  
2049
                    if (index != -1) {
2050
                        moduleIdToAxisModuleIndexMap.put(descendantAxisModule.getModuleId(), index);
2051
                        return;
2052
                    }
2053

  
2054
                    axisModule = axisModule.getParentModule();
2055
                }
2056
            }
2057
        });
2058
    }
... This diff was truncated because it exceeds the maximum size that can be displayed.

Also available in: Unified diff