tmf: Align the time-axis of time chart views
authorMarc-Andre Laperle <marc-andre.laperle@ericsson.com>
Wed, 29 Apr 2015 18:28:27 +0000 (14:28 -0400)
committerMarc-Andre Laperle <marc-andre.laperle@ericsson.com>
Thu, 7 May 2015 17:48:57 +0000 (13:48 -0400)
This patch introduces a logic for time-axis alignment across view. The
time chart based views use this new mechanism as a first implementation.

Change-Id: I31a05b686c8028b8f3e0643afa7aa540c9165cdf
Signed-off-by: Marc-Andre Laperle <marc-andre.laperle@ericsson.com>
Reviewed-on: https://git.eclipse.org/r/46810
Reviewed-by: Hudson CI
Reviewed-by: Bernd Hufmann <bernd.hufmann@ericsson.com>
Tested-by: Bernd Hufmann <bernd.hufmann@ericsson.com>
21 files changed:
org.eclipse.tracecompass.tmf.ui/META-INF/MANIFEST.MF
org.eclipse.tracecompass.tmf.ui/icons/elcl16/link.gif [new file with mode: 0644]
org.eclipse.tracecompass.tmf.ui/icons/etool16/link.gif [deleted file]
org.eclipse.tracecompass.tmf.ui/src/org/eclipse/tracecompass/internal/tmf/ui/ITmfImageConstants.java
org.eclipse.tracecompass.tmf.ui/src/org/eclipse/tracecompass/internal/tmf/ui/ITmfUIPreferences.java [new file with mode: 0644]
org.eclipse.tracecompass.tmf.ui/src/org/eclipse/tracecompass/internal/tmf/ui/Messages.java
org.eclipse.tracecompass.tmf.ui/src/org/eclipse/tracecompass/internal/tmf/ui/TmfUIPreferenceInitializer.java [new file with mode: 0644]
org.eclipse.tracecompass.tmf.ui/src/org/eclipse/tracecompass/internal/tmf/ui/messages.properties
org.eclipse.tracecompass.tmf.ui/src/org/eclipse/tracecompass/internal/tmf/ui/views/TimeAlignViewsAction.java [new file with mode: 0644]
org.eclipse.tracecompass.tmf.ui/src/org/eclipse/tracecompass/internal/tmf/ui/views/TmfAlignmentSynchronizer.java [new file with mode: 0644]
org.eclipse.tracecompass.tmf.ui/src/org/eclipse/tracecompass/tmf/ui/signal/TmfTimeViewAlignmentInfo.java [new file with mode: 0644]
org.eclipse.tracecompass.tmf.ui/src/org/eclipse/tracecompass/tmf/ui/signal/TmfTimeViewAlignmentSignal.java [new file with mode: 0644]
org.eclipse.tracecompass.tmf.ui/src/org/eclipse/tracecompass/tmf/ui/views/ITmfTimeAligned.java [new file with mode: 0644]
org.eclipse.tracecompass.tmf.ui/src/org/eclipse/tracecompass/tmf/ui/views/TmfView.java
org.eclipse.tracecompass.tmf.ui/src/org/eclipse/tracecompass/tmf/ui/views/callstack/CallStackView.java
org.eclipse.tracecompass.tmf.ui/src/org/eclipse/tracecompass/tmf/ui/views/histogram/HistogramView.java
org.eclipse.tracecompass.tmf.ui/src/org/eclipse/tracecompass/tmf/ui/views/timechart/TimeChartView.java
org.eclipse.tracecompass.tmf.ui/src/org/eclipse/tracecompass/tmf/ui/views/timegraph/AbstractTimeGraphView.java
org.eclipse.tracecompass.tmf.ui/src/org/eclipse/tracecompass/tmf/ui/widgets/timegraph/TimeGraphCombo.java
org.eclipse.tracecompass.tmf.ui/src/org/eclipse/tracecompass/tmf/ui/widgets/timegraph/TimeGraphViewer.java
org.eclipse.tracecompass.tmf.ui/src/org/eclipse/tracecompass/tmf/ui/widgets/timegraph/widgets/TimeGraphControl.java

index 9816d39874ed80e8b93bd4e467f0a4b19018be87..fe80fe560affb9efca4830dd0dc81a38be4e2d3b 100644 (file)
@@ -40,12 +40,14 @@ Export-Package: org.eclipse.tracecompass.internal.tmf.ui;x-friends:="org.eclipse
    org.eclipse.tracecompass.tmf.remote.ui",
  org.eclipse.tracecompass.internal.tmf.ui.project.wizards.tracepkg;x-friends:="org.eclipse.tracecompass.tmf.remote.ui,org.eclipse.tracecompass.tmf.remote.ui.tests",
  org.eclipse.tracecompass.internal.tmf.ui.project.wizards.tracepkg.importexport;x-friends:="org.eclipse.tracecompass.tmf.remote.ui",
+ org.eclipse.tracecompass.internal.tmf.ui.views;x-internal:=true,
  org.eclipse.tracecompass.tmf.ui,
  org.eclipse.tracecompass.tmf.ui.analysis,
  org.eclipse.tracecompass.tmf.ui.editors,
  org.eclipse.tracecompass.tmf.ui.project.model,
  org.eclipse.tracecompass.tmf.ui.project.wizards,
  org.eclipse.tracecompass.tmf.ui.properties,
+ org.eclipse.tracecompass.tmf.ui.signal,
  org.eclipse.tracecompass.tmf.ui.viewers,
  org.eclipse.tracecompass.tmf.ui.viewers.events,
  org.eclipse.tracecompass.tmf.ui.viewers.events.columns,
