### Eclipse Workspace Patch 1.0
#P org.jboss.tools.vpe
Index: src/org/jboss/tools/vpe/editor/VpeController.java
===================================================================
--- src/org/jboss/tools/vpe/editor/VpeController.java	(revision 38024)
+++ src/org/jboss/tools/vpe/editor/VpeController.java	(working copy)
@@ -32,12 +32,14 @@
 import org.eclipse.jface.bindings.keys.KeySequence;
 import org.eclipse.jface.bindings.keys.KeyStroke;
 import org.eclipse.jface.text.BadLocationException;
+import org.eclipse.jface.text.IDocument;
 import org.eclipse.jface.text.ITextSelection;
 import org.eclipse.jface.viewers.ISelection;
 import org.eclipse.jface.viewers.ISelectionChangedListener;
 import org.eclipse.jface.viewers.ISelectionProvider;
 import org.eclipse.jface.viewers.SelectionChangedEvent;
 import org.eclipse.swt.SWT;
+import org.eclipse.swt.browser.Browser;
 import org.eclipse.swt.custom.LineStyleEvent;
 import org.eclipse.swt.custom.LineStyleListener;
 import org.eclipse.swt.custom.StyleRange;
@@ -46,6 +48,10 @@
 import org.eclipse.swt.events.DisposeListener;
 import org.eclipse.swt.events.MenuEvent;
 import org.eclipse.swt.events.MenuListener;
+import org.eclipse.swt.events.MouseEvent;
+import org.eclipse.swt.events.MouseWheelListener;
+import org.eclipse.swt.events.PaintEvent;
+import org.eclipse.swt.events.PaintListener;
 import org.eclipse.swt.events.SelectionEvent;
 import org.eclipse.swt.events.SelectionListener;
 import org.eclipse.swt.graphics.Color;
@@ -56,6 +62,8 @@
 import org.eclipse.swt.widgets.Display;
 import org.eclipse.swt.widgets.Event;
 import org.eclipse.swt.widgets.Menu;
+import org.eclipse.swt.widgets.ScrollBar;
+import org.eclipse.swt.widgets.Scrollable;
 import org.eclipse.swt.widgets.Shell;
 import org.eclipse.ui.IEditorInput;
 import org.eclipse.ui.IFileEditorInput;
@@ -150,17 +158,25 @@
 import org.jboss.tools.vpe.resref.core.RelativeFolderReferenceList;
 import org.jboss.tools.vpe.resref.core.TaglibReferenceList;
 import org.jboss.tools.vpe.xulrunner.editor.XulRunnerEditor;
+import org.mozilla.interfaces.nsIBaseWindow;
 import org.mozilla.interfaces.nsIDOMDocument;
 import org.mozilla.interfaces.nsIDOMElement;
 import org.mozilla.interfaces.nsIDOMEvent;
+import org.mozilla.interfaces.nsIDOMEventListener;
+import org.mozilla.interfaces.nsIDOMEventTarget;
 import org.mozilla.interfaces.nsIDOMKeyEvent;
 import org.mozilla.interfaces.nsIDOMMouseEvent;
 import org.mozilla.interfaces.nsIDOMMutationEvent;
 import org.mozilla.interfaces.nsIDOMNSUIEvent;
 import org.mozilla.interfaces.nsIDOMNode;
+import org.mozilla.interfaces.nsIDOMWindow;
+import org.mozilla.interfaces.nsIDOMWindowInternal;
 import org.mozilla.interfaces.nsISelection;
 import org.mozilla.interfaces.nsISelectionDisplay;
 import org.mozilla.interfaces.nsISelectionListener;
+import org.mozilla.interfaces.nsISupports;
+import org.mozilla.interfaces.nsIWebBrowser;
+import org.mozilla.xpcom.XPCOMException;
 import org.w3c.dom.Attr;
 import org.w3c.dom.Element;
 import org.w3c.dom.Node;