diff --git a/org.eclipse.tracecompass.tmf.ui/icons/elcl16/link.gif b/org.eclipse.tracecompass.tmf.ui/icons/elcl16/link.gif
new file mode 100644 (file)
index 0000000..d6f89c6
Binary files /dev/null and b/org.eclipse.tracecompass.tmf.ui/icons/elcl16/link.gif differ
diff --git a/org.eclipse.tracecompass.tmf.ui/icons/etool16/link.gif b/org.eclipse.tracecompass.tmf.ui/icons/etool16/link.gif
deleted file mode 100644 (file)
index e085688..0000000
Binary files a/org.eclipse.tracecompass.tmf.ui/icons/etool16/link.gif and /dev/null differ
index a074c3015369b60885cb9648fc838260670fd57f..f78bcf6d87c814f2ea7888d3f9819cedbcb6c193 100755 (executable)
@@ -47,6 +47,7 @@ public interface ITmfImageConstants {
     String IMG_UI_FOLLOW_ARROW_BACKWARD = ICONS_PATH + "elcl16/follow_arrow_bwd.gif";
     String IMG_UI_SHOW_LOST_EVENTS = ICONS_PATH + "elcl16/hide_lost_events.gif";
     String IMG_UI_SHOW_HIST_TRACES = ICONS_PATH + "elcl16/show_hist_traces.gif";
+    String IMG_UI_LINK = ICONS_PATH + "elcl16/link.gif";
 
     /* eview16 */
     String IMG_UI_SEQ_DIAGRAM_OBJ = ICONS_PATH + "eview16/sequencediagram_view.gif";
diff --git a/org.eclipse.tracecompass.tmf.ui/src/org/eclipse/tracecompass/internal/tmf/ui/ITmfUIPreferences.java b/org.eclipse.tracecompass.tmf.ui/src/org/eclipse/tracecompass/internal/tmf/ui/ITmfUIPreferences.java
new file mode 100644 (file)
index 0000000..bb81bf0
--- /dev/null
@@ -0,0 +1,25 @@
+/*******************************************************************************
+ * Copyright (c) 2015 Ericsson
+ *
+ * All rights reserved. This program and the accompanying materials are
+ * made available under the terms of the Eclipse Public License v1.0 which
+ * accompanies this distribution, and is available at
+ * http://www.eclipse.org/legal/epl-v10.html
+ *
+ * Contributors:
+ *   Marc-Andre Laperle - Initial API and implementation
+ *******************************************************************************/
+
+package org.eclipse.tracecompass.internal.tmf.ui;
+
+/**
+ * Preferences for TMF UI
+ *
+ * @noimplement This interface is not intended to be implemented by clients.
+ */
+public interface ITmfUIPreferences {
+    /**
+     * Preference for aligning the views based on the time axis
+     */
+    String PREF_ALIGN_VIEWS = "PREF_ALIGN_VIEWS"; //$NON-NLS-1$
+}
index 48e6ff0e16fe2d795762305d9cbc86bd91afa28d..0f83b1a2ec377661fe0f064e73eacb21bce1963b 100644 (file)
@@ -279,6 +279,8 @@ public class Messages extends NLS {
 
     public static String TmfView_PinActionNameText;
     public static String TmfView_PinActionToolTipText;
+    public static String TmfView_AlignViewsActionNameText;
+    public static String TmfView_AlignViewsActionToolTipText;
 
     public static String CallStackPresentationProvider_Thread;
     public static String CallStackView_FunctionColumn;
diff --git a/org.eclipse.tracecompass.tmf.ui/src/org/eclipse/tracecompass/internal/tmf/ui/TmfUIPreferenceInitializer.java b/org.eclipse.tracecompass.tmf.ui/src/org/eclipse/tracecompass/internal/tmf/ui/TmfUIPreferenceInitializer.java
new file mode 100644 (file)
index 0000000..2b7f1ef
--- /dev/null
@@ -0,0 +1,29 @@
+/*******************************************************************************
+ * Copyright (c) 2015 Ericsson
+ *
+ * All rights reserved. This program and the accompanying materials are
+ * made available under the terms of the Eclipse Public License v1.0 which
+ * accompanies this distribution, and is available at
+ * http://www.eclipse.org/legal/epl-v10.html
+ *
+ * Contributors:
+ *   Marc-Andre Laperle - Initial API and implementation
+ *******************************************************************************/
+
+package org.eclipse.tracecompass.internal.tmf.ui;
+
+import org.eclipse.core.runtime.preferences.AbstractPreferenceInitializer;
+import org.eclipse.core.runtime.preferences.DefaultScope;
+import org.eclipse.core.runtime.preferences.IEclipsePreferences;
+
+/**
+ * Initializes TMF UI preferences
+ */
+public class TmfUIPreferenceInitializer extends AbstractPreferenceInitializer {
+
+    @Override
+    public void initializeDefaultPreferences() {
+        IEclipsePreferences defaultPreferences = DefaultScope.INSTANCE.getNode(Activator.PLUGIN_ID);
+        defaultPreferences.putBoolean(ITmfUIPreferences.PREF_ALIGN_VIEWS, true);
+    }
+}
index e79f9a31ebf00633fa6ff78ff3aeaf6c01960466..d697dc849e1d1d58ec19e82836008235d1519836 100644 (file)
@@ -278,6 +278,8 @@ FilterViewer_ValueLabel=value:
 
 TmfView_PinActionNameText=Pin View
 TmfView_PinActionToolTipText=Pin View
+TmfView_AlignViewsActionNameText=Align Views
+TmfView_AlignViewsActionToolTipText=Align Views
 
 # Call Stack View
 CallStackPresentationProvider_Thread=Thread
diff --git a/org.eclipse.tracecompass.tmf.ui/src/org/eclipse/tracecompass/internal/tmf/ui/views/TimeAlignViewsAction.java b/org.eclipse.tracecompass.tmf.ui/src/org/eclipse/tracecompass/internal/tmf/ui/views/TimeAlignViewsAction.java
new file mode 100644 (file)
index 0000000..251eecd
--- /dev/null
@@ -0,0 +1,52 @@
+/*******************************************************************************
+ * Copyright (c) 2015 Ericsson
+ *
+ * All rights reserved. This program and the accompanying materials are
+ * made available under the terms of the Eclipse Public License v1.0 which
+ * accompanies this distribution, and is available at
+ * http://www.eclipse.org/legal/epl-v10.html
+ *
+ * Contributors:
+ *   Marc-Andre Laperle - Initial API and implementation
+ *******************************************************************************/
+
+package org.eclipse.tracecompass.internal.tmf.ui.views;
+
+import org.eclipse.core.runtime.preferences.InstanceScope;
+import org.eclipse.jface.action.Action;
+import org.eclipse.jface.action.IAction;
+import org.eclipse.tracecompass.internal.tmf.ui.Activator;
+import org.eclipse.tracecompass.internal.tmf.ui.ITmfImageConstants;
+import org.eclipse.tracecompass.internal.tmf.ui.ITmfUIPreferences;
+import org.eclipse.tracecompass.internal.tmf.ui.Messages;
+import org.eclipse.tracecompass.tmf.ui.views.ITmfTimeAligned;
+
+/**
+ * An action that toggles time alignment of views.
+ *
+ * @see ITmfTimeAligned
+ */
+public class TimeAlignViewsAction extends Action {
+    /**
+     * Creates a AlignViewsAction
+     */
+    public TimeAlignViewsAction() {
+        super(Messages.TmfView_AlignViewsActionNameText, IAction.AS_CHECK_BOX);
+
+        setId("org.eclipse.tracecompass.tmf.ui.views.TimeAlignViewsAction"); //$NON-NLS-1$
+        setToolTipText(Messages.TmfView_AlignViewsActionToolTipText);
+        setImageDescriptor(Activator.getDefault().getImageDescripterFromPath(ITmfImageConstants.IMG_UI_LINK));
+        setChecked(isPreferenceEnabled());
+    }
+
+    @Override
+    public void run() {
+        boolean newValue = !isPreferenceEnabled();
+        InstanceScope.INSTANCE.getNode(Activator.PLUGIN_ID).putBoolean(ITmfUIPreferences.PREF_ALIGN_VIEWS, newValue);
+        setChecked(newValue);
+    }
+
+    private static boolean isPreferenceEnabled() {
+        return InstanceScope.INSTANCE.getNode(Activator.PLUGIN_ID).getBoolean(ITmfUIPreferences.PREF_ALIGN_VIEWS, true);
+    }
+}
diff --git a/org.eclipse.tracecompass.tmf.ui/src/org/eclipse/tracecompass/internal/tmf/ui/views/TmfAlignmentSynchronizer.java b/org.eclipse.tracecompass.tmf.ui/src/org/eclipse/tracecompass/internal/tmf/ui/views/TmfAlignmentSynchronizer.java
new file mode 100644 (file)
index 0000000..ccab3f7
--- /dev/null
@@ -0,0 +1,512 @@
+/*******************************************************************************
+ * Copyright (c) 2015 Ericsson
+ *
+ * All rights reserved. This program and the accompanying materials are
+ * made available under the terms of the Eclipse Public License v1.0 which
+ * accompanies this distribution, and is available at
+ * http://www.eclipse.org/legal/epl-v10.html
+ *
+ * Contributors:
+ *   Marc-Andre Laperle - Initial API and implementation
+ *******************************************************************************/
+
+package org.eclipse.tracecompass.internal.tmf.ui.views;
+
+import java.util.ArrayList;
+import java.util.Collections;
+import java.util.List;
+import java.util.Timer;
+import java.util.TimerTask;
+
+import org.eclipse.core.runtime.preferences.InstanceScope;
+import org.eclipse.core.runtime.preferences.IEclipsePreferences.IPreferenceChangeListener;
+import org.eclipse.core.runtime.preferences.IEclipsePreferences.PreferenceChangeEvent;
+import org.eclipse.swt.graphics.Point;
+import org.eclipse.swt.widgets.Composite;
+import org.eclipse.swt.widgets.Display;
+import org.eclipse.swt.widgets.Shell;
+import org.eclipse.tracecompass.internal.tmf.ui.Activator;
+import org.eclipse.tracecompass.internal.tmf.ui.ITmfUIPreferences;
+import org.eclipse.tracecompass.tmf.core.signal.TmfSignalHandler;
+import org.eclipse.tracecompass.tmf.core.signal.TmfSignalManager;
+import org.eclipse.tracecompass.tmf.ui.signal.TmfTimeViewAlignmentInfo;
+import org.eclipse.tracecompass.tmf.ui.signal.TmfTimeViewAlignmentSignal;
+import org.eclipse.tracecompass.tmf.ui.views.ITmfTimeAligned;
+import org.eclipse.tracecompass.tmf.ui.views.TmfView;
+import org.eclipse.ui.IViewPart;
+import org.eclipse.ui.IViewReference;
+import org.eclipse.ui.IWorkbenchPage;
+import org.eclipse.ui.IWorkbenchWindow;
+import org.eclipse.ui.PlatformUI;
+
+/**
+ * Receives various notifications for realignment and
+ * performs the alignment on the appropriate views.
+ *
+ * @since 1.0
+ */
+public class TmfAlignmentSynchronizer {
+
+    private static final long THROTTLE_DELAY = 500;
+    private static final int NEAR_THRESHOLD = 10;
+    private final Timer fTimer;
+    private final List<AlignmentOperation> fPendingOperations = Collections.synchronizedList(new ArrayList<AlignmentOperation>());
+
+    private TimerTask fCurrentTask;
+
+    /**
+     * Constructor
+     */
+    public TmfAlignmentSynchronizer() {
+        TmfSignalManager.register(this);
+        fTimer = new Timer();
+        createPreferenceListener();
+        fCurrentTask = new TimerTask() {
+            @Override
+            public void run() {
+                /* Do nothing */
+            }
+        };
+    }
+
+    private IPreferenceChangeListener createPreferenceListener() {
+        IPreferenceChangeListener listener = new IPreferenceChangeListener() {
+
+            @Override
+            public void preferenceChange(PreferenceChangeEvent event) {
+                if (event.getKey().equals(ITmfUIPreferences.PREF_ALIGN_VIEWS)) {
+                    Object oldValue = event.getOldValue();
+                    Object newValue = event.getNewValue();
+                    if (Boolean.toString(false).equals(oldValue) && Boolean.toString(true).equals(newValue)) {
+                        realignViews();
+                    } else if (Boolean.toString(true).equals(oldValue) && Boolean.toString(false).equals(newValue)) {
+                        restoreViews();
+                    }
+                }
+            }
+        };
+        InstanceScope.INSTANCE.getNode(Activator.PLUGIN_ID).addPreferenceChangeListener(listener);
+        return listener;
+    }
+
+    private class AlignmentOperation {
+        final TmfView fView;
+        final TmfTimeViewAlignmentInfo fAlignmentInfo;
+
+        public AlignmentOperation(TmfView view, TmfTimeViewAlignmentInfo timeViewAlignmentInfo) {
+            fView = view;
+            fAlignmentInfo = timeViewAlignmentInfo;
+        }
+    }
+
+    private class AlignTask extends TimerTask {
+
+        @Override
+        public void run() {
+            final List<AlignmentOperation> fCopy;
+            synchronized (fPendingOperations) {
+                fCopy = new ArrayList<>(fPendingOperations);
+                fPendingOperations.clear();
+            }
+            Display.getDefault().syncExec(new Runnable() {
+                @Override
+                public void run() {
+                    performAllAlignments(fCopy);
+                }
+            });
+        }
+    }
+
+    /**
+     * Handle a view that was just resized.
+     *
+     * @param view
+     *            the view that was resized
+     */
+    public void handleViewResized(TmfView view) {
+        TmfTimeViewAlignmentInfo alignmentInfo = new TmfTimeViewAlignmentInfo(view.getParentComposite().getShell(), getViewLocation(view), 0);
+
+        // Don't use a view that was just resized as a reference view.
+        // Otherwise, a view that was just
+        // created might use itself as a reference but we want to
+        // keep the existing alignment from the other views.
+        ITmfTimeAligned referenceView = getReferenceView(alignmentInfo, view);
+        if (referenceView != null) {
+            queueAlignment(referenceView.getTimeViewAlignmentInfo(), false);
+        }
+    }
+
+    /**
+     * Handle a view that was just closed.
+     *
+     * @param view
+     *            the view that was closed
+     */
+    public void handleViewClosed(TmfView view) {
+        // Realign views so that they can use the maximum available width in the
+        // event that a narrow view was just closed
+        realignViews(view.getSite().getPage());
+    }
+
+    /**
+     * Process signal for alignment.
+     *
+     * @param signal the alignment signal
+     */
+    @TmfSignalHandler
+    public void timeViewAlignmentUpdated(TmfTimeViewAlignmentSignal signal) {
+        queueAlignment(signal.getTimeViewAlignmentInfo(), signal.IsSynchronous());
+    }
+
+    /**
+     * Perform all alignment operations for the specified alignment
+     * informations.
+     *
+     * <pre>
+     * - The alignment algorithm chooses the narrowest width to accommodate all views.
+     * - View positions are recomputed for extra accuracy since the views could have been moved or resized.
+     * - Based on the up-to-date view positions, only views that are near and aligned with each other
+     * </pre>
+     */
+    private static void performAllAlignments(final List<AlignmentOperation> alignments) {
+        for (final AlignmentOperation info : alignments) {
+            performAlignment(info);
+        }
+    }
+
+    private static void performAlignment(AlignmentOperation info) {
+
+        TmfView referenceView = info.fView;
+        if (isDisposedView(referenceView)) {
+            return;
+        }
+
+        TmfTimeViewAlignmentInfo alignmentInfo = info.fAlignmentInfo;
+        // The location of the view might have changed (resize, etc). Update the alignment info.
+        alignmentInfo = new TmfTimeViewAlignmentInfo(alignmentInfo.getShell(), getViewLocation(referenceView), getClampedTimeAxisOffset(alignmentInfo));
+
+        TmfView narrowestView = getNarrowestView(alignmentInfo);
+        if (narrowestView == null) {
+            // No valid view found for this alignment. This could mean that the views for this alignment are now too narrow (width == 0) or that shell is not a workbench window.
+            return;
+        }
+
+        int narrowestWidth = ((ITmfTimeAligned) narrowestView).getAvailableWidth(getClampedTimeAxisOffset(alignmentInfo));
+        narrowestWidth = getClampedTimeAxisWidth(alignmentInfo, narrowestWidth);
+        IViewReference[] viewReferences = referenceView.getSite().getPage().getViewReferences();
+        for (IViewReference ref : viewReferences) {
+            IViewPart view = ref.getView(false);
+            if (isTimeAlignedView(view)) {
+                TmfView tmfView = (TmfView) view;
+                ITmfTimeAligned alignedView = (ITmfTimeAligned) view;
+                if (!isDisposedView(tmfView) && isViewLocationNear(getViewLocation(tmfView), alignmentInfo.getViewLocation())) {
+                    alignedView.performAlign(getClampedTimeAxisOffset(alignmentInfo), narrowestWidth);
+                }
+            }
+        }
+    }
+
+    /**
+     * Realign all views
+     */
+    private void realignViews() {
+        for (IWorkbenchWindow window : PlatformUI.getWorkbench().getWorkbenchWindows()) {
+            for (IWorkbenchPage page : window.getPages()) {
+                realignViews(page);
+            }
+        }
+    }
+
+    /**
+     * Realign views inside a given page
+     *
+     * @param page
+     *            the workbench page
+     */
+    private void realignViews(IWorkbenchPage page) {
+        IViewReference[] viewReferences = page.getViewReferences();
+        for (IViewReference ref : viewReferences) {
+            IViewPart view = ref.getView(false);
+            if (isTimeAlignedView(view)) {
+                queueAlignment(((ITmfTimeAligned) view).getTimeViewAlignmentInfo(), false);
+            }
+        }
+    }
+
+    /**
+     * Restore the views to their respective maximum widths
+     */
+    private static void restoreViews() {
+        // We set the width to Integer.MAX_VALUE so that the
+        // views remove any "filler" space they might have.
+        for (IWorkbenchWindow window : PlatformUI.getWorkbench().getWorkbenchWindows()) {
+            for (IWorkbenchPage page : window.getPages()) {
+                for (IViewReference ref : page.getViewReferences()) {
+                    restoreView(ref);
+                }
+            }
+        }
+    }
+
+    private static void restoreView(IViewReference ref) {
+        IViewPart view = ref.getView(false);
+        if (isTimeAlignedView(view)) {
+            ITmfTimeAligned alignedView = (ITmfTimeAligned) view;
+            alignedView.performAlign(getClampedTimeAxisOffset(alignedView.getTimeViewAlignmentInfo()), Integer.MAX_VALUE);
+        }
+    }
+
+    private static boolean isTimeAlignedView(IViewPart view) {
+        if (view instanceof TmfView && view instanceof ITmfTimeAligned) {
+            Composite parentComposite = ((TmfView) view).getParentComposite();
+            if (parentComposite != null && !parentComposite.isDisposed()) {
+                return true;
+            }
+        }
+        return view instanceof TmfView && view instanceof ITmfTimeAligned;
+    }
+
+    private static boolean isDisposedView(TmfView view) {
+        Composite parentComposite = (view).getParentComposite();
+        return parentComposite != null && parentComposite.isDisposed();
+    }
+
+    /**
+     * Queue the operation for processing. If an operation is considered the
+     * same alignment (shell, location) as a previously queued one, it will
+     * replace the old one. This way, only one up-to-date alignment operation is
+     * kept per set of time-axis aligned views. The processing of the operation
+     * is also throttled (TimerTask).
+     *
+     * @param operation
+     *            the operation to queue
+     */
+    private void queue(AlignmentOperation operation) {
+        synchronized(fPendingOperations) {
+            fCurrentTask.cancel();
+            for (AlignmentOperation pendingOperation : fPendingOperations) {
+                if (isSameAlignment(operation, pendingOperation)) {
+                    fPendingOperations.remove(pendingOperation);
+                    break;
+                }
+            }
+            fPendingOperations.add(operation);
+            fCurrentTask = new AlignTask();
+            fTimer.schedule(fCurrentTask, THROTTLE_DELAY);
+        }
+    }
+
+    /**
+     * Two operations are considered to be for the same set of time-axis aligned
+     * views if they are on the same Shell and near the same location.
+     */
+    private static boolean isSameAlignment(AlignmentOperation operation1, AlignmentOperation operation2) {
+        if (operation1.fView == operation2.fView) {
+            return true;
+        }
+
+        if (operation1.fAlignmentInfo.getShell() != operation2.fAlignmentInfo.getShell()) {
+            return false;
+        }
+
+        if (isViewLocationNear(getViewLocation(operation1.fView), getViewLocation(operation2.fView))) {
+            return true;
+        }
+
+        return false;
+    }
+
+    private static boolean isViewLocationNear(Point location1, Point location2) {
+        return Math.abs(location1.x - location2.x) < NEAR_THRESHOLD;
+    }
+
+    private static Point getViewLocation(TmfView view) {
+        return view.getParentComposite().toDisplay(0, 0);
+    }
+
+    private void queueAlignment(TmfTimeViewAlignmentInfo timeViewAlignmentInfo, boolean synchronous) {
+        if (isAlignViewsPreferenceEnabled()) {
+            IWorkbenchWindow workbenchWindow = getWorkbenchWindow(timeViewAlignmentInfo.getShell());
+            if (workbenchWindow == null || workbenchWindow.getActivePage() == null) {
+                // Only time aligned views that are part of a workbench window are supported
+                return;
+            }
+
+            // We need a view so that we can compute position right as we are
+            // about to realign the views. The view could have been resized,
+            // moved, etc.
+            TmfView view = (TmfView) getReferenceView(timeViewAlignmentInfo, null);
+            if (view == null) {
+                // No valid view found for this alignment
+                return;
+            }
+
+            AlignmentOperation operation = new AlignmentOperation(view, timeViewAlignmentInfo);
+            if (synchronous) {
+                performAlignment(operation);
+            } else {
+                queue(operation);
+            }
+        }
+    }
+
+    private static boolean isAlignViewsPreferenceEnabled() {
+        return InstanceScope.INSTANCE.getNode(Activator.PLUGIN_ID).getBoolean(ITmfUIPreferences.PREF_ALIGN_VIEWS, true);
+    }
+
+    /**
+     * Get a view that corresponds to the alignment information. The view is
+     * meant to be used as a "reference" for other views to align on. Heuristics
+     * are applied to choose the best view. For example, the view has to be
+     * visible. It also will prioritize the view with lowest time axis offset
+     * because most of the interesting data should be in the time widget.
+     *
+     * @param alignmentInfo
+     *            alignment information
+     * @param blackListedView
+     *            an optional black listed view that will not be used as
+     *            reference (useful for a view that just got created)
+     * @return the reference view
+     */
+    private static ITmfTimeAligned getReferenceView(TmfTimeViewAlignmentInfo alignmentInfo, TmfView blackListedView) {
+        IWorkbenchWindow workbenchWindow = getWorkbenchWindow(alignmentInfo.getShell());
+        if (workbenchWindow == null || workbenchWindow.getActivePage() == null) {
+            // Only time aligned views that are part of a workbench window are supported
+            return null;
+        }
+        IWorkbenchPage page = workbenchWindow.getActivePage();
+
+        int lowestTimeAxisOffset = Integer.MAX_VALUE;
+        ITmfTimeAligned referenceView = null;
+        for (IViewReference ref : page.getViewReferences()) {
+            IViewPart view = ref.getView(false);
+            if (view != blackListedView && isTimeAlignedView(view)) {
+                if (isCandidateForReferenceView((TmfView) view, alignmentInfo, lowestTimeAxisOffset)) {
+                    referenceView = (ITmfTimeAligned) view;
+                    lowestTimeAxisOffset = getClampedTimeAxisOffset(referenceView.getTimeViewAlignmentInfo());
+                    break;
+                }
+            }
+        }
+        return referenceView;
+    }
+
+    private static boolean isCandidateForReferenceView(TmfView tmfView, TmfTimeViewAlignmentInfo alignmentInfo, int lowestTimeAxisOffset) {
+        ITmfTimeAligned alignedView = (ITmfTimeAligned) tmfView;
+        TmfTimeViewAlignmentInfo timeViewAlignmentInfo = alignedView.getTimeViewAlignmentInfo();
+        if (timeViewAlignmentInfo == null) {
+            return false;
+        }
+
+        if (isDisposedView(tmfView)) {
+            return false;
+        }
+
+        Composite parentComposite = tmfView.getParentComposite();
+        boolean isVisible = parentComposite != null && parentComposite.isVisible();
+        if (isVisible) {
+            boolean isViewLocationNear = isViewLocationNear(alignmentInfo.getViewLocation(), getViewLocation(tmfView));
+            boolean isLowestTimeAxisOffset = getClampedTimeAxisOffset(timeViewAlignmentInfo) < lowestTimeAxisOffset;
+            if (isViewLocationNear && isLowestTimeAxisOffset) {
+                int availableWidth = alignedView.getAvailableWidth(getClampedTimeAxisOffset(timeViewAlignmentInfo));
+                availableWidth = getClampedTimeAxisWidth(timeViewAlignmentInfo, availableWidth);
+                if (availableWidth > 0) {
+                    return true;
+                }
+            }
+        }
+
+        return false;
+    }
+
+    /**
+     * Get the narrowest view that corresponds to the given alignment information.
+     */
+    private static TmfView getNarrowestView(TmfTimeViewAlignmentInfo alignmentInfo) {
+        IWorkbenchWindow workbenchWindow = getWorkbenchWindow(alignmentInfo.getShell());
+        if (workbenchWindow == null || workbenchWindow.getActivePage() == null) {
+            // Only time aligned views that are part of a workbench window are supported
+            return null;
+        }
+        IWorkbenchPage page = workbenchWindow.getActivePage();
+
+        int narrowestWidth = Integer.MAX_VALUE;
+        TmfView narrowestView = null;
+        for (IViewReference ref : page.getViewReferences()) {
+            IViewPart view = ref.getView(false);
+            if (isTimeAlignedView(view)) {
+                TmfView tmfView = (TmfView) view;
+                if (isCandidateForNarrowestView(tmfView, alignmentInfo, narrowestWidth)) {
+                    narrowestWidth = ((ITmfTimeAligned) tmfView).getAvailableWidth(getClampedTimeAxisOffset(alignmentInfo));
+                    narrowestWidth = getClampedTimeAxisWidth(alignmentInfo, narrowestWidth);
+                    narrowestView = tmfView;
+                }
+            }
+        }
+
+        return narrowestView;
+    }
+
+    private static int getClampedTimeAxisWidth(TmfTimeViewAlignmentInfo alignmentInfo, int width) {
+        int max = getMaxInt(alignmentInfo.getShell());
+        if (validateInt(width, max)) {
+            Activator.getDefault().logError("Time-axis width out of range (" + width + ")", new Throwable());  //$NON-NLS-1$//$NON-NLS-2$
+        }
+        return Math.min(max, Math.max(0, width));
+    }
+
+    private static int getClampedTimeAxisOffset(TmfTimeViewAlignmentInfo alignmentInfo) {
+        int timeAxisOffset = alignmentInfo.getTimeAxisOffset();
+        int max = getMaxInt(alignmentInfo.getShell());
+        if (validateInt(timeAxisOffset, max)) {
+            Activator.getDefault().logError("Time-axis offset out of range (" + timeAxisOffset + ")", new Throwable());  //$NON-NLS-1$//$NON-NLS-2$
+        }
+        return Math.min(max, Math.max(0, timeAxisOffset));
+    }
+
+    private static boolean validateInt(int value, int max) {
+        return value < 0 || value > max;
+    }
+
+    private static int getMaxInt(Shell shell) {
+        // Consider an integer to be buggy if it's bigger than 10 times the
+        // width of *all* monitors combined.
+        final int DISPLAY_WIDTH_FACTOR = 10;
+        return shell.getDisplay().getBounds().width * DISPLAY_WIDTH_FACTOR;
+    }
+
+    private static boolean isCandidateForNarrowestView(TmfView tmfView, TmfTimeViewAlignmentInfo alignmentInfo, int narrowestWidth) {
+        ITmfTimeAligned alignedView = (ITmfTimeAligned) tmfView;
+        TmfTimeViewAlignmentInfo timeViewAlignmentInfo = alignedView.getTimeViewAlignmentInfo();
+        if (timeViewAlignmentInfo == null) {
+            return false;
+        }
+
+        if (isDisposedView(tmfView)) {
+            return false;
+        }
+
+        Composite parentComposite = tmfView.getParentComposite();
+        boolean isVisible = parentComposite != null && parentComposite.isVisible();
+        if (isVisible) {
+            if (isViewLocationNear(getViewLocation(tmfView), alignmentInfo.getViewLocation())) {
+                int availableWidth = alignedView.getAvailableWidth(getClampedTimeAxisOffset(alignmentInfo));
+                availableWidth = getClampedTimeAxisWidth(alignmentInfo, availableWidth);
+                boolean isNarrower = availableWidth < narrowestWidth && availableWidth > 0;
+                return isNarrower;
+            }
+        }
+
+        return false;
+    }
+
+    private static IWorkbenchWindow getWorkbenchWindow(Shell shell) {
+        for (IWorkbenchWindow window : PlatformUI.getWorkbench().getWorkbenchWindows()) {
+            if (window.getShell().equals(shell)) {
+                return window;
+            }
+        }
+
+        return null;
+    }
+}
diff --git a/org.eclipse.tracecompass.tmf.ui/src/org/eclipse/tracecompass/tmf/ui/signal/TmfTimeViewAlignmentInfo.java b/org.eclipse.tracecompass.tmf.ui/src/org/eclipse/tracecompass/tmf/ui/signal/TmfTimeViewAlignmentInfo.java
new file mode 100644 (file)
index 0000000..659c7ee
--- /dev/null
@@ -0,0 +1,79 @@
+/*******************************************************************************
+ * Copyright (c) 2015 Ericsson
+ *
+ * All rights reserved. This program and the accompanying materials are
+ * made available under the terms of the Eclipse Public License v1.0 which
+ * accompanies this distribution, and is available at
+ * http://www.eclipse.org/legal/epl-v10.html
+ *
+ * Contributors:
+ *   Marc-Andre Laperle - Initial API and implementation
+ *******************************************************************************/
+
+package org.eclipse.tracecompass.tmf.ui.signal;
+
+import org.eclipse.swt.graphics.Point;
+import org.eclipse.swt.widgets.Shell;
+
+/**
+ * The responsibility of this class is to provide information necessary to
+ * decide whether or not views should be time-aligned with each other and at
+ * what offset.
+ *
+ * @see TmfTimeViewAlignmentSignal
+ *
+ * @since 1.0
+ */
+public class TmfTimeViewAlignmentInfo {
+    private final Point fViewLocation;
+    private final int fTimeAxisOffset;
+    private final Shell fShell;
+
+    /**
+     * Constructs a new TmfTimeViewAlignmentInfo.
+     *
+     * @param shell
+     *            used to determine whether or not views should be aligned
+     *            together
+     * @param viewLocation
+     *            location of the view, used to determine whether or not views
+     *            should be aligned together
+     * @param timeAxisOffset
+     *            offset relative to the view. This offset will be communicated
+     *            to the other views
+     */
+    public TmfTimeViewAlignmentInfo(Shell shell, Point viewLocation, int timeAxisOffset) {
+        fShell = shell;
+        fViewLocation = viewLocation;
+        fTimeAxisOffset = timeAxisOffset;
+    }
+
+    /**
+     * Get the shell containing this alignment.
+     *
+     * @return the shell
+     */
+    public Shell getShell() {
+        return fShell;
+    }
+
+    /**
+     * Get the absolute view location. This value is only valid at the time of
+     * the TmfTimeViewAlignmentInfo creation so extra care must be given in
+     * cases where the particular view might have been resized, moved, etc.
+     *
+     * @return the absolute view location
+     */
+    public Point getViewLocation() {
+        return fViewLocation;
+    }
+
+    /**
+     * Offset relative to the view corresponding to the start of the time axis.
+     *
+     * @return the offset in pixels
+     */
+    public int getTimeAxisOffset() {
+        return fTimeAxisOffset;
+    }
+}
diff --git a/org.eclipse.tracecompass.tmf.ui/src/org/eclipse/tracecompass/tmf/ui/signal/TmfTimeViewAlignmentSignal.java b/org.eclipse.tracecompass.tmf.ui/src/org/eclipse/tracecompass/tmf/ui/signal/TmfTimeViewAlignmentSignal.java
new file mode 100644 (file)
index 0000000..d1364c0
--- /dev/null
@@ -0,0 +1,86 @@
+/*******************************************************************************
+ * Copyright (c) 2015 Ericsson
+ *
+ * All rights reserved. This program and the accompanying materials are
+ * made available under the terms of the Eclipse Public License v1.0 which
+ * accompanies this distribution, and is available at
+ * http://www.eclipse.org/legal/epl-v10.html
+ *
+ * Contributors:
+ *   Marc-Andre Laperle - Initial API and implementation
+ *******************************************************************************/
+
+package org.eclipse.tracecompass.tmf.ui.signal;
+
+import org.eclipse.tracecompass.tmf.core.signal.TmfSignal;
+
+/**
+ * A signal to inform about the state of time alignment. Typically, the emitter
+ * will inform the receivers about the position of a sash that separates the
+ * time axis on right side and extra information on the left side.
+ *
+ * @see TmfTimeViewAlignmentInfo
+ *
+ * @since 1.0
+ */
+public class TmfTimeViewAlignmentSignal extends TmfSignal {
+
+    private final TmfTimeViewAlignmentInfo fTimeViewAlignmentInfo;
+    private final boolean fIsSynchronous;
+
+    /**
+     * Creates a new TmfTimeViewAlignmentSignal
+     *
+     * @param source
+     *            the source of the signal
+     * @param alignmentInfo
+     *            information about the time alignment
+     */
+    public TmfTimeViewAlignmentSignal(Object source, TmfTimeViewAlignmentInfo alignmentInfo) {
+        this(source, alignmentInfo, false);
+    }
+
+    /**
+     * Creates a new TmfTimeViewAlignmentSignal
+     *
+     * @param source
+     *            the source of the signal
+     * @param alignmentInfo
+     *            information about the time alignment
+     * @param synchronous
+     *            whether or not the signal should be processed right away. This
+     *            is useful for signals that are sent not repetitively.
+     *            For example, a sash being dragged would not be synchronous
+     *            because the signal gets fired repeatedly. A view that has
+     *            completed computing it's data could send a synchronous signal.
+     */
+    public TmfTimeViewAlignmentSignal(Object source, TmfTimeViewAlignmentInfo alignmentInfo, boolean synchronous) {
+        super(source);
+        fTimeViewAlignmentInfo = alignmentInfo;
+        fIsSynchronous = synchronous;
+    }
+
+    /**
+     * Get the time alignment information.
+     *
+     * @return the time alignment information
+     */
+    public TmfTimeViewAlignmentInfo getTimeViewAlignmentInfo() {
+        return fTimeViewAlignmentInfo;
+    }
+
+    @Override
+    public String toString() {
+        return "[TmfTimeViewAlignmentSignal (" + fTimeViewAlignmentInfo.toString() + ")]"; //$NON-NLS-1$ //$NON-NLS-2$
+    }
+
+    /**
+     * Get whether or not the signal should be processed right away, without
+     * being throttled.
+     *
+     * @return whether or not the signal should be processed right away
+     */
+    public boolean IsSynchronous() {
+        return fIsSynchronous;
+    }
+}
diff --git a/org.eclipse.tracecompass.tmf.ui/src/org/eclipse/tracecompass/tmf/ui/views/ITmfTimeAligned.java b/org.eclipse.tracecompass.tmf.ui/src/org/eclipse/tracecompass/tmf/ui/views/ITmfTimeAligned.java
new file mode 100644 (file)
index 0000000..b3782d2
--- /dev/null
@@ -0,0 +1,64 @@
+/*******************************************************************************
+ * Copyright (c) 2015 Ericsson
+ *
+ * All rights reserved. This program and the accompanying materials are
+ * made available under the terms of the Eclipse Public License v1.0 which
+ * accompanies this distribution, and is available at
+ * http://www.eclipse.org/legal/epl-v10.html
+ *
+ * Contributors:
+ *   Marc-Andre Laperle - Initial API and implementation
+ *******************************************************************************/
+
+package org.eclipse.tracecompass.tmf.ui.views;
+
+import org.eclipse.tracecompass.tmf.ui.signal.TmfTimeViewAlignmentInfo;
+
+/**
+ * An interface that adds the time-axis alignment feature to a view. This
+ * interface provides information about the current state of alignment of the
+ * view as well as performs alignment operations in case the views become
+ * misaligned (resize, moved, etc).
+ *
+ * @since 1.0
+ */
+public interface ITmfTimeAligned {
+
+    /**
+     * Get the time alignment information. The view provides information about
+     * where the time-axis is in addition to information necessary to decide
+     * whether or not views should be time-aligned with each other (Shell,
+     * location).
+     *
+     * @return the time alignment information
+     */
+    TmfTimeViewAlignmentInfo getTimeViewAlignmentInfo();
+
+    /**
+     * Get the available width for the specified time-axis offset. The
+     * implementation should return the width that would be available if the
+     * time-axis was to be at that offset. When about to perform a re-alignment,
+     * the alignment algorithm will choose the narrowest width to accommodate
+     * all views.
+     *
+     * @param requestedOffset
+     *            the requested time-axis offset. Greater or equal to zero.
+     * @return the available width. Should be greater or equal to zero.
+     */
+    int getAvailableWidth(int requestedOffset);
+
+    /**
+     * Perform the alignment by moving the time-axis to the specified offset and
+     * the resizing it to the specified width. Implementations should handle
+     * cases were the requested width is greater than the width of the view. For
+     * example, Integer.MAX_VALUE can be requested in order to obtain the
+     * largest width possible.
+     *
+     * @param offset
+     *            the time-axis offset. Greater or equal to zero.
+     * @param width
+     *            the time-axis width. Greater or equal to zero. Can be
+     *            Integer.MAX_VALUE.
+     */
+    void performAlign(int offset, int width);
+}
index 1925b60137093158ade34c79c4c1a0b3db9695c2..feaffa8e6fc3fc83859503860c57b52f8edb5317 100644 (file)
@@ -1,5 +1,5 @@
 /*******************************************************************************
- * Copyright (c) 2009, 2014 Ericsson
+ * Copyright (c) 2009, 2015 Ericsson
  *
  * All rights reserved. This program and the accompanying materials are
  * made available under the terms of the Eclipse Public License v1.0 which
@@ -9,16 +9,24 @@
  * Contributors:
  *   Francois Chouinard - Initial API and implementation
  *   Bernd Hufmann - Added possibility to pin view
+ *   Marc-Andre Laperle - Support for view alignment
  *******************************************************************************/
 
 package org.eclipse.tracecompass.tmf.ui.views;
 
 import org.eclipse.jface.action.IToolBarManager;
 import org.eclipse.jface.action.Separator;
+import org.eclipse.swt.events.ControlAdapter;
+import org.eclipse.swt.events.ControlEvent;
+import org.eclipse.swt.widgets.Composite;
+import org.eclipse.tracecompass.internal.tmf.ui.views.TimeAlignViewsAction;
+import org.eclipse.tracecompass.internal.tmf.ui.views.TmfAlignmentSynchronizer;
 import org.eclipse.tracecompass.tmf.core.component.ITmfComponent;
 import org.eclipse.tracecompass.tmf.core.signal.TmfSignal;
 import org.eclipse.tracecompass.tmf.core.signal.TmfSignalManager;
+import org.eclipse.ui.IPartListener;
 import org.eclipse.ui.IWorkbenchActionConstants;
+import org.eclipse.ui.IWorkbenchPart;
 import org.eclipse.ui.part.ViewPart;
 
 /**
@@ -32,11 +40,16 @@ import org.eclipse.ui.part.ViewPart;
 public abstract class TmfView extends ViewPart implements ITmfComponent {
 
     private final String fName;
+    /** This allows us to keep track of the view sizes */
+    private Composite fParentComposite;
+    private ControlAdapter fControlListener;
+    private static final TmfAlignmentSynchronizer TIME_ALIGNMENT_SYNCHRONIZER = new TmfAlignmentSynchronizer();
 
     /**
      * Action class for pinning of TmfView.
      */
     protected PinTmfViewAction fPinAction;
+    private static TimeAlignViewsAction fAlignViewsAction;
 
     // ------------------------------------------------------------------------
     // Constructor
@@ -110,4 +123,74 @@ public abstract class TmfView extends ViewPart implements ITmfComponent {
             toolBarManager.add(fPinAction);
         }
     }
+
+    @Override
+    public void createPartControl(final Composite parent) {
+        fParentComposite = parent;
+        if (this instanceof ITmfTimeAligned) {
+            contributeAlignViewsActionToToolbar();
+
+            fControlListener = new ControlAdapter() {
+                @Override
+                public void controlResized(ControlEvent e) {
+                    TIME_ALIGNMENT_SYNCHRONIZER.handleViewResized(TmfView.this);
+                }
+            };
+            parent.addControlListener(fControlListener);
+
+            getSite().getPage().addPartListener(new IPartListener() {
+                @Override
+                public void partOpened(IWorkbenchPart part) {
+                    // do nothing
+                }
+
+                @Override
+                public void partDeactivated(IWorkbenchPart part) {
+                    // do nothing
+                }
+
+                @Override
+                public void partClosed(IWorkbenchPart part) {
+                    if (part == TmfView.this && fControlListener != null && !fParentComposite.isDisposed()) {
+                        fParentComposite.removeControlListener(fControlListener);
+                        fControlListener = null;
+                        getSite().getPage().removePartListener(this);
+                        TIME_ALIGNMENT_SYNCHRONIZER.handleViewClosed(TmfView.this);
+                    }
+                }
+
+                @Override
+                public void partBroughtToTop(IWorkbenchPart part) {
+                    // do nothing
+                }
+
+                @Override
+                public void partActivated(IWorkbenchPart part) {
+                    // do nothing
+                }
+            });
+        }
+    }
+
+    private void contributeAlignViewsActionToToolbar() {
+        if (fAlignViewsAction == null) {
+            fAlignViewsAction = new TimeAlignViewsAction();
+        }
+
+        IToolBarManager toolBarManager = getViewSite().getActionBars()
+                .getToolBarManager();
+        toolBarManager.add(new Separator(IWorkbenchActionConstants.MB_ADDITIONS));
+        toolBarManager.add(fAlignViewsAction);
+    }
+
+    /**
+     * Returns the parent control of the view
+     *
+     * @return the parent control
+     *
+     * @since 1.0
+     */
+    public Composite getParentComposite() {
+        return fParentComposite;
+    }
 }