@@ -175,6 +191,17 @@
 		MozillaContextMenuListener, MozillaResizeListener,
 		MozillaAfterPaintListener, MozillaScrollListener {
 
+	/*
+	 * https://issues.jboss.org/browse/JBIDE-8701
+	 * Scroll listeners staff.
+	 */
+	private SelectionListener sourceScrollSelectionListener;
+	private ScrollBar sourceVB;
+	private nsIDOMEventListener visualScrollListener;
+	private nsIDOMEventTarget domEventTarget;
+	private boolean sourceScrollEvent = false;
+	private boolean visualScrollEvent = false;
+	
 	public static final int DEFAULT_UPDATE_DELAY_TIME = 400;
 	private boolean visualEditorVisible = true;
 	private boolean synced = true;
@@ -335,12 +362,98 @@
 		// sourceEditor.getViewerSelectionManager();
 		// selectionManager.addNodeSelectionListener(this);
 		// selectionManager.addTextSelectionListener(this);
-		StyledText textWidget = SelectionHelper
-				.getSourceTextWidget(sourceEditor);
+		final StyledText textWidget = SelectionHelper.getSourceTextWidget(sourceEditor);
 		if (textWidget != null) {
 			textWidget.addSelectionListener(this);
 		}
-
+		/*
+		 * Add ScrollBar Listeners
+		 */
+		if ((visualEditor != null) && (sourceEditor != null)) {
+			sourceVB = textWidget.getVerticalBar();
+			if (sourceVB != null) {
+				if (visualEditor.getXulRunnerEditor() != null) {
+					nsIWebBrowser webBrowser = visualEditor.getXulRunnerEditor().getWebBrowser();
+					if (webBrowser != null) {
+						/*
+						 * Initialize source and visual bars
+						 */
+						final nsIDOMWindow domWindow = webBrowser.getContentDOMWindow();
+						final nsIDOMWindowInternal windowInternal = org.jboss.tools.vpe.xulrunner.util.XPCOM
+								.queryInterface(domWindow, nsIDOMWindowInternal.class);
+						/*
+						 * Adding source listener
+						 */
+						sourceScrollSelectionListener = new SelectionListener() {
+							@Override
+							public void widgetSelected(SelectionEvent e) {
+								if (!visualScrollEvent && !selectionManager.isSetSelectionEvent()) { // ignore my visual scroll event
+									sourceScrollEvent = true;
+									removeVisualScrollListener();
+									ScrollBar sb = (ScrollBar)e.widget;
+									int pageYOffsetSrc = sb.getSelection();
+									int scrollMaxYSrc = sb.getMaximum() - sb.getThumb();
+									float percentsSrc = ((float)pageYOffsetSrc/scrollMaxYSrc);
+									if (getVisualScrollBar() != null) {
+										int scrollMaxYVisual = -1;
+										scrollMaxYVisual = windowInternal.getScrollMaxY();
+										if (scrollMaxYVisual != 0 && scrollMaxYVisual != -1) {
+											// there is a visual scroll bar
+											int posY = ((int) (scrollMaxYVisual*percentsSrc));
+											domWindow.scrollTo(windowInternal.getPageXOffset(),posY);
+										}
+									}
+									addVisualScrollListener();
+								} else {
+									visualScrollEvent = false;
+									selectionManager.setSelectionEvent(false);
+								}
+							}
+							@Override
+							public void widgetDefaultSelected(SelectionEvent e) { }
+						};
+						sourceVB.addSelectionListener(sourceScrollSelectionListener);
+						/*
+						 * Adding visual listener
+						 */
+						visualScrollListener = new nsIDOMEventListener() {
+							public nsISupports queryInterface(String interfaceId) { 
+								return interfaceId.equals(nsIDOMEventListener.NS_IDOMEVENTLISTENER_IID) ? this : null; 
+							}
+							public void handleEvent(nsIDOMEvent event) {
+								if (!sourceScrollEvent && !selectionManager.isSetSelectionEvent()) { // ignore my event from source
+									visualScrollEvent = true;
+									removeSourceScrollListener();
+									nsIDOMWindowInternal windowInternal = org.jboss.tools.vpe.xulrunner.util.XPCOM
+											.queryInterface(domWindow, nsIDOMWindowInternal.class); 
+									int pageYOffsetVisual = windowInternal.getPageYOffset();
+									int scrollMaxYVisual = windowInternal.getScrollMaxY();
+									float percentsVisual = ((float)pageYOffsetVisual/scrollMaxYVisual);
+									ScrollBar sb = getSourceScrollBar();
+									if ((sb != null) && (sb.getMaximum() != 1)) {
+										int srcLinesCount = -1;
+										srcLinesCount = textWidget.getLineCount();
+										// there is a source scroll bar
+										int posLines = ((int) (srcLinesCount*percentsVisual));
+										textWidget.setTopIndex(posLines);
+									}
+									addSourceScrollListener();
+								} else {
+									sourceScrollEvent = false;
+									selectionManager.setSelectionEvent(false);
+								}
+							}
+						};
+						try {
+							domEventTarget = queryInterface(domWindow, nsIDOMEventTarget.class);
+							domEventTarget.addEventListener("scroll", visualScrollListener, false); //$NON-NLS-1$
+						} catch (XPCOMException e) {
+							VpePlugin.getDefault().logError(e);
+						}
+					}
+				}
+			}
+		}
 		registerEventTargets();
 
 		if (optionsListener == null) {
@@ -378,6 +491,38 @@
 		refreshCommands();
 	}
 
+	private ScrollBar getSourceScrollBar() {
+		return sourceVB;
+	}
+	
+	private nsIDOMEventTarget getVisualScrollBar() {
+		return domEventTarget;
+	}
+	
+	private void removeSourceScrollListener() {
+		if (sourceVB != null && sourceScrollSelectionListener != null) {
+			sourceVB.removeSelectionListener(sourceScrollSelectionListener);
+		}
+	}
+
+	private void addSourceScrollListener() {
+		if (sourceVB != null && sourceScrollSelectionListener != null) {
+			sourceVB.addSelectionListener(sourceScrollSelectionListener);
+		}
+	}
+	
+	private void removeVisualScrollListener() {
+		if (domEventTarget != null && visualScrollListener != null) {
+			domEventTarget.removeEventListener("scroll", visualScrollListener, false);
+		}
+	}
+	
+	private void addVisualScrollListener() {
+		if (domEventTarget != null && visualScrollListener != null) {
+			domEventTarget.addEventListener("scroll", visualScrollListener, false);
+		}
+	}
+
 	public void dispose() {
 		if (job != null) {
 			job.cancel();
@@ -958,8 +1103,8 @@
 		}
 		onRefresh();
 	}
-
 
+
 	public boolean isKeyBinding(Event keyboardEvent) {
 		boolean keyBindingPressed = false;
 		List<KeyStroke> possibleKeyStrokes = WorkbenchKeyboard
@@ -1064,6 +1209,7 @@
 		if (uiJob != null && uiJob.getState() != Job.NONE) {
 			return;
 		}
+
 		if (visualRefreshJob == null || visualRefreshJob.getState() == Job.NONE) {
 			visualRefreshJob = new UIJob(VpeUIMessages.VPE_VISUAL_REFRESH_JOB) {
 				@Override
@@ -1768,10 +1914,10 @@
 
 	public void setZoomEventManager(IZoomEventManager zoomEventManager) {
 		this.zoomEventManager = zoomEventManager;
-	}
+	}
 
-
 
+
 	public VpeDropWindow getDropWindow() {
 		return dropWindow;
 	}