index a2f6d2effdc32a805a510d2cd54828e6e8747be0..aa1a5e4bd3cbd0e63e38b0cf1f6e9e2170c056c2 100644 (file)
@@ -89,6 +89,8 @@ import org.eclipse.tracecompass.tmf.core.trace.TmfTraceContext;
 import org.eclipse.tracecompass.tmf.core.trace.TmfTraceManager;
 import org.eclipse.tracecompass.tmf.core.trace.TmfTraceUtils;
 import org.eclipse.tracecompass.tmf.ui.editors.ITmfTraceEditor;
+import org.eclipse.tracecompass.tmf.ui.signal.TmfTimeViewAlignmentInfo;
+import org.eclipse.tracecompass.tmf.ui.views.ITmfTimeAligned;
 import org.eclipse.tracecompass.tmf.ui.views.TmfView;
 import org.eclipse.tracecompass.tmf.ui.widgets.timegraph.ITimeGraphRangeListener;
 import org.eclipse.tracecompass.tmf.ui.widgets.timegraph.ITimeGraphTimeListener;
@@ -113,7 +115,7 @@ import org.eclipse.ui.IEditorPart;
  *
  * @author Patrick Tasse
  */
-public class CallStackView extends TmfView {
+public class CallStackView extends TmfView implements ITmfTimeAligned {
 
     // ------------------------------------------------------------------------
     // Constants
@@ -496,6 +498,7 @@ public class CallStackView extends TmfView {
 
     @Override
     public void createPartControl(Composite parent) {
+        super.createPartControl(parent);
         fTimeGraphCombo = new TimeGraphCombo(parent, SWT.NONE);
 
         fTimeGraphCombo.setTreeContentProvider(new TimeGraphContentProvider());
@@ -1516,4 +1519,33 @@ public class CallStackView extends TmfView {
         return ret;
     }
 
+    /**
+     * @since 1.0
+     */
+    @Override
+    public TmfTimeViewAlignmentInfo getTimeViewAlignmentInfo() {
+        if (fTimeGraphCombo == null) {
+            return null;
+        }
+        return fTimeGraphCombo.getTimeViewAlignmentInfo();
+    }
+
+    /**
+     * @since 1.0
+     */
+    @Override
+    public int getAvailableWidth(int requestedOffset) {
+        if (fTimeGraphCombo == null) {
+            return 0;
+        }
+        return fTimeGraphCombo.getAvailableWidth(requestedOffset);
+    }
+
+    /**
+     * @since 1.0
+     */
+    @Override
+    public void performAlign(int offset, int width) {
+        fTimeGraphCombo.performAlign(offset, width);
+    }
 }
index a90499c8c267c56151974c875981f296bed5fcf5..ba96a52699136a106040ccf3c43d91f9a61d6287 100644 (file)
@@ -90,7 +90,7 @@ public class HistogramView extends TmfView {
      */
     public static final @NonNull String ID = "org.eclipse.linuxtools.tmf.ui.views.histogram"; //$NON-NLS-1$
 
-    private static final Image LINK_IMG = Activator.getDefault().getImageFromPath("/icons/etool16/link.gif"); //$NON-NLS-1$
+    private static final Image LINK_IMG = Activator.getDefault().getImageFromPath(ITmfImageConstants.IMG_UI_LINK);
 
     // ------------------------------------------------------------------------
     // Attributes
index 2f5ad6e8fe2cd3ab9b9354bcebbe6e8285641bc0..0501bdf8d4e7c49ca2eb334246aa00c231ec6c0e 100644 (file)
@@ -31,13 +31,13 @@ import org.eclipse.swt.widgets.Display;
 import org.eclipse.tracecompass.tmf.core.event.ITmfEvent;
 import org.eclipse.tracecompass.tmf.core.signal.TmfEventFilterAppliedSignal;
 import org.eclipse.tracecompass.tmf.core.signal.TmfEventSearchAppliedSignal;
-import org.eclipse.tracecompass.tmf.core.signal.TmfWindowRangeUpdatedSignal;
-import org.eclipse.tracecompass.tmf.core.signal.TmfSignalHandler;
 import org.eclipse.tracecompass.tmf.core.signal.TmfSelectionRangeUpdatedSignal;
+import org.eclipse.tracecompass.tmf.core.signal.TmfSignalHandler;
 import org.eclipse.tracecompass.tmf.core.signal.TmfTraceClosedSignal;
 import org.eclipse.tracecompass.tmf.core.signal.TmfTraceOpenedSignal;
 import org.eclipse.tracecompass.tmf.core.signal.TmfTraceSelectedSignal;
 import org.eclipse.tracecompass.tmf.core.signal.TmfTraceUpdatedSignal;
+import org.eclipse.tracecompass.tmf.core.signal.TmfWindowRangeUpdatedSignal;
 import org.eclipse.tracecompass.tmf.core.timestamp.ITmfTimestamp;
 import org.eclipse.tracecompass.tmf.core.timestamp.TmfTimeRange;
 import org.eclipse.tracecompass.tmf.core.timestamp.TmfTimestamp;
@@ -45,6 +45,8 @@ import org.eclipse.tracecompass.tmf.core.trace.ITmfContext;
 import org.eclipse.tracecompass.tmf.core.trace.ITmfTrace;
 import org.eclipse.tracecompass.tmf.core.trace.TmfTraceContext;
 import org.eclipse.tracecompass.tmf.core.trace.TmfTraceManager;
+import org.eclipse.tracecompass.tmf.ui.signal.TmfTimeViewAlignmentInfo;
+import org.eclipse.tracecompass.tmf.ui.views.ITmfTimeAligned;
 import org.eclipse.tracecompass.tmf.ui.views.TmfView;
 import org.eclipse.tracecompass.tmf.ui.views.colors.ColorSetting;
 import org.eclipse.tracecompass.tmf.ui.views.colors.ColorSettingsManager;
@@ -68,7 +70,7 @@ import org.eclipse.tracecompass.tmf.ui.widgets.timegraph.widgets.Utils.TimeForma
  * @version 1.0
  * @author Patrick Tasse
  */
-public class TimeChartView extends TmfView implements ITimeGraphRangeListener, ITimeGraphSelectionListener, ITimeGraphTimeListener, IColorSettingsListener, IResourceChangeListener {
+public class TimeChartView extends TmfView implements ITimeGraphRangeListener, ITimeGraphSelectionListener, ITimeGraphTimeListener, IColorSettingsListener, IResourceChangeListener, ITmfTimeAligned {
 
     /** TimeChartView's ID */
     public static final String ID = "org.eclipse.linuxtools.tmf.ui.views.timechart"; //$NON-NLS-1$
@@ -99,6 +101,7 @@ public class TimeChartView extends TmfView implements ITimeGraphRangeListener, I
 
     @Override
     public void createPartControl(Composite parent) {
+        super.createPartControl(parent);
         fViewer = new TimeGraphViewer(parent, SWT.NONE);
         fPresentationProvider = new TimeChartAnalysisProvider();
         fViewer.setTimeGraphProvider(fPresentationProvider);
@@ -750,4 +753,30 @@ public class TimeChartView extends TmfView implements ITimeGraphRangeListener, I
         redecorate();
     }
 
+    /**
+     * @since 1.0
+     */
+    @Override
+    public TmfTimeViewAlignmentInfo getTimeViewAlignmentInfo() {
+        if (fViewer == null) {
+            return null;
+        }
+        return fViewer.getTimeViewAlignmentInfo();
+    }
+
+    /**
+     * @since 1.0
+     */
+    @Override
+    public int getAvailableWidth(int requestedOffset) {
+        return fViewer.getAvailableWidth(requestedOffset);
+    }
+
+    /**
+     * @since 1.0
+     */
+    @Override
+    public void performAlign(int offset, int width) {
+        fViewer.performAlign(offset, width);
+    }
 }
index 20b2ab7720315505501c02d3437a7dd521ca2ff2..1219f4ddd1a57bd3c35ab766046504d6341e1d5f 100644 (file)
@@ -44,13 +44,13 @@ import org.eclipse.swt.graphics.Image;
 import org.eclipse.swt.widgets.Composite;
 import org.eclipse.swt.widgets.Display;
 import org.eclipse.swt.widgets.TreeColumn;
-import org.eclipse.tracecompass.tmf.core.signal.TmfWindowRangeUpdatedSignal;
-import org.eclipse.tracecompass.tmf.core.signal.TmfSignalHandler;
 import org.eclipse.tracecompass.tmf.core.signal.TmfSelectionRangeUpdatedSignal;
+import org.eclipse.tracecompass.tmf.core.signal.TmfSignalHandler;
 import org.eclipse.tracecompass.tmf.core.signal.TmfTimestampFormatUpdateSignal;
 import org.eclipse.tracecompass.tmf.core.signal.TmfTraceClosedSignal;
 import org.eclipse.tracecompass.tmf.core.signal.TmfTraceOpenedSignal;
 import org.eclipse.tracecompass.tmf.core.signal.TmfTraceSelectedSignal;
+import org.eclipse.tracecompass.tmf.core.signal.TmfWindowRangeUpdatedSignal;
 import org.eclipse.tracecompass.tmf.core.timestamp.ITmfTimestamp;
 import org.eclipse.tracecompass.tmf.core.timestamp.TmfNanoTimestamp;
 import org.eclipse.tracecompass.tmf.core.timestamp.TmfTimeRange;
@@ -58,6 +58,8 @@ import org.eclipse.tracecompass.tmf.core.trace.ITmfTrace;
 import org.eclipse.tracecompass.tmf.core.trace.TmfTraceContext;
 import org.eclipse.tracecompass.tmf.core.trace.TmfTraceManager;
 import org.eclipse.tracecompass.tmf.ui.TmfUiRefreshHandler;
+import org.eclipse.tracecompass.tmf.ui.signal.TmfTimeViewAlignmentInfo;
+import org.eclipse.tracecompass.tmf.ui.views.ITmfTimeAligned;
 import org.eclipse.tracecompass.tmf.ui.views.TmfView;
 import org.eclipse.tracecompass.tmf.ui.widgets.timegraph.ITimeGraphContentProvider;
 import org.eclipse.tracecompass.tmf.ui.widgets.timegraph.ITimeGraphPresentationProvider2;
@@ -83,7 +85,7 @@ import org.eclipse.ui.IActionBars;
  * This view contains either a time graph viewer, or a time graph combo which is
  * divided between a tree viewer on the left and a time graph viewer on the right.
  */
-public abstract class AbstractTimeGraphView extends TmfView {
+public abstract class AbstractTimeGraphView extends TmfView implements ITmfTimeAligned {
 
     /** Constant indicating that all levels of the time graph should be expanded */
     protected static final int ALL_LEVELS = AbstractTreeViewer.ALL_LEVELS;
@@ -197,6 +199,11 @@ public abstract class AbstractTimeGraphView extends TmfView {
 
         void setAutoExpandLevel(int level);
 
+        void performAlign(int offset, int width);
+
+        TmfTimeViewAlignmentInfo getTimeViewAlignmentInfo();
+
+        int getAvailableWidth(int requestedOffset);
     }
 
     private class TimeGraphViewerWrapper implements ITimeGraphWrapper {
@@ -265,6 +272,21 @@ public abstract class AbstractTimeGraphView extends TmfView {
         public void setAutoExpandLevel(int level) {
             viewer.setAutoExpandLevel(level);
         }
+
+        @Override
+        public void performAlign(int offset, int width) {
+            viewer.performAlign(offset, width);
+        }
+
+        @Override
+        public TmfTimeViewAlignmentInfo getTimeViewAlignmentInfo() {
+            return viewer.getTimeViewAlignmentInfo();
+        }
+
+        @Override
+        public int getAvailableWidth(int requestedOffset) {
+            return viewer.getAvailableWidth(requestedOffset);
+        }
     }
 
     private class TimeGraphComboWrapper implements ITimeGraphWrapper {
@@ -345,6 +367,21 @@ public abstract class AbstractTimeGraphView extends TmfView {
         IAction getShowFilterAction() {
             return combo.getShowFilterAction();
         }
+
+        @Override
+        public void performAlign(int offset, int width) {
+            combo.performAlign(offset, width);
+        }
+
+        @Override
+        public TmfTimeViewAlignmentInfo getTimeViewAlignmentInfo() {
+            return combo.getTimeViewAlignmentInfo();
+        }
+
+        @Override
+        public int getAvailableWidth(int requestedOffset) {
+            return combo.getAvailableWidth(requestedOffset);
+        }
     }
 
     /**
@@ -810,6 +847,7 @@ public abstract class AbstractTimeGraphView extends TmfView {
 
     @Override
     public void createPartControl(Composite parent) {
+        super.createPartControl(parent);
         if (fColumns == null || fLabelProvider == null) {
             fTimeGraphWrapper = new TimeGraphViewerWrapper(parent, SWT.NONE);
             TimeGraphViewer viewer = fTimeGraphWrapper.getTimeGraphViewer();
@@ -1259,4 +1297,36 @@ public abstract class AbstractTimeGraphView extends TmfView {
         manager.add(fTimeGraphWrapper.getTimeGraphViewer().getZoomOutAction());
         manager.add(new Separator());
     }
+
+    /**
+     * @since 1.0
+     */
+    @Override
+    public TmfTimeViewAlignmentInfo getTimeViewAlignmentInfo() {
+        if (fTimeGraphWrapper == null) {
+            return null;
+        }
+        return fTimeGraphWrapper.getTimeViewAlignmentInfo();
+    }
+
+    /**
+     * @since 1.0
+     */
+    @Override
+    public int getAvailableWidth(int requestedOffset) {
+        if (fTimeGraphWrapper == null) {
+            return 0;
+        }
+        return fTimeGraphWrapper.getAvailableWidth(requestedOffset);
+    }
+
+    /**
+     * @since 1.0
+     */
+    @Override
+    public void performAlign(int offset, int width) {
+        if (fTimeGraphWrapper != null) {
+            fTimeGraphWrapper.performAlign(offset, width);
+        }
+    }
 }
index 46345a2c9661ef79a9bc5d6832db08a04f98ea30..7a4907cf1b560a4fa644e4c34a6e5b4889b2804c 100644 (file)
@@ -1,5 +1,5 @@
 /*******************************************************************************
- * Copyright (c) 2012, 2014 Ericsson, others
+ * Copyright (c) 2012, 2015 Ericsson, others
  *
  * All rights reserved. This program and the accompanying materials are
  * made available under the terms of the Eclipse Public License v1.0 which
@@ -53,10 +53,13 @@ import org.eclipse.swt.graphics.Image;
 import org.eclipse.swt.graphics.Point;
 import org.eclipse.swt.graphics.Rectangle;
 import org.eclipse.swt.layout.FillLayout;
+import org.eclipse.swt.layout.GridLayout;
 import org.eclipse.swt.widgets.Composite;
+import org.eclipse.swt.widgets.Control;
 import org.eclipse.swt.widgets.Display;
 import org.eclipse.swt.widgets.Event;
 import org.eclipse.swt.widgets.Listener;
+import org.eclipse.swt.widgets.Sash;
 import org.eclipse.swt.widgets.Slider;
 import org.eclipse.swt.widgets.Tree;
 import org.eclipse.swt.widgets.TreeColumn;
@@ -64,6 +67,10 @@ import org.eclipse.swt.widgets.TreeItem;
 import org.eclipse.tracecompass.internal.tmf.ui.Activator;
 import org.eclipse.tracecompass.internal.tmf.ui.ITmfImageConstants;
 import org.eclipse.tracecompass.internal.tmf.ui.Messages;
+import org.eclipse.tracecompass.tmf.core.signal.TmfSignalManager;
+import org.eclipse.tracecompass.tmf.ui.signal.TmfTimeViewAlignmentInfo;
+import org.eclipse.tracecompass.tmf.ui.signal.TmfTimeViewAlignmentSignal;
+import org.eclipse.tracecompass.tmf.ui.views.ITmfTimeAligned;
 import org.eclipse.tracecompass.tmf.ui.widgets.timegraph.dialogs.ITimeGraphEntryActiveProvider;
 import org.eclipse.tracecompass.tmf.ui.widgets.timegraph.dialogs.TimeGraphFilterDialog;
 import org.eclipse.tracecompass.tmf.ui.widgets.timegraph.model.ILinkEvent;
@@ -131,6 +138,9 @@ public class TimeGraphCombo extends Composite {
     /** List of all expanded items whose parents are also expanded */
     private List<TreeItem> fVisibleExpandedItems = null;
 
+    private Listener fSashDragListener;
+    private SashForm fSashForm;
+
     // ------------------------------------------------------------------------
     // Classes
     // ------------------------------------------------------------------------
@@ -358,21 +368,21 @@ public class TimeGraphCombo extends Composite {
      * @param style
      *            the style of widget to construct
      * @param weights
-     *            The relative weights of each side of the sash form
+     *            The array (length 2) of relative weights of each side of the sash form
      */
     public TimeGraphCombo(Composite parent, int style, int[] weights) {
         super(parent, style);
         setLayout(new FillLayout());
 
-        final SashForm sash = new SashForm(this, SWT.NONE);
+        fSashForm = new SashForm(this, SWT.NONE);
 
-        fTreeViewer = new TreeViewer(sash, SWT.FULL_SELECTION | SWT.H_SCROLL);
+        fTreeViewer = new TreeViewer(fSashForm, SWT.FULL_SELECTION | SWT.H_SCROLL);
         fTreeViewer.setAutoExpandLevel(AbstractTreeViewer.ALL_LEVELS);
         final Tree tree = fTreeViewer.getTree();
         tree.setHeaderVisible(true);
         tree.setLinesVisible(true);
 
-        fTimeGraphViewer = new TimeGraphViewer(sash, SWT.NONE);
+        fTimeGraphViewer = new TimeGraphViewer(fSashForm, SWT.NONE);
         fTimeGraphViewer.setItemHeight(getItemHeight(tree));
         fTimeGraphViewer.setHeaderHeight(tree.getHeaderHeight());
         fTimeGraphViewer.setBorderWidth(tree.getBorderWidth());
@@ -619,7 +629,37 @@ public class TimeGraphCombo extends Composite {
         // to a value that would cause blank space to be drawn at the bottom of the tree.
         fNumFillerRows = Display.getDefault().getBounds().height / getItemHeight(tree);
 
-        sash.setWeights(weights);
+        fSashForm.setWeights(weights);
+
+        fTimeGraphViewer.getTimeGraphControl().addPaintListener(new PaintListener() {
+            @Override
+            public void paintControl(PaintEvent e) {
+                // Sashes in a SashForm are being created on layout so add the
+                // drag listener here
+                if (fSashDragListener == null) {
+                    for (Control control : fSashForm.getChildren()) {
+                        if (control instanceof Sash) {
+                            fSashDragListener = new Listener() {
+
+                                @Override
+                                public void handleEvent(Event event) {
+                                    sendTimeViewAlignmentChanged();
+
+                                }
+                            };
+                            control.removePaintListener(this);
+                            control.addListener(SWT.Selection, fSashDragListener);
+                            // There should be only one sash
+                            break;
+                        }
+                    }
+                }
+            }
+        });
+    }
+
+    private void sendTimeViewAlignmentChanged() {
+        TmfSignalManager.dispatchSignal(new TmfTimeViewAlignmentSignal(fSashForm, getTimeViewAlignmentInfo()));
     }
 
     // ------------------------------------------------------------------------
@@ -1134,4 +1174,64 @@ public class TimeGraphCombo extends Composite {
         }
     }
 
+    /**
+     * Return the time alignment information
+     *
+     * @return the time alignment information
+     *
+     * @see ITmfTimeAligned
+     *
+     * @since 1.0
+     */
+    public TmfTimeViewAlignmentInfo getTimeViewAlignmentInfo() {
+        int[] weights = fSashForm.getWeights();
+        int leftWidth = (int) (((float) weights[0] / (weights[0] + weights[1])) * fSashForm.getBounds().width) + fSashForm.getSashWidth();
+        Point location = fSashForm.toDisplay(0, 0);
+        return new TmfTimeViewAlignmentInfo(fSashForm.getShell(), location, leftWidth);
+    }
+
+    /**
+     * Return the available width for the time-axis.
+     *
+     * @see ITmfTimeAligned
+     *
+     * @param requestedOffset
+     *            the requested offset
+     * @return the available width for the time-axis
+     *
+     * @since 1.0
+     */
+    public int getAvailableWidth(int requestedOffset) {
+        int totalWidth = fSashForm.getBounds().width;
+        int timeWidth = totalWidth - requestedOffset;
+        return timeWidth;
+    }
+
+    /**
+     * Perform the alignment operation.
+     *
+     * @param offset
+     *            the alignment offset
+     * @param width
+     *            the alignment width
+     *
+     * @see ITmfTimeAligned
+     *
+     * @since 1.0
+     */
+    public void performAlign(int offset, int width) {
+        int total = fSashForm.getBounds().width;
+        int timeAxisOffset = Math.min(offset, total);
+        int sash1Width = (int) (timeAxisOffset / (float) total * 1000);
+        int sash2Width = (int) ((total - timeAxisOffset) / (float) total * 1000);
+        fSashForm.setWeights(new int[] { sash1Width, sash2Width });
+        fSashForm.layout();
+
+        Composite composite = fTimeGraphViewer.getTimeAlignedComposite();
+        GridLayout layout = (GridLayout) composite.getLayout();
+        int timeBasedControlsWidth = composite.getSize().x;
+        int marginSize = timeBasedControlsWidth - width;
+        layout.marginRight = Math.max(0, marginSize);
+        composite.layout();
+    }
 }
index 919627a7e25d54731ee8dbd59476d696f0622733..8fadb7a30cc78e0bbed45e6ebf593dd35f3a9871 100644 (file)
@@ -49,6 +49,8 @@ import org.eclipse.swt.widgets.Slider;
 import org.eclipse.tracecompass.internal.tmf.ui.Activator;
 import org.eclipse.tracecompass.internal.tmf.ui.ITmfImageConstants;
 import org.eclipse.tracecompass.internal.tmf.ui.Messages;
+import org.eclipse.tracecompass.tmf.ui.signal.TmfTimeViewAlignmentInfo;
+import org.eclipse.tracecompass.tmf.ui.views.ITmfTimeAligned;
 import org.eclipse.tracecompass.tmf.ui.widgets.timegraph.dialogs.TimeGraphLegend;
 import org.eclipse.tracecompass.tmf.ui.widgets.timegraph.model.ILinkEvent;
 import org.eclipse.tracecompass.tmf.ui.widgets.timegraph.model.ITimeEvent;
@@ -137,6 +139,8 @@ public class TimeGraphViewer implements ITimeDataProvider, SelectionListener {
     private ListenerNotifier fListenerNotifier;
     private final Object fListenerNotifierLock = new Object();
 
+    private Composite fTimeAlignedComposite;
+
     private class ListenerNotifier extends Thread {
         private static final long DELAY = 400L;
         private static final long POLLING_INTERVAL = 10L;
@@ -365,7 +369,22 @@ public class TimeGraphViewer implements ITimeDataProvider, SelectionListener {
         gl.horizontalSpacing = 0;
         fDataViewer.setLayout(gl);
 
-        fTimeScaleCtrl = new TimeGraphScale(fDataViewer, fColorScheme);
+        fTimeAlignedComposite = new Composite(fDataViewer, style) {
+            @Override
+            public void redraw() {
+                fDataViewer.redraw();
+                super.redraw();
+            }
+        };
+        GridLayout gl2 = new GridLayout(1, false);
+        gl2.marginHeight = fBorderWidth;
+        gl2.marginWidth = 0;
+        gl2.verticalSpacing = 0;
+        gl2.horizontalSpacing = 0;
+        fTimeAlignedComposite.setLayout(gl2);
+        fTimeAlignedComposite.setLayoutData(new GridData(SWT.FILL, SWT.FILL, true, true));
+
+        fTimeScaleCtrl = new TimeGraphScale(fTimeAlignedComposite, fColorScheme);
         fTimeScaleCtrl.setTimeProvider(fTimeDataProvider);
         fTimeScaleCtrl.setLayoutData(new GridData(SWT.FILL, SWT.DEFAULT, true, false));
         fTimeScaleCtrl.setHeight(fTimeScaleHeight);
@@ -376,16 +395,7 @@ public class TimeGraphViewer implements ITimeDataProvider, SelectionListener {
             }
         });
 
-        fVerticalScrollBar = new Slider(fDataViewer, SWT.VERTICAL | SWT.NO_FOCUS);
-        fVerticalScrollBar.setLayoutData(new GridData(SWT.DEFAULT, SWT.FILL, false, true, 1, 2));
-        fVerticalScrollBar.addSelectionListener(new SelectionAdapter() {
-            @Override
-            public void widgetSelected(SelectionEvent e) {
-                setTopIndex(fVerticalScrollBar.getSelection());
-            }
-        });
-
-        fTimeGraphCtrl = createTimeGraphControl(fDataViewer, fColorScheme);
+        fTimeGraphCtrl = createTimeGraphControl(fTimeAlignedComposite, fColorScheme);
 
         fTimeGraphCtrl.setTimeProvider(this);
         fTimeGraphCtrl.setTimeGraphScale(fTimeScaleCtrl);
@@ -409,6 +419,15 @@ public class TimeGraphViewer implements ITimeDataProvider, SelectionListener {
             }
         });
 
+        fVerticalScrollBar = new Slider(fDataViewer, SWT.VERTICAL | SWT.NO_FOCUS);
+        fVerticalScrollBar.setLayoutData(new GridData(SWT.DEFAULT, SWT.FILL, false, true, 1, 1));
+        fVerticalScrollBar.addSelectionListener(new SelectionAdapter() {
+            @Override
+            public void widgetSelected(SelectionEvent e) {
+                setTopIndex(fVerticalScrollBar.getSelection());
+            }
+        });
+
         fHorizontalScrollBar = new Slider(fDataViewer, SWT.HORIZONTAL | SWT.NO_FOCUS);
         fHorizontalScrollBar.setLayoutData(new GridData(SWT.FILL, SWT.DEFAULT, true, false));
         fHorizontalScrollBar.addListener(SWT.MouseWheel, new Listener() {
@@ -1277,6 +1296,17 @@ public class TimeGraphViewer implements ITimeDataProvider, SelectionListener {
         return fTimeScaleCtrl;
     }
 
+    /**
+     * Returns the composite containing all the controls that are time aligned,
+     * i.e. TimeGraphScale, TimeGraphControl.
+     *
+     * @return the time based composite
+     * @since 1.0
+     */
+    public Composite getTimeAlignedComposite() {
+        return fTimeAlignedComposite;
+    }
+
     /**
      * Return the x coordinate corresponding to a time
      *
@@ -1802,4 +1832,54 @@ public class TimeGraphViewer implements ITimeDataProvider, SelectionListener {
         refresh();
     }
 
+    /**
+     * Return the time alignment information
+     *
+     * @return the time alignment information
+     *
+     * @see ITmfTimeAligned
+     *
+     * @since 1.0
+     */
+    public TmfTimeViewAlignmentInfo getTimeViewAlignmentInfo() {
+        return fTimeGraphCtrl.getTimeViewAlignmentInfo();
+    }
+
+    /**
+     * Return the available width for the time-axis.
+     *
+     * @see ITmfTimeAligned
+     *
+     * @param requestedOffset
+     *            the requested offset
+     * @return the available width for the time-axis
+     *
+     * @since 1.0
+     */
+    public int getAvailableWidth(int requestedOffset) {
+        return fTimeAlignedComposite.getSize().x - requestedOffset;
+    }
+
+    /**
+     * Perform the alignment operation.
+     *
+     * @param offset
+     *            the alignment offset
+     * @param width
+     *            the alignment width
+     *
+     * @see ITmfTimeAligned
+     *
+     * @since 1.0
+     */
+    public void performAlign(int offset, int width) {
+        fTimeGraphCtrl.performAlign(offset);
+        int alignmentWidth = width;
+        int size = fTimeAlignedComposite.getSize().x;
+        GridLayout layout = (GridLayout) fTimeAlignedComposite.getLayout();
+        int marginSize = size - alignmentWidth - offset;
+        layout.marginRight = Math.max(0, marginSize);
+        fTimeAlignedComposite.layout();
+    }
+
 }
index 35d77bfd46e2d1f0714a04fcc2c9d3a696a5d490..052997c5fe9988016fed09088019440dcaf9530c 100644 (file)
@@ -63,6 +63,10 @@ import org.eclipse.swt.widgets.Composite;
 import org.eclipse.swt.widgets.Display;
 import org.eclipse.swt.widgets.Event;
 import org.eclipse.swt.widgets.Listener;
+import org.eclipse.tracecompass.tmf.core.signal.TmfSignalManager;
+import org.eclipse.tracecompass.tmf.ui.signal.TmfTimeViewAlignmentInfo;
+import org.eclipse.tracecompass.tmf.ui.signal.TmfTimeViewAlignmentSignal;
+import org.eclipse.tracecompass.tmf.ui.views.ITmfTimeAligned;
 import org.eclipse.tracecompass.tmf.ui.widgets.timegraph.ITimeGraphColorListener;
 import org.eclipse.tracecompass.tmf.ui.widgets.timegraph.ITimeGraphPresentationProvider;
 import org.eclipse.tracecompass.tmf.ui.widgets.timegraph.ITimeGraphPresentationProvider2;
@@ -2002,6 +2006,7 @@ public class TimeGraphControl extends TimeGraphBaseControl
         } else if (DRAG_SPLIT_LINE == fDragState) {
             fDragX = e.x;
             fTimeProvider.setNameSpace(e.x);
+            TmfSignalManager.dispatchSignal(new TmfTimeViewAlignmentSignal(this, getTimeViewAlignmentInfo()));
         } else if (DRAG_SELECTION == fDragState) {
             fDragX = Math.min(Math.max(e.x, fTimeProvider.getNameSpace()), size.x - RIGHT_MARGIN);
             redraw();
@@ -2035,6 +2040,7 @@ public class TimeGraphControl extends TimeGraphBaseControl
                     redraw();
                 }
                 fMouseOverSplitLine = mouseOverSplitLine;
+                TmfSignalManager.dispatchSignal(new TmfTimeViewAlignmentSignal(this, getTimeViewAlignmentInfo()));
                 return;
             }
             int idx = getItemIndexAtY(e.y);
@@ -2630,6 +2636,32 @@ public class TimeGraphControl extends TimeGraphBaseControl
         }
     }
 
+    /**
+     * Perform the alignment operation.
+     *
+     * @param offset
+     *            the alignment offset
+     *
+     * @see ITmfTimeAligned
+     *
+     * @since 1.0
+     */
+    public void performAlign(int offset) {
+        fTimeProvider.setNameSpace(offset);
+    }
+
+    /**
+     * Return the time alignment information
+     *
+     * @return the time alignment information
+     *
+     * @see ITmfTimeAligned
+     *
+     * @since 1.0
+     */
+    public TmfTimeViewAlignmentInfo getTimeViewAlignmentInfo() {
+        return new TmfTimeViewAlignmentInfo(getShell(), toDisplay(0, 0), fTimeProvider.getNameSpace());
+    }
 }
 
 
This page took 0.063504 seconds and 5 git commands to generate.